MythTV master
housekeeper.cpp
Go to the documentation of this file.
1/* -*- Mode: c++ -*-
2*
3* Class HouseKeeperTask
4* Class HouseKeeperThread
5* Class HouseKeeper
6*
7* Copyright (C) Raymond Wagner 2013
8*
9* This program is free software; you can redistribute it and/or modify
10* it under the terms of the GNU General Public License as published by
11* the Free Software Foundation; either version 2 of the License, or
12* (at your option) any later version.
13*
14* This program is distributed in the hope that it will be useful,
15* but WITHOUT ANY WARRANTY; without even the implied warranty of
16* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17* GNU General Public License for more details.
18*
19* You should have received a copy of the GNU General Public License
20* along with this program; if not, write to the Free Software
21* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22*/
23
24
25
52#include <chrono>
53#include <utility>
54
55#include <QMutexLocker>
56
57#include "mythevent.h"
58#include "mythdbcon.h"
59#include "housekeeper.h"
60#include "mythcorecontext.h"
61#include "mythlogging.h"
62#include "mythrandom.h"
63
102 ReferenceCounter(dbTag), m_dbTag(dbTag), m_scope(scope),
103 m_startup(startup),
104 m_lastRun(MythDate::fromSecsSinceEpoch(0)),
105 m_lastSuccess(MythDate::fromSecsSinceEpoch(0)),
106 m_lastUpdate(MythDate::fromSecsSinceEpoch(0))
107{
108}
109
110bool HouseKeeperTask::CheckRun(const QDateTime& now)
111{
112 bool check = false;
113 if (!m_confirm && !m_running)
114 {
115 check = DoCheckRun(now);
116 if (check)
117 {
118 // if m_confirm is already set, the task is already in the queue
119 // and should not be queued a second time
120 m_confirm = true;
121 }
122 }
123 LOG(VB_GENERAL, LOG_DEBUG, QString("%1 Running? %2/In window? %3.")
124 .arg(GetTag(), m_running ? "Yes" : "No", check ? "Yes" : "No"));
125 return check;
126}
127
129{
130 return ((m_startup == kHKRunImmediateOnStartup) &&
132}
133
135{
137 {
138 m_confirm = true;
139 return true;
140 }
141 return false;
142}
143
145{
146 LOG(VB_GENERAL, LOG_INFO, QString("Running HouseKeeperTask '%1'.")
147 .arg(m_dbTag));
148 if (m_running)
149 {
150 // something else is already running me, bail out
151 LOG(VB_GENERAL, LOG_WARNING, QString("HouseKeeperTask '%1' already "
152 "running. Refusing to run concurrently").arg(m_dbTag));
153 return false;
154 }
155
156 m_running = true;
157 bool res = DoRun();
158 m_running = false;
159 if (!res)
160 {
161 LOG(VB_GENERAL, LOG_INFO, QString("HouseKeeperTask '%1' Failed.")
162 .arg(m_dbTag));
163 }
164 else
165 {
166 LOG(VB_GENERAL, LOG_INFO,
167 QString("HouseKeeperTask '%1' Finished Successfully.")
168 .arg(m_dbTag));
169 }
170 return res;
171}
172
174{
175 QueryLast();
176 return m_lastRun;
177}
178
180{
181 QueryLast();
182 return m_lastRun;
183}
184
186{
187 if (m_scope != kHKInst)
188 {
189 if (m_lastUpdate.addSecs(30) > MythDate::current())
190 // just to cut down on unnecessary queries
191 return;
192
194
197
198 if (m_scope == kHKGlobal)
199 {
200 query.prepare("SELECT lastrun,lastsuccess FROM housekeeping"
201 " WHERE tag = :TAG"
202 " AND hostname IS NULL");
203 }
204 else
205 {
206 query.prepare("SELECT lastrun,lastsuccess FROM housekeeping"
207 " WHERE tag = :TAG"
208 " AND hostname = :HOST");
209 query.bindValue(":HOST", gCoreContext->GetHostName());
210 }
211
212 query.bindValue(":TAG", m_dbTag);
213
214 if (query.exec() && query.next())
215 {
216 m_lastRun = MythDate::as_utc(query.value(0).toDateTime());
217 m_lastSuccess = MythDate::as_utc(query.value(1).toDateTime());
218 }
219 }
220
222}
223
224QDateTime HouseKeeperTask::UpdateLastRun(const QDateTime& last, bool successful)
225{
226 m_lastRun = last;
227 if (successful)
228 m_lastSuccess = last;
229 m_confirm = false;
230
231 if (m_scope != kHKInst)
232 {
234 if (!query.isConnected())
235 return last;
236
237 if (m_scope == kHKGlobal)
238 {
239 query.prepare("UPDATE `housekeeping` SET `lastrun`=:TIME,"
240 " `lastsuccess`=:STIME"
241 " WHERE `tag` = :TAG"
242 " AND `hostname` IS NULL");
243 }
244 else
245 {
246 query.prepare("UPDATE `housekeeping` SET `lastrun`=:TIME,"
247 " `lastsuccess`=:STIME"
248 " WHERE `tag` = :TAG"
249 " AND `hostname` = :HOST");
250 }
251
252 if (m_scope == kHKLocal)
253 query.bindValue(":HOST", gCoreContext->GetHostName());
254 query.bindValue(":TAG", m_dbTag);
255 query.bindValue(":TIME", MythDate::as_utc(m_lastRun));
256 query.bindValue(":STIME", MythDate::as_utc(m_lastSuccess));
257
258 if (!query.exec())
259 MythDB::DBError("HouseKeeperTask::updateLastRun, UPDATE", query);
260
261 if (VERBOSE_LEVEL_CHECK(VB_GENERAL, LOG_DEBUG) &&
262 query.numRowsAffected() > 0)
263 {
264 LOG(VB_GENERAL, LOG_DEBUG, QString("%1: UPDATEd %2 run time.")
265 .arg(m_dbTag, m_scope == kHKGlobal ? "global" : "local"));
266 }
267
268 if (query.numRowsAffected() == 0)
269 {
270 if (m_scope == kHKGlobal)
271 {
272 query.prepare("INSERT INTO `housekeeping`"
273 " (`tag`, `lastrun`, `lastsuccess`)"
274 " VALUES (:TAG, :TIME, :STIME)");
275 }
276 else
277 {
278 query.prepare("INSERT INTO `housekeeping`"
279 " (`tag`, `hostname`, `lastrun`, `lastsuccess`)"
280 " VALUES (:TAG, :HOST, :TIME, :STIME)");
281 }
282
283 if (m_scope == kHKLocal)
284 query.bindValue(":HOST", gCoreContext->GetHostName());
285 query.bindValue(":TAG", m_dbTag);
286 query.bindValue(":TIME", MythDate::as_utc(m_lastRun));
287 query.bindValue(":STIME", MythDate::as_utc(m_lastSuccess));
288
289 if (!query.exec())
290 MythDB::DBError("HouseKeeperTask::updateLastRun INSERT", query);
291
292 LOG(VB_GENERAL, LOG_DEBUG, QString("%1: INSERTed %2 run time.")
293 .arg(m_dbTag, m_scope == kHKGlobal ? "global" : "local"));
294 }
295 }
296
297 QString msg;
298 if (successful)
299 msg = QString("HOUSE_KEEPER_SUCCESSFUL %1 %2 %3");
300 else
301 msg = QString("HOUSE_KEEPER_RUNNING %1 %2 %3");
302 msg = msg.arg(gCoreContext->GetHostName(),
303 m_dbTag,
307
308 return last;
309}
310
311void HouseKeeperTask::SetLastRun(const QDateTime &last, bool successful)
312{
313 m_lastRun = last;
314 if (successful)
315 m_lastSuccess = last;
316
318}
319
334 std::chrono::seconds period, float min, float max, std::chrono::seconds retry,
336 HouseKeeperTask(dbTag, scope, startup), m_period(period), m_retry(retry),
337 m_windowPercent(min, max)
338{
340 if (m_retry == 0s)
342}
343
345{
346 std::chrono::seconds period = m_period;
347 if (GetLastRun() > GetLastSuccess())
348 {
349 // last attempt was not successful
350 // try shortened period
351 period = m_retry;
352 }
353
354 m_windowElapsed.first = chronomult(period, m_windowPercent.first);
355 m_windowElapsed.second = chronomult(period, m_windowPercent.second);
356}
357
358void PeriodicHouseKeeperTask::SetWindow(float min, float max)
359{
360 m_windowPercent.first = min;
361 m_windowPercent.second = max;
363}
364
365QDateTime PeriodicHouseKeeperTask::UpdateLastRun(const QDateTime& last,
366 bool successful)
367{
368 QDateTime res = HouseKeeperTask::UpdateLastRun(last, successful);
370 m_currentProb = 1.0;
371 return res;
372}
373
374void PeriodicHouseKeeperTask::SetLastRun(const QDateTime& last, bool successful)
375{
376 HouseKeeperTask::SetLastRun(last, successful);
378 m_currentProb = 1.0;
379}
380
381bool PeriodicHouseKeeperTask::DoCheckRun(const QDateTime& now)
382{
383 auto elapsed = std::chrono::seconds(GetLastRun().secsTo(now));
384
385 if (elapsed < 0s)
386 // something bad has happened. let's just move along
387 return false;
388
389 if (elapsed < m_windowElapsed.first)
390 // insufficient time elapsed to test
391 return false;
392 if (elapsed > m_windowElapsed.second)
393 // too much time has passed. force run
394 return true;
395
396 // calculate probability that task should not have yet run
397 // it's backwards, but it makes the math simplier
398 double prob = 1.0 - (duration_cast<floatsecs>(elapsed - m_windowElapsed.first) /
399 duration_cast<floatsecs>(m_windowElapsed.second - m_windowElapsed.first));
400 if (m_currentProb < prob)
401 // more bad stuff
402 return false;
403
404 // calculate current probability to achieve overall probability
405 // this should be nearly one
406 double prob2 = prob/m_currentProb;
407 // so rand() should have to return nearly RAND_MAX to get a positive
408 // remember, this is computing the probability that up to this point, one
409 // of these tests has returned positive, so each individual test has
410 // a necessarily low probability
411 //
412 bool res = (MythRandom() > (uint32_t)(prob2 * std::numeric_limits<uint32_t>::max()));
413 m_currentProb = prob;
414// if (res)
415// LOG(VB_GENERAL, LOG_DEBUG, QString("%1 will run: this=%2; total=%3")
416// .arg(GetTag()).arg(1-prob2).arg(1-prob));
417// else
418// LOG(VB_GENERAL, LOG_DEBUG, QString("%1 will not run: this=%2; total=%3")
419// .arg(GetTag()).arg(1-prob2).arg(1-prob));
420 return res;
421}
422
423bool PeriodicHouseKeeperTask::InWindow(const QDateTime& now)
424{
425 auto elapsed = std::chrono::seconds(GetLastRun().secsTo(now));
426
427 if (elapsed < 0s)
428 // something bad has happened. let's just move along
429 return false;
430
431 return (elapsed > m_windowElapsed.first) &&
432 (elapsed < m_windowElapsed.second);
433}
434
435bool PeriodicHouseKeeperTask::PastWindow(const QDateTime &now)
436{
437 return std::chrono::seconds(GetLastRun().secsTo(now)) > m_windowElapsed.second;
438}
439
455 PeriodicHouseKeeperTask(dbTag, 24h, .5, 1.5, 0s, scope, startup),
456 m_windowHour(0h, 23h)
457{
459}
460
462 std::chrono::hours minhour, std::chrono::hours maxhour,
464 PeriodicHouseKeeperTask(dbTag, 24h, .5, 1.5, 0s, scope, startup),
465 m_windowHour(minhour, maxhour)
466{
468}
469
471{
473 QDate date = GetLastRun().addDays(1).date();
474
475 QDateTime tmp = QDateTime(date, QTime(m_windowHour.first.count(), 0));
476 if (GetLastRun().addSecs(m_windowElapsed.first.count()) < tmp)
477 m_windowElapsed.first = std::chrono::seconds(GetLastRun().secsTo(tmp));
478
479 tmp = QDateTime(date, QTime(m_windowHour.second.count(), 30));
480 // we want to make sure this gets run before the end of the day
481 // so add a 30 minute buffer prior to the end of the window
482 if (GetLastRun().addSecs(m_windowElapsed.second.count()) > tmp)
483 m_windowElapsed.second = std::chrono::seconds(GetLastRun().secsTo(tmp));
484
485 LOG(VB_GENERAL, LOG_DEBUG, QString("%1 Run window between %2 - %3.")
486 .arg(GetTag()).arg(m_windowElapsed.first.count()).arg(m_windowElapsed.second.count()));
487}
488
489void DailyHouseKeeperTask::SetHourWindow(std::chrono::hours min, std::chrono::hours max)
490{
491 m_windowHour.first = min;
492 m_windowHour.second = max;
494}
495
496bool DailyHouseKeeperTask::InWindow(const QDateTime& now)
497{
499 // parent says we're in the window
500 return true;
501
502 auto hour = std::chrono::hours(now.time().hour());
503 // true if we've missed the window, but we're within our time constraints
504 return PastWindow(now) && (m_windowHour.first <= hour)
505 && (m_windowHour.second > hour);
506}
507
519{
520 RunProlog();
521 m_waitMutex.lock();
522 HouseKeeperTask *task = nullptr;
523
524 while (m_keepRunning)
525 {
526 m_idle = false;
527
528 while ((task = m_parent->GetQueuedTask()))
529 {
530 // pull task from housekeeper and process it
531 ReferenceLocker rlock(task);
532
533 if (!task->ConfirmRun())
534 {
535 // something else has caused the lastrun time to
536 // change since this was requested to run. abort.
537 task = nullptr;
538 continue;
539 }
540
541 task->UpdateLastRun(false);
542 if (task->Run())
543 task->UpdateLastRun(task->GetLastRun(), true);
544 task = nullptr;
545
546 if (!m_keepRunning)
547 // thread has been discarded, don't try to start another task
548 break;
549 }
550
551 m_idle = true;
552
553 if (!m_keepRunning)
554 // short out rather than potentially hitting another sleep cycle
555 break;
556
558 }
559
560 m_waitMutex.unlock();
561 RunEpilog();
562}
563
581 : m_timer(new QTimer(this))
582{
583 connect(m_timer, &QTimer::timeout, this, &HouseKeeper::Run);
584 m_timer->setInterval(1min);
585 m_timer->setSingleShot(false);
586}
587
589{
591
592 if (m_timer)
593 {
594 m_timer->stop();
595 disconnect(m_timer);
596 delete m_timer;
597 m_timer = nullptr;
598 }
599
600 {
601 // remove anything from the queue first, so it does not start
602 QMutexLocker queueLock(&m_queueLock);
603 while (!m_taskQueue.isEmpty())
604 m_taskQueue.takeFirst()->DecrRef();
605 }
606
607 {
608 // issue a terminate call to any long-running tasks
609 // this is just a noop unless overwritten by a subclass
610 QMutexLocker mapLock(&m_mapLock);
611 for (auto *it : std::as_const(m_taskMap))
612 it->Terminate();
613 }
614
615 if (!m_threadList.isEmpty())
616 {
617 QMutexLocker threadLock(&m_threadLock);
618 // tell primary thread to self-terminate and wake it
619 m_threadList.first()->Discard();
620 m_threadList.first()->Wake();
621 // wait for any remaining threads to self-terminate and close
622 while (!m_threadList.isEmpty())
623 {
624 HouseKeepingThread *thread = m_threadList.takeFirst();
625 thread->wait();
626 delete thread;
627 }
628 }
629
630 {
631 // unload any registered tasks
632 QMutexLocker mapLock(&m_mapLock);
633 QMap<QString,HouseKeeperTask*>::iterator it = m_taskMap.begin();
634 while (it != m_taskMap.end())
635 {
636 (*it)->DecrRef();
637 it = m_taskMap.erase(it);
638 }
639 }
640}
641
643{
644 QMutexLocker mapLock(&m_mapLock);
645 QString tag = task->GetTag();
646 if (m_taskMap.contains(tag))
647 {
648 task->DecrRef();
649 LOG(VB_GENERAL, LOG_ERR,
650 QString("HouseKeeperTask '%1' already registered. "
651 "Rejecting duplicate.").arg(tag));
652 }
653 else
654 {
655 LOG(VB_GENERAL, LOG_INFO,
656 QString("Registering HouseKeeperTask '%1'.").arg(tag));
657 m_taskMap.insert(tag, task);
658 }
659}
660
661void HouseKeeper::UnregisterTask(const QString& tag)
662{
663 QMutexLocker mapLock(&m_mapLock);
664 auto it = m_taskMap.find(tag);
665 if (it == m_taskMap.end())
666 {
667 LOG(VB_GENERAL, LOG_ERR,
668 QString("HouseKeeperTask '%1' doesn't exist.").arg(tag));
669 return;
670 }
671
672 delete *it;
673 LOG(VB_GENERAL, LOG_INFO,
674 QString("HouseKeeperTask '%1' destroyed.").arg(tag));
675}
676
678{
679 QMutexLocker queueLock(&m_queueLock);
680 HouseKeeperTask *task = nullptr;
681
682 if (!m_taskQueue.isEmpty())
683 {
684 task = m_taskQueue.dequeue();
685 }
686
687 // returning nullptr tells the thread that the queue is empty and
688 // to go into standby
689 return task;
690}
691
693{
694 // no need to be fine grained, nothing else should be accessing this map
695 QMutexLocker mapLock(&m_mapLock);
696
697 if (m_timer->isActive())
698 // Start() should only be called once
699 return;
700
702 query.prepare("SELECT `tag`,`lastrun`"
703 " FROM `housekeeping`"
704 " WHERE `hostname` = :HOST"
705 " OR `hostname` IS NULL");
706 query.bindValue(":HOST", gCoreContext->GetHostName());
707
708 if (!query.exec())
709 {
710 MythDB::DBError("HouseKeeper::Run", query);
711 }
712 else
713 {
714 while (query.next())
715 {
716 // loop through housekeeping table and load last run timestamps
717 QString tag = query.value(0).toString();
718 QDateTime lastrun = MythDate::as_utc(query.value(1).toDateTime());
719
720 if (m_taskMap.contains(tag))
721 m_taskMap[tag]->SetLastRun(lastrun);
722 }
723 }
724
726
727 for (auto it = m_taskMap.cbegin(); it != m_taskMap.cend(); ++it)
728 {
729 if ((*it)->CheckImmediate())
730 {
731 // run any tasks marked for immediate operation in-thread
732 (*it)->UpdateLastRun();
733 (*it)->Run();
734 }
735 else if ((*it)->CheckStartup())
736 {
737 // queue any tasks marked for startup
738 LOG(VB_GENERAL, LOG_INFO,
739 QString("Queueing HouseKeeperTask '%1'.").arg(it.key()));
740 QMutexLocker queueLock(&m_queueLock);
741 (*it)->IncrRef();
742 m_taskQueue.enqueue(*it);
743 }
744 }
745
746 LOG(VB_GENERAL, LOG_INFO, "Starting HouseKeeper.");
747
748 m_timer->start();
749}
750
752{
753 LOG(VB_GENERAL, LOG_DEBUG, "Running HouseKeeper.");
754
755 QDateTime now = MythDate::current();
756
757 QMutexLocker mapLock(&m_mapLock);
758 // Remove any tasks that have finished
759 for (auto it = m_taskMap.begin(); it != m_taskMap.end(); )
760 {
761 if ((*it)->IsFinished())
762 {
763 LOG(VB_GENERAL, LOG_INFO,
764 QString("Removing finished HouseKeeperTask '%1'.")
765 .arg(it.key()));
766 it = m_taskMap.erase(it);
767 }
768 else
769 {
770 it++;
771 }
772 }
773
774 // check if any tasks are ready to run, and add to queue
775 for (auto it = m_taskMap.begin(); it != m_taskMap.end(); ++it)
776 {
777 if ((*it)->CheckRun(now))
778 {
779 LOG(VB_GENERAL, LOG_INFO,
780 QString("Queueing HouseKeeperTask '%1'.").arg(it.key()));
781 QMutexLocker queueLock(&m_queueLock);
782 (*it)->IncrRef();
783 m_taskQueue.enqueue(*it);
784 }
785 }
786
787 if (!m_taskQueue.isEmpty())
788 StartThread();
789
790 if (m_threadList.size() > 1)
791 {
792 // spent threads exist in the thread list
793 // check to see if any have finished up their task and terminated
794 QMutexLocker threadLock(&m_threadLock);
795 int count1 = m_threadList.size();
796
797 auto it = m_threadList.begin();
798 ++it; // skip the primary thread
799 while (it != m_threadList.end())
800 {
801 if ((*it)->isRunning())
802 {
803 ++it;
804 }
805 else
806 {
807 delete *it;
808 it = m_threadList.erase(it);
809 }
810 }
811
812 int count2 = m_threadList.size();
813 if (count1 > count2)
814 {
815 LOG(VB_GENERAL, LOG_DEBUG,
816 QString("Discarded HouseKeepingThreads have completed and "
817 "been deleted. Current count %1 -> %2.")
818 .arg(count1).arg(count2));
819 }
820 }
821}
822
837{
838 QMutexLocker threadLock(&m_threadLock);
839
840 if (m_threadList.isEmpty())
841 {
842 // we're running for the first time
843 // start up a new thread
844 LOG(VB_GENERAL, LOG_DEBUG, "Running initial HouseKeepingThread.");
845 auto *thread = new HouseKeepingThread(this);
846 m_threadList.append(thread);
847 thread->start();
848 }
849
850 else if (!m_threadList.first()->isIdle())
851 {
852 // the old thread is still off processing something
853 // discard it and start a new one because we have more stuff
854 // that wants to run
855 LOG(VB_GENERAL, LOG_DEBUG,
856 QString("Current HouseKeepingThread is delayed on task, "
857 "spawning replacement. Current count %1.")
858 .arg(m_threadList.size()));
859 m_threadList.first()->Discard();
860 auto *thread = new HouseKeepingThread(this);
861 m_threadList.prepend(thread);
862 thread->start();
863 }
864
865 else
866 {
867 // the old thread is idle, so just wake it for processing
868 LOG(VB_GENERAL, LOG_DEBUG, "Waking HouseKeepingThread.");
869 m_threadList.first()->Wake();
870 }
871}
872
874{
875 if (e->type() == MythEvent::kMythEventMessage)
876 {
877 auto *me = dynamic_cast<MythEvent*>(e);
878 if (me == nullptr)
879 return;
880 if ((me->Message().left(20) == "HOUSE_KEEPER_RUNNING") ||
881 (me->Message().left(23) == "HOUSE_KEEPER_SUCCESSFUL"))
882 {
883 QStringList tokens = me->Message()
884 .split(" ", Qt::SkipEmptyParts);
885 if (tokens.size() != 4)
886 return;
887
888 const QString& hostname = tokens[1];
889 const QString& tag = tokens[2];
890 QDateTime last = MythDate::fromString(tokens[3]);
891 bool successful = me->Message().contains("SUCCESSFUL");
892
893 QMutexLocker mapLock(&m_mapLock);
894 if (m_taskMap.contains(tag))
895 {
896 if ((m_taskMap[tag]->GetScope() == kHKGlobal) ||
897 ((m_taskMap[tag]->GetScope() == kHKLocal) &&
899 {
900 // task being run in the same scope as us.
901 // update the run time so we don't attempt to run
902 // it ourselves
903 m_taskMap[tag]->SetLastRun(last, successful);
904 }
905 }
906 }
907 }
908}
909
911{
912 GetMythDB()->GetDBManager()->PurgeIdleConnections(false);
913 return true;
914}
bool DoRun(void) override
DailyHouseKeeperTask(const QString &dbTag, HouseKeeperScope scope=kHKGlobal, HouseKeeperStartup startup=kHKNormal)
virtual void SetHourWindow(std::chrono::hours min, std::chrono::hours max)
bool InWindow(const QDateTime &now) override
QPair< std::chrono::hours, std::chrono::hours > m_windowHour
Definition: housekeeper.h:128
void CalculateWindow(void) override
Definition for a single task to be run by the HouseKeeper.
Definition: housekeeper.h:41
QDateTime QueryLastSuccess(void)
virtual bool DoRun(void)
Definition: housekeeper.h:69
HouseKeeperScope m_scope
Definition: housekeeper.h:79
QDateTime m_lastSuccess
Definition: housekeeper.h:84
QDateTime QueryLastRun(void)
bool CheckStartup(void)
bool CheckImmediate(void)
QDateTime GetLastRun(void)
Definition: housekeeper.h:58
bool CheckRun(const QDateTime &now)
bool Run(void)
QDateTime UpdateLastRun(bool successful=true)
Definition: housekeeper.h:63
QString m_dbTag
Definition: housekeeper.h:77
virtual void SetLastRun(const QDateTime &last, bool successful=true)
HouseKeeperTask(const QString &dbTag, HouseKeeperScope scope=kHKGlobal, HouseKeeperStartup startup=kHKNormal)
QDateTime m_lastRun
Definition: housekeeper.h:83
void QueryLast(void)
virtual bool DoCheckRun(const QDateTime &)
Definition: housekeeper.h:68
HouseKeeperStartup m_startup
Definition: housekeeper.h:80
QString GetTag(void)
Definition: housekeeper.h:57
QDateTime GetLastSuccess(void)
Definition: housekeeper.h:59
bool ConfirmRun(void) const
Definition: housekeeper.h:51
QDateTime m_lastUpdate
Definition: housekeeper.h:85
QTimer * m_timer
Definition: housekeeper.h:175
void customEvent(QEvent *e) override
QMap< QString, HouseKeeperTask * > m_taskMap
Definition: housekeeper.h:180
void Start(void)
QMutex m_mapLock
Definition: housekeeper.h:181
HouseKeeper(void)
void Run(void)
~HouseKeeper() override
void StartThread(void)
Wake the primary run thread, or create a new one.
QQueue< HouseKeeperTask * > m_taskQueue
Definition: housekeeper.h:177
QList< HouseKeepingThread * > m_threadList
Definition: housekeeper.h:183
HouseKeeperTask * GetQueuedTask(void)
QMutex m_threadLock
Definition: housekeeper.h:184
void UnregisterTask(const QString &tag)
void RegisterTask(HouseKeeperTask *task)
QMutex m_queueLock
Definition: housekeeper.h:178
Thread used to perform queued HouseKeeper tasks.
Definition: housekeeper.h:132
void run(void) override
Runs the Qt event loop unless we have a QRunnable, in which case we run the runnable run instead.
QWaitCondition m_waitCondition
Definition: housekeeper.h:151
HouseKeeper * m_parent
Definition: housekeeper.h:149
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:128
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:838
QVariant value(int i) const
Definition: mythdbcon.h:204
int numRowsAffected() const
Definition: mythdbcon.h:217
bool isConnected(void) const
Only updated once during object creation.
Definition: mythdbcon.h:137
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:619
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:889
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:813
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:551
void RunProlog(void)
Sets up a thread, call this if you reimplement run().
Definition: mthread.cpp:180
void RunEpilog(void)
Cleans up a thread's resources, call this if you reimplement run().
Definition: mthread.cpp:193
bool wait(std::chrono::milliseconds time=std::chrono::milliseconds::max())
Wait for the MThread to exit, with a maximum timeout.
Definition: mthread.cpp:284
QString GetHostName(void)
void SendEvent(const MythEvent &event)
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:225
This class is used as a container for messages.
Definition: mythevent.h:17
const QString & Message() const
Definition: mythevent.h:65
static const Type kMythEventMessage
Definition: mythevent.h:79
void addListener(QObject *listener)
Add a listener to the observable.
void removeListener(QObject *listener)
Remove a listener to the observable.
Modified HouseKeeperTask for tasks to be run at a regular interval.
Definition: housekeeper.h:89
bool DoCheckRun(const QDateTime &now) override
virtual void CalculateWindow(void)
PeriodicHouseKeeperTask(const QString &dbTag, std::chrono::seconds period, float min=0.5, float max=1.1, std::chrono::seconds retry=0s, HouseKeeperScope scope=kHKGlobal, HouseKeeperStartup startup=kHKNormal)
QPair< float, float > m_windowPercent
Definition: housekeeper.h:106
void SetLastRun(const QDateTime &last, bool successful=true) override
virtual bool PastWindow(const QDateTime &now)
std::chrono::seconds m_retry
Definition: housekeeper.h:105
QDateTime UpdateLastRun(const QDateTime &last, bool successful=true) override
virtual bool InWindow(const QDateTime &now)
virtual void SetWindow(float min, float max)
std::chrono::seconds m_period
Definition: housekeeper.h:104
QPair< std::chrono::seconds, std::chrono::seconds > m_windowElapsed
Definition: housekeeper.h:107
General purpose reference counter.
virtual int DecrRef(void)
Decrements reference count and deletes on 0.
This decrements the reference on destruction.
HouseKeeperScope
Definition: housekeeper.h:25
@ kHKGlobal
task should only run once per cluster e.g.
Definition: housekeeper.h:26
@ kHKInst
task should run on every process e.g.
Definition: housekeeper.h:30
@ kHKLocal
task should only run once per machine e.g.
Definition: housekeeper.h:28
HouseKeeperStartup
Definition: housekeeper.h:34
@ kHKRunImmediateOnStartup
task is run during HouseKeeper startup
Definition: housekeeper.h:37
@ kHKRunOnStartup
task is queued when HouseKeeper is started
Definition: housekeeper.h:36
static constexpr T chronomult(T duration, double f)
Multiply a duration by a float, returning a duration.
Definition: mythchrono.h:189
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
MythDB * GetMythDB(void)
Definition: mythdb.cpp:50
static bool VERBOSE_LEVEL_CHECK(uint64_t mask, LogLevel_t level)
Definition: mythlogging.h:29
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
Convenience inline random number generator functions.
static int startup()
QDateTime as_utc(const QDateTime &old_dt)
Returns copy of QDateTime with TimeSpec set to UTC.
Definition: mythdate.cpp:28
MBASE_PUBLIC QDateTime fromSecsSinceEpoch(int64_t seconds)
This function takes the number of seconds since the start of the epoch and returns a QDateTime with t...
Definition: mythdate.cpp:81
QString toString(const QDateTime &raw_dt, uint format)
Returns formatted string representing the time.
Definition: mythdate.cpp:93
@ ISODate
Default UTC.
Definition: mythdate.h:17
QDateTime fromString(const QString &dtstr)
Converts kFilename && kISODate formats to QDateTime.
Definition: mythdate.cpp:39
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:15
uint32_t MythRandom()
generate 32 random bits
Definition: mythrandom.h:20
string hostname
Definition: caa.py:17