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(const QDateTime& last, bool successful)
222 {
223  m_lastRun = last;
224  if (successful)
225  m_lastSuccess = last;
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(const QDateTime &last, bool successful)
299 {
300  m_lastRun = last;
301  if (successful)
302  m_lastSuccess = last;
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 
352 QDateTime PeriodicHouseKeeperTask::UpdateLastRun(const QDateTime& last,
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(const 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  //
399  // Pseudo-random is good enough. Don't need a true random.
400  // NOLINTNEXTLINE(cert-msc30-c,cert-msc50-cpp)
401  bool res = (rand() > (int)(prob2 * static_cast<float>(RAND_MAX)));
402  m_currentProb = prob;
403 // if (res)
404 // LOG(VB_GENERAL, LOG_DEBUG, QString("%1 will run: this=%2; total=%3")
405 // .arg(GetTag()).arg(1-prob2).arg(1-prob));
406 // else
407 // LOG(VB_GENERAL, LOG_DEBUG, QString("%1 will not run: this=%2; total=%3")
408 // .arg(GetTag()).arg(1-prob2).arg(1-prob));
409  return res;
410 }
411 
412 bool PeriodicHouseKeeperTask::InWindow(const QDateTime& now)
413 {
414  int elapsed = GetLastRun().secsTo(now);
415 
416  if (elapsed < 0)
417  // something bad has happened. let's just move along
418  return false;
419 
420  return (elapsed > m_windowElapsed.first) &&
421  (elapsed < m_windowElapsed.second);
422 }
423 
424 bool PeriodicHouseKeeperTask::PastWindow(const QDateTime &now)
425 {
426  return GetLastRun().secsTo(now) > m_windowElapsed.second;
427 }
428 
444  PeriodicHouseKeeperTask(dbTag, 86400, .5, 1.5, 0, scope, startup),
445  m_windowHour(0, 23)
446 {
448 }
449 
450 DailyHouseKeeperTask::DailyHouseKeeperTask(const QString &dbTag, int minhour,
451  int maxhour, HouseKeeperScope scope, HouseKeeperStartup startup) :
452  PeriodicHouseKeeperTask(dbTag, 86400, .5, 1.5, 0, scope, startup),
453  m_windowHour(minhour, maxhour)
454 {
456 }
457 
459 {
461  QDate date = GetLastRun().addDays(1).date();
462 
463  QDateTime tmp = QDateTime(date, QTime(m_windowHour.first, 0));
464  if (GetLastRun().addSecs(m_windowElapsed.first) < tmp)
465  m_windowElapsed.first = GetLastRun().secsTo(tmp);
466 
467  tmp = QDateTime(date, QTime(m_windowHour.second, 30));
468  // we want to make sure this gets run before the end of the day
469  // so add a 30 minute buffer prior to the end of the window
470  if (GetLastRun().addSecs(m_windowElapsed.second) > tmp)
471  m_windowElapsed.second = GetLastRun().secsTo(tmp);
472 
473  LOG(VB_GENERAL, LOG_DEBUG, QString("%1 Run window between %2 - %3.")
474  .arg(GetTag()).arg(m_windowElapsed.first).arg(m_windowElapsed.second));
475 }
476 
478 {
479  m_windowHour.first = min;
480  m_windowHour.second = max;
481  CalculateWindow();
482 }
483 
484 bool DailyHouseKeeperTask::InWindow(const QDateTime& now)
485 {
487  // parent says we're in the window
488  return true;
489 
490  int hour = now.time().hour();
491  // true if we've missed the window, but we're within our time constraints
492  return PastWindow(now) && (m_windowHour.first <= hour)
493  && (m_windowHour.second > hour);
494 }
495 
507 {
508  RunProlog();
509  m_waitMutex.lock();
510  HouseKeeperTask *task = nullptr;
511 
512  while (m_keepRunning)
513  {
514  m_idle = false;
515 
516  while ((task = m_parent->GetQueuedTask()))
517  {
518  // pull task from housekeeper and process it
519  ReferenceLocker rlock(task);
520 
521  if (!task->ConfirmRun())
522  {
523  // something else has caused the lastrun time to
524  // change since this was requested to run. abort.
525  task = nullptr;
526  continue;
527  }
528 
529  task->UpdateLastRun(false);
530  if (task->Run())
531  task->UpdateLastRun(task->GetLastRun(), true);
532  task = nullptr;
533 
534  if (!m_keepRunning)
535  // thread has been discarded, don't try to start another task
536  break;
537  }
538 
539  m_idle = true;
540 
541  if (!m_keepRunning)
542  // short out rather than potentially hitting another sleep cycle
543  break;
544 
546  }
547 
548  m_waitMutex.unlock();
549  RunEpilog();
550 }
551 
568 HouseKeeper::HouseKeeper(void) : m_timer(nullptr)
569 {
570  m_timer = new QTimer(this);
571  connect(m_timer, SIGNAL(timeout()), this, SLOT(Run()));
572  m_timer->setInterval(60000);
573  m_timer->setSingleShot(false);
574 }
575 
577 {
579 
580  if (m_timer)
581  {
582  m_timer->stop();
583  disconnect(m_timer);
584  delete m_timer;
585  m_timer = nullptr;
586  }
587 
588  {
589  // remove anything from the queue first, so it does not start
590  QMutexLocker queueLock(&m_queueLock);
591  while (!m_taskQueue.isEmpty())
592  m_taskQueue.takeFirst()->DecrRef();
593  }
594 
595  {
596  // issue a terminate call to any long-running tasks
597  // this is just a noop unless overwritten by a subclass
598  QMutexLocker mapLock(&m_mapLock);
599  QMap<QString,HouseKeeperTask*>::iterator it = m_taskMap.begin();
600  for (; it != m_taskMap.end(); ++it)
601  (*it)->Terminate();
602  }
603 
604  if (!m_threadList.isEmpty())
605  {
606  QMutexLocker threadLock(&m_threadLock);
607  // tell primary thread to self-terminate and wake it
608  m_threadList.first()->Discard();
609  m_threadList.first()->Wake();
610  // wait for any remaining threads to self-terminate and close
611  while (!m_threadList.isEmpty())
612  {
613  HouseKeepingThread *thread = m_threadList.takeFirst();
614  thread->wait();
615  delete thread;
616  }
617  }
618 
619  {
620  // unload any registered tasks
621  QMutexLocker mapLock(&m_mapLock);
622  QMap<QString,HouseKeeperTask*>::iterator it = m_taskMap.begin();
623  while (it != m_taskMap.end())
624  {
625  (*it)->DecrRef();
626  it = m_taskMap.erase(it);
627  }
628  }
629 }
630 
632 {
633  QMutexLocker mapLock(&m_mapLock);
634  QString tag = task->GetTag();
635  if (m_taskMap.contains(tag))
636  {
637  task->DecrRef();
638  LOG(VB_GENERAL, LOG_ERR,
639  QString("HouseKeeperTask '%1' already registered. "
640  "Rejecting duplicate.").arg(tag));
641  }
642  else
643  {
644  LOG(VB_GENERAL, LOG_INFO,
645  QString("Registering HouseKeeperTask '%1'.").arg(tag));
646  m_taskMap.insert(tag, task);
647  }
648 }
649 
651 {
652  QMutexLocker queueLock(&m_queueLock);
653  HouseKeeperTask *task = nullptr;
654 
655  if (!m_taskQueue.isEmpty())
656  {
657  task = m_taskQueue.dequeue();
658  }
659 
660  // returning nullptr tells the thread that the queue is empty and
661  // to go into standby
662  return task;
663 }
664 
666 {
667  // no need to be fine grained, nothing else should be accessing this map
668  QMutexLocker mapLock(&m_mapLock);
669 
670  if (m_timer->isActive())
671  // Start() should only be called once
672  return;
673 
674  MSqlQuery query(MSqlQuery::InitCon());
675  query.prepare("SELECT tag,lastrun"
676  " FROM housekeeping"
677  " WHERE hostname = :HOST"
678  " OR hostname IS NULL");
679  query.bindValue(":HOST", gCoreContext->GetHostName());
680 
681  if (!query.exec())
682  MythDB::DBError("HouseKeeper::Run", query);
683  else
684  {
685  while (query.next())
686  {
687  // loop through housekeeping table and load last run timestamps
688  QString tag = query.value(0).toString();
689  QDateTime lastrun = MythDate::as_utc(query.value(1).toDateTime());
690 
691  if (m_taskMap.contains(tag))
692  m_taskMap[tag]->SetLastRun(lastrun);
693  }
694  }
695 
696  gCoreContext->addListener(this);
697 
698  QMap<QString,HouseKeeperTask*>::const_iterator it;
699  for (it = m_taskMap.begin(); it != m_taskMap.end(); ++it)
700  {
701  if ((*it)->CheckImmediate())
702  {
703  // run any tasks marked for immediate operation in-thread
704  (*it)->UpdateLastRun();
705  (*it)->Run();
706  }
707  else if ((*it)->CheckStartup())
708  {
709  // queue any tasks marked for startup
710  LOG(VB_GENERAL, LOG_INFO,
711  QString("Queueing HouseKeeperTask '%1'.").arg(it.key()));
712  QMutexLocker queueLock(&m_queueLock);
713  (*it)->IncrRef();
714  m_taskQueue.enqueue(*it);
715  }
716  }
717 
718  LOG(VB_GENERAL, LOG_INFO, "Starting HouseKeeper.");
719 
720  m_timer->start();
721 }
722 
724 {
725  LOG(VB_GENERAL, LOG_DEBUG, "Running HouseKeeper.");
726 
727  QDateTime now = MythDate::current();
728 
729  QMutexLocker mapLock(&m_mapLock);
730  for (auto it = m_taskMap.begin(); it != m_taskMap.end(); ++it)
731  {
732  if ((*it)->CheckRun(now))
733  {
734  // check if any tasks are ready to run, and add to queue
735  LOG(VB_GENERAL, LOG_INFO,
736  QString("Queueing HouseKeeperTask '%1'.").arg(it.key()));
737  QMutexLocker queueLock(&m_queueLock);
738  (*it)->IncrRef();
739  m_taskQueue.enqueue(*it);
740  }
741  }
742 
743  if (!m_taskQueue.isEmpty())
744  StartThread();
745 
746  if (m_threadList.size() > 1)
747  {
748  // spent threads exist in the thread list
749  // check to see if any have finished up their task and terminated
750  QMutexLocker threadLock(&m_threadLock);
751  int count1 = m_threadList.size();
752 
753  auto it = m_threadList.begin();
754  ++it; // skip the primary thread
755  while (it != m_threadList.end())
756  {
757  if ((*it)->isRunning())
758  ++it;
759  else
760  {
761  delete *it;
762  it = m_threadList.erase(it);
763  }
764  }
765 
766  int count2 = m_threadList.size();
767  if (count1 > count2)
768  LOG(VB_GENERAL, LOG_DEBUG,
769  QString("Discarded HouseKeepingThreads have completed and "
770  "been deleted. Current count %1 -> %2.")
771  .arg(count1).arg(count2));
772  }
773 }
774 
789 {
790  QMutexLocker threadLock(&m_threadLock);
791 
792  if (m_threadList.isEmpty())
793  {
794  // we're running for the first time
795  // start up a new thread
796  LOG(VB_GENERAL, LOG_DEBUG, "Running initial HouseKeepingThread.");
797  auto *thread = new HouseKeepingThread(this);
798  m_threadList.append(thread);
799  thread->start();
800  }
801 
802  else if (!m_threadList.first()->isIdle())
803  {
804  // the old thread is still off processing something
805  // discard it and start a new one because we have more stuff
806  // that wants to run
807  LOG(VB_GENERAL, LOG_DEBUG,
808  QString("Current HouseKeepingThread is delayed on task, "
809  "spawning replacement. Current count %1.")
810  .arg(m_threadList.size()));
811  m_threadList.first()->Discard();
812  auto *thread = new HouseKeepingThread(this);
813  m_threadList.prepend(thread);
814  thread->start();
815  }
816 
817  else
818  {
819  // the old thread is idle, so just wake it for processing
820  LOG(VB_GENERAL, LOG_DEBUG, "Waking HouseKeepingThread.");
821  m_threadList.first()->Wake();
822  }
823 }
824 
826 {
827  if (e->type() == MythEvent::MythEventMessage)
828  {
829  auto *me = dynamic_cast<MythEvent*>(e);
830  if (me == nullptr)
831  return;
832  if ((me->Message().left(20) == "HOUSE_KEEPER_RUNNING") ||
833  (me->Message().left(23) == "HOUSE_KEEPER_SUCCESSFUL"))
834  {
835  QStringList tokens = me->Message()
836  .split(" ", QString::SkipEmptyParts);
837  if (tokens.size() != 4)
838  return;
839 
840  QString hostname = tokens[1];
841  QString tag = tokens[2];
842  QDateTime last = MythDate::fromString(tokens[3]);
843  bool successful = me->Message().contains("SUCCESSFUL");
844 
845  QMutexLocker mapLock(&m_mapLock);
846  if (m_taskMap.contains(tag))
847  {
848  if ((m_taskMap[tag]->GetScope() == kHKGlobal) ||
849  ((m_taskMap[tag]->GetScope() == kHKLocal) &&
851  // task being run in the same scope as us.
852  // update the run time so we don't attempt to run
853  // it ourselves
854  m_taskMap[tag]->SetLastRun(last, successful);
855  }
856  }
857  }
858 }
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
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
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
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.
void SetLastRun(const QDateTime &last, bool successful=true) override
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
virtual void SetLastRun(const QDateTime &last, bool successful=true)
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
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)
bool InWindow(const QDateTime &now) override
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:10
QPair< int, int > m_windowHour
Definition: housekeeper.h:123
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
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(const 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)
Default UTC.
Definition: mythdate.h:14
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:603
virtual bool PastWindow(const QDateTime &now)
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
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
virtual bool InWindow(const QDateTime &now)
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)