Ticket #7762: shutdownSlaveEnhanced.diff
| File shutdownSlaveEnhanced.diff, 17.6 KB (added by , 16 years ago) |
|---|
-
programs/mythbackend/scheduler.h
77 77 78 78 bool WasStartedAutomatically(); 79 79 80 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, EncoderLink *enc); 136 QDateTime getDailyWakeupTime(QString sPeriod); 135 137 136 138 int FillRecordingDir(RecordingInfo *pginfo, RecList& reclist); 137 139 void FillDirectoryInfoCache(bool force = false); -
programs/mythbackend/main.cpp
1080 1080 1081 1081 if (nosched) 1082 1082 sched->DisableScheduling(); 1083 } else { 1084 // just initialise the scheduler but do not start it 1085 sched = new Scheduler(false, &tvList); 1086 int err = sched->GetError(); 1087 if (err) 1088 { 1089 return err; 1090 } 1091 sched->DisableScheduling(); 1083 1092 } 1084 1093 1085 1094 // Get any initial housekeeping done before we fire up anything else -
programs/mythbackend/mainserver.cpp
2514 2514 void MainServer::HandleGoToSleep(PlaybackSock *pbs) 2515 2515 { 2516 2516 QStringList strlist; 2517 QDateTime idleSince; 2518 bool blockShutdown = gContext->GetNumSetting("blockSDWUwithoutClient", 1); 2519 bool status = m_sched->CheckShutdownServer(0, idleSince, blockShutdown); 2517 2520 2518 QString sleepCmd = gContext->GetSetting("SleepCommand"); 2519 if (!sleepCmd.isEmpty()) 2520 { 2521 if (status) { 2521 2522 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);2526 2523 } 2527 2524 else 2528 2525 { 2529 strlist << "ERROR: SleepCommand is empty"; 2530 VERBOSE(VB_IMPORTANT, 2531 "ERROR: in HandleGoToSleep(), but no SleepCommand found!"); 2532 SendResponse(pbs->getSocket(), strlist); 2526 // not allowed to sleep 2527 strlist << "BUSY"; 2533 2528 } 2529 SendResponse(pbs->getSocket(), strlist); 2530 2531 if (status) { 2532 // shutdown 2533 QString halt_cmd = gContext->GetSetting("ServerHaltCommand", 2534 "sudo /sbin/halt -p"); 2535 2536 if (!halt_cmd.isEmpty()) 2537 { 2538 VERBOSE(VB_GENERAL, QString("Running the command to shutdown " 2539 "this computer :-\n\t\t\t\t\t\t") + halt_cmd); 2540 2541 // and now shutdown myself 2542 if (!myth_system(halt_cmd)) 2543 return; 2544 else 2545 VERBOSE(VB_IMPORTANT, "ServerHaltCommand failed, shutdown aborted"); 2546 } 2547 } 2534 2548 } 2535 2549 2536 2550 /** -
programs/mythbackend/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())))2281 (!slavesInUse.contains(enc->GetHostName()))) 2280 2282 { 2281 if (pginfo->recstatus == rsWillRecord) 2283 if (pginfo->recstatus == rsWillRecord) { 2282 2284 VERBOSE(VB_SCHEDULE+VB_EXTRA, QString(" Slave %1 will " 2283 2285 "be in use in %2 minutes").arg(enc->GetHostName()) 2284 2286 .arg(secsleft / 60)); 2285 else 2286 VERBOSE(VB_SCHEDULE+VB_EXTRA, QString(" Slave %1 is " 2287 "in use currently recording '%1'") 2287 slavesInUse << enc->GetHostName(); 2288 } /* else if (enc->GetState() == kState_None) { 2289 VERBOSE(VB_IMPORTANT, QString(" Slave %1 is " 2290 "idling") 2291 .arg(enc->GetHostName())); 2292 } else { 2293 VERBOSE(VB_IMPORTANT, QString(" Slave %1 is " 2294 "in use currently recording '%2'") 2288 2295 .arg(enc->GetHostName()).arg(pginfo->title)); 2289 SlavesInUse << enc->GetHostName(); 2296 slavesInUse << enc->GetHostName(); 2297 } */ 2290 2298 } 2291 2299 } 2292 2300 } … … 2300 2308 if (query.exec() && query.size() > 0) 2301 2309 { 2302 2310 while(query.next()) { 2303 SlavesInUse << query.value(0).toString();2311 slavesInUse << query.value(0).toString(); 2304 2312 VERBOSE(VB_SCHEDULE+VB_EXTRA, QString(" Slave %1 is marked as " 2305 2313 "in use by a %2") 2306 2314 .arg(query.value(0).toString()) … … 2308 2316 } 2309 2317 } 2310 2318 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)); 2319 QStringList slavesThatCanWake; 2314 2320 2315 2321 enciter = m_tvList->begin(); 2316 2322 for (; enciter != m_tvList->end(); ++enciter) … … 2319 2325 2320 2326 if ((!enc->IsLocal()) && 2321 2327 (enc->IsAwake()) && 2322 (!SlavesInUse.contains(enc->GetHostName())) && 2323 (!enc->IsFallingAsleep())) 2328 (!slavesInUse.contains(enc->GetHostName())) && 2329 (!enc->IsFallingAsleep()) && 2330 (enc->GetSleepStatusTime().secsTo(curtime) > 300)) 2324 2331 { 2325 QString sl eepCommand = gContext->GetSettingOnHost("SleepCommand",2326 enc->GetHostName());2332 QString slaveHost = enc->GetHostName(); 2333 bool allowSlaveToSleep = gContext->GetNumSettingOnHost("AllowSlaveToSleep", slaveHost, 0); 2327 2334 QString wakeUpCommand = gContext->GetSettingOnHost("WakeUpCommand", 2328 enc->GetHostName());2335 slaveHost); 2329 2336 2330 if ( !sleepCommand.isEmpty() && !wakeUpCommand.isEmpty())2337 if (allowSlaveToSleep && !wakeUpCommand.isEmpty() && !slavesThatCanWake.contains(slaveHost)) 2331 2338 { 2332 QString thisHost = enc->GetHostName(); 2339 // avoid asking the same slave to go to sleep 2340 slavesThatCanWake << slaveHost; 2333 2341 2334 VERBOSE(VB_SCHEDULE+VB_EXTRA, QString(" Commanding %1 to "2335 "go to sleep.").arg(thisHost));2342 VERBOSE(VB_SCHEDULE+VB_EXTRA, QString(" Asking %1 to " 2343 "go to sleep.").arg(slaveHost)); 2336 2344 2337 2345 if (enc->GoToSleep()) 2338 2346 { … … 2341 2349 for (; slviter != m_tvList->end(); ++slviter) 2342 2350 { 2343 2351 EncoderLink *slv = *slviter; 2344 if (slv->GetHostName() == thisHost)2352 if (slv->GetHostName() == slaveHost) 2345 2353 { 2346 2354 VERBOSE(VB_SCHEDULE+VB_EXTRA, 2347 2355 QString(" Marking card %1 on slave %2 " … … 2352 2360 } 2353 2361 } 2354 2362 } 2355 else2356 {2357 VERBOSE(VB_IMPORTANT, LOC_ERR + QString("Unable to "2358 "shutdown %1 slave backend, setting sleep "2359 "status to undefined.").arg(thisHost));2360 QMap<int, EncoderLink *>::Iterator slviter =2361 m_tvList->begin();2362 for (; slviter != m_tvList->end(); ++slviter)2363 {2364 EncoderLink *slv = *slviter;2365 if (slv->GetHostName() == thisHost)2366 slv->SetSleepStatus(sStatus_Undefined);2367 }2368 }2369 2363 } 2370 2364 } 2371 2365 } … … 2404 2398 for (; enciter != m_tvList->end(); ++enciter) 2405 2399 { 2406 2400 EncoderLink *enc = *enciter; 2407 if (setWakingStatus && (enc->GetHostName() == slaveHostname)) 2401 if (setWakingStatus && (enc->GetHostName() == slaveHostname)) 2408 2402 enc->SetSleepStatus(sStatus_Waking); 2403 2409 2404 enc->SetLastWakeTime(curtime); 2410 2405 } 2411 2406 2407 VERBOSE(VB_SCHEDULE, QString("Trying to Wake Up %1.").arg(slaveHostname)); 2408 2412 2409 if (!IsMACAddress(wakeUpCommand)) 2413 2410 { 2411 wakeUpCommand = wakeUpCommand.replace(QRegExp("%SLAVE%"), QString("%1") 2412 .arg(slaveHostname)); 2414 2413 VERBOSE(VB_SCHEDULE, QString("Executing '%1' to wake up slave.") 2415 .arg(wakeUpCommand));2414 .arg(wakeUpCommand)); 2416 2415 myth_system(wakeUpCommand); 2417 2416 } 2418 2417 else … … 2421 2420 return true; 2422 2421 } 2423 2422 2424 void Scheduler::WakeUpSlaves(void)2423 bool Scheduler::WakeUpSlaves(bool forceWakeAll) 2425 2424 { 2426 QStringList SlavesThatCanWake; 2425 VERBOSE(VB_SCHEDULE, "Scheduler, Checking for slaves that can be wake up"); 2426 QStringList slavesThatCanWake; 2427 2427 QString thisSlave; 2428 bool slaveWaken = false; 2428 2429 QMap<int, EncoderLink *>::Iterator enciter = m_tvList->begin(); 2429 2430 for (; enciter != m_tvList->end(); ++enciter) 2430 2431 { 2431 2432 EncoderLink *enc = *enciter; 2432 2433 2433 if ( enc->IsLocal())2434 if ((!forceWakeAll && !enc->CanSleep()) || enc->IsAwake() || enc->IsLocal()) 2434 2435 continue; 2435 2436 2436 2437 thisSlave = enc->GetHostName(); 2437 2438 2438 2439 if ((!gContext->GetSettingOnHost("WakeUpCommand", thisSlave) 2439 .isEmpty()) && 2440 (!SlavesThatCanWake.contains(thisSlave))) 2441 SlavesThatCanWake << thisSlave; 2440 .isEmpty()) && 2441 (!slavesThatCanWake.contains(thisSlave))) { 2442 slavesThatCanWake << thisSlave; 2443 2444 if (forceWakeAll || (!forceWakeAll && CheckDailyWakeUpPeriodSlave(thisSlave, enc))) 2445 { 2446 VERBOSE(VB_SCHEDULE, 2447 QString("Scheduler, Sending wakeup command to slave: %1") 2448 .arg(thisSlave)); 2449 WakeUpSlave(thisSlave); 2450 slaveWaken = true; 2451 } 2452 } 2442 2453 } 2454 return slaveWaken; 2455 } 2443 2456 2444 int slave = 0; 2445 for (; slave < SlavesThatCanWake.count(); slave++) 2457 QDateTime Scheduler::getDailyWakeupTime(QString sPeriod) 2458 { 2459 QString sTime = gContext->GetSetting(sPeriod, "00:00"); 2460 QTime tTime = QTime::fromString(sTime, "hh:mm"); 2461 QDateTime dtDateTime = QDateTime(QDate::currentDate(), tTime); 2462 2463 return dtDateTime; 2464 } 2465 2466 bool Scheduler::CheckDailyWakeUpPeriodSlave(QString slaveHostname, EncoderLink *enc) 2467 { 2468 QDateTime dtPeriod1Start = getDailyWakeupTime("DailyWakeupStartPeriod1"); 2469 QDateTime dtPeriod1End = getDailyWakeupTime("DailyWakeupEndPeriod1"); 2470 QDateTime dtPeriod2Start = getDailyWakeupTime("DailyWakeupStartPeriod2"); 2471 QDateTime dtPeriod2End = getDailyWakeupTime("DailyWakeupEndPeriod2"); 2472 QDateTime dtCurrent = QDateTime::currentDateTime(); 2473 2474 bool inPeriod = false; 2475 2476 // taken from mythshutdown 2477 // Check for time periods that cross midnight 2478 if (dtPeriod1End < dtPeriod1Start) 2446 2479 { 2447 thisSlave = SlavesThatCanWake[slave]; 2448 VERBOSE(VB_SCHEDULE, 2449 QString("Scheduler, Sending wakeup command to slave: %1") 2450 .arg(thisSlave)); 2451 WakeUpSlave(thisSlave, false); 2480 if (dtCurrent > dtPeriod1End) 2481 dtPeriod1End = dtPeriod1End.addDays(1); 2482 else 2483 dtPeriod1Start = dtPeriod1Start.addDays(-1); 2452 2484 } 2485 2486 if (dtPeriod2End < dtPeriod2Start) 2487 { 2488 if (dtCurrent > dtPeriod2End) 2489 dtPeriod2End = dtPeriod2End.addDays(1); 2490 else 2491 dtPeriod2Start = dtPeriod2Start.addDays(-1); 2492 } 2493 2494 // Check for one of the daily wakeup periods 2495 if (dtPeriod1Start != dtPeriod1End) 2496 { 2497 if (dtCurrent >= dtPeriod1Start && dtCurrent <= dtPeriod1End) 2498 { 2499 VERBOSE(VB_SCHEDULE+VB_EXTRA, "In a daily wakeup period (1)."); 2500 inPeriod = true; 2501 } 2502 } 2503 2504 if (dtPeriod2Start != dtPeriod2End) 2505 { 2506 if (dtCurrent >= dtPeriod2Start && dtCurrent <= dtPeriod2End) 2507 { 2508 VERBOSE(VB_SCHEDULE+VB_EXTRA, "In a daily wakeup period (2)."); 2509 inPeriod = true; 2510 } 2511 } 2512 2513 2514 if (inPeriod) 2515 { 2516 if (enc->IsAsleep() && !enc->IsWaking()) 2517 { 2518 VERBOSE(VB_SCHEDULE, QString("DailyWakupPeriod starts for " 2519 "slave backend %1, waking it up").arg(slaveHostname)); 2520 return true; 2521 } 2522 else if ((enc->IsWaking()) && (enc->GetSleepStatusTime() 2523 .secsTo(dtCurrent) < 370) && 2524 (enc->GetLastWakeTime().secsTo(dtCurrent) > 60)) 2525 { 2526 VERBOSE(VB_SCHEDULE, QString("DailyWakupPeriod already " 2527 "started for slave backend %1 but not yet " 2528 "available, trying to wake it up again.") 2529 .arg(slaveHostname)); 2530 return true; 2531 } 2532 } 2533 2534 return false; 2453 2535 } 2454 2536 2455 2537 void *Scheduler::SchedulerThread(void *param) -
programs/mythbackend/encoderlink.cpp
95 95 { 96 96 lsock->UpRef(); 97 97 98 if (gContext->GetSettingOnHost("SleepCommand", hostname).isEmpty()) 98 if (gContext->GetNumSettingOnHost("AllowSlaveToSleep", hostname, 0)) 99 SetSleepStatus(sStatus_Awake); 100 else 99 101 SetSleepStatus(sStatus_Undefined); 100 else101 SetSleepStatus(sStatus_Awake);102 102 } 103 103 else 104 104 {
