Ticket #7762: SWpatch_shutdownEnhanced09Feb.diff
| File SWpatch_shutdownEnhanced09Feb.diff, 19.4 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())2521 2522 if (status) 2520 2523 { 2521 2524 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); 2525 VERBOSE(VB_IMPORTANT, "Received a request to shut down this machine.... response is OK."); 2526 2526 } 2527 2527 else 2528 2528 { 2529 strlist << "ERROR: SleepCommand is empty"; 2530 VERBOSE(VB_IMPORTANT, 2531 "ERROR: in HandleGoToSleep(), but no SleepCommand found!"); 2532 SendResponse(pbs->getSocket(), strlist); 2529 // not allowed to sleep 2530 strlist << "BUSY"; 2531 VERBOSE(VB_IMPORTANT, "Received a request to shut down this machine.... response is BUSY."); 2533 2532 } 2533 2534 SendResponse(pbs->getSocket(), strlist); 2535 2536 if (status) 2537 { 2538 // shutdown 2539 QString SleepCmd = gContext->GetSetting("SleepCommand", ""); 2540 2541 if (!SleepCmd.isEmpty()) 2542 { 2543 VERBOSE(VB_GENERAL, QString("Running SleepCommand.")); 2544 2545 // and now shutdown myself 2546 if (!myth_system(SleepCmd)) 2547 return; 2548 else 2549 VERBOSE(VB_IMPORTANT, "SleepCommand failed, shutdown aborted."); 2550 } 2551 else 2552 { 2553 strlist << "ERROR: SleepCommand is empty"; 2554 VERBOSE(VB_IMPORTANT, 2555 "ERROR: in HandleGoToSleep(), but no SleepCommand found!"); 2556 SendResponse(pbs->getSocket(), strlist); 2557 } 2558 } 2534 2559 } 2535 2560 2536 2561 /** -
programs/mythbackend/scheduler.cpp
1700 1700 } 1701 1701 firstRun = false; 1702 1702 } 1703 1704 PutInactiveSlavesToSleep();1705 lastSleepCheck = QDateTime::currentDateTime();1706 1703 } 1707 1704 } 1708 1705 … … 1712 1709 1713 1710 curtime = QDateTime::currentDateTime(); 1714 1711 1715 // About every 5 minutes check for slaves that can be put to sleep1716 if (lastSleepCheck.secsTo(curtime) > 300)1717 {1718 PutInactiveSlavesToSleep();1719 lastSleepCheck = QDateTime::currentDateTime();1720 }1721 1722 1712 // Go through the list of recordings starting in the next few minutes 1723 1713 // and wakeup any slaves that are asleep 1724 1714 RecIter recIter = startIter; … … 1965 1955 idleSince = QDateTime(); 1966 1956 } 1967 1957 1958 // About every minute check for slaves that can be waken up or put to sleep 1959 if (lastSleepCheck.secsTo(curtime) >= 60) 1960 { 1961 bool slaveWaken = WakeUpSlaves(false); 1962 if (!slaveWaken) 1963 PutInactiveSlavesToSleep(); 1964 lastSleepCheck = QDateTime::currentDateTime(); 1965 } 1966 1968 1967 // if idletimeout is 0, the user disabled the auto-shutdown feature 1969 1968 if ((idleTimeoutSecs > 0) && (m_mainServer != NULL)) 1970 1969 { … … 2093 2092 int state = 0; 2094 2093 if (!preSDWUCheckCommand.isEmpty()) 2095 2094 { 2095 VERBOSE(VB_GENERAL, QString("Running preSDWUCheckCommand which is: ") + preSDWUCheckCommand); 2096 2096 state = myth_system(preSDWUCheckCommand); 2097 2097 2098 2098 if (GENERIC_EXIT_NOT_OK != state) … … 2143 2143 if ((*recIter)->recstatus == rsWillRecord) 2144 2144 break; 2145 2145 2146 // set the wakeuptime if needed 2147 if (recIter != reclist.end()) 2146 // set the wakeuptime if needed and if we are the master 2147 // otherwise, the master will wake up us 2148 if (recIter != reclist.end() && gContext->IsMasterBackend()) 2148 2149 { 2149 2150 RecordingInfo *nextRecording = (*recIter); 2150 2151 QDateTime restarttime = nextRecording->recstartts.addSecs((-1) * … … 2193 2194 } 2194 2195 } 2195 2196 2196 // tell anyone who is listening the master server is going down now 2197 MythEvent me(QString("SHUTDOWN_NOW")); 2198 gContext->dispatch(me); 2199 2197 if (gContext->IsMasterBackend()) 2198 { 2199 // tell anyone who is listening the master server is going down now 2200 MythEvent me(QString("SHUTDOWN_NOW")); 2201 gContext->dispatch(me); 2202 } 2200 2203 QString halt_cmd = gContext->GetSetting("ServerHaltCommand", 2201 2204 "sudo /sbin/halt -p"); 2202 2205 … … 2237 2240 someSlavesCanSleep = true; 2238 2241 } 2239 2242 2240 if (!someSlavesCanSleep) 2243 if (!someSlavesCanSleep) 2241 2244 return; 2242 2245 2243 2246 VERBOSE(VB_SCHEDULE, 2244 2247 "Scheduler, Checking for slaves that can be shut down"); 2245 2248 2246 2249 int sleepThreshold = 2247 gContext->GetNumSetting( " SleepThreshold", 60 * 45);2250 gContext->GetNumSetting( "idleWaitForRecordingTime", 15) * 60; 2248 2251 2249 2252 VERBOSE(VB_SCHEDULE+VB_EXTRA, QString(" Getting list of slaves that " 2250 2253 "will be active in the next %1 minutes.") … … 2253 2256 VERBOSE(VB_SCHEDULE+VB_EXTRA, "Checking scheduler's reclist"); 2254 2257 RecIter recIter = reclist.begin(); 2255 2258 QDateTime curtime = QDateTime::currentDateTime(); 2256 QStringList SlavesInUse;2259 QStringList slavesInUse; 2257 2260 for ( ; recIter != reclist.end(); recIter++) 2258 2261 { 2259 2262 RecordingInfo *pginfo = *recIter; … … 2270 2273 { 2271 2274 enc = (*m_tvList)[pginfo->cardid]; 2272 2275 if ((!enc->IsLocal()) && 2273 (! SlavesInUse.contains(enc->GetHostName())))2276 (!slavesInUse.contains(enc->GetHostName()))) 2274 2277 { 2275 if (pginfo->recstatus == rsWillRecord) 2278 if (pginfo->recstatus == rsWillRecord) { 2276 2279 VERBOSE(VB_SCHEDULE+VB_EXTRA, QString(" Slave %1 will " 2277 2280 "be in use in %2 minutes").arg(enc->GetHostName()) 2278 2281 .arg(secsleft / 60)); 2279 else 2280 VERBOSE(VB_SCHEDULE+VB_EXTRA, QString(" Slave %1 is " 2281 "in use currently recording '%1'") 2282 slavesInUse << enc->GetHostName(); 2283 } /* else if (enc->GetState() == kState_None) { 2284 VERBOSE(VB_IMPORTANT, QString(" Slave %1 is " 2285 "idling") 2286 .arg(enc->GetHostName())); 2287 } else { 2288 VERBOSE(VB_IMPORTANT, QString(" Slave %1 is " 2289 "in use currently recording '%2'") 2282 2290 .arg(enc->GetHostName()).arg(pginfo->title)); 2283 SlavesInUse << enc->GetHostName(); 2291 slavesInUse << enc->GetHostName(); 2292 } */ 2284 2293 } 2285 2294 } 2286 2295 } … … 2294 2303 if (query.exec() && query.size() > 0) 2295 2304 { 2296 2305 while(query.next()) { 2297 SlavesInUse << query.value(0).toString();2306 slavesInUse << query.value(0).toString(); 2298 2307 VERBOSE(VB_SCHEDULE+VB_EXTRA, QString(" Slave %1 is marked as " 2299 2308 "in use by a %2") 2300 2309 .arg(query.value(0).toString()) 2301 2310 .arg(query.value(1).toString())); 2302 2311 } 2303 2312 } 2313 else 2314 { 2315 VERBOSE(VB_SCHEDULE+VB_EXTRA, " No entries."); 2316 } 2304 2317 2305 VERBOSE(VB_SCHEDULE+VB_EXTRA, QString(" Shutting down slaves which will " 2306 "be inactive for the next %1 minutes and can be put to sleep.") 2307 .arg(sleepThreshold / 60)); 2318 QStringList slavesThatCanWake; 2308 2319 2309 2320 enciter = m_tvList->begin(); 2310 2321 for (; enciter != m_tvList->end(); ++enciter) … … 2313 2324 2314 2325 if ((!enc->IsLocal()) && 2315 2326 (enc->IsAwake()) && 2316 (!SlavesInUse.contains(enc->GetHostName())) && 2317 (!enc->IsFallingAsleep())) 2327 (!slavesInUse.contains(enc->GetHostName())) && 2328 (!enc->IsFallingAsleep()) && 2329 (enc->GetSleepStatusTime().secsTo(curtime) > 300)) 2318 2330 { 2319 QString sl eepCommand = gContext->GetSettingOnHost("SleepCommand",2320 enc->GetHostName());2331 QString slaveHost = enc->GetHostName(); 2332 bool allowSlaveToSleep = gContext->GetNumSettingOnHost("AllowSlaveToSleep", slaveHost, 0); 2321 2333 QString wakeUpCommand = gContext->GetSettingOnHost("WakeUpCommand", 2322 enc->GetHostName());2334 slaveHost); 2323 2335 2324 if ( !sleepCommand.isEmpty() && !wakeUpCommand.isEmpty())2336 if (allowSlaveToSleep && !wakeUpCommand.isEmpty() && !slavesThatCanWake.contains(slaveHost)) 2325 2337 { 2326 QString thisHost = enc->GetHostName(); 2338 // avoid asking the same slave to go to sleep 2339 slavesThatCanWake << slaveHost; 2327 2340 2328 VERBOSE(VB_ SCHEDULE+VB_EXTRA, QString(" Commanding %1 to "2329 "go to sleep.").arg(thisHost));2341 VERBOSE(VB_IMPORTANT, QString(" Asking %1 to " 2342 "go to sleep.").arg(slaveHost)); 2330 2343 2331 2344 if (enc->GoToSleep()) 2332 2345 { … … 2335 2348 for (; slviter != m_tvList->end(); ++slviter) 2336 2349 { 2337 2350 EncoderLink *slv = *slviter; 2338 if (slv->GetHostName() == thisHost)2351 if (slv->GetHostName() == slaveHost) 2339 2352 { 2340 2353 VERBOSE(VB_SCHEDULE+VB_EXTRA, 2341 QString(" Marking card %1 on slave %2 "2354 QString(" Marking card %1 on slave %2 " 2342 2355 "as falling asleep.") 2343 2356 .arg(slv->GetCardID()) 2344 2357 .arg(slv->GetHostName())); … … 2348 2361 } 2349 2362 else 2350 2363 { 2351 VERBOSE(VB_IMPORTANT, LOC_ERR + QString("Unable to " 2352 "shutdown %1 slave backend, setting sleep " 2353 "status to undefined.").arg(thisHost)); 2354 QMap<int, EncoderLink *>::Iterator slviter = 2355 m_tvList->begin(); 2356 for (; slviter != m_tvList->end(); ++slviter) 2357 { 2358 EncoderLink *slv = *slviter; 2359 if (slv->GetHostName() == thisHost) 2360 slv->SetSleepStatus(sStatus_Undefined); 2361 } 2364 VERBOSE(VB_IMPORTANT, QString(" Slave %1 responded " 2365 "that it will not go to sleep.").arg(slaveHost)); 2362 2366 } 2363 2367 } 2364 2368 } … … 2398 2402 for (; enciter != m_tvList->end(); ++enciter) 2399 2403 { 2400 2404 EncoderLink *enc = *enciter; 2401 if (setWakingStatus && (enc->GetHostName() == slaveHostname)) 2405 if (setWakingStatus && (enc->GetHostName() == slaveHostname)) 2402 2406 enc->SetSleepStatus(sStatus_Waking); 2407 2403 2408 enc->SetLastWakeTime(curtime); 2404 2409 } 2405 2410 2411 VERBOSE(VB_SCHEDULE, QString("Trying to Wake Up %1.").arg(slaveHostname)); 2412 2406 2413 if (!IsMACAddress(wakeUpCommand)) 2407 2414 { 2415 wakeUpCommand = wakeUpCommand.replace(QRegExp("%SLAVE%"), QString("%1") 2416 .arg(slaveHostname)); 2408 2417 VERBOSE(VB_SCHEDULE, QString("Executing '%1' to wake up slave.") 2409 .arg(wakeUpCommand));2418 .arg(wakeUpCommand)); 2410 2419 myth_system(wakeUpCommand); 2411 2420 } 2412 2421 else … … 2415 2424 return true; 2416 2425 } 2417 2426 2418 void Scheduler::WakeUpSlaves(void)2427 bool Scheduler::WakeUpSlaves(bool forceWakeAll) 2419 2428 { 2420 QStringList SlavesThatCanWake; 2429 VERBOSE(VB_SCHEDULE, "Scheduler, Checking for slaves that can be wake up"); 2430 QStringList slavesThatCanWake; 2421 2431 QString thisSlave; 2432 bool slaveWaken = false; 2422 2433 QMap<int, EncoderLink *>::Iterator enciter = m_tvList->begin(); 2423 2434 for (; enciter != m_tvList->end(); ++enciter) 2424 2435 { 2425 2436 EncoderLink *enc = *enciter; 2426 2437 2427 if ( enc->IsLocal())2438 if ((!forceWakeAll && !enc->CanSleep()) || enc->IsAwake() || enc->IsLocal()) 2428 2439 continue; 2429 2440 2430 2441 thisSlave = enc->GetHostName(); 2431 2442 2432 2443 if ((!gContext->GetSettingOnHost("WakeUpCommand", thisSlave) 2433 .isEmpty()) && 2434 (!SlavesThatCanWake.contains(thisSlave))) 2435 SlavesThatCanWake << thisSlave; 2444 .isEmpty()) && 2445 (!slavesThatCanWake.contains(thisSlave))) { 2446 slavesThatCanWake << thisSlave; 2447 2448 if (forceWakeAll || (!forceWakeAll && CheckDailyWakeUpPeriodSlave(thisSlave, enc))) 2449 { 2450 VERBOSE(VB_SCHEDULE, 2451 QString("Scheduler, Sending wakeup command to slave: %1") 2452 .arg(thisSlave)); 2453 WakeUpSlave(thisSlave); 2454 slaveWaken = true; 2455 } 2456 } 2436 2457 } 2458 return slaveWaken; 2459 } 2437 2460 2438 int slave = 0; 2439 for (; slave < SlavesThatCanWake.count(); slave++) 2461 QDateTime Scheduler::getDailyWakeupTime(QString sPeriod) 2462 { 2463 QString sTime = gContext->GetSetting(sPeriod, "00:00"); 2464 QTime tTime = QTime::fromString(sTime, "hh:mm"); 2465 QDateTime dtDateTime = QDateTime(QDate::currentDate(), tTime); 2466 2467 return dtDateTime; 2468 } 2469 2470 bool Scheduler::CheckDailyWakeUpPeriodSlave(QString slaveHostname, EncoderLink *enc) 2471 { 2472 QDateTime dtPeriod1Start = getDailyWakeupTime("DailyWakeupStartPeriod1"); 2473 QDateTime dtPeriod1End = getDailyWakeupTime("DailyWakeupEndPeriod1"); 2474 QDateTime dtPeriod2Start = getDailyWakeupTime("DailyWakeupStartPeriod2"); 2475 QDateTime dtPeriod2End = getDailyWakeupTime("DailyWakeupEndPeriod2"); 2476 QDateTime dtCurrent = QDateTime::currentDateTime(); 2477 2478 bool inPeriod = false; 2479 2480 // taken from mythshutdown 2481 // Check for time periods that cross midnight 2482 if (dtPeriod1End < dtPeriod1Start) 2440 2483 { 2441 thisSlave = SlavesThatCanWake[slave]; 2442 VERBOSE(VB_SCHEDULE, 2443 QString("Scheduler, Sending wakeup command to slave: %1") 2444 .arg(thisSlave)); 2445 WakeUpSlave(thisSlave, false); 2484 if (dtCurrent > dtPeriod1End) 2485 dtPeriod1End = dtPeriod1End.addDays(1); 2486 else 2487 dtPeriod1Start = dtPeriod1Start.addDays(-1); 2446 2488 } 2489 2490 if (dtPeriod2End < dtPeriod2Start) 2491 { 2492 if (dtCurrent > dtPeriod2End) 2493 dtPeriod2End = dtPeriod2End.addDays(1); 2494 else 2495 dtPeriod2Start = dtPeriod2Start.addDays(-1); 2496 } 2497 2498 // Check for one of the daily wakeup periods 2499 if (dtPeriod1Start != dtPeriod1End) 2500 { 2501 if (dtCurrent >= dtPeriod1Start && dtCurrent <= dtPeriod1End) 2502 { 2503 VERBOSE(VB_SCHEDULE+VB_EXTRA, "In a daily wakeup period (1)."); 2504 inPeriod = true; 2505 } 2506 } 2507 2508 if (dtPeriod2Start != dtPeriod2End) 2509 { 2510 if (dtCurrent >= dtPeriod2Start && dtCurrent <= dtPeriod2End) 2511 { 2512 VERBOSE(VB_SCHEDULE+VB_EXTRA, "In a daily wakeup period (2)."); 2513 inPeriod = true; 2514 } 2515 } 2516 2517 2518 if (inPeriod) 2519 { 2520 if (enc->IsAsleep() && !enc->IsWaking()) 2521 { 2522 VERBOSE(VB_SCHEDULE, QString("DailyWakupPeriod starts for " 2523 "slave backend %1, waking it up").arg(slaveHostname)); 2524 return true; 2525 } 2526 else if ((enc->IsWaking()) && (enc->GetSleepStatusTime() 2527 .secsTo(dtCurrent) < 370) && 2528 (enc->GetLastWakeTime().secsTo(dtCurrent) > 60)) 2529 { 2530 VERBOSE(VB_SCHEDULE, QString("DailyWakupPeriod already " 2531 "started for slave backend %1 but not yet " 2532 "available, trying to wake it up again.") 2533 .arg(slaveHostname)); 2534 return true; 2535 } 2536 } 2537 2538 return false; 2447 2539 } 2448 2540 2449 2541 void *Scheduler::SchedulerThread(void *param) -
programs/mythbackend/httpstatus.cpp
715 715 (SleepStatus) e.attribute("sleepstatus", 716 716 QString((int)sStatus_Undefined)).toInt(); 717 717 718 if (sleepStatus == sStatus_Asleep) 718 switch( sleepStatus ) 719 { 720 case sStatus_Asleep: 719 721 os << " (currently asleep).<br />"; 720 else 722 break; 723 724 case sStatus_FallingAsleep: 725 os << " (currently falling asleep).<br />"; 726 break; 727 728 case sStatus_Waking: 729 os << " (currently waking up).<br />"; 730 break; 731 732 case sStatus_Undefined: 733 os << " (currently undefined).<br />"; 734 break; 735 736 default: 721 737 os << " (currently not connected).<br />"; 738 break; 739 } 722 740 723 741 node = node.nextSibling(); 724 742 continue;
