Ticket #7762: shutdownSlaveEnhanced.diff

File shutdownSlaveEnhanced.diff, 17.6 KB (added by gmembre@…, 16 years ago)

patch of this enhancement

  • 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())
    2520     {
     2521    if (status) {
    25212522        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);
    25262523    }
    25272524    else
    25282525    {
    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";
    25332528    }
     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    }
    25342548}
    25352549
    25362550/**
  • programs/mythbackend/scheduler.cpp

     
    17061706                }
    17071707                firstRun = false;
    17081708            }
    1709 
    1710             PutInactiveSlavesToSleep();
    1711             lastSleepCheck = QDateTime::currentDateTime();
    17121709        }
    17131710      }
    17141711
     
    17181715
    17191716        curtime = QDateTime::currentDateTime();
    17201717
    1721         // About every 5 minutes check for slaves that can be put to sleep
    1722         if (lastSleepCheck.secsTo(curtime) > 300)
    1723         {
    1724             PutInactiveSlavesToSleep();
    1725             lastSleepCheck = QDateTime::currentDateTime();
    1726         }
    1727 
    17281718        // Go through the list of recordings starting in the next few minutes
    17291719        // and wakeup any slaves that are asleep
    17301720        RecIter recIter = startIter;
     
    19711961            idleSince = QDateTime();
    19721962        }
    19731963
     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
    19741973        // if idletimeout is 0, the user disabled the auto-shutdown feature
    19751974        if ((idleTimeoutSecs > 0) && (m_mainServer != NULL))
    19761975        {
     
    21492148        if ((*recIter)->recstatus == rsWillRecord)
    21502149            break;
    21512150
    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())
    21542154    {
    21552155        RecordingInfo *nextRecording = (*recIter);
    21562156        QDateTime restarttime = nextRecording->recstartts.addSecs((-1) *
     
    21992199        }
    22002200    }
    22012201
    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    }
    22062208    QString halt_cmd = gContext->GetSetting("ServerHaltCommand",
    22072209                                            "sudo /sbin/halt -p");
    22082210
     
    22432245            someSlavesCanSleep = true;
    22442246    }
    22452247
    2246     if (!someSlavesCanSleep)
     2248    if (!someSlavesCanSleep) 
    22472249        return;
    22482250
    22492251    VERBOSE(VB_SCHEDULE,
    22502252            "Scheduler, Checking for slaves that can be shut down");
    22512253
    22522254    int sleepThreshold =
    2253         gContext->GetNumSetting( "SleepThreshold", 60 * 45);
     2255        gContext->GetNumSetting( "idleWaitForRecordingTime", 15) * 60;
    22542256
    22552257    VERBOSE(VB_SCHEDULE+VB_EXTRA, QString("  Getting list of slaves that "
    22562258            "will be active in the next %1 minutes.")
     
    22592261    VERBOSE(VB_SCHEDULE+VB_EXTRA, "Checking scheduler's reclist");
    22602262    RecIter recIter = reclist.begin();
    22612263    QDateTime curtime = QDateTime::currentDateTime();
    2262     QStringList SlavesInUse;
     2264    QStringList slavesInUse;
    22632265    for ( ; recIter != reclist.end(); recIter++)
    22642266    {
    22652267        RecordingInfo *pginfo = *recIter;
     
    22762278        {
    22772279            enc = (*m_tvList)[pginfo->cardid];
    22782280            if ((!enc->IsLocal()) &&
    2279                 (!SlavesInUse.contains(enc->GetHostName())))
     2281                (!slavesInUse.contains(enc->GetHostName())))
    22802282            {
    2281                 if (pginfo->recstatus == rsWillRecord)
     2283                if (pginfo->recstatus == rsWillRecord) {
    22822284                    VERBOSE(VB_SCHEDULE+VB_EXTRA, QString("    Slave %1 will "
    22832285                            "be in use in %2 minutes").arg(enc->GetHostName())
    22842286                            .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'")
    22882295                            .arg(enc->GetHostName()).arg(pginfo->title));
    2289                 SlavesInUse << enc->GetHostName();
     2296                    slavesInUse << enc->GetHostName();
     2297                } */
    22902298            }
    22912299        }
    22922300    }
     
    23002308    if (query.exec() && query.size() > 0)
    23012309    {
    23022310        while(query.next()) {
    2303             SlavesInUse << query.value(0).toString();
     2311            slavesInUse << query.value(0).toString();
    23042312            VERBOSE(VB_SCHEDULE+VB_EXTRA, QString("    Slave %1 is marked as "
    23052313                    "in use by a %2")
    23062314                    .arg(query.value(0).toString())
     
    23082316        }
    23092317    }
    23102318
    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;
    23142320
    23152321    enciter = m_tvList->begin();
    23162322    for (; enciter != m_tvList->end(); ++enciter)
     
    23192325
    23202326        if ((!enc->IsLocal()) &&
    23212327            (enc->IsAwake()) &&
    2322             (!SlavesInUse.contains(enc->GetHostName())) &&
    2323             (!enc->IsFallingAsleep()))
     2328            (!slavesInUse.contains(enc->GetHostName())) &&
     2329            (!enc->IsFallingAsleep()) &&
     2330            (enc->GetSleepStatusTime().secsTo(curtime) > 300))
    23242331        {
    2325             QString sleepCommand = gContext->GetSettingOnHost("SleepCommand",
    2326                 enc->GetHostName());
     2332            QString slaveHost = enc->GetHostName();
     2333            bool allowSlaveToSleep = gContext->GetNumSettingOnHost("AllowSlaveToSleep", slaveHost, 0);
    23272334            QString wakeUpCommand = gContext->GetSettingOnHost("WakeUpCommand",
    2328                 enc->GetHostName());
     2335                slaveHost);
    23292336
    2330             if (!sleepCommand.isEmpty() && !wakeUpCommand.isEmpty())
     2337            if (allowSlaveToSleep && !wakeUpCommand.isEmpty() && !slavesThatCanWake.contains(slaveHost))
    23312338            {
    2332                 QString thisHost = enc->GetHostName();
     2339                // avoid asking the same slave to go to sleep
     2340                slavesThatCanWake << slaveHost;
    23332341
    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));
    23362344
    23372345                if (enc->GoToSleep())
    23382346                {
     
    23412349                    for (; slviter != m_tvList->end(); ++slviter)
    23422350                    {
    23432351                        EncoderLink *slv = *slviter;
    2344                         if (slv->GetHostName() == thisHost)
     2352                        if (slv->GetHostName() == slaveHost)
    23452353                        {
    23462354                            VERBOSE(VB_SCHEDULE+VB_EXTRA,
    23472355                                    QString("    Marking card %1 on slave %2 "
     
    23522360                        }
    23532361                    }
    23542362                }
    2355                 else
    2356                 {
    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                 }
    23692363            }
    23702364        }
    23712365    }
     
    24042398    for (; enciter != m_tvList->end(); ++enciter)
    24052399    {
    24062400        EncoderLink *enc = *enciter;
    2407         if (setWakingStatus && (enc->GetHostName() == slaveHostname))
     2401        if (setWakingStatus && (enc->GetHostName() == slaveHostname)) 
    24082402            enc->SetSleepStatus(sStatus_Waking);
     2403
    24092404        enc->SetLastWakeTime(curtime);
    24102405    }
    24112406
     2407    VERBOSE(VB_SCHEDULE, QString("Trying to Wake Up %1.").arg(slaveHostname));
     2408
    24122409    if (!IsMACAddress(wakeUpCommand))
    24132410    {
     2411        wakeUpCommand = wakeUpCommand.replace(QRegExp("%SLAVE%"), QString("%1")
     2412            .arg(slaveHostname));
    24142413        VERBOSE(VB_SCHEDULE, QString("Executing '%1' to wake up slave.")
    2415                 .arg(wakeUpCommand));
     2414            .arg(wakeUpCommand));
    24162415        myth_system(wakeUpCommand);
    24172416    }
    24182417    else
     
    24212420    return true;
    24222421}
    24232422
    2424 void Scheduler::WakeUpSlaves(void)
     2423bool Scheduler::WakeUpSlaves(bool forceWakeAll)
    24252424{
    2426     QStringList SlavesThatCanWake;
     2425    VERBOSE(VB_SCHEDULE, "Scheduler, Checking for slaves that can be wake up");
     2426    QStringList slavesThatCanWake;
    24272427    QString thisSlave;
     2428    bool slaveWaken = false;
    24282429    QMap<int, EncoderLink *>::Iterator enciter = m_tvList->begin();
    24292430    for (; enciter != m_tvList->end(); ++enciter)
    24302431    {
    24312432        EncoderLink *enc = *enciter;
    24322433
    2433         if (enc->IsLocal())
     2434        if ((!forceWakeAll && !enc->CanSleep()) || enc->IsAwake() || enc->IsLocal())
    24342435            continue;
    24352436
    24362437        thisSlave = enc->GetHostName();
    24372438
    24382439        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        }
    24422453    }
     2454    return slaveWaken;
     2455}
    24432456
    2444     int slave = 0;
    2445     for (; slave < SlavesThatCanWake.count(); slave++)
     2457QDateTime 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
     2466bool 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)
    24462479    {
    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);
    24522484    }
     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;
    24532535}
    24542536
    24552537void *Scheduler::SchedulerThread(void *param)
  • programs/mythbackend/encoderlink.cpp

     
    9595    {
    9696        lsock->UpRef();
    9797
    98         if (gContext->GetSettingOnHost("SleepCommand", hostname).isEmpty())
     98        if (gContext->GetNumSettingOnHost("AllowSlaveToSleep", hostname, 0))
     99            SetSleepStatus(sStatus_Awake);
     100        else
    99101            SetSleepStatus(sStatus_Undefined);
    100         else
    101             SetSleepStatus(sStatus_Awake);
    102102    }
    103103    else
    104104    {