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(const 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  {
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  return check;
124 }
125 
127 {
128  return ((m_startup == kHKRunImmediateOnStartup) &&
130 }
131 
133 {
135  {
136  m_confirm = true;
137  return true;
138  }
139  return false;
140 }
141 
143 {
144  LOG(VB_GENERAL, LOG_INFO, QString("Running HouseKeeperTask '%1'.")
145  .arg(m_dbTag));
146  if (m_running)
147  {
148  // something else is already running me, bail out
149  LOG(VB_GENERAL, LOG_WARNING, QString("HouseKeeperTask '%1' already "
150  "running. Refusing to run concurrently").arg(m_dbTag));
151  return false;
152  }
153 
154  m_running = true;
155  bool res = DoRun();
156  m_running = false;
157  if (!res)
158  {
159  LOG(VB_GENERAL, LOG_INFO, QString("HouseKeeperTask '%1' Failed.")
160  .arg(m_dbTag));
161  }
162  else
163  {
164  LOG(VB_GENERAL, LOG_INFO,
165  QString("HouseKeeperTask '%1' Finished Successfully.")
166  .arg(m_dbTag));
167  }
168  return res;
169 }
170 
172 {
173  QueryLast();
174  return m_lastRun;
175 }
176 
178 {
179  QueryLast();
180  return m_lastRun;
181 }
182 
184 {
185  if (m_scope != kHKInst)
186  {
187  if (m_lastUpdate.addSecs(30) > MythDate::current())
188  // just to cut down on unnecessary queries
189  return;
190 
191  MSqlQuery query(MSqlQuery::InitCon());
192 
193 #if QT_VERSION < QT_VERSION_CHECK(5,8,0)
194  m_lastRun = MythDate::fromTime_t(0);
195  m_lastSuccess = MythDate::fromTime_t(0);
196 #else
199 #endif
200 
201  if (m_scope == kHKGlobal)
202  {
203  query.prepare("SELECT lastrun,lastsuccess FROM housekeeping"
204  " WHERE tag = :TAG"
205  " AND hostname IS NULL");
206  }
207  else
208  {
209  query.prepare("SELECT lastrun,lastsuccess FROM housekeeping"
210  " WHERE tag = :TAG"
211  " AND hostname = :HOST");
212  query.bindValue(":HOST", gCoreContext->GetHostName());
213  }
214 
215  query.bindValue(":TAG", m_dbTag);
216 
217  if (query.exec() && query.next())
218  {
219  m_lastRun = MythDate::as_utc(query.value(0).toDateTime());
220  m_lastSuccess = MythDate::as_utc(query.value(1).toDateTime());
221  }
222  }
223 
225 }
226 
227 QDateTime HouseKeeperTask::UpdateLastRun(const QDateTime& last, bool successful)
228 {
229  m_lastRun = last;
230  if (successful)
231  m_lastSuccess = last;
232  m_confirm = false;
233 
234  if (m_scope != kHKInst)
235  {
236  MSqlQuery query(MSqlQuery::InitCon());
237  if (!query.isConnected())
238  return last;
239 
240 #if QT_VERSION < QT_VERSION_CHECK(5,8,0)
241  if (m_lastRun == MythDate::fromTime_t(0))
242 #else
244 #endif
245  {
246  // not previously set, perform insert
247 
248  if (m_scope == kHKGlobal)
249  {
250  query.prepare("INSERT INTO housekeeping"
251  " (tag, lastrun, lastsuccess)"
252  " VALUES (:TAG, :TIME, :STIME)");
253  }
254  else
255  {
256  query.prepare("INSERT INTO housekeeping"
257  " (tag, hostname, lastrun, lastsuccess)"
258  " VALUES (:TAG, :HOST, :TIME, :STIME)");
259  }
260  }
261  else
262  {
263  // previously set, perform update
264 
265  if (m_scope == kHKGlobal)
266  {
267  query.prepare("UPDATE housekeeping SET lastrun=:TIME,"
268  " lastsuccess=:STIME"
269  " WHERE tag = :TAG"
270  " AND hostname IS NULL");
271  }
272  else
273  {
274  query.prepare("UPDATE housekeeping SET lastrun=:TIME,"
275  " lastsuccess=:STIME"
276  " WHERE tag = :TAG"
277  " AND hostname = :HOST");
278  }
279  }
280 
281  if (m_scope == kHKGlobal)
282  {
283  LOG(VB_GENERAL, LOG_DEBUG,
284  QString("Updating global run time for %1").arg(m_dbTag));
285  }
286  else
287  {
288  LOG(VB_GENERAL, LOG_DEBUG,
289  QString("Updating local run time for %1").arg(m_dbTag));
290  }
291 
292  if (m_scope == kHKLocal)
293  query.bindValue(":HOST", gCoreContext->GetHostName());
294  query.bindValue(":TAG", m_dbTag);
295  query.bindValue(":TIME", MythDate::as_utc(m_lastRun));
296  query.bindValue(":STIME", MythDate::as_utc(m_lastSuccess));
297 
298  if (!query.exec())
299  MythDB::DBError("HouseKeeperTask::updateLastRun", query);
300  }
301 
302  QString msg;
303  if (successful)
304  msg = QString("HOUSE_KEEPER_SUCCESSFUL %1 %2 %3");
305  else
306  msg = QString("HOUSE_KEEPER_RUNNING %1 %2 %3");
307  msg = msg.arg(gCoreContext->GetHostName())
308  .arg(m_dbTag)
312 
313  return last;
314 }
315 
316 void HouseKeeperTask::SetLastRun(const QDateTime &last, bool successful)
317 {
318  m_lastRun = last;
319  if (successful)
320  m_lastSuccess = last;
321 
323 }
324 
339  int period, float min, float max, int retry,
341  HouseKeeperTask(dbTag, scope, startup), m_period(period), m_retry(retry),
342  m_windowPercent(min, max), m_currentProb(1.0)
343 {
345  if (m_retry == 0)
346  m_retry = m_period;
347 }
348 
350 {
351  int period = m_period;
352  if (GetLastRun() > GetLastSuccess())
353  {
354  // last attempt was not successful
355  // try shortened period
356  period = m_retry;
357  }
358 
359  m_windowElapsed.first =
360  (uint32_t)((float)period * m_windowPercent.first);
361  m_windowElapsed.second =
362  (uint32_t)((float)period * m_windowPercent.second);
363 }
364 
365 void PeriodicHouseKeeperTask::SetWindow(float min, float max)
366 {
367  m_windowPercent.first = min;
368  m_windowPercent.second = max;
369  CalculateWindow();
370 }
371 
372 QDateTime PeriodicHouseKeeperTask::UpdateLastRun(const QDateTime& last,
373  bool successful)
374 {
375  QDateTime res = HouseKeeperTask::UpdateLastRun(last, successful);
376  CalculateWindow();
377  m_currentProb = 1.0;
378  return res;
379 }
380 
381 void PeriodicHouseKeeperTask::SetLastRun(const QDateTime& last, bool successful)
382 {
383  HouseKeeperTask::SetLastRun(last, successful);
384  CalculateWindow();
385  m_currentProb = 1.0;
386 }
387 
388 bool PeriodicHouseKeeperTask::DoCheckRun(const QDateTime& now)
389 {
390  int elapsed = GetLastRun().secsTo(now);
391 
392  if (elapsed < 0)
393  // something bad has happened. let's just move along
394  return false;
395 
396  if (elapsed < m_windowElapsed.first)
397  // insufficient time elapsed to test
398  return false;
399  if (elapsed > m_windowElapsed.second)
400  // too much time has passed. force run
401  return true;
402 
403  // calculate probability that task should not have yet run
404  // it's backwards, but it makes the math simplier
405  float prob = 1.0F - ((float)(elapsed - m_windowElapsed.first) /
406  (float)(m_windowElapsed.second - m_windowElapsed.first));
407  if (m_currentProb < prob)
408  // more bad stuff
409  return false;
410 
411  // calculate current probability to achieve overall probability
412  // this should be nearly one
413  float prob2 = prob/m_currentProb;
414  // so rand() should have to return nearly RAND_MAX to get a positive
415  // remember, this is computing the probability that up to this point, one
416  // of these tests has returned positive, so each individual test has
417  // a necessarily low probability
418  //
419  // Pseudo-random is good enough. Don't need a true random.
420  // NOLINTNEXTLINE(cert-msc30-c,cert-msc50-cpp)
421  bool res = (rand() > (int)(prob2 * static_cast<float>(RAND_MAX)));
422  m_currentProb = prob;
423 // if (res)
424 // LOG(VB_GENERAL, LOG_DEBUG, QString("%1 will run: this=%2; total=%3")
425 // .arg(GetTag()).arg(1-prob2).arg(1-prob));
426 // else
427 // LOG(VB_GENERAL, LOG_DEBUG, QString("%1 will not run: this=%2; total=%3")
428 // .arg(GetTag()).arg(1-prob2).arg(1-prob));
429  return res;
430 }
431 
432 bool PeriodicHouseKeeperTask::InWindow(const QDateTime& now)
433 {
434  int elapsed = GetLastRun().secsTo(now);
435 
436  if (elapsed < 0)
437  // something bad has happened. let's just move along
438  return false;
439 
440  return (elapsed > m_windowElapsed.first) &&
441  (elapsed < m_windowElapsed.second);
442 }
443 
444 bool PeriodicHouseKeeperTask::PastWindow(const QDateTime &now)
445 {
446  return GetLastRun().secsTo(now) > m_windowElapsed.second;
447 }
448 
464  PeriodicHouseKeeperTask(dbTag, 86400, .5, 1.5, 0, scope, startup),
465  m_windowHour(0, 23)
466 {
468 }
469 
470 DailyHouseKeeperTask::DailyHouseKeeperTask(const QString &dbTag, int minhour,
471  int maxhour, HouseKeeperScope scope, HouseKeeperStartup startup) :
472  PeriodicHouseKeeperTask(dbTag, 86400, .5, 1.5, 0, scope, startup),
473  m_windowHour(minhour, maxhour)
474 {
476 }
477 
479 {
481  QDate date = GetLastRun().addDays(1).date();
482 
483  QDateTime tmp = QDateTime(date, QTime(m_windowHour.first, 0));
484  if (GetLastRun().addSecs(m_windowElapsed.first) < tmp)
485  m_windowElapsed.first = GetLastRun().secsTo(tmp);
486 
487  tmp = QDateTime(date, QTime(m_windowHour.second, 30));
488  // we want to make sure this gets run before the end of the day
489  // so add a 30 minute buffer prior to the end of the window
490  if (GetLastRun().addSecs(m_windowElapsed.second) > tmp)
491  m_windowElapsed.second = GetLastRun().secsTo(tmp);
492 
493  LOG(VB_GENERAL, LOG_DEBUG, QString("%1 Run window between %2 - %3.")
494  .arg(GetTag()).arg(m_windowElapsed.first).arg(m_windowElapsed.second));
495 }
496 
498 {
499  m_windowHour.first = min;
500  m_windowHour.second = max;
501  CalculateWindow();
502 }
503 
504 bool DailyHouseKeeperTask::InWindow(const QDateTime& now)
505 {
507  // parent says we're in the window
508  return true;
509 
510  int hour = now.time().hour();
511  // true if we've missed the window, but we're within our time constraints
512  return PastWindow(now) && (m_windowHour.first <= hour)
513  && (m_windowHour.second > hour);
514 }
515 
527 {
528  RunProlog();
529  m_waitMutex.lock();
530  HouseKeeperTask *task = nullptr;
531 
532  while (m_keepRunning)
533  {
534  m_idle = false;
535 
536  while ((task = m_parent->GetQueuedTask()))
537  {
538  // pull task from housekeeper and process it
539  ReferenceLocker rlock(task);
540 
541  if (!task->ConfirmRun())
542  {
543  // something else has caused the lastrun time to
544  // change since this was requested to run. abort.
545  task = nullptr;
546  continue;
547  }
548 
549  task->UpdateLastRun(false);
550  if (task->Run())
551  task->UpdateLastRun(task->GetLastRun(), true);
552  task = nullptr;
553 
554  if (!m_keepRunning)
555  // thread has been discarded, don't try to start another task
556  break;
557  }
558 
559  m_idle = true;
560 
561  if (!m_keepRunning)
562  // short out rather than potentially hitting another sleep cycle
563  break;
564 
566  }
567 
568  m_waitMutex.unlock();
569  RunEpilog();
570 }
571 
589 {
590  m_timer = new QTimer(this);
591  connect(m_timer, SIGNAL(timeout()), this, SLOT(Run()));
592  m_timer->setInterval(60000);
593  m_timer->setSingleShot(false);
594 }
595 
597 {
599 
600  if (m_timer)
601  {
602  m_timer->stop();
603  disconnect(m_timer);
604  delete m_timer;
605  m_timer = nullptr;
606  }
607 
608  {
609  // remove anything from the queue first, so it does not start
610  QMutexLocker queueLock(&m_queueLock);
611  while (!m_taskQueue.isEmpty())
612  m_taskQueue.takeFirst()->DecrRef();
613  }
614 
615  {
616  // issue a terminate call to any long-running tasks
617  // this is just a noop unless overwritten by a subclass
618  QMutexLocker mapLock(&m_mapLock);
619  foreach (auto & it, m_taskMap)
620  it->Terminate();
621  }
622 
623  if (!m_threadList.isEmpty())
624  {
625  QMutexLocker threadLock(&m_threadLock);
626  // tell primary thread to self-terminate and wake it
627  m_threadList.first()->Discard();
628  m_threadList.first()->Wake();
629  // wait for any remaining threads to self-terminate and close
630  while (!m_threadList.isEmpty())
631  {
632  HouseKeepingThread *thread = m_threadList.takeFirst();
633  thread->wait();
634  delete thread;
635  }
636  }
637 
638  {
639  // unload any registered tasks
640  QMutexLocker mapLock(&m_mapLock);
641  QMap<QString,HouseKeeperTask*>::iterator it = m_taskMap.begin();
642  while (it != m_taskMap.end())
643  {
644  (*it)->DecrRef();
645  it = m_taskMap.erase(it);
646  }
647  }
648 }
649 
651 {
652  QMutexLocker mapLock(&m_mapLock);
653  QString tag = task->GetTag();
654  if (m_taskMap.contains(tag))
655  {
656  task->DecrRef();
657  LOG(VB_GENERAL, LOG_ERR,
658  QString("HouseKeeperTask '%1' already registered. "
659  "Rejecting duplicate.").arg(tag));
660  }
661  else
662  {
663  LOG(VB_GENERAL, LOG_INFO,
664  QString("Registering HouseKeeperTask '%1'.").arg(tag));
665  m_taskMap.insert(tag, task);
666  }
667 }
668 
670 {
671  QMutexLocker queueLock(&m_queueLock);
672  HouseKeeperTask *task = nullptr;
673 
674  if (!m_taskQueue.isEmpty())
675  {
676  task = m_taskQueue.dequeue();
677  }
678 
679  // returning nullptr tells the thread that the queue is empty and
680  // to go into standby
681  return task;
682 }
683 
685 {
686  // no need to be fine grained, nothing else should be accessing this map
687  QMutexLocker mapLock(&m_mapLock);
688 
689  if (m_timer->isActive())
690  // Start() should only be called once
691  return;
692 
693  MSqlQuery query(MSqlQuery::InitCon());
694  query.prepare("SELECT tag,lastrun"
695  " FROM housekeeping"
696  " WHERE hostname = :HOST"
697  " OR hostname IS NULL");
698  query.bindValue(":HOST", gCoreContext->GetHostName());
699 
700  if (!query.exec())
701  MythDB::DBError("HouseKeeper::Run", query);
702  else
703  {
704  while (query.next())
705  {
706  // loop through housekeeping table and load last run timestamps
707  QString tag = query.value(0).toString();
708  QDateTime lastrun = MythDate::as_utc(query.value(1).toDateTime());
709 
710  if (m_taskMap.contains(tag))
711  m_taskMap[tag]->SetLastRun(lastrun);
712  }
713  }
714 
715  gCoreContext->addListener(this);
716 
717  QMap<QString,HouseKeeperTask*>::const_iterator it;
718  for (it = m_taskMap.begin(); it != m_taskMap.end(); ++it)
719  {
720  if ((*it)->CheckImmediate())
721  {
722  // run any tasks marked for immediate operation in-thread
723  (*it)->UpdateLastRun();
724  (*it)->Run();
725  }
726  else if ((*it)->CheckStartup())
727  {
728  // queue any tasks marked for startup
729  LOG(VB_GENERAL, LOG_INFO,
730  QString("Queueing HouseKeeperTask '%1'.").arg(it.key()));
731  QMutexLocker queueLock(&m_queueLock);
732  (*it)->IncrRef();
733  m_taskQueue.enqueue(*it);
734  }
735  }
736 
737  LOG(VB_GENERAL, LOG_INFO, "Starting HouseKeeper.");
738 
739  m_timer->start();
740 }
741 
743 {
744  LOG(VB_GENERAL, LOG_DEBUG, "Running HouseKeeper.");
745 
746  QDateTime now = MythDate::current();
747 
748  QMutexLocker mapLock(&m_mapLock);
749  for (auto it = m_taskMap.begin(); it != m_taskMap.end(); ++it)
750  {
751  if ((*it)->CheckRun(now))
752  {
753  // check if any tasks are ready to run, and add to queue
754  LOG(VB_GENERAL, LOG_INFO,
755  QString("Queueing HouseKeeperTask '%1'.").arg(it.key()));
756  QMutexLocker queueLock(&m_queueLock);
757  (*it)->IncrRef();
758  m_taskQueue.enqueue(*it);
759  }
760  }
761 
762  if (!m_taskQueue.isEmpty())
763  StartThread();
764 
765  if (m_threadList.size() > 1)
766  {
767  // spent threads exist in the thread list
768  // check to see if any have finished up their task and terminated
769  QMutexLocker threadLock(&m_threadLock);
770  int count1 = m_threadList.size();
771 
772  auto it = m_threadList.begin();
773  ++it; // skip the primary thread
774  while (it != m_threadList.end())
775  {
776  if ((*it)->isRunning())
777  ++it;
778  else
779  {
780  delete *it;
781  it = m_threadList.erase(it);
782  }
783  }
784 
785  int count2 = m_threadList.size();
786  if (count1 > count2)
787  {
788  LOG(VB_GENERAL, LOG_DEBUG,
789  QString("Discarded HouseKeepingThreads have completed and "
790  "been deleted. Current count %1 -> %2.")
791  .arg(count1).arg(count2));
792  }
793  }
794 }
795 
810 {
811  QMutexLocker threadLock(&m_threadLock);
812 
813  if (m_threadList.isEmpty())
814  {
815  // we're running for the first time
816  // start up a new thread
817  LOG(VB_GENERAL, LOG_DEBUG, "Running initial HouseKeepingThread.");
818  auto *thread = new HouseKeepingThread(this);
819  m_threadList.append(thread);
820  thread->start();
821  }
822 
823  else if (!m_threadList.first()->isIdle())
824  {
825  // the old thread is still off processing something
826  // discard it and start a new one because we have more stuff
827  // that wants to run
828  LOG(VB_GENERAL, LOG_DEBUG,
829  QString("Current HouseKeepingThread is delayed on task, "
830  "spawning replacement. Current count %1.")
831  .arg(m_threadList.size()));
832  m_threadList.first()->Discard();
833  auto *thread = new HouseKeepingThread(this);
834  m_threadList.prepend(thread);
835  thread->start();
836  }
837 
838  else
839  {
840  // the old thread is idle, so just wake it for processing
841  LOG(VB_GENERAL, LOG_DEBUG, "Waking HouseKeepingThread.");
842  m_threadList.first()->Wake();
843  }
844 }
845 
847 {
848  if (e->type() == MythEvent::MythEventMessage)
849  {
850  auto *me = dynamic_cast<MythEvent*>(e);
851  if (me == nullptr)
852  return;
853  if ((me->Message().left(20) == "HOUSE_KEEPER_RUNNING") ||
854  (me->Message().left(23) == "HOUSE_KEEPER_SUCCESSFUL"))
855  {
856  QStringList tokens = me->Message()
857  .split(" ", QString::SkipEmptyParts);
858  if (tokens.size() != 4)
859  return;
860 
861  QString hostname = tokens[1];
862  QString tag = tokens[2];
863  QDateTime last = MythDate::fromString(tokens[3]);
864  bool successful = me->Message().contains("SUCCESSFUL");
865 
866  QMutexLocker mapLock(&m_mapLock);
867  if (m_taskMap.contains(tag))
868  {
869  if ((m_taskMap[tag]->GetScope() == kHKGlobal) ||
870  ((m_taskMap[tag]->GetScope() == kHKLocal) &&
872  {
873  // task being run in the same scope as us.
874  // update the run time so we don't attempt to run
875  // it ourselves
876  m_taskMap[tag]->SetLastRun(last, successful);
877  }
878  }
879  }
880  }
881 }
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:783
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:864
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:73
QDateTime fromString(const QString &dtstr)
Converts kFilename && kISODate formats to QDateTime.
Definition: mythdate.cpp:30
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 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.
bool DoCheckRun(const QDateTime &now) override
void addListener(QObject *listener)
Add a listener to the observable.
virtual bool DoCheckRun(const QDateTime &)
Definition: housekeeper.h:65
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
bool CheckRun(const QDateTime &now)
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 _reuse=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
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)
~HouseKeeper() override
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:808
#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)
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)