Ticket #7762: SWpatch_shutdownEnhanced09Feb.diff

File SWpatch_shutdownEnhanced09Feb.diff, 19.4 KB (added by simonwalls@…, 14 years ago)

Modified patch. Closer to [20084] and uses SleepCommand? not HaltCommand?

  • programs/mythbackend/scheduler.h

     
    7777
    7878    bool WasStartedAutomatically();
    7979
     80    bool CheckShutdownServer(int prerollseconds, QDateTime &idleSince,
     81                             bool &blockShutdown);
    8082    int GetError(void) const { return error; }
    8183
    8284  protected:
     
    126128    bool ChangeRecordingEnd(RecordingInfo *oldp, RecordingInfo *newp);
    127129
    128130    void findAllScheduledPrograms(RecList &proglist);
    129     bool CheckShutdownServer(int prerollseconds, QDateTime &idleSince,
    130                              bool &blockShutdown);
    131131    void ShutdownServer(int prerollseconds, QDateTime &idleSince);
    132132    void PutInactiveSlavesToSleep(void);
    133133    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);
    135137
    136138    int FillRecordingDir(RecordingInfo *pginfo, RecList& reclist);
    137139    void FillDirectoryInfoCache(bool force = false);
  • programs/mythbackend/main.cpp

     
    10801080
    10811081        if (nosched)
    10821082            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();
    10831092    }
    10841093
    10851094    // Get any initial housekeeping done before we fire up anything else
  • programs/mythbackend/mainserver.cpp

     
    25142514void MainServer::HandleGoToSleep(PlaybackSock *pbs)
    25152515{
    25162516    QStringList strlist;
     2517    QDateTime idleSince;
     2518    bool blockShutdown = gContext->GetNumSetting("blockSDWUwithoutClient", 1);
     2519    bool status = m_sched->CheckShutdownServer(0, idleSince,  blockShutdown);
    25172520
    2518     QString sleepCmd = gContext->GetSetting("SleepCommand");
    2519     if (!sleepCmd.isEmpty())
     2521
     2522    if (status)
    25202523    {
    25212524        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.");
    25262526    }
    25272527    else
    25282528    {
    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.");
    25332532    }
     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    }
    25342559}
    25352560
    25362561/**
  • programs/mythbackend/scheduler.cpp

     
    17001700                }
    17011701                firstRun = false;
    17021702            }
    1703 
    1704             PutInactiveSlavesToSleep();
    1705             lastSleepCheck = QDateTime::currentDateTime();
    17061703        }
    17071704      }
    17081705
     
    17121709
    17131710        curtime = QDateTime::currentDateTime();
    17141711
    1715         // About every 5 minutes check for slaves that can be put to sleep
    1716         if (lastSleepCheck.secsTo(curtime) > 300)
    1717         {
    1718             PutInactiveSlavesToSleep();
    1719             lastSleepCheck = QDateTime::currentDateTime();
    1720         }
    1721 
    17221712        // Go through the list of recordings starting in the next few minutes
    17231713        // and wakeup any slaves that are asleep
    17241714        RecIter recIter = startIter;
     
    19651955            idleSince = QDateTime();
    19661956        }
    19671957
     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
    19681967        // if idletimeout is 0, the user disabled the auto-shutdown feature
    19691968        if ((idleTimeoutSecs > 0) && (m_mainServer != NULL))
    19701969        {
     
    20932092    int state = 0;
    20942093    if (!preSDWUCheckCommand.isEmpty())
    20952094    {
     2095        VERBOSE(VB_GENERAL, QString("Running preSDWUCheckCommand which is: ") + preSDWUCheckCommand);
    20962096        state = myth_system(preSDWUCheckCommand);
    20972097
    20982098        if (GENERIC_EXIT_NOT_OK != state)
     
    21432143        if ((*recIter)->recstatus == rsWillRecord)
    21442144            break;
    21452145
    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())
    21482149    {
    21492150        RecordingInfo *nextRecording = (*recIter);
    21502151        QDateTime restarttime = nextRecording->recstartts.addSecs((-1) *
     
    21932194        }
    21942195    }
    21952196
    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    }
    22002203    QString halt_cmd = gContext->GetSetting("ServerHaltCommand",
    22012204                                            "sudo /sbin/halt -p");
    22022205
     
    22372240            someSlavesCanSleep = true;
    22382241    }
    22392242
    2240     if (!someSlavesCanSleep)
     2243    if (!someSlavesCanSleep) 
    22412244        return;
    22422245
    22432246    VERBOSE(VB_SCHEDULE,
    22442247            "Scheduler, Checking for slaves that can be shut down");
    22452248
    22462249    int sleepThreshold =
    2247         gContext->GetNumSetting( "SleepThreshold", 60 * 45);
     2250        gContext->GetNumSetting( "idleWaitForRecordingTime", 15) * 60;
    22482251
    22492252    VERBOSE(VB_SCHEDULE+VB_EXTRA, QString("  Getting list of slaves that "
    22502253            "will be active in the next %1 minutes.")
     
    22532256    VERBOSE(VB_SCHEDULE+VB_EXTRA, "Checking scheduler's reclist");
    22542257    RecIter recIter = reclist.begin();
    22552258    QDateTime curtime = QDateTime::currentDateTime();
    2256     QStringList SlavesInUse;
     2259    QStringList slavesInUse;
    22572260    for ( ; recIter != reclist.end(); recIter++)
    22582261    {
    22592262        RecordingInfo *pginfo = *recIter;
     
    22702273        {
    22712274            enc = (*m_tvList)[pginfo->cardid];
    22722275            if ((!enc->IsLocal()) &&
    2273                 (!SlavesInUse.contains(enc->GetHostName())))
     2276                (!slavesInUse.contains(enc->GetHostName())))
    22742277            {
    2275                 if (pginfo->recstatus == rsWillRecord)
     2278                if (pginfo->recstatus == rsWillRecord) {
    22762279                    VERBOSE(VB_SCHEDULE+VB_EXTRA, QString("    Slave %1 will "
    22772280                            "be in use in %2 minutes").arg(enc->GetHostName())
    22782281                            .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'")
    22822290                            .arg(enc->GetHostName()).arg(pginfo->title));
    2283                 SlavesInUse << enc->GetHostName();
     2291                    slavesInUse << enc->GetHostName();
     2292                } */
    22842293            }
    22852294        }
    22862295    }
     
    22942303    if (query.exec() && query.size() > 0)
    22952304    {
    22962305        while(query.next()) {
    2297             SlavesInUse << query.value(0).toString();
     2306            slavesInUse << query.value(0).toString();
    22982307            VERBOSE(VB_SCHEDULE+VB_EXTRA, QString("    Slave %1 is marked as "
    22992308                    "in use by a %2")
    23002309                    .arg(query.value(0).toString())
    23012310                    .arg(query.value(1).toString()));
    23022311        }
    23032312    }
     2313    else
     2314    {
     2315        VERBOSE(VB_SCHEDULE+VB_EXTRA, "    No entries.");
     2316    }
    23042317
    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;
    23082319
    23092320    enciter = m_tvList->begin();
    23102321    for (; enciter != m_tvList->end(); ++enciter)
     
    23132324
    23142325        if ((!enc->IsLocal()) &&
    23152326            (enc->IsAwake()) &&
    2316             (!SlavesInUse.contains(enc->GetHostName())) &&
    2317             (!enc->IsFallingAsleep()))
     2327            (!slavesInUse.contains(enc->GetHostName())) &&
     2328            (!enc->IsFallingAsleep()) &&
     2329            (enc->GetSleepStatusTime().secsTo(curtime) > 300))
    23182330        {
    2319             QString sleepCommand = gContext->GetSettingOnHost("SleepCommand",
    2320                 enc->GetHostName());
     2331            QString slaveHost = enc->GetHostName();
     2332            bool allowSlaveToSleep = gContext->GetNumSettingOnHost("AllowSlaveToSleep", slaveHost, 0);
    23212333            QString wakeUpCommand = gContext->GetSettingOnHost("WakeUpCommand",
    2322                 enc->GetHostName());
     2334                slaveHost);
    23232335
    2324             if (!sleepCommand.isEmpty() && !wakeUpCommand.isEmpty())
     2336            if (allowSlaveToSleep && !wakeUpCommand.isEmpty() && !slavesThatCanWake.contains(slaveHost))
    23252337            {
    2326                 QString thisHost = enc->GetHostName();
     2338                // avoid asking the same slave to go to sleep
     2339                slavesThatCanWake << slaveHost;
    23272340
    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));
    23302343
    23312344                if (enc->GoToSleep())
    23322345                {
     
    23352348                    for (; slviter != m_tvList->end(); ++slviter)
    23362349                    {
    23372350                        EncoderLink *slv = *slviter;
    2338                         if (slv->GetHostName() == thisHost)
     2351                        if (slv->GetHostName() == slaveHost)
    23392352                        {
    23402353                            VERBOSE(VB_SCHEDULE+VB_EXTRA,
    2341                                     QString("    Marking card %1 on slave %2 "
     2354                                    QString("      Marking card %1 on slave %2 "
    23422355                                            "as falling asleep.")
    23432356                                            .arg(slv->GetCardID())
    23442357                                            .arg(slv->GetHostName()));
     
    23482361                }
    23492362                else
    23502363                {
    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));
    23622366                }
    23632367            }
    23642368        }
     
    23982402    for (; enciter != m_tvList->end(); ++enciter)
    23992403    {
    24002404        EncoderLink *enc = *enciter;
    2401         if (setWakingStatus && (enc->GetHostName() == slaveHostname))
     2405        if (setWakingStatus && (enc->GetHostName() == slaveHostname)) 
    24022406            enc->SetSleepStatus(sStatus_Waking);
     2407
    24032408        enc->SetLastWakeTime(curtime);
    24042409    }
    24052410
     2411    VERBOSE(VB_SCHEDULE, QString("Trying to Wake Up %1.").arg(slaveHostname));
     2412
    24062413    if (!IsMACAddress(wakeUpCommand))
    24072414    {
     2415        wakeUpCommand = wakeUpCommand.replace(QRegExp("%SLAVE%"), QString("%1")
     2416            .arg(slaveHostname));
    24082417        VERBOSE(VB_SCHEDULE, QString("Executing '%1' to wake up slave.")
    2409                 .arg(wakeUpCommand));
     2418            .arg(wakeUpCommand));
    24102419        myth_system(wakeUpCommand);
    24112420    }
    24122421    else
     
    24152424    return true;
    24162425}
    24172426
    2418 void Scheduler::WakeUpSlaves(void)
     2427bool Scheduler::WakeUpSlaves(bool forceWakeAll)
    24192428{
    2420     QStringList SlavesThatCanWake;
     2429    VERBOSE(VB_SCHEDULE, "Scheduler, Checking for slaves that can be wake up");
     2430    QStringList slavesThatCanWake;
    24212431    QString thisSlave;
     2432    bool slaveWaken = false;
    24222433    QMap<int, EncoderLink *>::Iterator enciter = m_tvList->begin();
    24232434    for (; enciter != m_tvList->end(); ++enciter)
    24242435    {
    24252436        EncoderLink *enc = *enciter;
    24262437
    2427         if (enc->IsLocal())
     2438        if ((!forceWakeAll && !enc->CanSleep()) || enc->IsAwake() || enc->IsLocal())
    24282439            continue;
    24292440
    24302441        thisSlave = enc->GetHostName();
    24312442
    24322443        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        }
    24362457    }
     2458    return slaveWaken;
     2459}
    24372460
    2438     int slave = 0;
    2439     for (; slave < SlavesThatCanWake.count(); slave++)
     2461QDateTime 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
     2470bool 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)
    24402483    {
    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);
    24462488    }
     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;
    24472539}
    24482540
    24492541void *Scheduler::SchedulerThread(void *param)
  • programs/mythbackend/httpstatus.cpp

     
    715715                        (SleepStatus) e.attribute("sleepstatus",
    716716                            QString((int)sStatus_Undefined)).toInt();
    717717
    718                     if (sleepStatus == sStatus_Asleep)
     718                    switch( sleepStatus )
     719                    {
     720                        case  sStatus_Asleep:
    719721                        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:
    721737                        os << " (currently not connected).<br />";
     738                        break;
     739                    }
    722740
    723741                    node = node.nextSibling();
    724742                    continue;