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 
53 #include <QMutexLocker>
54 #include <utility>
55 
56 #include "mythevent.h"
57 #include "mythdbcon.h"
58 #include "housekeeper.h"
59 #include "mythcorecontext.h"
60 
99  ReferenceCounter(dbTag), m_dbTag(dbTag), m_scope(scope),
100  m_startup(startup),
101 #if QT_VERSION < QT_VERSION_CHECK(5,8,0)
102  m_lastRun(MythDate::fromTime_t(0)),
103  m_lastSuccess(MythDate::fromTime_t(0)),
104  m_lastUpdate(MythDate::fromTime_t(0))
105 #else
106  m_lastRun(MythDate::fromSecsSinceEpoch(0)),
107  m_lastSuccess(MythDate::fromSecsSinceEpoch(0)),
108  m_lastUpdate(MythDate::fromSecsSinceEpoch(0))
109 #endif
110 {
111 }
112 
113 bool HouseKeeperTask::CheckRun(QDateTime now)
114 {
115  LOG(VB_GENERAL, LOG_DEBUG, QString("Checking to run %1").arg(GetTag()));
116  bool check = false;
117  if (!m_confirm && !m_running && (check = DoCheckRun(std::move(now))))
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  return check;
122 }
123 
125 {
126  return ((m_startup == kHKRunImmediateOnStartup) &&
128 }
129 
131 {
133  {
134  m_confirm = true;
135  return true;
136  }
137  return false;
138 }
139 
141 {
142  LOG(VB_GENERAL, LOG_INFO, QString("Running HouseKeeperTask '%1'.")
143  .arg(m_dbTag));
144  if (m_running)
145  {
146  // something else is already running me, bail out
147  LOG(VB_GENERAL, LOG_WARNING, QString("HouseKeeperTask '%1' already "
148  "running. Refusing to run concurrently").arg(m_dbTag));
149  return false;
150  }
151 
152  m_running = true;
153  bool res = DoRun();
154  m_running = false;
155  if (!res)
156  LOG(VB_GENERAL, LOG_INFO, QString("HouseKeeperTask '%1' Failed.")
157  .arg(m_dbTag));
158  else
159  LOG(VB_GENERAL, LOG_INFO,
160  QString("HouseKeeperTask '%1' Finished Successfully.")
161  .arg(m_dbTag));
162  return res;
163 }
164 
166 {
167  QueryLast();
168  return m_lastRun;
169 }
170 
172 {
173  QueryLast();
174  return m_lastRun;
175 }
176 
178 {
179  if (m_scope != kHKInst)
180  {
181  if (m_lastUpdate.addSecs(30) > MythDate::current())
182  // just to cut down on unnecessary queries
183  return;
184 
185  MSqlQuery query(MSqlQuery::InitCon());
186 
187 #if QT_VERSION < QT_VERSION_CHECK(5,8,0)
188  m_lastRun = MythDate::fromTime_t(0);
189  m_lastSuccess = MythDate::fromTime_t(0);
190 #else
193 #endif
194 
195  if (m_scope == kHKGlobal)
196  {
197  query.prepare("SELECT lastrun,lastsuccess FROM housekeeping"
198  " WHERE tag = :TAG"
199  " AND hostname IS NULL");
200  }
201  else
202  {
203  query.prepare("SELECT lastrun,lastsuccess FROM housekeeping"
204  " WHERE tag = :TAG"
205  " AND hostname = :HOST");
206  query.bindValue(":HOST", gCoreContext->GetHostName());
207  }
208 
209  query.bindValue(":TAG", m_dbTag);
210 
211  if (query.exec() && query.next())
212  {
213  m_lastRun = MythDate::as_utc(query.value(0).toDateTime());
214  m_lastSuccess = MythDate::as_utc(query.value(1).toDateTime());
215  }
216  }
217 
219 }
220 
221 QDateTime HouseKeeperTask::UpdateLastRun(QDateTime last, bool successful)
222 {
223  m_lastRun = last;
224  if (successful)
226  m_confirm = false;
227 
228  if (m_scope != kHKInst)
229  {
230  MSqlQuery query(MSqlQuery::InitCon());
231  if (!query.isConnected())
232  return last;
233 
234 #if QT_VERSION < QT_VERSION_CHECK(5,8,0)
235  if (m_lastRun == MythDate::fromTime_t(0))
236 #else
238 #endif
239  {
240  // not previously set, perform insert
241 
242  if (m_scope == kHKGlobal)
243  query.prepare("INSERT INTO housekeeping"
244  " (tag, lastrun, lastsuccess)"
245  " VALUES (:TAG, :TIME, :STIME)");
246  else
247  query.prepare("INSERT INTO housekeeping"
248  " (tag, hostname, lastrun, lastsuccess)"
249  " VALUES (:TAG, :HOST, :TIME, :STIME)");
250  }
251  else
252  {
253  // previously set, perform update
254 
255  if (m_scope == kHKGlobal)
256  query.prepare("UPDATE housekeeping SET lastrun=:TIME,"
257  " lastsuccess=:STIME"
258  " WHERE tag = :TAG"
259  " AND hostname IS NULL");
260  else
261  query.prepare("UPDATE housekeeping SET lastrun=:TIME,"
262  " lastsuccess=:STIME"
263  " WHERE tag = :TAG"
264  " AND hostname = :HOST");
265  }
266 
267  if (m_scope == kHKGlobal)
268  LOG(VB_GENERAL, LOG_DEBUG,
269  QString("Updating global run time for %1").arg(m_dbTag));
270  else
271  LOG(VB_GENERAL, LOG_DEBUG,
272  QString("Updating local run time for %1").arg(m_dbTag));
273 
274  if (m_scope == kHKLocal)
275  query.bindValue(":HOST", gCoreContext->GetHostName());
276  query.bindValue(":TAG", m_dbTag);
277  query.bindValue(":TIME", MythDate::as_utc(m_lastRun));
278  query.bindValue(":STIME", MythDate::as_utc(m_lastSuccess));
279 
280  if (!query.exec())
281  MythDB::DBError("HouseKeeperTask::updateLastRun", query);
282  }
283 
284  QString msg;
285  if (successful)
286  msg = QString("HOUSE_KEEPER_SUCCESSFUL %1 %2 %3");
287  else
288  msg = QString("HOUSE_KEEPER_RUNNING %1 %2 %3");
289  msg = msg.arg(gCoreContext->GetHostName())
290  .arg(m_dbTag)
294 
295  return last;
296 }
297 
298 void HouseKeeperTask::SetLastRun(QDateTime last, bool successful)
299 {
300  m_lastRun = last;
301  if (successful)
303 
305 }
306 
321  int period, float min, float max, int retry,
323  HouseKeeperTask(dbTag, scope, startup), m_period(period), m_retry(retry),
324  m_windowPercent(min, max), m_currentProb(1.0)
325 {
327  if (m_retry == 0)
328  m_retry = m_period;
329 }
330 
332 {
333  int period = m_period;
334  if (GetLastRun() > GetLastSuccess())
335  // last attempt was not successful
336  // try shortened period
337  period = m_retry;
338 
339  m_windowElapsed.first =
340  (uint32_t)((float)period * m_windowPercent.first);
341  m_windowElapsed.second =
342  (uint32_t)((float)period * m_windowPercent.second);
343 }
344 
345 void PeriodicHouseKeeperTask::SetWindow(float min, float max)
346 {
347  m_windowPercent.first = min;
348  m_windowPercent.second = max;
349  CalculateWindow();
350 }
351 
353  bool successful)
354 {
355  QDateTime res = HouseKeeperTask::UpdateLastRun(last, successful);
356  CalculateWindow();
357  m_currentProb = 1.0;
358  return res;
359 }
360 
361 void PeriodicHouseKeeperTask::SetLastRun(QDateTime last, bool successful)
362 {
363  HouseKeeperTask::SetLastRun(last, successful);
364  CalculateWindow();
365  m_currentProb = 1.0;
366 }
367 
369 {
370  int elapsed = GetLastRun().secsTo(now);
371 
372  if (elapsed < 0)
373  // something bad has happened. let's just move along
374  return false;
375 
376  if (elapsed < m_windowElapsed.first)
377  // insufficient time elapsed to test
378  return false;
379  if (elapsed > m_windowElapsed.second)
380  // too much time has passed. force run
381  return true;
382 
383  // calculate probability that task should not have yet run
384  // it's backwards, but it makes the math simplier
385  float prob = 1.0F - ((float)(elapsed - m_windowElapsed.first) /
386  (float)(m_windowElapsed.second - m_windowElapsed.first));
387  if (m_currentProb < prob)
388  // more bad stuff
389  return false;
390 
391  // calculate current probability to achieve overall probability
392  // this should be nearly one
393  float prob2 = prob/m_currentProb;
394  // so rand() should have to return nearly RAND_MAX to get a positive
395  // remember, this is computing the probability that up to this point, one
396  // of these tests has returned positive, so each individual test has
397  // a necessarily low probability
398  bool res = (rand() > (int)(prob2 * RAND_MAX));
399  m_currentProb = prob;
400 // if (res)
401 // LOG(VB_GENERAL, LOG_DEBUG, QString("%1 will run: this=%2; total=%3")
402 // .arg(GetTag()).arg(1-prob2).arg(1-prob));
403 // else
404 // LOG(VB_GENERAL, LOG_DEBUG, QString("%1 will not run: this=%2; total=%3")
405 // .arg(GetTag()).arg(1-prob2).arg(1-prob));
406  return res;
407 }
408 
410 {
411  int elapsed = GetLastRun().secsTo(now);
412 
413  if (elapsed < 0)
414  // something bad has happened. let's just move along
415  return false;
416 
417  return (elapsed > m_windowElapsed.first) &&
418  (elapsed < m_windowElapsed.second);
419 }
420 
422 {
423  return GetLastRun().secsTo(now) > m_windowElapsed.second;
424 }
425 
441  PeriodicHouseKeeperTask(dbTag, 86400, .5, 1.5, 0, scope, startup),
442  m_windowHour(0, 23)
443 {
445 }
446 
447 DailyHouseKeeperTask::DailyHouseKeeperTask(const QString &dbTag, int minhour,
448  int maxhour, HouseKeeperScope scope, HouseKeeperStartup startup) :
449  PeriodicHouseKeeperTask(dbTag, 86400, .5, 1.5, 0, scope, startup),
450  m_windowHour(minhour, maxhour)
451 {
453 }
454 
456 {
458  QDate date = GetLastRun().addDays(1).date();
459 
460  QDateTime tmp = QDateTime(date, QTime(m_windowHour.first, 0));
461  if (GetLastRun().addSecs(m_windowElapsed.first) < tmp)
462  m_windowElapsed.first = GetLastRun().secsTo(tmp);
463 
464  tmp = QDateTime(date, QTime(m_windowHour.second, 30));
465  // we want to make sure this gets run before the end of the day
466  // so add a 30 minute buffer prior to the end of the window
467  if (GetLastRun().addSecs(m_windowElapsed.second) > tmp)
468  m_windowElapsed.second = GetLastRun().secsTo(tmp);
469 
470  LOG(VB_GENERAL, LOG_DEBUG, QString("%1 Run window between %2 - %3.")
471  .arg(GetTag()).arg(m_windowElapsed.first).arg(m_windowElapsed.second));
472 }
473 
475 {
476  m_windowHour.first = min;
477  m_windowHour.second = max;
478  CalculateWindow();
479 }
480 
482 {
484  // parent says we're in the window
485  return true;
486 
487  int hour = now.time().hour();
488  // true if we've missed the window, but we're within our time constraints
489  return PastWindow(now) && (m_windowHour.first <= hour)
490  && (m_windowHour.second > hour);
491 }
492 
504 {
505  RunProlog();
506  m_waitMutex.lock();
507  HouseKeeperTask *task = nullptr;
508 
509  while (m_keepRunning)
510  {
511  m_idle = false;
512 
513  while ((task = m_parent->GetQueuedTask()))
514  {
515  // pull task from housekeeper and process it
516  ReferenceLocker rlock(task);
517 
518  if (!task->ConfirmRun())
519  {
520  // something else has caused the lastrun time to
521  // change since this was requested to run. abort.
522  task = nullptr;
523  continue;
524  }
525 
526  task->UpdateLastRun(false);
527  if (task->Run())
528  task->UpdateLastRun(task->GetLastRun(), true);
529  task = nullptr;
530 
531  if (!m_keepRunning)
532  // thread has been discarded, don't try to start another task
533  break;
534  }
535 
536  m_idle = true;
537 
538  if (!m_keepRunning)
539  // short out rather than potentially hitting another sleep cycle
540  break;
541 
543  }
544 
545  m_waitMutex.unlock();
546  RunEpilog();
547 }
548 
565 HouseKeeper::HouseKeeper(void) : m_timer(nullptr)
566 {
567  m_timer = new QTimer(this);
568  connect(m_timer, SIGNAL(timeout()), this, SLOT(Run()));
569  m_timer->setInterval(60000);
570  m_timer->setSingleShot(false);
571 }
572 
574 {
576 
577  if (m_timer)
578  {
579  m_timer->stop();
580  disconnect(m_timer);
581  delete m_timer;
582  m_timer = nullptr;
583  }
584 
585  {
586  // remove anything from the queue first, so it does not start
587  QMutexLocker queueLock(&m_queueLock);
588  while (!m_taskQueue.isEmpty())
589  m_taskQueue.takeFirst()->DecrRef();
590  }
591 
592  {
593  // issue a terminate call to any long-running tasks
594  // this is just a noop unless overwritten by a subclass
595  QMutexLocker mapLock(&m_mapLock);
596  QMap<QString,HouseKeeperTask*>::iterator it = m_taskMap.begin();
597  for (; it != m_taskMap.end(); ++it)
598  (*it)->Terminate();
599  }
600 
601  if (!m_threadList.isEmpty())
602  {
603  QMutexLocker threadLock(&m_threadLock);
604  // tell primary thread to self-terminate and wake it
605  m_threadList.first()->Discard();
606  m_threadList.first()->Wake();
607  // wait for any remaining threads to self-terminate and close
608  while (!m_threadList.isEmpty())
609  {
610  HouseKeepingThread *thread = m_threadList.takeFirst();
611  thread->wait();
612  delete thread;
613  }
614  }
615 
616  {
617  // unload any registered tasks
618  QMutexLocker mapLock(&m_mapLock);
619  QMap<QString,HouseKeeperTask*>::iterator it = m_taskMap.begin();
620  while (it != m_taskMap.end())
621  {
622  (*it)->DecrRef();
623  it = m_taskMap.erase(it);
624  }
625  }
626 }
627 
629 {
630  QMutexLocker mapLock(&m_mapLock);
631  QString tag = task->GetTag();
632  if (m_taskMap.contains(tag))
633  {
634  task->DecrRef();
635  LOG(VB_GENERAL, LOG_ERR,
636  QString("HouseKeeperTask '%1' already registered. "
637  "Rejecting duplicate.").arg(tag));
638  }
639  else
640  {
641  LOG(VB_GENERAL, LOG_INFO,
642  QString("Registering HouseKeeperTask '%1'.").arg(tag));
643  m_taskMap.insert(tag, task);
644  }
645 }
646 
648 {
649  QMutexLocker queueLock(&m_queueLock);
650  HouseKeeperTask *task = nullptr;
651 
652  if (!m_taskQueue.isEmpty())
653  {
654  task = m_taskQueue.dequeue();
655  }
656 
657  // returning nullptr tells the thread that the queue is empty and
658  // to go into standby
659  return task;
660 }
661 
663 {
664  // no need to be fine grained, nothing else should be accessing this map
665  QMutexLocker mapLock(&m_mapLock);
666 
667  if (m_timer->isActive())
668  // Start() should only be called once
669  return;
670 
671  MSqlQuery query(MSqlQuery::InitCon());
672  query.prepare("SELECT tag,lastrun"
673  " FROM housekeeping"
674  " WHERE hostname = :HOST"
675  " OR hostname IS NULL");
676  query.bindValue(":HOST", gCoreContext->GetHostName());
677 
678  if (!query.exec())
679  MythDB::DBError("HouseKeeper::Run", query);
680  else
681  {
682  while (query.next())
683  {
684  // loop through housekeeping table and load last run timestamps
685  QString tag = query.value(0).toString();
686  QDateTime lastrun = MythDate::as_utc(query.value(1).toDateTime());
687 
688  if (m_taskMap.contains(tag))
689  m_taskMap[tag]->SetLastRun(lastrun);
690  }
691  }
692 
693  gCoreContext->addListener(this);
694 
695  QMap<QString,HouseKeeperTask*>::const_iterator it;
696  for (it = m_taskMap.begin(); it != m_taskMap.end(); ++it)
697  {
698  if ((*it)->CheckImmediate())
699  {
700  // run any tasks marked for immediate operation in-thread
701  (*it)->UpdateLastRun();
702  (*it)->Run();
703  }
704  else if ((*it)->CheckStartup())
705  {
706  // queue any tasks marked for startup
707  LOG(VB_GENERAL, LOG_INFO,
708  QString("Queueing HouseKeeperTask '%1'.").arg(it.key()));
709  QMutexLocker queueLock(&m_queueLock);
710  (*it)->IncrRef();
711  m_taskQueue.enqueue(*it);
712  }
713  }
714 
715  LOG(VB_GENERAL, LOG_INFO, "Starting HouseKeeper.");
716 
717  m_timer->start();
718 }
719 
721 {
722  LOG(VB_GENERAL, LOG_DEBUG, "Running HouseKeeper.");
723 
724  QDateTime now = MythDate::current();
725 
726  QMutexLocker mapLock(&m_mapLock);
727  for (auto it = m_taskMap.begin(); it != m_taskMap.end(); ++it)
728  {
729  if ((*it)->CheckRun(now))
730  {
731  // check if any tasks are ready to run, and add to queue
732  LOG(VB_GENERAL, LOG_INFO,
733  QString("Queueing HouseKeeperTask '%1'.").arg(it.key()));
734  QMutexLocker queueLock(&m_queueLock);
735  (*it)->IncrRef();
736  m_taskQueue.enqueue(*it);
737  }
738  }
739 
740  if (!m_taskQueue.isEmpty())
741  StartThread();
742 
743  if (m_threadList.size() > 1)
744  {
745  // spent threads exist in the thread list
746  // check to see if any have finished up their task and terminated
747  QMutexLocker threadLock(&m_threadLock);
748  int count1 = m_threadList.size();
749 
750  auto it = m_threadList.begin();
751  ++it; // skip the primary thread
752  while (it != m_threadList.end())
753  {
754  if ((*it)->isRunning())
755  ++it;
756  else
757  {
758  delete *it;
759  it = m_threadList.erase(it);
760  }
761  }
762 
763  int count2 = m_threadList.size();
764  if (count1 > count2)
765  LOG(VB_GENERAL, LOG_DEBUG,
766  QString("Discarded HouseKeepingThreads have completed and "
767  "been deleted. Current count %1 -> %2.")
768  .arg(count1).arg(count2));
769  }
770 }
771 
786 {
787  QMutexLocker threadLock(&m_threadLock);
788 
789  if (m_threadList.isEmpty())
790  {
791  // we're running for the first time
792  // start up a new thread
793  LOG(VB_GENERAL, LOG_DEBUG, "Running initial HouseKeepingThread.");
794  HouseKeepingThread *thread = new HouseKeepingThread(this);
795  m_threadList.append(thread);
796  thread->start();
797  }
798 
799  else if (!m_threadList.first()->isIdle())
800  {
801  // the old thread is still off processing something
802  // discard it and start a new one because we have more stuff
803  // that wants to run
804  LOG(VB_GENERAL, LOG_DEBUG,
805  QString("Current HouseKeepingThread is delayed on task, "
806  "spawning replacement. Current count %1.")
807  .arg(m_threadList.size()));
808  m_threadList.first()->Discard();
809  HouseKeepingThread *thread = new HouseKeepingThread(this);
810  m_threadList.prepend(thread);
811  thread->start();
812  }
813 
814  else
815  {
816  // the old thread is idle, so just wake it for processing
817  LOG(VB_GENERAL, LOG_DEBUG, "Waking HouseKeepingThread.");
818  m_threadList.first()->Wake();
819  }
820 }
821 
823 {
824  if (e->type() == MythEvent::MythEventMessage)
825  {
826  MythEvent *me = static_cast<MythEvent*>(e);
827  if ((me->Message().left(20) == "HOUSE_KEEPER_RUNNING") ||
828  (me->Message().left(23) == "HOUSE_KEEPER_SUCCESSFUL"))
829  {
830  QStringList tokens = me->Message()
831  .split(" ", QString::SkipEmptyParts);
832  if (tokens.size() != 4)
833  return;
834 
835  QString hostname = tokens[1];
836  QString tag = tokens[2];
837  QDateTime last = MythDate::fromString(tokens[3]);
838  bool successful = me->Message().contains("SUCCESSFUL");
839 
840  QMutexLocker mapLock(&m_mapLock);
841  if (m_taskMap.contains(tag))
842  {
843  if ((m_taskMap[tag]->GetScope() == kHKGlobal) ||
844  ((m_taskMap[tag]->GetScope() == kHKLocal) &&
846  // task being run in the same scope as us.
847  // update the run time so we don't attempt to run
848  // it ourselves
849  m_taskMap[tag]->SetLastRun(last, successful);
850  }
851  }
852  }
853 }
void RunEpilog(void)
Cleans up a thread's resources, call this if you reimplement run().
Definition: mthread.cpp:215
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:782
void start(QThread::Priority=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
Definition: mthread.cpp:294
QDateTime m_lastRun
Definition: housekeeper.h:79
void CalculateWindow(void) override
QDateTime QueryLastRun(void)
Definition for a single task to be run by the HouseKeeper.
Definition: housekeeper.h:39
virtual bool PastWindow(QDateTime now)
HouseKeeperScope m_scope
Definition: housekeeper.h:75
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:863
QList< HouseKeepingThread * > m_threadList
Definition: housekeeper.h:175
struct exc__state * last
Definition: pxsup2dast.c:98
QMutex m_mapLock
Definition: housekeeper.h:173
QMutex m_threadLock
Definition: housekeeper.h:176
void RegisterTask(HouseKeeperTask *task)
void Run(void)
static Type MythEventMessage
Definition: mythevent.h:66
QDateTime GetLastRun(void)
Definition: housekeeper.h:55
void removeListener(QObject *listener)
Remove a listener to the observable.
General purpose reference counter.
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:125
HouseKeeperTask(const QString &dbTag, HouseKeeperScope scope=kHKGlobal, HouseKeeperStartup startup=kHKNormal)
Definition: housekeeper.cpp:97
bool wait(unsigned long time=ULONG_MAX)
Wait for the MThread to exit, with a maximum timeout.
Definition: mthread.cpp:311
void customEvent(QEvent *e) override
static int startup()
bool DoCheckRun(QDateTime now) override
bool isConnected(void)
Only updated once during object creation.
Definition: mythdbcon.h:135
PeriodicHouseKeeperTask(const QString &dbTag, int period, float min=0.5, float max=1.1, int retry=0, HouseKeeperScope scope=kHKGlobal, HouseKeeperStartup startup=kHKNormal)
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
bool CheckImmediate(void)
This decrements the reference on destruction.
void addListener(QObject *listener)
Add a listener to the observable.
static guint32 * tmp
Definition: goom_core.c:35
QDateTime as_utc(const QDateTime &old_dt)
Returns copy of QDateTime with TimeSpec set to UTC.
Definition: mythdate.cpp:23
QMutex m_queueLock
Definition: housekeeper.h:170
QVariant value(int i) const
Definition: mythdbcon.h:198
DailyHouseKeeperTask(const QString &dbTag, HouseKeeperScope scope=kHKGlobal, HouseKeeperStartup startup=kHKNormal)
virtual void CalculateWindow(void)
QQueue< HouseKeeperTask * > m_taskQueue
Definition: housekeeper.h:169
task should only run once per cluster e.g.
Definition: housekeeper.h:25
bool InWindow(QDateTime now) override
Thread used to perform queued HouseKeeper tasks.
Definition: housekeeper.h:126
This class is used as a container for messages.
Definition: mythevent.h:16
MBASE_PUBLIC QDateTime fromSecsSinceEpoch(uint seconds)
This function takes the number of seconds since the start of the epoch and returns a QDateTime with t...
Definition: mythdate.cpp:88
task should run on every process e.g.
Definition: housekeeper.h:29
HouseKeeperScope
Definition: housekeeper.h:24
task is queued when HouseKeeper is started
Definition: housekeeper.h:35
bool Run(void)
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:10
QPair< int, int > m_windowHour
Definition: housekeeper.h:123
virtual bool InWindow(QDateTime now)
HouseKeeper * m_parent
Definition: housekeeper.h:143
void QueryLast(void)
virtual int DecrRef(void)
Decrements reference count and deletes on 0.
QTimer * m_timer
Definition: housekeeper.h:167
virtual void SetLastRun(QDateTime last, bool successful=true)
string hostname
Definition: caa.py:17
Modified HouseKeeperTask for tasks to be run at a regular interval.
Definition: housekeeper.h:84
static MSqlQueryInfo InitCon(ConnectionReuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:535
HouseKeeperStartup m_startup
Definition: housekeeper.h:76
QPair< int, int > m_windowElapsed
Definition: housekeeper.h:103
QString toString(const QDateTime &raw_dt, uint format)
Returns formatted string representing the time.
Definition: mythdate.cpp:101
QMap< QString, HouseKeeperTask * > m_taskMap
Definition: housekeeper.h:172
virtual bool DoCheckRun(QDateTime)
Definition: housekeeper.h:65
void run(void) override
Runs the Qt event loop unless we have a QRunnable, in which case we run the runnable run instead.
bool ConfirmRun(void)
Definition: housekeeper.h:48
QString m_dbTag
Definition: housekeeper.h:73
virtual void SetHourWindow(int min, int max)
QString GetTag(void)
Definition: housekeeper.h:54
QPair< float, float > m_windowPercent
Definition: housekeeper.h:102
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:807
bool CheckRun(QDateTime now)
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
bool CheckStartup(void)
QWaitCondition m_waitCondition
Definition: housekeeper.h:145
task is run during HouseKeeper startup
Definition: housekeeper.h:36
QDateTime UpdateLastRun(QDateTime last, bool successful=true) override
void RunProlog(void)
Sets up a thread, call this if you reimplement run().
Definition: mthread.cpp:202
QDateTime UpdateLastRun(bool successful=true)
Definition: housekeeper.h:60
QDateTime m_lastUpdate
Definition: housekeeper.h:81
HouseKeeperTask * GetQueuedTask(void)
HouseKeeper(void)
HouseKeeperStartup
Definition: housekeeper.h:33
virtual void SetWindow(float min, float max)
void SetLastRun(QDateTime last, bool successful=true) override
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:603
void StartThread(void)
Wake the primary run thread, or create a new one.
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:179
const QString & Message() const
Definition: mythevent.h:58
QString GetHostName(void)
QDateTime fromString(const QString &dtstr)
Converts kFilename && kISODate formats to QDateTime.
Definition: mythdate.cpp:30
void SendEvent(const MythEvent &event)
QDateTime m_lastSuccess
Definition: housekeeper.h:80
Default UTC.
Definition: mythdate.h:14
task should only run once per machine e.g.
Definition: housekeeper.h:27
virtual bool DoRun(void)
Definition: housekeeper.h:66
QDateTime GetLastSuccess(void)
Definition: housekeeper.h:56
void Start(void)
QDateTime QueryLastSuccess(void)