Ticket #7762: shutdownSlaveEnhanced_v0.3.diff

File shutdownSlaveEnhanced_v0.3.diff, 19.1 KB (added by gmembre@…, 14 years ago)

Better handling of daily wakeup period for the slave

  • playbacksock.h

     
    4242    void setIP(QString &lip) { ip = lip; }
    4343    QString getIP(void) { return ip; }
    4444
    45     bool GoToSleep(void);
     45    int GoToSleep(void);
    4646    void GetDiskSpace(QStringList &o_strlist);
    4747    int DeleteFile(const QString filename, const QString sgroup);
    4848    int StopRecording(const ProgramInfo *pginfo);
  • scheduler.h

     
    7777
    7878    bool WasStartedAutomatically();
    7979
     80    static 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);
     136    bool CheckDailyWakeUpPeriodSlaveAndEncoderStatus(QString slaveHostname, EncoderLink *enc);
     137    QDateTime getDailyWakeupTime(QString sPeriod, QString slaveHostname);
    135138
    136139    int FillRecordingDir(RecordingInfo *pginfo, RecList& reclist);
    137140    void FillDirectoryInfoCache(bool force = false);
  • encoderlink.h

     
    6565    TVRec *GetTVRec(void) { return tv; }
    6666
    6767    /// \brief Tell a slave backend to go to sleep
    68     bool GoToSleep(void);
     68    int GoToSleep(void);
    6969    int LockTuner(void);
    7070    /// \brief Unlock the tuner.
    7171    /// \sa LockTuner(), IsTunerLocked()
  • playbacksock.cpp

     
    117117
    118118/** \brief Tells a slave to go to sleep
    119119 */
    120 bool PlaybackSock::GoToSleep(void)
     120int PlaybackSock::GoToSleep(void)
    121121{
    122122    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;
    125130}
    126131
    127132/**
  • mainserver.cpp

     
    25142514void MainServer::HandleGoToSleep(PlaybackSock *pbs)
    25152515{
    25162516    QStringList strlist;
     2517    QDateTime idleSince;
     2518    bool blockShutdown;
    25172519
    2518     QString sleepCmd = gContext->GetSetting("SleepCommand");
    2519     if (!sleepCmd.isEmpty())
     2520    if (Scheduler::CheckShutdownServer(0, idleSince,  blockShutdown))
    25202521    {
    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        }
    25262546    }
    25272547    else
    25282548    {
    2529         strlist << "ERROR: SleepCommand is empty";
    2530         VERBOSE(VB_IMPORTANT,
    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";
    25322552        SendResponse(pbs->getSocket(), strlist);
    25332553    }
    25342554}
  • 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())))
    2280             {
    2281                 if (pginfo->recstatus == rsWillRecord)
     2281                (!slavesInUse.contains(enc->GetHostName())) &&
     2282                (pginfo->recstatus == rsWillRecord)) {
    22822283                    VERBOSE(VB_SCHEDULE+VB_EXTRA, QString("    Slave %1 will "
    22832284                            "be in use in %2 minutes").arg(enc->GetHostName())
    22842285                            .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();
    22902287            }
    22912288        }
    22922289    }
    22932290
    2294     VERBOSE(VB_SCHEDULE+VB_EXTRA, "  Checking inuseprograms table:");
     2291    VERBOSE(VB_SCHEDULE+VB_EXTRA, "2  Checking inuseprograms table:");
    22952292    QDateTime oneHourAgo = QDateTime::currentDateTime().addSecs(-61 * 60);
    22962293    MSqlQuery query(MSqlQuery::InitCon());
    22972294    query.prepare("SELECT DISTINCT hostname, recusage FROM inuseprograms "
     
    23002297    if (query.exec() && query.size() > 0)
    23012298    {
    23022299        while(query.next()) {
    2303             SlavesInUse << query.value(0).toString();
     2300            slavesInUse << query.value(0).toString();
    23042301            VERBOSE(VB_SCHEDULE+VB_EXTRA, QString("    Slave %1 is marked as "
    23052302                    "in use by a %2")
    23062303                    .arg(query.value(0).toString())
     
    23082305        }
    23092306    }
    23102307
    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;
    23142309
    23152310    enciter = m_tvList->begin();
    23162311    for (; enciter != m_tvList->end(); ++enciter)
    23172312    {
    23182313        enc = *enciter;
     2314        QString slaveHost = enc->GetHostName();
    23192315
    23202316        if ((!enc->IsLocal()) &&
    23212317            (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)))
    23242322        {
    23252323            QString sleepCommand = gContext->GetSettingOnHost("SleepCommand",
    2326                 enc->GetHostName());
     2324                slaveHost);
    23272325            QString wakeUpCommand = gContext->GetSettingOnHost("WakeUpCommand",
    2328                 enc->GetHostName());
     2326                slaveHost);
    23292327
    2330             if (!sleepCommand.isEmpty() && !wakeUpCommand.isEmpty())
     2328            if (!sleepCommand.isEmpty() && !wakeUpCommand.isEmpty()
     2329                    && !slavesThatCanWake.contains(slaveHost))
    23312330            {
    2332                 QString thisHost = enc->GetHostName();
     2331                // avoid asking the same slave to go to sleep
     2332                slavesThatCanWake << slaveHost;
    23332333
    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)
    23382338                {
    23392339                    QMap<int, EncoderLink *>::Iterator slviter =
    23402340                        m_tvList->begin();
    23412341                    for (; slviter != m_tvList->end(); ++slviter)
    23422342                    {
    23432343                        EncoderLink *slv = *slviter;
    2344                         if (slv->GetHostName() == thisHost)
     2344                        if (slv->GetHostName() == slaveHost)
    23452345                        {
    23462346                            VERBOSE(VB_SCHEDULE+VB_EXTRA,
    23472347                                    QString("    Marking card %1 on slave %2 "
     
    23522352                        }
    23532353                    }
    23542354                }
    2355                 else
     2355                else if (goToSleep == -1)
    23562356                {
    23572357                    VERBOSE(VB_IMPORTANT, LOC_ERR + QString("Unable to "
    23582358                            "shutdown %1 slave backend, setting sleep "
    2359                             "status to undefined.").arg(thisHost));
     2359                            "status to undefined.").arg(slaveHost));
    23602360                    QMap<int, EncoderLink *>::Iterator slviter =
    23612361                        m_tvList->begin();
    23622362                    for (; slviter != m_tvList->end(); ++slviter)
    23632363                    {
    23642364                        EncoderLink *slv = *slviter;
    2365                         if (slv->GetHostName() == thisHost)
     2365                        if (slv->GetHostName() == slaveHost)
    23662366                            slv->SetSleepStatus(sStatus_Undefined);
    23672367                    }
    23682368                }
     
    24042404    for (; enciter != m_tvList->end(); ++enciter)
    24052405    {
    24062406        EncoderLink *enc = *enciter;
    2407         if (setWakingStatus && (enc->GetHostName() == slaveHostname))
     2407        if (setWakingStatus && (enc->GetHostName() == slaveHostname)) 
    24082408            enc->SetSleepStatus(sStatus_Waking);
     2409
    24092410        enc->SetLastWakeTime(curtime);
    24102411    }
    24112412
     2413    VERBOSE(VB_SCHEDULE, QString("Trying to Wake Up %1.").arg(slaveHostname));
     2414
    24122415    if (!IsMACAddress(wakeUpCommand))
    24132416    {
     2417        wakeUpCommand = wakeUpCommand.replace(QRegExp("%SLAVE%"), QString("%1")
     2418            .arg(slaveHostname));
    24142419        VERBOSE(VB_SCHEDULE, QString("Executing '%1' to wake up slave.")
    2415                 .arg(wakeUpCommand));
     2420            .arg(wakeUpCommand));
    24162421        myth_system(wakeUpCommand);
    24172422    }
    24182423    else
     
    24212426    return true;
    24222427}
    24232428
    2424 void Scheduler::WakeUpSlaves(void)
     2429bool Scheduler::WakeUpSlaves(bool forceWakeAll)
    24252430{
    2426     QStringList SlavesThatCanWake;
     2431    VERBOSE(VB_SCHEDULE, "Scheduler, Checking for slaves that can be wake up");
     2432    QStringList slavesThatCanWake;
    24272433    QString thisSlave;
     2434    bool slaveWaken = false;
    24282435    QMap<int, EncoderLink *>::Iterator enciter = m_tvList->begin();
    24292436    for (; enciter != m_tvList->end(); ++enciter)
    24302437    {
    24312438        EncoderLink *enc = *enciter;
    24322439
    2433         if (enc->IsLocal())
     2440        if ((!forceWakeAll && !enc->CanSleep()) || enc->IsAwake() || enc->IsLocal() || enc->IsWaking())
    24342441            continue;
    24352442
    24362443        thisSlave = enc->GetHostName();
    24372444
    24382445        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        }
    24422459    }
     2460    return slaveWaken;
     2461}
    24432462
    2444     int slave = 0;
    2445     for (; slave < SlavesThatCanWake.count(); slave++)
     2463QDateTime 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
     2472bool Scheduler::CheckDailyWakeUpPeriodSlaveAndEncoderStatus(QString slaveHostname, EncoderLink *enc)
     2473{
     2474   
     2475    QDateTime dtCurrent = QDateTime::currentDateTime();
     2476    if (Scheduler::CheckDailyWakeUpPeriodSlave(slaveHostname))
    24462477    {
    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            }
    24522494    }
     2495
     2496    return false;
     2497
    24532498}
     2499bool 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();
    24542506
     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
    24552549void *Scheduler::SchedulerThread(void *param)
    24562550{
    24572551    // Lower scheduling priority, to avoid problems with recordings.
  • encoderlink.cpp

     
    358358
    359359/** \brief Tell a slave to go to sleep
    360360 */
    361 bool EncoderLink::GoToSleep(void)
     361int EncoderLink::GoToSleep(void)
    362362{
    363363    if (IsLocal() || !sock)
    364         return false;
     364        return -1;
    365365
    366366    lastSleepTime = QDateTime::currentDateTime();
    367367