Ticket #7762: shutdownSlaveEnhanced_v0.3.diff
File shutdownSlaveEnhanced_v0.3.diff, 19.1 KB (added by , 14 years ago) |
---|
-
playbacksock.h
42 42 void setIP(QString &lip) { ip = lip; } 43 43 QString getIP(void) { return ip; } 44 44 45 boolGoToSleep(void);45 int GoToSleep(void); 46 46 void GetDiskSpace(QStringList &o_strlist); 47 47 int DeleteFile(const QString filename, const QString sgroup); 48 48 int StopRecording(const ProgramInfo *pginfo); -
scheduler.h
77 77 78 78 bool WasStartedAutomatically(); 79 79 80 static bool CheckShutdownServer(int prerollseconds, QDateTime &idleSince, 81 bool &blockShutdown); 80 82 int GetError(void) const { return error; } 81 83 82 84 protected: … … 126 128 bool ChangeRecordingEnd(RecordingInfo *oldp, RecordingInfo *newp); 127 129 128 130 void findAllScheduledPrograms(RecList &proglist); 129 bool CheckShutdownServer(int prerollseconds, QDateTime &idleSince,130 bool &blockShutdown);131 131 void ShutdownServer(int prerollseconds, QDateTime &idleSince); 132 132 void PutInactiveSlavesToSleep(void); 133 133 bool WakeUpSlave(QString slaveHostname, bool setWakingStatus = true); 134 void WakeUpSlaves(void); 134 bool WakeUpSlaves(bool forceWakeAll = true); 135 bool CheckDailyWakeUpPeriodSlave(QString slaveHostname); 136 bool CheckDailyWakeUpPeriodSlaveAndEncoderStatus(QString slaveHostname, EncoderLink *enc); 137 QDateTime getDailyWakeupTime(QString sPeriod, QString slaveHostname); 135 138 136 139 int FillRecordingDir(RecordingInfo *pginfo, RecList& reclist); 137 140 void FillDirectoryInfoCache(bool force = false); -
encoderlink.h
65 65 TVRec *GetTVRec(void) { return tv; } 66 66 67 67 /// \brief Tell a slave backend to go to sleep 68 boolGoToSleep(void);68 int GoToSleep(void); 69 69 int LockTuner(void); 70 70 /// \brief Unlock the tuner. 71 71 /// \sa LockTuner(), IsTunerLocked() -
playbacksock.cpp
117 117 118 118 /** \brief Tells a slave to go to sleep 119 119 */ 120 boolPlaybackSock::GoToSleep(void)120 int PlaybackSock::GoToSleep(void) 121 121 { 122 122 QStringList strlist( QString("GO_TO_SLEEP") ); 123 124 return SendReceiveStringList(strlist, 1) && (strlist[0] == "OK"); 123 if (SendReceiveStringList(strlist, 1)) { 124 if (strlist[0] == "OK") 125 return 1; 126 else if (strlist[0] == "BUSY") 127 return 0; 128 } 129 return -1; 125 130 } 126 131 127 132 /** -
mainserver.cpp
2514 2514 void MainServer::HandleGoToSleep(PlaybackSock *pbs) 2515 2515 { 2516 2516 QStringList strlist; 2517 QDateTime idleSince; 2518 bool blockShutdown; 2517 2519 2518 QString sleepCmd = gContext->GetSetting("SleepCommand"); 2519 if (!sleepCmd.isEmpty()) 2520 if (Scheduler::CheckShutdownServer(0, idleSince, blockShutdown)) 2520 2521 { 2521 strlist << "OK"; 2522 SendResponse(pbs->getSocket(), strlist); 2523 VERBOSE(VB_IMPORTANT, "Received GO_TO_SLEEP command from master, " 2524 "running SleepCommand."); 2525 myth_system(sleepCmd); 2522 VERBOSE(VB_IDLE, "Received a request to shut down this machine.... response is OK."); 2523 // sleep 2524 QString sleep_cmd = gContext->GetSetting("SleepCommand", ""); 2525 2526 if (!sleep_cmd.isEmpty()) 2527 { 2528 VERBOSE(VB_GENERAL, QString("Running the command to shutdown " 2529 "this computer :-\n\t\t\t\t\t\t") + sleep_cmd); 2530 2531 strlist << "OK"; 2532 SendResponse(pbs->getSocket(), strlist); 2533 // and now shutdown myself 2534 if (!myth_system(sleep_cmd)) 2535 return; 2536 else 2537 VERBOSE(VB_IMPORTANT, "SleepCommand failed, shutdown aborted"); 2538 } 2539 else 2540 { 2541 strlist << "ERROR: SleepCommand is empty"; 2542 VERBOSE(VB_IMPORTANT, "ERROR: Slave backend should go to sleep " 2543 "but no SleepCommand found!"); 2544 SendResponse(pbs->getSocket(), strlist); 2545 } 2526 2546 } 2527 2547 else 2528 2548 { 2529 strlist << "ERROR: SleepCommand is empty";2530 VERBOSE(VB_I MPORTANT,2531 "ERROR: in HandleGoToSleep(), but no SleepCommand found!");2549 // not allowed to sleep 2550 VERBOSE(VB_IDLE, "Received a request to shut down this machine.... response is BUSY."); 2551 strlist << "BUSY"; 2532 2552 SendResponse(pbs->getSocket(), strlist); 2533 2553 } 2534 2554 } -
scheduler.cpp
1706 1706 } 1707 1707 firstRun = false; 1708 1708 } 1709 1710 PutInactiveSlavesToSleep();1711 lastSleepCheck = QDateTime::currentDateTime();1712 1709 } 1713 1710 } 1714 1711 … … 1718 1715 1719 1716 curtime = QDateTime::currentDateTime(); 1720 1717 1721 // About every 5 minutes check for slaves that can be put to sleep1722 if (lastSleepCheck.secsTo(curtime) > 300)1723 {1724 PutInactiveSlavesToSleep();1725 lastSleepCheck = QDateTime::currentDateTime();1726 }1727 1728 1718 // Go through the list of recordings starting in the next few minutes 1729 1719 // and wakeup any slaves that are asleep 1730 1720 RecIter recIter = startIter; … … 1971 1961 idleSince = QDateTime(); 1972 1962 } 1973 1963 1964 // About every minute check for slaves that can be waken up or put to sleep 1965 if (lastSleepCheck.secsTo(curtime) >= 60) 1966 { 1967 bool slaveWaken = WakeUpSlaves(false); 1968 if (!slaveWaken) 1969 PutInactiveSlavesToSleep(); 1970 lastSleepCheck = QDateTime::currentDateTime(); 1971 } 1972 1974 1973 // if idletimeout is 0, the user disabled the auto-shutdown feature 1975 1974 if ((idleTimeoutSecs > 0) && (m_mainServer != NULL)) 1976 1975 { … … 2149 2148 if ((*recIter)->recstatus == rsWillRecord) 2150 2149 break; 2151 2150 2152 // set the wakeuptime if needed 2153 if (recIter != reclist.end()) 2151 // set the wakeuptime if needed and if we are the master 2152 // otherwise, the master will wake up us 2153 if (recIter != reclist.end() && gContext->IsMasterBackend()) 2154 2154 { 2155 2155 RecordingInfo *nextRecording = (*recIter); 2156 2156 QDateTime restarttime = nextRecording->recstartts.addSecs((-1) * … … 2199 2199 } 2200 2200 } 2201 2201 2202 // tell anyone who is listening the master server is going down now 2203 MythEvent me(QString("SHUTDOWN_NOW")); 2204 gContext->dispatch(me); 2205 2202 if (gContext->IsMasterBackend()) 2203 { 2204 // tell anyone who is listening the master server is going down now 2205 MythEvent me(QString("SHUTDOWN_NOW")); 2206 gContext->dispatch(me); 2207 } 2206 2208 QString halt_cmd = gContext->GetSetting("ServerHaltCommand", 2207 2209 "sudo /sbin/halt -p"); 2208 2210 … … 2243 2245 someSlavesCanSleep = true; 2244 2246 } 2245 2247 2246 if (!someSlavesCanSleep) 2248 if (!someSlavesCanSleep) 2247 2249 return; 2248 2250 2249 2251 VERBOSE(VB_SCHEDULE, 2250 2252 "Scheduler, Checking for slaves that can be shut down"); 2251 2253 2252 2254 int sleepThreshold = 2253 gContext->GetNumSetting( " SleepThreshold", 60 * 45);2255 gContext->GetNumSetting( "idleWaitForRecordingTime", 15) * 60; 2254 2256 2255 2257 VERBOSE(VB_SCHEDULE+VB_EXTRA, QString(" Getting list of slaves that " 2256 2258 "will be active in the next %1 minutes.") … … 2259 2261 VERBOSE(VB_SCHEDULE+VB_EXTRA, "Checking scheduler's reclist"); 2260 2262 RecIter recIter = reclist.begin(); 2261 2263 QDateTime curtime = QDateTime::currentDateTime(); 2262 QStringList SlavesInUse;2264 QStringList slavesInUse; 2263 2265 for ( ; recIter != reclist.end(); recIter++) 2264 2266 { 2265 2267 RecordingInfo *pginfo = *recIter; … … 2276 2278 { 2277 2279 enc = (*m_tvList)[pginfo->cardid]; 2278 2280 if ((!enc->IsLocal()) && 2279 (!SlavesInUse.contains(enc->GetHostName()))) 2280 { 2281 if (pginfo->recstatus == rsWillRecord) 2281 (!slavesInUse.contains(enc->GetHostName())) && 2282 (pginfo->recstatus == rsWillRecord)) { 2282 2283 VERBOSE(VB_SCHEDULE+VB_EXTRA, QString(" Slave %1 will " 2283 2284 "be in use in %2 minutes").arg(enc->GetHostName()) 2284 2285 .arg(secsleft / 60)); 2285 else 2286 VERBOSE(VB_SCHEDULE+VB_EXTRA, QString(" Slave %1 is " 2287 "in use currently recording '%1'") 2288 .arg(enc->GetHostName()).arg(pginfo->title)); 2289 SlavesInUse << enc->GetHostName(); 2286 slavesInUse << enc->GetHostName(); 2290 2287 } 2291 2288 } 2292 2289 } 2293 2290 2294 VERBOSE(VB_SCHEDULE+VB_EXTRA, " Checking inuseprograms table:");2291 VERBOSE(VB_SCHEDULE+VB_EXTRA, "2 Checking inuseprograms table:"); 2295 2292 QDateTime oneHourAgo = QDateTime::currentDateTime().addSecs(-61 * 60); 2296 2293 MSqlQuery query(MSqlQuery::InitCon()); 2297 2294 query.prepare("SELECT DISTINCT hostname, recusage FROM inuseprograms " … … 2300 2297 if (query.exec() && query.size() > 0) 2301 2298 { 2302 2299 while(query.next()) { 2303 SlavesInUse << query.value(0).toString();2300 slavesInUse << query.value(0).toString(); 2304 2301 VERBOSE(VB_SCHEDULE+VB_EXTRA, QString(" Slave %1 is marked as " 2305 2302 "in use by a %2") 2306 2303 .arg(query.value(0).toString()) … … 2308 2305 } 2309 2306 } 2310 2307 2311 VERBOSE(VB_SCHEDULE+VB_EXTRA, QString(" Shutting down slaves which will " 2312 "be inactive for the next %1 minutes and can be put to sleep.") 2313 .arg(sleepThreshold / 60)); 2308 QStringList slavesThatCanWake; 2314 2309 2315 2310 enciter = m_tvList->begin(); 2316 2311 for (; enciter != m_tvList->end(); ++enciter) 2317 2312 { 2318 2313 enc = *enciter; 2314 QString slaveHost = enc->GetHostName(); 2319 2315 2320 2316 if ((!enc->IsLocal()) && 2321 2317 (enc->IsAwake()) && 2322 (!SlavesInUse.contains(enc->GetHostName())) && 2323 (!enc->IsFallingAsleep())) 2318 (!slavesInUse.contains(slaveHost)) && 2319 (!enc->IsFallingAsleep()) && 2320 (enc->GetSleepStatusTime().secsTo(curtime) > 300) && 2321 (!Scheduler::CheckDailyWakeUpPeriodSlave(slaveHost))) 2324 2322 { 2325 2323 QString sleepCommand = gContext->GetSettingOnHost("SleepCommand", 2326 enc->GetHostName());2324 slaveHost); 2327 2325 QString wakeUpCommand = gContext->GetSettingOnHost("WakeUpCommand", 2328 enc->GetHostName());2326 slaveHost); 2329 2327 2330 if (!sleepCommand.isEmpty() && !wakeUpCommand.isEmpty()) 2328 if (!sleepCommand.isEmpty() && !wakeUpCommand.isEmpty() 2329 && !slavesThatCanWake.contains(slaveHost)) 2331 2330 { 2332 QString thisHost = enc->GetHostName(); 2331 // avoid asking the same slave to go to sleep 2332 slavesThatCanWake << slaveHost; 2333 2333 2334 VERBOSE(VB_SCHEDULE+VB_EXTRA, QString(" Commanding %1 to "2335 "go to sleep.").arg(thisHost));2336 2337 if ( enc->GoToSleep())2334 VERBOSE(VB_SCHEDULE+VB_EXTRA, QString(" Asking %1 to " 2335 "go to sleep.").arg(slaveHost)); 2336 int goToSleep = enc->GoToSleep(); 2337 if (goToSleep == 1) 2338 2338 { 2339 2339 QMap<int, EncoderLink *>::Iterator slviter = 2340 2340 m_tvList->begin(); 2341 2341 for (; slviter != m_tvList->end(); ++slviter) 2342 2342 { 2343 2343 EncoderLink *slv = *slviter; 2344 if (slv->GetHostName() == thisHost)2344 if (slv->GetHostName() == slaveHost) 2345 2345 { 2346 2346 VERBOSE(VB_SCHEDULE+VB_EXTRA, 2347 2347 QString(" Marking card %1 on slave %2 " … … 2352 2352 } 2353 2353 } 2354 2354 } 2355 else 2355 else if (goToSleep == -1) 2356 2356 { 2357 2357 VERBOSE(VB_IMPORTANT, LOC_ERR + QString("Unable to " 2358 2358 "shutdown %1 slave backend, setting sleep " 2359 "status to undefined.").arg( thisHost));2359 "status to undefined.").arg(slaveHost)); 2360 2360 QMap<int, EncoderLink *>::Iterator slviter = 2361 2361 m_tvList->begin(); 2362 2362 for (; slviter != m_tvList->end(); ++slviter) 2363 2363 { 2364 2364 EncoderLink *slv = *slviter; 2365 if (slv->GetHostName() == thisHost)2365 if (slv->GetHostName() == slaveHost) 2366 2366 slv->SetSleepStatus(sStatus_Undefined); 2367 2367 } 2368 2368 } … … 2404 2404 for (; enciter != m_tvList->end(); ++enciter) 2405 2405 { 2406 2406 EncoderLink *enc = *enciter; 2407 if (setWakingStatus && (enc->GetHostName() == slaveHostname)) 2407 if (setWakingStatus && (enc->GetHostName() == slaveHostname)) 2408 2408 enc->SetSleepStatus(sStatus_Waking); 2409 2409 2410 enc->SetLastWakeTime(curtime); 2410 2411 } 2411 2412 2413 VERBOSE(VB_SCHEDULE, QString("Trying to Wake Up %1.").arg(slaveHostname)); 2414 2412 2415 if (!IsMACAddress(wakeUpCommand)) 2413 2416 { 2417 wakeUpCommand = wakeUpCommand.replace(QRegExp("%SLAVE%"), QString("%1") 2418 .arg(slaveHostname)); 2414 2419 VERBOSE(VB_SCHEDULE, QString("Executing '%1' to wake up slave.") 2415 2420 .arg(wakeUpCommand)); 2416 2421 myth_system(wakeUpCommand); 2417 2422 } 2418 2423 else … … 2421 2426 return true; 2422 2427 } 2423 2428 2424 void Scheduler::WakeUpSlaves(void)2429 bool Scheduler::WakeUpSlaves(bool forceWakeAll) 2425 2430 { 2426 QStringList SlavesThatCanWake; 2431 VERBOSE(VB_SCHEDULE, "Scheduler, Checking for slaves that can be wake up"); 2432 QStringList slavesThatCanWake; 2427 2433 QString thisSlave; 2434 bool slaveWaken = false; 2428 2435 QMap<int, EncoderLink *>::Iterator enciter = m_tvList->begin(); 2429 2436 for (; enciter != m_tvList->end(); ++enciter) 2430 2437 { 2431 2438 EncoderLink *enc = *enciter; 2432 2439 2433 if ( enc->IsLocal())2440 if ((!forceWakeAll && !enc->CanSleep()) || enc->IsAwake() || enc->IsLocal() || enc->IsWaking()) 2434 2441 continue; 2435 2442 2436 2443 thisSlave = enc->GetHostName(); 2437 2444 2438 2445 if ((!gContext->GetSettingOnHost("WakeUpCommand", thisSlave) 2439 .isEmpty()) && 2440 (!SlavesThatCanWake.contains(thisSlave))) 2441 SlavesThatCanWake << thisSlave; 2446 .isEmpty()) && 2447 (!slavesThatCanWake.contains(thisSlave))) { 2448 slavesThatCanWake << thisSlave; 2449 2450 if (forceWakeAll || (!forceWakeAll && Scheduler::CheckDailyWakeUpPeriodSlaveAndEncoderStatus(thisSlave, enc))) 2451 { 2452 VERBOSE(VB_SCHEDULE, 2453 QString("Scheduler, Sending wakeup command to slave: %1") 2454 .arg(thisSlave)); 2455 WakeUpSlave(thisSlave); 2456 slaveWaken = true; 2457 } 2458 } 2442 2459 } 2460 return slaveWaken; 2461 } 2443 2462 2444 int slave = 0; 2445 for (; slave < SlavesThatCanWake.count(); slave++) 2463 QDateTime Scheduler::getDailyWakeupTime(QString sPeriod, QString slaveHostname) 2464 { 2465 QString sTime = gContext->GetSettingOnHost(sPeriod, slaveHostname, "00:00"); 2466 QTime tTime = QTime::fromString(sTime, "hh:mm"); 2467 QDateTime dtDateTime = QDateTime(QDate::currentDate(), tTime); 2468 2469 return dtDateTime; 2470 } 2471 2472 bool Scheduler::CheckDailyWakeUpPeriodSlaveAndEncoderStatus(QString slaveHostname, EncoderLink *enc) 2473 { 2474 2475 QDateTime dtCurrent = QDateTime::currentDateTime(); 2476 if (Scheduler::CheckDailyWakeUpPeriodSlave(slaveHostname)) 2446 2477 { 2447 thisSlave = SlavesThatCanWake[slave]; 2448 VERBOSE(VB_SCHEDULE, 2449 QString("Scheduler, Sending wakeup command to slave: %1") 2450 .arg(thisSlave)); 2451 WakeUpSlave(thisSlave, false); 2478 if (enc->IsAsleep() && !enc->IsWaking()) 2479 { 2480 VERBOSE(VB_SCHEDULE, QString("DailyWakupPeriod starts for " 2481 "slave backend %1, waking it up").arg(slaveHostname)); 2482 return true; 2483 } 2484 else if ((enc->IsWaking()) && (enc->GetSleepStatusTime() 2485 .secsTo(dtCurrent) < 370) && 2486 (enc->GetLastWakeTime().secsTo(dtCurrent) > 60)) 2487 { 2488 VERBOSE(VB_SCHEDULE, QString("DailyWakupPeriod already " 2489 "started for slave backend %1 but not yet " 2490 "available, trying to wake it up again.") 2491 .arg(slaveHostname)); 2492 return true; 2493 } 2452 2494 } 2495 2496 return false; 2497 2453 2498 } 2499 bool Scheduler::CheckDailyWakeUpPeriodSlave(QString slaveHostname) 2500 { 2501 QDateTime dtPeriod1Start = getDailyWakeupTime("DailyWakeupStartPeriod1", slaveHostname); 2502 QDateTime dtPeriod1End = getDailyWakeupTime("DailyWakeupEndPeriod1", slaveHostname); 2503 QDateTime dtPeriod2Start = getDailyWakeupTime("DailyWakeupStartPeriod2", slaveHostname); 2504 QDateTime dtPeriod2End = getDailyWakeupTime("DailyWakeupEndPeriod2", slaveHostname); 2505 QDateTime dtCurrent = QDateTime::currentDateTime(); 2454 2506 2507 bool inPeriod = false; 2508 2509 // taken from mythshutdown 2510 // Check for time periods that cross midnight 2511 if (dtPeriod1End < dtPeriod1Start) 2512 { 2513 if (dtCurrent > dtPeriod1End) 2514 dtPeriod1End = dtPeriod1End.addDays(1); 2515 else 2516 dtPeriod1Start = dtPeriod1Start.addDays(-1); 2517 } 2518 2519 if (dtPeriod2End < dtPeriod2Start) 2520 { 2521 if (dtCurrent > dtPeriod2End) 2522 dtPeriod2End = dtPeriod2End.addDays(1); 2523 else 2524 dtPeriod2Start = dtPeriod2Start.addDays(-1); 2525 } 2526 2527 // Check for one of the daily wakeup periods 2528 if (dtPeriod1Start != dtPeriod1End) 2529 { 2530 if (dtCurrent >= dtPeriod1Start && dtCurrent <= dtPeriod1End) 2531 { 2532 VERBOSE(VB_SCHEDULE+VB_EXTRA, "In a daily wakeup period (1)."); 2533 inPeriod = true; 2534 } 2535 } 2536 2537 if (dtPeriod2Start != dtPeriod2End) 2538 { 2539 if (dtCurrent >= dtPeriod2Start && dtCurrent <= dtPeriod2End) 2540 { 2541 VERBOSE(VB_SCHEDULE+VB_EXTRA, "In a daily wakeup period (2)."); 2542 inPeriod = true; 2543 } 2544 } 2545 2546 return inPeriod; 2547 } 2548 2455 2549 void *Scheduler::SchedulerThread(void *param) 2456 2550 { 2457 2551 // Lower scheduling priority, to avoid problems with recordings. -
encoderlink.cpp
358 358 359 359 /** \brief Tell a slave to go to sleep 360 360 */ 361 boolEncoderLink::GoToSleep(void)361 int EncoderLink::GoToSleep(void) 362 362 { 363 363 if (IsLocal() || !sock) 364 return false;364 return -1; 365 365 366 366 lastSleepTime = QDateTime::currentDateTime(); 367 367