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 <QChar> // Fix Qt6 GCC SFINAE warning
56#include <QMutexLocker>
57
58#include "mythevent.h"
59#include "mythdbcon.h"
60#include "housekeeper.h"
61#include "mythcorecontext.h"
62#include "mythlogging.h"
63#include "mythrandom.h"
64
103 ReferenceCounter(dbTag), m_dbTag(dbTag), m_scope(scope),
104 m_startup(startup),
105 m_lastRun(MythDate::fromSecsSinceEpoch(0)),
106 m_lastSuccess(MythDate::fromSecsSinceEpoch(0)),
107 m_lastUpdate(MythDate::fromSecsSinceEpoch(0))
108{
109}
110
111bool HouseKeeperTask::CheckRun(const QDateTime& now)
112{
113 bool check = false;
114 if (!m_confirm && !m_running)
115 {
116 check = DoCheckRun(now);
117 if (check)
118 {
119 // if m_confirm is already set, the task is already in the queue
120 // and should not be queued a second time
121 m_confirm = true;
122 }
123 }
124 LOG(VB_GENERAL, LOG_DEBUG, QString("%1 Running? %2/In window? %3.")
125 .arg(GetTag(), m_running ? "Yes" : "No", check ? "Yes" : "No"));
126 return check;
127}
128
130{
131 return ((m_startup == kHKRunImmediateOnStartup) &&
133}
134
136{
138 {
139 m_confirm = true;
140 return true;
141 }
142 return false;
143}
144
146{
147 LOG(VB_GENERAL, LOG_INFO, QString("Running HouseKeeperTask '%1'.")
148 .arg(m_dbTag));
149 if (m_running)
150 {
151 // something else is already running me, bail out
152 LOG(VB_GENERAL, LOG_WARNING, QString("HouseKeeperTask '%1' already "
153 "running. Refusing to run concurrently").arg(m_dbTag));
154 return false;
155 }
156
157 m_running = true;
158 bool res = DoRun();
159 m_running = false;
160 if (!res)
161 {
162 LOG(VB_GENERAL, LOG_INFO, QString("HouseKeeperTask '%1' Failed.")
163 .arg(m_dbTag));
164 }
165 else
166 {
167 LOG(VB_GENERAL, LOG_INFO,
168 QString("HouseKeeperTask '%1' Finished Successfully.")
169 .arg(m_dbTag));
170 }
171 return res;
172}
173
175{
176 QueryLast();
177 return m_lastRun;
178}
179
181{
182 QueryLast();
183 return m_lastRun;
184}
185
187{
188 if (m_scope != kHKInst)
189 {
190 if (m_lastUpdate.addSecs(30) > MythDate::current())
191 // just to cut down on unnecessary queries
192 return;
193
195
198
199 if (m_scope == kHKGlobal)
200 {
201 query.prepare("SELECT lastrun,lastsuccess FROM housekeeping"
202 " WHERE tag = :TAG"
203 " AND hostname IS NULL");
204 }
205 else
206 {
207 query.prepare("SELECT lastrun,lastsuccess FROM housekeeping"
208 " WHERE tag = :TAG"
209 " AND hostname = :HOST");
210 query.bindValue(":HOST", gCoreContext->GetHostName());
211 }
212
213 query.bindValue(":TAG", m_dbTag);
214
215 if (query.exec() && query.next())
216 {
217 m_lastRun = MythDate::as_utc(query.value(0).toDateTime());
218 m_lastSuccess = MythDate::as_utc(query.value(1).toDateTime());
219 }
220 }
221
223}
224
225QDateTime HouseKeeperTask::UpdateLastRun(const QDateTime& last, bool successful)
226{
227 m_lastRun = last;
228 if (successful)
229 m_lastSuccess = last;
230 m_confirm = false;
231
232 if (m_scope != kHKInst)
233 {
235 if (!query.isConnected())
236 return last;
237
238 if (m_scope == kHKGlobal)
239 {
240 query.prepare("UPDATE `housekeeping` SET `lastrun`=:TIME,"
241 " `lastsuccess`=:STIME"
242 " WHERE `tag` = :TAG"
243 " AND `hostname` IS NULL");
244 }
245 else
246 {
247 query.prepare("UPDATE `housekeeping` SET `lastrun`=:TIME,"
248 " `lastsuccess`=:STIME"
249 " WHERE `tag` = :TAG"
250 " AND `hostname` = :HOST");
251 }
252
253 if (m_scope == kHKLocal)
254 query.bindValue(":HOST", gCoreContext->GetHostName());
255 query.bindValue(":TAG", m_dbTag);
256 query.bindValue(":TIME", MythDate::as_utc(m_lastRun));
257 query.bindValue(":STIME", MythDate::as_utc(m_lastSuccess));
258
259 if (!query.exec())
260 MythDB::DBError("HouseKeeperTask::updateLastRun, UPDATE", query);
261
262 if (VERBOSE_LEVEL_CHECK(VB_GENERAL, LOG_DEBUG) &&
263 query.numRowsAffected() > 0)
264 {
265 LOG(VB_GENERAL, LOG_DEBUG, QString("%1: UPDATEd %2 run time.")
266 .arg(m_dbTag, m_scope == kHKGlobal ? "global" : "local"));
267 }
268
269 if (query.numRowsAffected() == 0)
270 {
271 if (m_scope == kHKGlobal)
272 {
273 query.prepare("INSERT INTO `housekeeping`"
274 " (`tag`, `lastrun`, `lastsuccess`)"
275 " VALUES (:TAG, :TIME, :STIME)");
276 }
277 else
278 {
279 query.prepare("INSERT INTO `housekeeping`"
280 " (`tag`, `hostname`, `lastrun`, `lastsuccess`)"
281 " VALUES (:TAG, :HOST, :TIME, :STIME)");
282 }
283
284 if (m_scope == kHKLocal)
285 query.bindValue(":HOST", gCoreContext->GetHostName());
286 query.bindValue(":TAG", m_dbTag);
287 query.bindValue(":TIME", MythDate::as_utc(m_lastRun));
288 query.bindValue(":STIME", MythDate::as_utc(m_lastSuccess));
289
290 if (!query.exec())
291 MythDB::DBError("HouseKeeperTask::updateLastRun INSERT", query);
292
293 LOG(VB_GENERAL, LOG_DEBUG, QString("%1: INSERTed %2 run time.")
294 .arg(m_dbTag, m_scope == kHKGlobal ? "global" : "local"));
295 }
296 }
297
298 QString msg;
299 if (successful)
300 msg = QString("HOUSE_KEEPER_SUCCESSFUL %1 %2 %3");
301 else
302 msg = QString("HOUSE_KEEPER_RUNNING %1 %2 %3");
303 msg = msg.arg(gCoreContext->GetHostName(),
304 m_dbTag,
308
309 return last;
310}
311
312void HouseKeeperTask::SetLastRun(const QDateTime &last, bool successful)
313{
314 m_lastRun = last;
315 if (successful)
316 m_lastSuccess = last;
317
319}
320
335 std::chrono::seconds period, float min, float max, std::chrono::seconds retry,
337 HouseKeeperTask(dbTag, scope, startup), m_period(period), m_retry(retry),
338 m_windowPercent(min, max)
339{
341 if (m_retry == 0s)
343}
344
346{
347 std::chrono::seconds period = m_period;
348 if (GetLastRun() > GetLastSuccess())
349 {
350 // last attempt was not successful
351 // try shortened period
352 period = m_retry;
353 }
354
355 m_windowElapsed.first = chronomult(period, m_windowPercent.first);
356 m_windowElapsed.second = chronomult(period, m_windowPercent.second);
357}
358
359void PeriodicHouseKeeperTask::SetWindow(float min, float max)
360{
361 m_windowPercent.first = min;
362 m_windowPercent.second = max;
364}
365
366QDateTime PeriodicHouseKeeperTask::UpdateLastRun(const QDateTime& last,
367 bool successful)
368{
369 QDateTime res = HouseKeeperTask::UpdateLastRun(last, successful);
371 m_currentProb = 1.0;
372 return res;
373}
374
375void PeriodicHouseKeeperTask::SetLastRun(const QDateTime& last, bool successful)
376{
377 HouseKeeperTask::SetLastRun(last, successful);
379 m_currentProb = 1.0;
380}
381
382bool PeriodicHouseKeeperTask::DoCheckRun(const QDateTime& now)
383{
384 auto elapsed = std::chrono::seconds(GetLastRun().secsTo(now));
385
386 if (elapsed < 0s)
387 // something bad has happened. let's just move along
388 return false;
389
390 if (elapsed < m_windowElapsed.first)
391 // insufficient time elapsed to test
392 return false;
393 if (elapsed > m_windowElapsed.second)
394 // too much time has passed. force run
395 return true;
396
397 // calculate probability that task should not have yet run
398 // it's backwards, but it makes the math simplier
399 double prob = 1.0 - (duration_cast<floatsecs>(elapsed - m_windowElapsed.first) /
400 duration_cast<floatsecs>(m_windowElapsed.second - m_windowElapsed.first));
401 if (m_currentProb < prob)
402 // more bad stuff
403 return false;
404
405 // calculate current probability to achieve overall probability
406 // this should be nearly one
407 double prob2 = prob/m_currentProb;
408 // so rand() should have to return nearly RAND_MAX to get a positive
409 // remember, this is computing the probability that up to this point, one
410 // of these tests has returned positive, so each individual test has
411 // a necessarily low probability
412 //
413 bool res = (MythRandom() > (uint32_t)(prob2 * std::numeric_limits<uint32_t>::max()));
414 m_currentProb = prob;
415// if (res)
416// LOG(VB_GENERAL, LOG_DEBUG, QString("%1 will run: this=%2; total=%3")
417// .arg(GetTag()).arg(1-prob2).arg(1-prob));
418// else
419// LOG(VB_GENERAL, LOG_DEBUG, QString("%1 will not run: this=%2; total=%3")
420// .arg(GetTag()).arg(1-prob2).arg(1-prob));
421 return res;
422}
423
424bool PeriodicHouseKeeperTask::InWindow(const QDateTime& now)
425{
426 auto elapsed = std::chrono::seconds(GetLastRun().secsTo(now));
427
428 if (elapsed < 0s)
429 // something bad has happened. let's just move along
430 return false;
431
432 return (elapsed > m_windowElapsed.first) &&
433 (elapsed < m_windowElapsed.second);
434}
435
436bool PeriodicHouseKeeperTask::PastWindow(const QDateTime &now)
437{
438 return std::chrono::seconds(GetLastRun().secsTo(now)) > m_windowElapsed.second;
439}
440
456 PeriodicHouseKeeperTask(dbTag, 24h, .5, 1.5, 0s, scope, startup),
457 m_windowHour(0h, 23h)
458{
460}
461
463 std::chrono::hours minhour, std::chrono::hours maxhour,
465 PeriodicHouseKeeperTask(dbTag, 24h, .5, 1.5, 0s, scope, startup),
466 m_windowHour(minhour, maxhour)
467{
469}
470
472{
474 QDate date = GetLastRun().addDays(1).date();
475
476 QDateTime tmp = QDateTime(date, QTime(m_windowHour.first.count(), 0));
477 if (GetLastRun().addSecs(m_windowElapsed.first.count()) < tmp)
478 m_windowElapsed.first = std::chrono::seconds(GetLastRun().secsTo(tmp));
479
480 tmp = QDateTime(date, QTime(m_windowHour.second.count(), 30));
481 // we want to make sure this gets run before the end of the day
482 // so add a 30 minute buffer prior to the end of the window
483 if (GetLastRun().addSecs(m_windowElapsed.second.count()) > tmp)
484 m_windowElapsed.second = std::chrono::seconds(GetLastRun().secsTo(tmp));
485
486 LOG(VB_GENERAL, LOG_DEBUG, QString("%1 Run window between %2 - %3.")
487 .arg(GetTag()).arg(m_windowElapsed.first.count()).arg(m_windowElapsed.second.count()));
488}
489
490void DailyHouseKeeperTask::SetHourWindow(std::chrono::hours min, std::chrono::hours max)
491{
492 m_windowHour.first = min;
493 m_windowHour.second = max;
495}
496
497bool DailyHouseKeeperTask::InWindow(const QDateTime& now)
498{
500 // parent says we're in the window
501 return true;
502
503 auto hour = std::chrono::hours(now.time().hour());
504 // true if we've missed the window, but we're within our time constraints
505 return PastWindow(now) && (m_windowHour.first <= hour)
506 && (m_windowHour.second > hour);
507}
508
520{
521 RunProlog();
522 m_waitMutex.lock();
523 HouseKeeperTask *task = nullptr;
524
525 while (m_keepRunning)
526 {
527 m_idle = false;
528
529 while ((task = m_parent->GetQueuedTask()))
530 {
531 // pull task from housekeeper and process it
532 ReferenceLocker rlock(task);
533
534 if (!task->ConfirmRun())
535 {
536 // something else has caused the lastrun time to
537 // change since this was requested to run. abort.
538 task = nullptr;
539 continue;
540 }
541
542 task->UpdateLastRun(false);
543 if (task->Run())
544 task->UpdateLastRun(task->GetLastRun(), true);
545 task = nullptr;
546
547 if (!m_keepRunning)
548 // thread has been discarded, don't try to start another task
549 break;
550 }
551
552 m_idle = true;
553
554 if (!m_keepRunning)
555 // short out rather than potentially hitting another sleep cycle
556 break;
557
559 }
560
561 m_waitMutex.unlock();
562 RunEpilog();
563}
564
582 : m_timer(new QTimer(this))
583{
584 connect(m_timer, &QTimer::timeout, this, &HouseKeeper::Run);
585 m_timer->setInterval(1min);
586 m_timer->setSingleShot(false);
587}
588
590{
592
593 if (m_timer)
594 {
595 m_timer->stop();
596 disconnect(m_timer);
597 delete m_timer;
598 m_timer = nullptr;
599 }
600
601 {
602 // remove anything from the queue first, so it does not start
603 QMutexLocker queueLock(&m_queueLock);
604 while (!m_taskQueue.isEmpty())
605 m_taskQueue.takeFirst()->DecrRef();
606 }
607
608 {
609 // issue a terminate call to any long-running tasks
610 // this is just a noop unless overwritten by a subclass
611 QMutexLocker mapLock(&m_mapLock);
612 for (auto *it : std::as_const(m_taskMap))
613 it->Terminate();
614 }
615
616 if (!m_threadList.isEmpty())
617 {
618 QMutexLocker threadLock(&m_threadLock);
619 // tell primary thread to self-terminate and wake it
620 m_threadList.first()->Discard();
621 m_threadList.first()->Wake();
622 // wait for any remaining threads to self-terminate and close
623 while (!m_threadList.isEmpty())
624 {
625 HouseKeepingThread *thread = m_threadList.takeFirst();
626 thread->wait();
627 delete thread;
628 }
629 }
630
631 {
632 // unload any registered tasks
633 QMutexLocker mapLock(&m_mapLock);
634 QMap<QString,HouseKeeperTask*>::iterator it = m_taskMap.begin();
635 while (it != m_taskMap.end())
636 {
637 (*it)->DecrRef();
638 it = m_taskMap.erase(it);
639 }
640 }
641}
642
644{
645 QMutexLocker mapLock(&m_mapLock);
646 QString tag = task->GetTag();
647 if (m_taskMap.contains(tag))
648 {
649 task->DecrRef();
650 LOG(VB_GENERAL, LOG_ERR,
651 QString("HouseKeeperTask '%1' already registered. "
652 "Rejecting duplicate.").arg(tag));
653 }
654 else
655 {
656 LOG(VB_GENERAL, LOG_INFO,
657 QString("Registering HouseKeeperTask '%1'.").arg(tag));
658 m_taskMap.insert(tag, task);
659 }
660}
661
662void HouseKeeper::UnregisterTask(const QString& tag)
663{
664 QMutexLocker mapLock(&m_mapLock);
665 auto it = m_taskMap.find(tag);
666 if (it == m_taskMap.end())
667 {
668 LOG(VB_GENERAL, LOG_ERR,
669 QString("HouseKeeperTask '%1' doesn't exist.").arg(tag));
670 return;
671 }
672
673 delete *it;
674 LOG(VB_GENERAL, LOG_INFO,
675 QString("HouseKeeperTask '%1' destroyed.").arg(tag));
676}
677
679{
680 QMutexLocker queueLock(&m_queueLock);
681 HouseKeeperTask *task = nullptr;
682
683 if (!m_taskQueue.isEmpty())
684 {
685 task = m_taskQueue.dequeue();
686 }
687
688 // returning nullptr tells the thread that the queue is empty and
689 // to go into standby
690 return task;
691}
692
694{
695 // no need to be fine grained, nothing else should be accessing this map
696 QMutexLocker mapLock(&m_mapLock);
697
698 if (m_timer->isActive())
699 // Start() should only be called once
700 return;
701
703 query.prepare("SELECT `tag`,`lastrun`"
704 " FROM `housekeeping`"
705 " WHERE `hostname` = :HOST"
706 " OR `hostname` IS NULL");
707 query.bindValue(":HOST", gCoreContext->GetHostName());
708
709 if (!query.exec())
710 {
711 MythDB::DBError("HouseKeeper::Run", query);
712 }
713 else
714 {
715 while (query.next())
716 {
717 // loop through housekeeping table and load last run timestamps
718 QString tag = query.value(0).toString();
719 QDateTime lastrun = MythDate::as_utc(query.value(1).toDateTime());
720
721 if (m_taskMap.contains(tag))
722 m_taskMap[tag]->SetLastRun(lastrun);
723 }
724 }
725
727
728 for (auto it = m_taskMap.cbegin(); it != m_taskMap.cend(); ++it)
729 {
730 if ((*it)->CheckImmediate())
731 {
732 // run any tasks marked for immediate operation in-thread
733 (*it)->UpdateLastRun();
734 (*it)->Run();
735 }
736 else if ((*it)->CheckStartup())
737 {
738 // queue any tasks marked for startup
739 LOG(VB_GENERAL, LOG_INFO,
740 QString("Queueing HouseKeeperTask '%1'.").arg(it.key()));
741 QMutexLocker queueLock(&m_queueLock);
742 (*it)->IncrRef();
743 m_taskQueue.enqueue(*it);
744 }
745 }
746
747 LOG(VB_GENERAL, LOG_INFO, "Starting HouseKeeper.");
748
749 m_timer->start();
750}
751
753{
754 LOG(VB_GENERAL, LOG_DEBUG, "Running HouseKeeper.");
755
756 QDateTime now = MythDate::current();
757
758 QMutexLocker mapLock(&m_mapLock);
759 // Remove any tasks that have finished
760 for (auto it = m_taskMap.begin(); it != m_taskMap.end(); )
761 {
762 if ((*it)->IsFinished())
763 {
764 LOG(VB_GENERAL, LOG_INFO,
765 QString("Removing finished HouseKeeperTask '%1'.")
766 .arg(it.key()));
767 it = m_taskMap.erase(it);
768 }
769 else
770 {
771 it++;
772 }
773 }
774
775 // check if any tasks are ready to run, and add to queue
776 for (auto it = m_taskMap.begin(); it != m_taskMap.end(); ++it)
777 {
778 if ((*it)->CheckRun(now))
779 {
780 LOG(VB_GENERAL, LOG_INFO,
781 QString("Queueing HouseKeeperTask '%1'.").arg(it.key()));
782 QMutexLocker queueLock(&m_queueLock);
783 (*it)->IncrRef();
784 m_taskQueue.enqueue(*it);
785 }
786 }
787
788 if (!m_taskQueue.isEmpty())
789 StartThread();
790
791 if (m_threadList.size() > 1)
792 {
793 // spent threads exist in the thread list
794 // check to see if any have finished up their task and terminated
795 QMutexLocker threadLock(&m_threadLock);
796 int count1 = m_threadList.size();
797
798 auto it = m_threadList.begin();
799 ++it; // skip the primary thread
800 while (it != m_threadList.end())
801 {
802 if ((*it)->isRunning())
803 {
804 ++it;
805 }
806 else
807 {
808 delete *it;
809 it = m_threadList.erase(it);
810 }
811 }
812
813 int count2 = m_threadList.size();
814 if (count1 > count2)
815 {
816 LOG(VB_GENERAL, LOG_DEBUG,
817 QString("Discarded HouseKeepingThreads have completed and "
818 "been deleted. Current count %1 -> %2.")
819 .arg(count1).arg(count2));
820 }
821 }
822}
823
838{
839 QMutexLocker threadLock(&m_threadLock);
840
841 if (m_threadList.isEmpty())
842 {
843 // we're running for the first time
844 // start up a new thread
845 LOG(VB_GENERAL, LOG_DEBUG, "Running initial HouseKeepingThread.");
846 auto *thread = new HouseKeepingThread(this);
847 m_threadList.append(thread);
848 thread->start();
849 }
850
851 else if (!m_threadList.first()->isIdle())
852 {
853 // the old thread is still off processing something
854 // discard it and start a new one because we have more stuff
855 // that wants to run
856 LOG(VB_GENERAL, LOG_DEBUG,
857 QString("Current HouseKeepingThread is delayed on task, "
858 "spawning replacement. Current count %1.")
859 .arg(m_threadList.size()));
860 m_threadList.first()->Discard();
861 auto *thread = new HouseKeepingThread(this);
862 m_threadList.prepend(thread);
863 thread->start();
864 }
865
866 else
867 {
868 // the old thread is idle, so just wake it for processing
869 LOG(VB_GENERAL, LOG_DEBUG, "Waking HouseKeepingThread.");
870 m_threadList.first()->Wake();
871 }
872}
873
875{
876 if (e->type() == MythEvent::kMythEventMessage)
877 {
878 auto *me = dynamic_cast<MythEvent*>(e);
879 if (me == nullptr)
880 return;
881 if ((me->Message().left(20) == "HOUSE_KEEPER_RUNNING") ||
882 (me->Message().left(23) == "HOUSE_KEEPER_SUCCESSFUL"))
883 {
884 QStringList tokens = me->Message()
885 .split(" ", Qt::SkipEmptyParts);
886 if (tokens.size() != 4)
887 return;
888
889 const QString& hostname = tokens[1];
890 const QString& tag = tokens[2];
891 QDateTime last = MythDate::fromString(tokens[3]);
892 bool successful = me->Message().contains("SUCCESSFUL");
893
894 QMutexLocker mapLock(&m_mapLock);
895 if (m_taskMap.contains(tag))
896 {
897 if ((m_taskMap[tag]->GetScope() == kHKGlobal) ||
898 ((m_taskMap[tag]->GetScope() == kHKLocal) &&
900 {
901 // task being run in the same scope as us.
902 // update the run time so we don't attempt to run
903 // it ourselves
904 m_taskMap[tag]->SetLastRun(last, successful);
905 }
906 }
907 }
908 }
909}
910
912{
913 GetMythDB()->GetDBManager()->PurgeIdleConnections(false);
914 return true;
915}
916
917#include "moc_housekeeper.cpp"
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:129
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:839
QVariant value(int i) const
Definition: mythdbcon.h:205
int numRowsAffected() const
Definition: mythdbcon.h:218
bool isConnected(void) const
Only updated once during object creation.
Definition: mythdbcon.h:138
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:620
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:890
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:814
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:552
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:190
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:18
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