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
101 ReferenceCounter(dbTag), m_dbTag(dbTag), m_scope(scope),
102 m_startup(startup),
103 m_lastRun(MythDate::fromSecsSinceEpoch(0)),
104 m_lastSuccess(MythDate::fromSecsSinceEpoch(0)),
105 m_lastUpdate(MythDate::fromSecsSinceEpoch(0))
106{
107}
108
109bool HouseKeeperTask::CheckRun(const QDateTime& now)
110{
111 bool check = false;
112 if (!m_confirm && !m_running)
113 {
114 check = DoCheckRun(now);
115 if (check)
116 {
117 // if m_confirm is already set, the task is already in the queue
118 // and should not be queued a second time
119 m_confirm = true;
120 }
121 }
122 LOG(VB_GENERAL, LOG_DEBUG, QString("%1 Running? %2/In window? %3.")
123 .arg(GetTag(), m_running ? "Yes" : "No", check ? "Yes" : "No"));
124 return check;
125}
126
128{
129 return ((m_startup == kHKRunImmediateOnStartup) &&
131}
132
134{
136 {
137 m_confirm = true;
138 return true;
139 }
140 return false;
141}
142
144{
145 LOG(VB_GENERAL, LOG_INFO, QString("Running HouseKeeperTask '%1'.")
146 .arg(m_dbTag));
147 if (m_running)
148 {
149 // something else is already running me, bail out
150 LOG(VB_GENERAL, LOG_WARNING, QString("HouseKeeperTask '%1' already "
151 "running. Refusing to run concurrently").arg(m_dbTag));
152 return false;
153 }
154
155 m_running = true;
156 bool res = DoRun();
157 m_running = false;
158 if (!res)
159 {
160 LOG(VB_GENERAL, LOG_INFO, QString("HouseKeeperTask '%1' Failed.")
161 .arg(m_dbTag));
162 }
163 else
164 {
165 LOG(VB_GENERAL, LOG_INFO,
166 QString("HouseKeeperTask '%1' Finished Successfully.")
167 .arg(m_dbTag));
168 }
169 return res;
170}
171
173{
174 QueryLast();
175 return m_lastRun;
176}
177
179{
180 QueryLast();
181 return m_lastRun;
182}
183
185{
186 if (m_scope != kHKInst)
187 {
188 if (m_lastUpdate.addSecs(30) > MythDate::current())
189 // just to cut down on unnecessary queries
190 return;
191
193
196
197 if (m_scope == kHKGlobal)
198 {
199 query.prepare("SELECT lastrun,lastsuccess FROM housekeeping"
200 " WHERE tag = :TAG"
201 " AND hostname IS NULL");
202 }
203 else
204 {
205 query.prepare("SELECT lastrun,lastsuccess FROM housekeeping"
206 " WHERE tag = :TAG"
207 " AND hostname = :HOST");
208 query.bindValue(":HOST", gCoreContext->GetHostName());
209 }
210
211 query.bindValue(":TAG", m_dbTag);
212
213 if (query.exec() && query.next())
214 {
215 m_lastRun = MythDate::as_utc(query.value(0).toDateTime());
216 m_lastSuccess = MythDate::as_utc(query.value(1).toDateTime());
217 }
218 }
219
221}
222
223QDateTime HouseKeeperTask::UpdateLastRun(const QDateTime& last, bool successful)
224{
225 m_lastRun = last;
226 if (successful)
227 m_lastSuccess = last;
228 m_confirm = false;
229
230 if (m_scope != kHKInst)
231 {
233 if (!query.isConnected())
234 return last;
235
236 if (m_scope == kHKGlobal)
237 {
238 query.prepare("UPDATE `housekeeping` SET `lastrun`=:TIME,"
239 " `lastsuccess`=:STIME"
240 " WHERE `tag` = :TAG"
241 " AND `hostname` IS NULL");
242 }
243 else
244 {
245 query.prepare("UPDATE `housekeeping` SET `lastrun`=:TIME,"
246 " `lastsuccess`=:STIME"
247 " WHERE `tag` = :TAG"
248 " AND `hostname` = :HOST");
249 }
250
251 if (m_scope == kHKLocal)
252 query.bindValue(":HOST", gCoreContext->GetHostName());
253 query.bindValue(":TAG", m_dbTag);
254 query.bindValue(":TIME", MythDate::as_utc(m_lastRun));
255 query.bindValue(":STIME", MythDate::as_utc(m_lastSuccess));
256
257 if (!query.exec())
258 MythDB::DBError("HouseKeeperTask::updateLastRun, UPDATE", query);
259
260 if (VERBOSE_LEVEL_CHECK(VB_GENERAL, LOG_DEBUG) &&
261 query.numRowsAffected() > 0)
262 {
263 LOG(VB_GENERAL, LOG_DEBUG, QString("%1: UPDATEd %2 run time.")
264 .arg(m_dbTag, m_scope == kHKGlobal ? "global" : "local"));
265 }
266
267 if (query.numRowsAffected() == 0)
268 {
269 if (m_scope == kHKGlobal)
270 {
271 query.prepare("INSERT INTO `housekeeping`"
272 " (`tag`, `lastrun`, `lastsuccess`)"
273 " VALUES (:TAG, :TIME, :STIME)");
274 }
275 else
276 {
277 query.prepare("INSERT INTO `housekeeping`"
278 " (`tag`, `hostname`, `lastrun`, `lastsuccess`)"
279 " VALUES (:TAG, :HOST, :TIME, :STIME)");
280 }
281
282 if (m_scope == kHKLocal)
283 query.bindValue(":HOST", gCoreContext->GetHostName());
284 query.bindValue(":TAG", m_dbTag);
285 query.bindValue(":TIME", MythDate::as_utc(m_lastRun));
286 query.bindValue(":STIME", MythDate::as_utc(m_lastSuccess));
287
288 if (!query.exec())
289 MythDB::DBError("HouseKeeperTask::updateLastRun INSERT", query);
290
291 LOG(VB_GENERAL, LOG_DEBUG, QString("%1: INSERTed %2 run time.")
292 .arg(m_dbTag, m_scope == kHKGlobal ? "global" : "local"));
293 }
294 }
295
296 QString msg;
297 if (successful)
298 msg = QString("HOUSE_KEEPER_SUCCESSFUL %1 %2 %3");
299 else
300 msg = QString("HOUSE_KEEPER_RUNNING %1 %2 %3");
301 msg = msg.arg(gCoreContext->GetHostName(),
302 m_dbTag,
306
307 return last;
308}
309
310void HouseKeeperTask::SetLastRun(const QDateTime &last, bool successful)
311{
312 m_lastRun = last;
313 if (successful)
314 m_lastSuccess = last;
315
317}
318
333 std::chrono::seconds period, float min, float max, std::chrono::seconds retry,
335 HouseKeeperTask(dbTag, scope, startup), m_period(period), m_retry(retry),
336 m_windowPercent(min, max)
337{
339 if (m_retry == 0s)
341}
342
344{
345 std::chrono::seconds period = m_period;
346 if (GetLastRun() > GetLastSuccess())
347 {
348 // last attempt was not successful
349 // try shortened period
350 period = m_retry;
351 }
352
353 m_windowElapsed.first = chronomult(period, m_windowPercent.first);
354 m_windowElapsed.second = chronomult(period, m_windowPercent.second);
355}
356
357void PeriodicHouseKeeperTask::SetWindow(float min, float max)
358{
359 m_windowPercent.first = min;
360 m_windowPercent.second = max;
362}
363
364QDateTime PeriodicHouseKeeperTask::UpdateLastRun(const QDateTime& last,
365 bool successful)
366{
367 QDateTime res = HouseKeeperTask::UpdateLastRun(last, successful);
369 m_currentProb = 1.0;
370 return res;
371}
372
373void PeriodicHouseKeeperTask::SetLastRun(const QDateTime& last, bool successful)
374{
375 HouseKeeperTask::SetLastRun(last, successful);
377 m_currentProb = 1.0;
378}
379
380bool PeriodicHouseKeeperTask::DoCheckRun(const QDateTime& now)
381{
382 auto elapsed = std::chrono::seconds(GetLastRun().secsTo(now));
383
384 if (elapsed < 0s)
385 // something bad has happened. let's just move along
386 return false;
387
388 if (elapsed < m_windowElapsed.first)
389 // insufficient time elapsed to test
390 return false;
391 if (elapsed > m_windowElapsed.second)
392 // too much time has passed. force run
393 return true;
394
395 // calculate probability that task should not have yet run
396 // it's backwards, but it makes the math simplier
397 double prob = 1.0 - (duration_cast<floatsecs>(elapsed - m_windowElapsed.first) /
398 duration_cast<floatsecs>(m_windowElapsed.second - m_windowElapsed.first));
399 if (m_currentProb < prob)
400 // more bad stuff
401 return false;
402
403 // calculate current probability to achieve overall probability
404 // this should be nearly one
405 double prob2 = prob/m_currentProb;
406 // so rand() should have to return nearly RAND_MAX to get a positive
407 // remember, this is computing the probability that up to this point, one
408 // of these tests has returned positive, so each individual test has
409 // a necessarily low probability
410 //
411 // Pseudo-random is good enough. Don't need a true random.
412 // NOLINTNEXTLINE(cert-msc30-c,cert-msc50-cpp)
413 bool res = (rand() > (int)(prob2 * static_cast<double>(RAND_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
663{
664 QMutexLocker queueLock(&m_queueLock);
665 HouseKeeperTask *task = nullptr;
666
667 if (!m_taskQueue.isEmpty())
668 {
669 task = m_taskQueue.dequeue();
670 }
671
672 // returning nullptr tells the thread that the queue is empty and
673 // to go into standby
674 return task;
675}
676
678{
679 // no need to be fine grained, nothing else should be accessing this map
680 QMutexLocker mapLock(&m_mapLock);
681
682 if (m_timer->isActive())
683 // Start() should only be called once
684 return;
685
687 query.prepare("SELECT `tag`,`lastrun`"
688 " FROM `housekeeping`"
689 " WHERE `hostname` = :HOST"
690 " OR `hostname` IS NULL");
691 query.bindValue(":HOST", gCoreContext->GetHostName());
692
693 if (!query.exec())
694 MythDB::DBError("HouseKeeper::Run", query);
695 else
696 {
697 while (query.next())
698 {
699 // loop through housekeeping table and load last run timestamps
700 QString tag = query.value(0).toString();
701 QDateTime lastrun = MythDate::as_utc(query.value(1).toDateTime());
702
703 if (m_taskMap.contains(tag))
704 m_taskMap[tag]->SetLastRun(lastrun);
705 }
706 }
707
709
710 for (auto it = m_taskMap.cbegin(); it != m_taskMap.cend(); ++it)
711 {
712 if ((*it)->CheckImmediate())
713 {
714 // run any tasks marked for immediate operation in-thread
715 (*it)->UpdateLastRun();
716 (*it)->Run();
717 }
718 else if ((*it)->CheckStartup())
719 {
720 // queue any tasks marked for startup
721 LOG(VB_GENERAL, LOG_INFO,
722 QString("Queueing HouseKeeperTask '%1'.").arg(it.key()));
723 QMutexLocker queueLock(&m_queueLock);
724 (*it)->IncrRef();
725 m_taskQueue.enqueue(*it);
726 }
727 }
728
729 LOG(VB_GENERAL, LOG_INFO, "Starting HouseKeeper.");
730
731 m_timer->start();
732}
733
735{
736 LOG(VB_GENERAL, LOG_DEBUG, "Running HouseKeeper.");
737
738 QDateTime now = MythDate::current();
739
740 QMutexLocker mapLock(&m_mapLock);
741 for (auto it = m_taskMap.begin(); it != m_taskMap.end(); ++it)
742 {
743 if ((*it)->CheckRun(now))
744 {
745 // check if any tasks are ready to run, and add to queue
746 LOG(VB_GENERAL, LOG_INFO,
747 QString("Queueing HouseKeeperTask '%1'.").arg(it.key()));
748 QMutexLocker queueLock(&m_queueLock);
749 (*it)->IncrRef();
750 m_taskQueue.enqueue(*it);
751 }
752 }
753
754 if (!m_taskQueue.isEmpty())
755 StartThread();
756
757 if (m_threadList.size() > 1)
758 {
759 // spent threads exist in the thread list
760 // check to see if any have finished up their task and terminated
761 QMutexLocker threadLock(&m_threadLock);
762 int count1 = m_threadList.size();
763
764 auto it = m_threadList.begin();
765 ++it; // skip the primary thread
766 while (it != m_threadList.end())
767 {
768 if ((*it)->isRunning())
769 ++it;
770 else
771 {
772 delete *it;
773 it = m_threadList.erase(it);
774 }
775 }
776
777 int count2 = m_threadList.size();
778 if (count1 > count2)
779 {
780 LOG(VB_GENERAL, LOG_DEBUG,
781 QString("Discarded HouseKeepingThreads have completed and "
782 "been deleted. Current count %1 -> %2.")
783 .arg(count1).arg(count2));
784 }
785 }
786}
787
802{
803 QMutexLocker threadLock(&m_threadLock);
804
805 if (m_threadList.isEmpty())
806 {
807 // we're running for the first time
808 // start up a new thread
809 LOG(VB_GENERAL, LOG_DEBUG, "Running initial HouseKeepingThread.");
810 auto *thread = new HouseKeepingThread(this);
811 m_threadList.append(thread);
812 thread->start();
813 }
814
815 else if (!m_threadList.first()->isIdle())
816 {
817 // the old thread is still off processing something
818 // discard it and start a new one because we have more stuff
819 // that wants to run
820 LOG(VB_GENERAL, LOG_DEBUG,
821 QString("Current HouseKeepingThread is delayed on task, "
822 "spawning replacement. Current count %1.")
823 .arg(m_threadList.size()));
824 m_threadList.first()->Discard();
825 auto *thread = new HouseKeepingThread(this);
826 m_threadList.prepend(thread);
827 thread->start();
828 }
829
830 else
831 {
832 // the old thread is idle, so just wake it for processing
833 LOG(VB_GENERAL, LOG_DEBUG, "Waking HouseKeepingThread.");
834 m_threadList.first()->Wake();
835 }
836}
837
839{
840 if (e->type() == MythEvent::kMythEventMessage)
841 {
842 auto *me = dynamic_cast<MythEvent*>(e);
843 if (me == nullptr)
844 return;
845 if ((me->Message().left(20) == "HOUSE_KEEPER_RUNNING") ||
846 (me->Message().left(23) == "HOUSE_KEEPER_SUCCESSFUL"))
847 {
848 QStringList tokens = me->Message()
849 .split(" ", Qt::SkipEmptyParts);
850 if (tokens.size() != 4)
851 return;
852
853 const QString& hostname = tokens[1];
854 const QString& tag = tokens[2];
855 QDateTime last = MythDate::fromString(tokens[3]);
856 bool successful = me->Message().contains("SUCCESSFUL");
857
858 QMutexLocker mapLock(&m_mapLock);
859 if (m_taskMap.contains(tag))
860 {
861 if ((m_taskMap[tag]->GetScope() == kHKGlobal) ||
862 ((m_taskMap[tag]->GetScope() == kHKLocal) &&
864 {
865 // task being run in the same scope as us.
866 // update the run time so we don't attempt to run
867 // it ourselves
868 m_taskMap[tag]->SetLastRun(last, successful);
869 }
870 }
871 }
872 }
873}
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:125
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:67
HouseKeeperScope m_scope
Definition: housekeeper.h:76
QDateTime m_lastSuccess
Definition: housekeeper.h:81
QDateTime QueryLastRun(void)
bool CheckStartup(void)
bool CheckImmediate(void)
QDateTime GetLastRun(void)
Definition: housekeeper.h:56
bool CheckRun(const QDateTime &now)
bool Run(void)
QDateTime UpdateLastRun(bool successful=true)
Definition: housekeeper.h:61
QString m_dbTag
Definition: housekeeper.h:74
virtual void SetLastRun(const QDateTime &last, bool successful=true)
HouseKeeperTask(const QString &dbTag, HouseKeeperScope scope=kHKGlobal, HouseKeeperStartup startup=kHKNormal)
Definition: housekeeper.cpp:99
QDateTime m_lastRun
Definition: housekeeper.h:80
void QueryLast(void)
virtual bool DoCheckRun(const QDateTime &)
Definition: housekeeper.h:66
HouseKeeperStartup m_startup
Definition: housekeeper.h:77
QString GetTag(void)
Definition: housekeeper.h:55
QDateTime GetLastSuccess(void)
Definition: housekeeper.h:57
bool ConfirmRun(void) const
Definition: housekeeper.h:49
QDateTime m_lastUpdate
Definition: housekeeper.h:82
QTimer * m_timer
Definition: housekeeper.h:168
void customEvent(QEvent *e) override
QMap< QString, HouseKeeperTask * > m_taskMap
Definition: housekeeper.h:173
void Start(void)
QMutex m_mapLock
Definition: housekeeper.h:174
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:170
QList< HouseKeepingThread * > m_threadList
Definition: housekeeper.h:176
HouseKeeperTask * GetQueuedTask(void)
QMutex m_threadLock
Definition: housekeeper.h:177
void RegisterTask(HouseKeeperTask *task)
QMutex m_queueLock
Definition: housekeeper.h:171
Thread used to perform queued HouseKeeper tasks.
Definition: housekeeper.h:129
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:146
HouseKeeper * m_parent
Definition: housekeeper.h:144
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:837
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:618
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:888
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:812
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:550
void RunProlog(void)
Sets up a thread, call this if you reimplement run().
Definition: mthread.cpp:196
void RunEpilog(void)
Cleans up a thread's resources, call this if you reimplement run().
Definition: mthread.cpp:209
bool wait(std::chrono::milliseconds time=std::chrono::milliseconds::max())
Wait for the MThread to exit, with a maximum timeout.
Definition: mthread.cpp:300
QString GetHostName(void)
void SendEvent(const MythEvent &event)
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:226
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:86
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:103
void SetLastRun(const QDateTime &last, bool successful=true) override
virtual bool PastWindow(const QDateTime &now)
std::chrono::seconds m_retry
Definition: housekeeper.h:102
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:101
QPair< std::chrono::seconds, std::chrono::seconds > m_windowElapsed
Definition: housekeeper.h:104
General purpose reference counter.
virtual int DecrRef(void)
Decrements reference count and deletes on 0.
This decrements the reference on destruction.
static guint32 * tmp
Definition: goom_core.cpp:26
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:199
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
static bool VERBOSE_LEVEL_CHECK(uint64_t mask, LogLevel_t level)
Definition: mythlogging.h:29
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
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
string hostname
Definition: caa.py:17