HouseKeeper::~HouseKeeper(void) { gCoreContext->removeListener(this); if (m_timer) { m_timer->stop(); disconnect(m_timer); delete m_timer; m_timer = NULL; } { // remove anything from the queue first, so it does not start QMutexLocker queueLock(&m_queueLock); while (!m_taskQueue.isEmpty()) m_taskQueue.takeFirst()->DecrRef(); } { // issue a terminate call to any long-running tasks // this is just a noop unless overwritten by a subclass QMutexLocker mapLock(&m_mapLock); QMap<QString,HouseKeeperTask*>::iterator it = m_taskMap.begin(); for (; it != m_taskMap.end(); ++it) (*it)->Terminate(); } if (!m_threadList.isEmpty()) { QMutexLocker threadLock(&m_threadLock); // tell primary thread to self-terminate and wake it m_threadList.first()->Discard(); m_threadList.first()->Wake(); // wait for any remaining threads to self-terminate and close while (!m_threadList.isEmpty()) { HouseKeepingThread *thread = m_threadList.takeFirst(); thread->wait(); delete thread; } } { // unload any registered tasks QMutexLocker mapLock(&m_mapLock); QMap<QString,HouseKeeperTask*>::iterator it = m_taskMap.begin(); while (it != m_taskMap.end()) { (*it)->DecrRef(); it = m_taskMap.erase(it); } } }
void HouseKeeper::customEvent(QEvent *e) { if ((MythEvent::Type)(e->type()) == MythEvent::MythEventMessage) { MythEvent *me = (MythEvent*)e; if (me->Message().left(20) == "HOUSE_KEEPER_RUNNING") { QStringList tokens = me->Message() .split(" ", QString::SkipEmptyParts); if (tokens.size() != 4) return; QString hostname = tokens[1]; QString tag = tokens[2]; QDateTime last = MythDate::fromString(tokens[3]); QMutexLocker mapLock(&m_mapLock); if (m_taskMap.contains(tag)) { if ((m_taskMap[tag]->GetScope() == kHKGlobal) || ((m_taskMap[tag]->GetScope() == kHKLocal) && (gCoreContext->GetHostName() == hostname))) // task being run in the same scope as us. // update the run time so we don't attempt to run // it ourselves m_taskMap[tag]->SetLastRun(last); } } } }
void HouseKeeper::Start(void) { // no need to be fine grained, nothing else should be accessing this map QMutexLocker mapLock(&m_mapLock); if (m_timer->isActive()) // Start() should only be called once return; MSqlQuery query(MSqlQuery::InitCon()); query.prepare("SELECT tag,lastrun" " FROM housekeeping" " WHERE hostname = :HOST" " OR hostname IS NULL"); query.bindValue(":HOST", gCoreContext->GetHostName()); if (!query.exec()) MythDB::DBError("HouseKeeper::Run", query); else { while (query.next()) { // loop through housekeeping table and load last run timestamps QString tag = query.value(0).toString(); QDateTime lastrun = MythDate::as_utc(query.value(1).toDateTime()); if (m_taskMap.contains(tag)) m_taskMap[tag]->SetLastRun(lastrun); } } gCoreContext->addListener(this); QMap<QString,HouseKeeperTask*>::const_iterator it; for (it = m_taskMap.begin(); it != m_taskMap.end(); ++it) { if ((*it)->CheckImmediate()) { // run any tasks marked for immediate operation in-thread (*it)->UpdateLastRun(); (*it)->Run(); } else if ((*it)->CheckStartup()) { // queue any tasks marked for startup LOG(VB_GENERAL, LOG_INFO, QString("Queueing HouseKeeperTask '%1'.").arg(it.key())); QMutexLocker queueLock(&m_queueLock); (*it)->IncrRef(); m_taskQueue.enqueue(*it); } } LOG(VB_GENERAL, LOG_INFO, "Starting HouseKeeper."); if (!m_taskQueue.isEmpty()) StartThread(); m_timer->start(); }
void Cold::clip( const Id& chunkId, const std::size_t chunkNum, const std::size_t id) { if (chunkNum < m_chunkVec.size()) { FastSlot& slot(m_chunkVec[chunkNum]); CountedChunk& countedChunk(*slot.chunk); m_pool->add([this, &countedChunk, id]() { unrefChunk(countedChunk, id, true); }); } else { std::unique_lock<std::mutex> mapLock(m_mapMutex); CountedChunk& countedChunk(*m_chunkMap.at(chunkId)); mapLock.unlock(); m_pool->add([this, &countedChunk, id]() { unrefChunk(countedChunk, id, false); }); } }
void Cold::growSlow(const Climber& climber, Clipper& clipper) { const Id& chunkId(climber.chunkId()); if (clipper.insert(chunkId, climber.chunkNum())) { std::unique_lock<std::mutex> mapLock(m_mapMutex); const bool exists(m_chunkMap.count(chunkId)); auto& countedChunk(m_chunkMap[chunkId]); if (!exists) countedChunk.reset(new CountedChunk()); std::lock_guard<std::mutex> chunkLock(countedChunk->mutex); mapLock.unlock(); if (!countedChunk->refs.count(clipper.id())) { countedChunk->refs[clipper.id()] = 1; } else { ++countedChunk->refs[clipper.id()]; } ensureChunk(climber, countedChunk->chunk, exists); } }
Cell& Cold::getCell(const Climber& climber, Clipper& clipper) { CountedChunk* countedChunk(nullptr); const std::size_t chunkNum(climber.chunkNum()); const Id& chunkId(climber.chunkId()); if (chunkNum < m_chunkVec.size()) { growFast(climber, clipper); countedChunk = m_chunkVec[chunkNum].chunk.get(); } else { growSlow(climber, clipper); std::lock_guard<std::mutex> mapLock(m_mapMutex); countedChunk = m_chunkMap.at(chunkId).get(); } if (!countedChunk) { throw std::runtime_error("CountedChunk has missing contents."); } return countedChunk->chunk->getCell(climber); }
bool framework::registerComponent(COMPONENT_ID id, Sdf_cl_commonMessageQueue *pQueue) { mapLock(); bool result = false; std::map<int , Sdf_cl_commonMessageQueue*> :: iterator it = componentMap.find(id); if ( it == componentMap.end() ) { componentMap[id] = pQueue; result = true; } mapUnlock(); return result; }
void HouseKeeper::Run(void) { LOG(VB_GENERAL, LOG_DEBUG, "Running HouseKeeper."); QDateTime now = MythDate::current(); QMutexLocker mapLock(&m_mapLock); QMap<QString,HouseKeeperTask*>::const_iterator it; for (it = m_taskMap.begin(); it != m_taskMap.end(); ++it) { if ((*it)->CheckRun(now)) { // check if any tasks are ready to run, and add to queue LOG(VB_GENERAL, LOG_INFO, QString("Queueing HouseKeeperTask '%1'.").arg(it.key())); QMutexLocker queueLock(&m_queueLock); (*it)->IncrRef(); m_taskQueue.enqueue(*it); } } if (!m_taskQueue.isEmpty()) StartThread(); if (m_threadList.size() > 1) { // spent threads exist in the thread list // check to see if any have finished up their task and terminated QMutexLocker threadLock(&m_threadLock); int count1 = m_threadList.size(); QList<HouseKeepingThread*>::iterator it = m_threadList.begin(); ++it; // skip the primary thread while (it != m_threadList.end()) { if ((*it)->isRunning()) ++it; else it = m_threadList.erase(it); } int count2 = m_threadList.size(); if (count1 > count2) LOG(VB_GENERAL, LOG_DEBUG, QString("Discarded HouseKeepingThreads have completed and " "been deleted. Current count %1 -> %2.") .arg(count1).arg(count2)); } }
bool framework::post(COMPONENT_ID id, dtmf_msgFormat* pMsg) { mapLock(); // printf("post msgType:%d\n",pMsg->msgType); bool result = false; std::map<int , Sdf_cl_commonMessageQueue*> :: iterator it = componentMap.find(id); if ( it != componentMap.end() ) { //printf("post msgType22222222222:%d\n",pMsg->msgType); it->second->post(pMsg); result = true; } mapUnlock(); return result; }
void HouseKeeper::RegisterTask(HouseKeeperTask *task) { QMutexLocker mapLock(&m_mapLock); QString tag = task->GetTag(); if (m_taskMap.contains(tag)) { task->DecrRef(); LOG(VB_GENERAL, LOG_ERR, QString("HouseKeeperTask '%1' already registered. " "Rejecting duplicate.").arg(tag)); } else { LOG(VB_GENERAL, LOG_INFO, QString("Registering HouseKeeperTask '%1'.").arg(tag)); m_taskMap.insert(tag, task); } }