Ticket #10533: schedopt2.patch

File schedopt2.patch, 67.1 KB (added by gigem, 12 years ago)
  • mythtv/libs/libmyth/programinfo.cpp

    diff --git a/mythtv/libs/libmyth/programinfo.cpp b/mythtv/libs/libmyth/programinfo.cpp
    index 83e0d21..b6c24a1 100644
    a b void ProgramInfo::SaveDeletePendingFlag(bool deleteFlag) 
    26782678    MSqlQuery query(MSqlQuery::InitCon());
    26792679
    26802680    query.prepare("UPDATE recorded"
    2681                   " SET deletepending = :DELETEFLAG"
     2681                  " SET deletepending = :DELETEFLAG, "
     2682                  "     duplicate = 0 "
    26822683                  " WHERE chanid = :CHANID"
    26832684                  " AND starttime = :STARTTIME ;");
    26842685    query.bindValue(":CHANID", chanid);
  • mythtv/libs/libmythtv/eitscanner.cpp

    diff --git a/mythtv/libs/libmythtv/eitscanner.cpp b/mythtv/libs/libmythtv/eitscanner.cpp
    index 6135e08..cde2f69 100644
    a b void EITScanner::RescheduleRecordings(void) 
    177177        QDateTime::currentDateTime().addSecs(kMinRescheduleInterval);
    178178    resched_lock.unlock();
    179179
    180     ScheduledRecording::signalChange(-1);
     180    ScheduledRecording::RescheduleMatch(0, 0, 0, QDateTime(), "EITScanner");
    181181}
    182182
    183183/** \fn EITScanner::StartPassiveScan(ChannelBase*, EITSource*, bool)
  • mythtv/libs/libmythtv/recordinginfo.cpp

    diff --git a/mythtv/libs/libmythtv/recordinginfo.cpp b/mythtv/libs/libmythtv/recordinginfo.cpp
    index 73cc9ef..2c42e2d 100644
    a b void RecordingInfo::ReactivateRecording(void) 
    11551155    if (!result.exec())
    11561156        MythDB::DBError("ReactivateRecording", result);
    11571157
    1158     ScheduledRecording::signalChange(0);
     1158    ScheduledRecording::ReschedulePlace("Reactivate");
    11591159}
    11601160
    11611161/**
    void RecordingInfo::AddHistory(bool resched, bool forcedup, bool future) 
    12231223    // The adding of an entry to oldrecorded may affect near-future
    12241224    // scheduling decisions, so recalculate if told
    12251225    if (resched)
    1226         ScheduledRecording::signalChange(0);
     1226        ScheduledRecording::RescheduleCheck(*this, "AddHistory");
    12271227}
    12281228
    12291229/** \fn RecordingInfo::DeleteHistory(void)
    void RecordingInfo::DeleteHistory(void) 
    12571257
    12581258    // The removal of an entry from oldrecorded may affect near-future
    12591259    // scheduling decisions, so recalculate
    1260     ScheduledRecording::signalChange(0);
     1260    ScheduledRecording::RescheduleCheck(*this, "DeleteHistory");
    12611261}
    12621262
    12631263/** \fn RecordingInfo::ForgetHistory(void)
    void RecordingInfo::ForgetHistory(void) 
    13211321
    13221322    // The removal of an entry from oldrecorded may affect near-future
    13231323    // scheduling decisions, so recalculate
    1324     ScheduledRecording::signalChange(0);
     1324    ScheduledRecording::RescheduleCheck(*this, "ForgetHistory");
    13251325}
    13261326
    13271327/** \fn RecordingInfo::SetDupHistory(void)
    void RecordingInfo::SetDupHistory(void) 
    13471347    if (!result.exec())
    13481348        MythDB::DBError("setDupHistory", result);
    13491349
    1350     ScheduledRecording::signalChange(0);
     1350    ScheduledRecording::RescheduleCheck(*this, "SetHistory");
    13511351}
    13521352
    13531353/**
  • mythtv/libs/libmythtv/recordinginfo.h

    diff --git a/mythtv/libs/libmythtv/recordinginfo.h b/mythtv/libs/libmythtv/recordinginfo.h
    index 5ca56bf..4c8378a 100644
    a b class MTV_PUBLIC RecordingInfo : public ProgramInfo 
    228228    void ApplyTranscoderProfileChange(const QString &profile) const;//pi
    229229    void ApplyTranscoderProfileChangeById(int);
    230230
    231     static void signalChange(int recordid);
    232 
    233231    RecStatusType oldrecstatus;
    234232    RecStatusType savedrecstatus;
    235233    bool future;
  • mythtv/libs/libmythtv/recordingrule.cpp

    diff --git a/mythtv/libs/libmythtv/recordingrule.cpp b/mythtv/libs/libmythtv/recordingrule.cpp
    index f7a9981..907f92b 100644
    a b  
    88#include "mythcorecontext.h"
    99
    1010// libmythtv
    11 #include "scheduledrecording.h" // For signalChange()
     11#include "scheduledrecording.h" // For RescheduleMatch()
    1212#include "playgroup.h" // For GetInitialName()
    1313#include "recordingprofile.h" // For constants
    1414#include "mythmiscutil.h"
    bool RecordingRule::Save(bool sendSig) 
    380380        m_recordID = query.lastInsertId().toInt();
    381381
    382382    if (sendSig)
    383         ScheduledRecording::signalChange(m_recordID);
     383        ScheduledRecording::RescheduleMatch(m_recordID, 0, 0, QDateTime(),
     384            QString("SaveRule %1").arg(m_title));
    384385
    385386    return true;
    386387}
    bool RecordingRule::Delete(bool sendSig) 
    408409    }
    409410
    410411    if (sendSig)
    411         ScheduledRecording::signalChange(m_recordID);
     412        ScheduledRecording::RescheduleMatch(m_recordID, 0, 0, QDateTime(),
     413            QString("DeleteRule %1").arg(m_title));
    412414
    413415    // Set m_recordID to zero, the rule is no longer in the database so it's
    414416    // not valid. Should you want, this allows a rule to be removed from the
  • mythtv/libs/libmythtv/scheduledrecording.cpp

    diff --git a/mythtv/libs/libmythtv/scheduledrecording.cpp b/mythtv/libs/libmythtv/scheduledrecording.cpp
    index 4e162b2..0c0fa1c 100644
    a b ScheduledRecording::~ScheduledRecording() 
    99{
    1010}
    1111
    12 void ScheduledRecording::signalChange(int recordid)
     12void ScheduledRecording::SendReschedule(const QStringList &request)
    1313{
    1414    if (gCoreContext->IsBackend())
    1515    {
    16         MythEvent me(QString("RESCHEDULE_RECORDINGS %1").arg(recordid));
     16        MythEvent me(QString("RESCHEDULE_RECORDINGS"), request);
    1717        gCoreContext->dispatch(me);
    1818    }
    1919    else
    2020    {
    2121        QStringList slist;
    22         slist << QString("RESCHEDULE_RECORDINGS %1").arg(recordid);
     22        slist << QString("RESCHEDULE_RECORDINGS");
     23        slist << request;
    2324        if (!gCoreContext->SendReceiveStringList(slist))
    2425            LOG(VB_GENERAL, LOG_ERR,
    25                 QString("Error rescheduling id %1 in "
    26                         "ScheduledRecording::signalChange") .arg(recordid));
     26                QString("Error rescheduling %1 in "
     27                        "ScheduledRecording::SendReschedule").arg(request[0]));
    2728    }
    2829}
    2930
     31QStringList ScheduledRecording::BuildMatchRequest(uint recordid,
     32                uint sourceid, uint mplexid, const QDateTime &maxstarttime,
     33                const QString &why)
     34{
     35    return QStringList(QString("MATCH %1 %2 %3 %4 %5")
     36                       .arg(recordid).arg(sourceid).arg(mplexid)
     37                       .arg(maxstarttime.isValid() ?
     38                            maxstarttime.toString(Qt::ISODate) :
     39                            "-")
     40                       .arg(why));
     41};
     42
     43QStringList ScheduledRecording::BuildCheckRequest(const RecordingInfo &recinfo,
     44                                                  const QString &why)
     45{
     46    return QStringList(QString("CHECK %1 %2 %3 %4")
     47                       .arg(recinfo.GetRecordingStatus())
     48                       .arg(recinfo.GetParentRecordingRuleID() ?
     49                            recinfo.GetParentRecordingRuleID() :
     50                            recinfo.GetRecordingRuleID())
     51                       .arg(recinfo.GetFindID())
     52                       .arg(why))
     53        << recinfo.GetTitle()
     54        << recinfo.GetSubtitle()
     55        << recinfo.GetDescription()
     56        << recinfo.GetProgramID();
     57};
     58
     59QStringList ScheduledRecording::BuildPlaceRequest(const QString &why)
     60{
     61    return QStringList(QString("PLACE %1").arg(why));
     62};
     63
    3064/* vim: set expandtab tabstop=4 shiftwidth=4: */
  • mythtv/libs/libmythtv/scheduledrecording.h

    diff --git a/mythtv/libs/libmythtv/scheduledrecording.h b/mythtv/libs/libmythtv/scheduledrecording.h
    index 4a230fb..2f14d2e 100644
    a b  
    22#define SCHEDULEDRECORDING_H
    33
    44#include "mythtvexp.h"
     5#include "qdatetime.h"
     6#include "recordinginfo.h"
    57
    68class MTV_PUBLIC ScheduledRecording
    79{
     10    friend class Scheduler;
     11
    812  public:
     13    // Use when a recording rule or program data changes.  Use 0 for
     14    // recordid when all recordids are potentially affected, Use
     15    // invalid starttime and 0 for chanids when not time nor channel
     16    // specific.
     17    static void RescheduleMatch(uint recordid, uint sourceid, uint mplexid,
     18                             const QDateTime &maxstarttime, const QString &why)
     19        { SendReschedule(BuildMatchRequest(recordid, sourceid, mplexid,
     20                                           maxstarttime, why)); };
     21
     22    // Use when previous or current recorded duplicate status changes.
     23    static void RescheduleCheck(const RecordingInfo &recinfo,
     24                                const QString &why)
     25        { SendReschedule(BuildCheckRequest(recinfo, why)); };
     26
     27    // Use when none of recording rule, program data or duplicate
     28    // status changes.
     29    static void ReschedulePlace(const QString &why)
     30        { SendReschedule(BuildPlaceRequest(why)); };
     31
     32  private:
    933    ScheduledRecording();
    1034    ~ScheduledRecording();
    1135
    12     static void signalChange(int recordid);
    13     // Use -1 for recordid when all recordids are potentially
    14     // affected, such as when the program table is updated.
    15     // Use 0 for recordid when a reschdule isn't specific to a single
    16     // recordid, such as when a recording type priority is changed.
     36    static void SendReschedule(const QStringList &request);
     37    static QStringList BuildMatchRequest(uint recordid, uint sourceid,
     38              uint mplexid, const QDateTime &maxstarttime, const QString &why);
     39    static QStringList BuildCheckRequest(const RecordingInfo &recinfo,
     40                                         const QString &why);
     41    static QStringList BuildPlaceRequest(const QString &why);
    1742};
    1843
    1944#endif
  • mythtv/libs/libmythtv/tv_rec.cpp

    diff --git a/mythtv/libs/libmythtv/tv_rec.cpp b/mythtv/libs/libmythtv/tv_rec.cpp
    index bf15151..1e88080 100644
    a b void TVRec::NotifySchedulerOfRecording(RecordingInfo *rec) 
    26682668    rec->AddHistory(false);
    26692669
    26702670    // + save RecordingRule so that we get a recordid
    2671     //   (don't allow signalChange(), avoiding unneeded reschedule)
     2671    //   (don't allow RescheduleMatch(), avoiding unneeded reschedule)
    26722672    rec->GetRecordingRule()->Save(false);
    26732673
    26742674    // + save recordid to recorded entry
  • mythtv/programs/mythbackend/main_helpers.cpp

    diff --git a/mythtv/programs/mythbackend/main_helpers.cpp b/mythtv/programs/mythbackend/main_helpers.cpp
    index 5017af4..9bcac95 100644
    a b int handle_command(const MythBackendCommandLineParser &cmdline) 
    381381        if (gCoreContext->ConnectToMasterServer())
    382382        {
    383383            LOG(VB_GENERAL, LOG_INFO, "Connected to master for reschedule");
    384             ScheduledRecording::signalChange(-1);
     384            ScheduledRecording::RescheduleMatch(0, 0, 0, QDateTime(),
     385                                                "MythBackendCommand");
    385386            ok = true;
    386387        }
    387388        else
  • mythtv/programs/mythbackend/mainserver.cpp

    diff --git a/mythtv/programs/mythbackend/mainserver.cpp b/mythtv/programs/mythbackend/mainserver.cpp
    index ff002b4..802232c 100644
    a b void MainServer::ProcessRequestWork(MythSocket *sock) 
    525525    }
    526526    else if (command == "RESCHEDULE_RECORDINGS")
    527527    {
    528         if (tokens.size() != 2)
    529             LOG(VB_GENERAL, LOG_ERR, "Bad RESCHEDULE_RECORDINGS request");
    530         else
    531             HandleRescheduleRecordings(tokens[1].toInt(), pbs);
     528        listline.pop_front();
     529        HandleRescheduleRecordings(listline, pbs);
    532530    }
    533531    else if (command == "FORGET_RECORDING")
    534532    {
    void MainServer::customEvent(QEvent *e) 
    10071005
    10081006        if (me->Message().left(21) == "RESCHEDULE_RECORDINGS" && m_sched)
    10091007        {
    1010             QStringList tokens = me->Message()
    1011                 .split(" ", QString::SkipEmptyParts);
    1012 
    1013             if (tokens.size() != 2)
    1014             {
    1015                 LOG(VB_GENERAL, LOG_ERR, "Bad RESCHEDULE_RECORDINGS message");
    1016                 return;
    1017             }
    1018 
    1019             int recordid = tokens[1].toInt();
    1020             m_sched->Reschedule(recordid);
     1008            QStringList request = me->ExtraDataList();
     1009            m_sched->Reschedule(request);
    10211010            return;
    10221011        }
    10231012
    void MainServer::HandleAnnounce(QStringList &slist, QStringList commands, 
    14441433        }
    14451434
    14461435        if (!wasAsleep && m_sched)
    1447             m_sched->Reschedule(0);
     1436            m_sched->ReschedulePlace("SlaveConnected");
    14481437
    14491438        QString message = QString("LOCAL_SLAVE_BACKEND_ONLINE %2")
    14501439                                  .arg(commands[2]);
    void MainServer::DoDeleteThread(DeleteStruct *ds) 
    20011990
    20021991    DoDeleteInDB(ds);
    20031992
    2004     if (pginfo.GetRecordingGroup() != "LiveTV")
    2005         ScheduledRecording::signalChange(0);
    2006 
    20071993    deletelock.unlock();
    20081994
    20091995    if (slowDeletes && fd >= 0)
    void MainServer::DoHandleDeleteRecording( 
    25132499        if (forgetHistory)
    25142500            recinfo.ForgetHistory();
    25152501        else if (m_sched)
    2516             m_sched->Reschedule(0);
     2502            m_sched->RescheduleCheck(recinfo, "DoHandleDelete1");
    25172503        QStringList outputlist( QString::number(0) );
    25182504        SendResponse(pbssock, outputlist);
    25192505        return;
    void MainServer::DoHandleDeleteRecording( 
    25342520            else if (m_sched &&
    25352521                     recinfo.GetRecordingGroup() != "Deleted" &&
    25362522                     recinfo.GetRecordingGroup() != "LiveTV")
    2537                 m_sched->Reschedule(0);
     2523                m_sched->RescheduleCheck(recinfo, "DoHandleDelete2");
    25382524
    25392525            if (pbssock)
    25402526            {
    void MainServer::DoHandleDeleteRecording( 
    25942580    else if (m_sched &&
    25952581             recinfo.GetRecordingGroup() != "Deleted" &&
    25962582             recinfo.GetRecordingGroup() != "LiveTV")
    2597         m_sched->Reschedule(0);
     2583        m_sched->RescheduleCheck(recinfo, "DoHandleDelete3");
    25982584
    25992585    // Tell MythTV frontends that the recording list needs to be updated.
    26002586    if (fileExists || !recinfo.GetFilesize() || forceMetadataDelete)
    void MainServer::DoHandleUndeleteRecording( 
    26512637    SendResponse(pbssock, outputlist);
    26522638}
    26532639
    2654 void MainServer::HandleRescheduleRecordings(int recordid, PlaybackSock *pbs)
     2640void MainServer::HandleRescheduleRecordings(const QStringList &request,
     2641                                            PlaybackSock *pbs)
    26552642{
    26562643    QStringList result;
    26572644    if (m_sched)
    26582645    {
    2659         m_sched->Reschedule(recordid);
     2646        m_sched->Reschedule(request);
    26602647        result = QStringList( QString::number(1) );
    26612648    }
    26622649    else
    void MainServer::HandleGetPendingRecordings(PlaybackSock *pbs, 
    31513138                    record->m_recordID = recordid;
    31523139                    if (record->Load() &&
    31533140                        record->m_searchType == kManualSearch)
    3154                         HandleRescheduleRecordings(recordid, NULL);
     3141                        m_sched->RescheduleMatch(recordid, 0, 0, QDateTime(),
     3142                                                 "Speculation");
    31553143                    delete record;
    31563144                }
    31573145                query.prepare("DELETE FROM program WHERE manualid = :RECID;");
    void MainServer::HandleLockTuner(PlaybackSock *pbs, int cardid) 
    34133401                        << query.value(2).toString();
    34143402
    34153403                if (m_sched)
    3416                     m_sched->Reschedule(0);
     3404                    m_sched->ReschedulePlace("LockTuner");
    34173405
    34183406                SendResponse(pbssock, strlist);
    34193407                return;
    void MainServer::HandleFreeTuner(int cardid, PlaybackSock *pbs) 
    34593447        LOG(VB_GENERAL, LOG_INFO, msg);
    34603448
    34613449        if (m_sched)
    3462             m_sched->Reschedule(0);
     3450            m_sched->ReschedulePlace("FreeTuner");
    34633451
    34643452        strlist << "OK";
    34653453    }
    void MainServer::HandleSlaveDisconnectedEvent(const MythEvent &event) 
    62246212            m_sched->SlaveDisconnected(event.ExtraData(i).toUInt());
    62256213
    62266214        if (needsReschedule)
    6227             m_sched->Reschedule(0);
     6215            m_sched->ReschedulePlace("SlaveDisconnected");
    62286216    }
    62296217}
    62306218
  • mythtv/programs/mythbackend/mainserver.h

    diff --git a/mythtv/programs/mythbackend/mainserver.h b/mythtv/programs/mythbackend/mainserver.h
    index 0349f8e..e27c9ae 100644
    a b class MainServer : public QObject, public MythSocketCBs 
    163163    void HandleUndeleteRecording(QStringList &slist, PlaybackSock *pbs);
    164164    void DoHandleUndeleteRecording(RecordingInfo &recinfo, PlaybackSock *pbs);
    165165    void HandleForgetRecording(QStringList &slist, PlaybackSock *pbs);
    166     void HandleRescheduleRecordings(int recordid, PlaybackSock *pbs);
     166    void HandleRescheduleRecordings(const QStringList &request,
     167                                    PlaybackSock *pbs);
    167168    void HandleGoToSleep(PlaybackSock *pbs);
    168169    void HandleQueryFreeSpace(PlaybackSock *pbs, bool allBackends);
    169170    void HandleQueryFreeSpaceSummary(PlaybackSock *pbs);
  • mythtv/programs/mythbackend/scheduler.cpp

    diff --git a/mythtv/programs/mythbackend/scheduler.cpp b/mythtv/programs/mythbackend/scheduler.cpp
    index 23db70c..469570d 100644
    a b bool Scheduler::FillRecordList(void) 
    400400
    401401/** \fn Scheduler::FillRecordListFromDB(int)
    402402 *  \param recordid Record ID of recording that has changed,
    403  *                  or -1 if anything might have been changed.
     403 *                  or 0 if anything might have been changed.
    404404 */
    405 void Scheduler::FillRecordListFromDB(int recordid)
     405void Scheduler::FillRecordListFromDB(uint recordid)
    406406{
    407407    struct timeval fillstart, fillend;
    408     float matchTime, placeTime;
     408    float matchTime, checkTime, placeTime;
    409409
    410410    MSqlQuery query(dbConn);
    411411    QString thequery;
    412412    QString where = "";
    413413
    414414    // This will cause our temp copy of recordmatch to be empty
    415     if (recordid == -1)
     415    if (recordid == 0)
    416416        where = "WHERE recordid IS NULL ";
    417417
    418418    thequery = QString("CREATE TEMPORARY TABLE recordmatch ") +
    void Scheduler::FillRecordListFromDB(int recordid) 
    449449    QMutexLocker locker(&schedLock);
    450450
    451451    gettimeofday(&fillstart, NULL);
    452     UpdateMatches(recordid);
     452    UpdateMatches(recordid, 0, 0, QDateTime());
    453453    gettimeofday(&fillend, NULL);
    454454    matchTime = ((fillend.tv_sec - fillstart.tv_sec ) * 1000000 +
    455455                 (fillend.tv_usec - fillstart.tv_usec)) / 1000000.0;
    456456
     457    CreateTempTables();
     458
     459    gettimeofday(&fillstart, NULL);
     460    UpdateDuplicates();
     461    gettimeofday(&fillend, NULL);
     462    checkTime = ((fillend.tv_sec - fillstart.tv_sec ) * 1000000 +
     463                 (fillend.tv_usec - fillstart.tv_usec)) / 1000000.0;
     464
    457465    gettimeofday(&fillstart, NULL);
    458466    FillRecordList();
    459467    gettimeofday(&fillend, NULL);
    460468    placeTime = ((fillend.tv_sec - fillstart.tv_sec ) * 1000000 +
    461469                 (fillend.tv_usec - fillstart.tv_usec)) / 1000000.0;
    462470
     471    DeleteTempTables();
     472
    463473    MSqlQuery queryDrop(dbConn);
    464474    queryDrop.prepare("DROP TABLE recordmatch;");
    465475    if (!queryDrop.exec())
    void Scheduler::FillRecordListFromDB(int recordid) 
    469479    }
    470480
    471481    QString msg;
    472     msg.sprintf("Speculative scheduled %d items in "
    473                 "%.1f = %.2f match + %.2f place", (int)reclist.size(),
    474                 matchTime + placeTime, matchTime, placeTime);
     482    msg.sprintf("Speculative scheduled %d items in %.1f "
     483                "= %.2f match + %.2f check + %.2f place",
     484                (int)reclist.size(),
     485                matchTime + checkTime + placeTime,
     486                matchTime, checkTime, placeTime);
    475487    LOG(VB_GENERAL, LOG_INFO, msg);
    476488}
    477489
    void Scheduler::UpdateRecStatus(RecordingInfo *pginfo) 
    593605                p->AddHistory(false);
    594606                if (resched)
    595607                {
    596                     reschedQueue.enqueue(0);
     608                    EnqueueCheck(*p, "UpdateRecStatus1");
    597609                    reschedWait.wakeOne();
    598610                }
    599611                else
    void Scheduler::UpdateRecStatus(uint cardid, uint chanid, 
    643655                p->AddHistory(false);
    644656                if (resched)
    645657                {
    646                     reschedQueue.enqueue(0);
     658                    EnqueueCheck(*p, "UpdateRecStatus2");
    647659                    reschedWait.wakeOne();
    648660                }
    649661                else
    bool Scheduler::ChangeRecordingEnd(RecordingInfo *oldp, RecordingInfo *newp) 
    665677        return false;
    666678
    667679    RecordingType oldrectype = oldp->GetRecordingRuleType();
    668     int oldrecordid = oldp->GetRecordingRuleID();
     680    uint oldrecordid = oldp->GetRecordingRuleID();
    669681    QDateTime oldrecendts = oldp->GetRecordingEndTime();
    670682
    671683    oldp->SetRecordingRuleType(newp->GetRecordingRuleType());
    void Scheduler::GetAllScheduled(QStringList &strList) 
    16131625    }
    16141626}
    16151627
    1616 void Scheduler::Reschedule(int recordid)
     1628void Scheduler::Reschedule(const QStringList &request)
    16171629{
    16181630    QMutexLocker locker(&schedLock);
    1619 
    1620     if (recordid == -1)
    1621         reschedQueue.clear();
    1622 
    1623     if (recordid != 0 || reschedQueue.empty())
    1624         reschedQueue.enqueue(recordid);
    1625 
     1631    reschedQueue.enqueue(request);
    16261632    reschedWait.wakeOne();
    16271633}
    16281634
    void Scheduler::AddRecording(const RecordingInfo &pi) 
    16611667    new_pi->GetRecordingRule();
    16621668
    16631669    // Trigger reschedule..
    1664     reschedQueue.enqueue(pi.GetRecordingRuleID());
     1670    EnqueueMatch(pi.GetRecordingRuleID(), 0, 0, QDateTime(),
     1671                 QString("AddRecording %1").arg(pi.GetTitle()));
    16651672    reschedWait.wakeOne();
    16661673}
    16671674
    void Scheduler::OldRecordedFixups(void) 
    17431750    // during normal processing.
    17441751    query.prepare("UPDATE oldrecorded SET future = 0 "
    17451752                  "WHERE future > 0 AND "
    1746                   "      endtime < (NOW() - INTERVAL 8 HOUR)");
     1753                  "      endtime < (NOW() - INTERVAL 475 MINUTE)");
    17471754    if (!query.exec())
    17481755        MythDB::DBError("UpdateFuture", query);
    17491756}
    void Scheduler::run(void) 
    17681775    QMutexLocker lockit(&schedLock);
    17691776
    17701777    reschedQueue.clear();
    1771     reschedQueue.enqueue(-1);
     1778    EnqueueMatch(0, 0, 0, QDateTime(), "SchedulerInit");
    17721779
    17731780    int       prerollseconds  = 0;
    17741781    int       wakeThreshold   = 300;
    int Scheduler::CalcTimeToNextHandleRecordingEvent( 
    19921999    return min(msecs, max_sleep);
    19932000}
    19942001
     2002void Scheduler::ResetDuplicates(uint recordid, uint findid,
     2003                                const QString &title, const QString &subtitle,
     2004                                const QString &descrip,
     2005                                const QString &programid)
     2006{
     2007    MSqlQuery query(dbConn);
     2008    QString filterClause;
     2009    MSqlBindings bindings;
     2010
     2011    // "**any**" is special value set in ProgLister::DeleteOldSeries()
     2012    if (programid != "**any**")
     2013    {
     2014        filterClause = "AND (0 ";
     2015        if (!subtitle.isEmpty())
     2016        {
     2017            // Need to check both for kDupCheckSubThenDesc
     2018            filterClause += "OR p.subtitle = :SUBTITLE "
     2019                            "OR p.description = :SUBTITLE ";
     2020            bindings[":SUBTITLE"] = subtitle;
     2021        }
     2022        if (!descrip.isEmpty())
     2023        {
     2024            // Need to check both for kDupCheckSubThenDesc
     2025            filterClause += "OR p.description = :DESCRIP "
     2026                            "OR p.subtitle = :DESCRIP ";
     2027            bindings[":DESCRIP"] = descrip;
     2028        }
     2029        if (!programid.isEmpty())
     2030        {
     2031            filterClause += "OR p.programid = :PROGRAMID ";
     2032            bindings[":PROGRAMID"] = programid;
     2033        }
     2034        filterClause += ") ";
     2035    }
     2036
     2037    query.prepare(QString("UPDATE recordmatch rm "
     2038                          "INNER JOIN %1 r "
     2039                          "      ON rm.recordid = r.recordid "
     2040                          "INNER JOIN program p "
     2041                          "      ON rm.chanid = p.chanid "
     2042                          "         AND rm.starttime = p.starttime "
     2043                          "         AND rm.manualid = p.manualid "
     2044                          "SET oldrecduplicate = -1 "
     2045                          "WHERE p.title = :TITLE"
     2046                          "      AND p.generic = 0 "
     2047                          "      AND r.type NOT IN (%2, %3, %4) ")
     2048                  .arg(recordTable)
     2049                  .arg(kSingleRecord)
     2050                  .arg(kOverrideRecord)
     2051                  .arg(kDontRecord)
     2052                  + filterClause);
     2053    query.bindValue(":TITLE", title);
     2054    MSqlBindings::const_iterator it;
     2055    for (it = bindings.begin(); it != bindings.end(); ++it)
     2056        query.bindValue(it.key(), it.value());
     2057    if (!query.exec())
     2058        MythDB::DBError("ResetDuplicates1", query);
     2059
     2060    if (findid && programid != "**any**")
     2061    {
     2062        query.prepare("UPDATE recordmatch rm "
     2063                      "SET oldrecduplicate = -1 "
     2064                      "WHERE rm.recordid = :RECORDID "
     2065                      "      AND rm.findid = :FINDID");
     2066        query.bindValue("RECORDID", recordid);
     2067        query.bindValue("FINDID", findid);
     2068        if (!query.exec())
     2069            MythDB::DBError("ResetDuplicates2", query);
     2070    }
     2071 }
     2072
    19952073bool Scheduler::HandleReschedule(void)
    19962074{
    19972075    // We might have been inactive for a long time, so make
    19982076    // sure our DB connection is fresh before continuing.
    19992077    dbConn = MSqlQuery::SchedCon();
    20002078
    2001     struct timeval fillstart;
     2079    struct timeval fillstart, fillend;
     2080    float matchTime, checkTime, placeTime;
     2081
    20022082    gettimeofday(&fillstart, NULL);
    20032083    QString msg;
    20042084    bool deleteFuture = false;
     2085    bool runCheck = false;
    20052086
    20062087    while (!reschedQueue.empty())
    20072088    {
    2008         int recordid = reschedQueue.dequeue();
     2089        QStringList request = reschedQueue.dequeue();
     2090        QStringList tokens;
     2091        if (request.size() >= 1)
     2092            tokens = request[0].split(' ', QString::SkipEmptyParts);
    20092093
    2010         LOG(VB_GENERAL, LOG_INFO, QString("Reschedule requested for id %1.")
    2011                 .arg(recordid));
     2094        if (request.size() < 1 || tokens.size() < 1)
     2095        {
     2096            LOG(VB_GENERAL, LOG_ERR, "Empty Reschedule request received");
     2097            return false;
     2098        }
    20122099
    2013         if (recordid != 0)
     2100        LOG(VB_GENERAL, LOG_INFO, QString("Reschedule requested for %1 %2")
     2101            .arg(request[0]).arg((request.size() > 1) ? request[1] : ""));
     2102
     2103        if (tokens[0] == "MATCH")
    20142104        {
    2015             if (recordid == -1)
    2016                 reschedQueue.clear();
     2105            if (tokens.size() < 5)
     2106            {
     2107                LOG(VB_GENERAL, LOG_ERR,
     2108                    QString("Invalid RescheduleMatch request received (%1)")
     2109                    .arg(request[0]));
     2110                continue;
     2111            }
    20172112
     2113            uint recordid = tokens[1].toUInt();
     2114            uint sourceid = tokens[2].toUInt();
     2115            uint mplexid = tokens[3].toUInt();
     2116            QDateTime maxstarttime =
     2117                QDateTime::fromString(tokens[4], Qt::ISODate);
    20182118            deleteFuture = true;
     2119            runCheck = true;
    20192120            schedLock.unlock();
    20202121            recordmatchLock.lock();
    2021             UpdateMatches(recordid);
     2122            UpdateMatches(recordid, sourceid, mplexid, maxstarttime);
    20222123            recordmatchLock.unlock();
    20232124            schedLock.lock();
    20242125        }
     2126        else if (tokens[0] == "CHECK")
     2127        {
     2128            if (tokens.size() < 4 || request.size() < 5)
     2129            {
     2130                LOG(VB_GENERAL, LOG_ERR,
     2131                    QString("Invalid RescheduleCheck request received (%1)")
     2132                    .arg(request[0]));
     2133                continue;
     2134            }
     2135
     2136            uint recordid = tokens[2].toUInt();
     2137            uint findid = tokens[3].toUInt();
     2138            QString title = request[1];
     2139            QString subtitle = request[2];
     2140            QString descrip = request[3];
     2141            QString programid = request[4];
     2142            runCheck = true;
     2143            schedLock.unlock();
     2144            recordmatchLock.lock();
     2145            ResetDuplicates(recordid, findid, title, subtitle, descrip,
     2146                            programid);
     2147            recordmatchLock.unlock();
     2148            schedLock.lock();
     2149        }
     2150        else if (tokens[0] != "PLACE")
     2151        {
     2152            LOG(VB_GENERAL, LOG_ERR,
     2153                QString("Unknown Reschedule request received (%1)")
     2154                .arg(request[0]));
     2155        }
    20252156    }
    20262157
    20272158    // Delete future oldrecorded entries that no longer
    bool Scheduler::HandleReschedule(void) 
    20392170            MythDB::DBError("DeleteFuture", query);
    20402171    }
    20412172
    2042     struct timeval fillend;
    20432173    gettimeofday(&fillend, NULL);
     2174    matchTime = ((fillend.tv_sec - fillstart.tv_sec ) * 1000000 +
     2175                 (fillend.tv_usec - fillstart.tv_usec)) / 1000000.0;
     2176
     2177    CreateTempTables();
    20442178
    2045     float matchTime = ((fillend.tv_sec - fillstart.tv_sec ) * 1000000 +
    2046                        (fillend.tv_usec - fillstart.tv_usec)) / 1000000.0;
     2179    gettimeofday(&fillstart, NULL);
     2180    if (runCheck)
     2181        UpdateDuplicates();
     2182    gettimeofday(&fillend, NULL);
     2183    checkTime = ((fillend.tv_sec - fillstart.tv_sec ) * 1000000 +
     2184                 (fillend.tv_usec - fillstart.tv_usec)) / 1000000.0;
    20472185
    20482186    gettimeofday(&fillstart, NULL);
    20492187    bool worklistused = FillRecordList();
    20502188    gettimeofday(&fillend, NULL);
     2189    placeTime = ((fillend.tv_sec - fillstart.tv_sec ) * 1000000 +
     2190                 (fillend.tv_usec - fillstart.tv_usec)) / 1000000.0;
     2191
     2192    DeleteTempTables();
     2193
    20512194    if (worklistused)
    20522195    {
    20532196        UpdateNextRecord();
    bool Scheduler::HandleReschedule(void) 
    20562199    else
    20572200    {
    20582201        LOG(VB_GENERAL, LOG_INFO, "Reschedule interrupted, will retry");
    2059         reschedQueue.enqueue(0);
     2202        EnqueuePlace("Interrupted");
    20602203        return false;
    20612204    }
    20622205
    2063     float placeTime = ((fillend.tv_sec - fillstart.tv_sec ) * 1000000 +
    2064                        (fillend.tv_usec - fillstart.tv_usec)) / 1000000.0;
    2065 
    2066     msg.sprintf("Scheduled %d items in %.1f = %.2f match + %.2f place",
    2067                 (int)reclist.size(), matchTime + placeTime, matchTime,
    2068                 placeTime);
     2206    msg.sprintf("Scheduled %d items in %.1f "
     2207                "= %.2f match + %.2f check + %.2f place",
     2208                (int)reclist.size(), matchTime + checkTime + placeTime,
     2209                matchTime, checkTime, placeTime);
    20692210    LOG(VB_GENERAL, LOG_INFO, msg);
    20702211
    20712212    fsInfoCacheFillTime = QDateTime::currentDateTime().addSecs(-1000);
    void Scheduler::HandleWakeSlave(RecordingInfo &ri, int prerollseconds) 
    22162357                .arg(nexttv->GetHostName()).arg(ri.GetTitle()));
    22172358
    22182359        if (!WakeUpSlave(nexttv->GetHostName()))
    2219             reschedQueue.enqueue(0);
     2360            EnqueuePlace("HandleWakeSlave1");
    22202361    }
    22212362    else if ((nexttv->IsWaking()) &&
    22222363             ((secsleft - prerollseconds) < 210) &&
    void Scheduler::HandleWakeSlave(RecordingInfo &ri, int prerollseconds) 
    22292370                .arg(nexttv->GetHostName()));
    22302371
    22312372        if (!WakeUpSlave(nexttv->GetHostName(), false))
    2232             reschedQueue.enqueue(0);
     2373            EnqueuePlace("HandleWakeSlave2");
    22332374    }
    22342375    else if ((nexttv->IsWaking()) &&
    22352376             ((secsleft - prerollseconds) < 150) &&
    void Scheduler::HandleWakeSlave(RecordingInfo &ri, int prerollseconds) 
    22492390                (*it)->SetSleepStatus(sStatus_Undefined);
    22502391        }
    22512392
    2252         reschedQueue.enqueue(0);
     2393        EnqueuePlace("HandleWakeSlave3");
    22532394    }
    22542395}
    22552396
    bool Scheduler::HandleRecording( 
    22872428            livetvTime = (livetvTime < nextrectime) ?
    22882429                nextrectime : livetvTime;
    22892430
    2290             reschedQueue.enqueue(0);
     2431            EnqueuePlace("PrepareToRecord");
    22912432        }
    22922433    }
    22932434
    bool Scheduler::HandleRecording( 
    23702511                    enc->SetSleepStatus(sStatus_Undefined);
    23712512            }
    23722513
    2373             reschedQueue.enqueue(0);
     2514            EnqueuePlace("SlaveNotAwake");
    23742515        }
    23752516
    23762517        return false;
    void Scheduler::WakeUpSlaves(void) 
    30293170    }
    30303171}
    30313172
    3032 void Scheduler::UpdateManuals(int recordid)
     3173void Scheduler::UpdateManuals(uint recordid)
    30333174{
    30343175    MSqlQuery query(dbConn);
    30353176
    void Scheduler::UpdateManuals(int recordid) 
    31083249            if (weekday && startdt.date().dayOfWeek() >= 6)
    31093250                continue;
    31103251
    3111             query.prepare("REPLACE INTO program (chanid,starttime,endtime,"
    3112                           " title,subtitle,manualid) "
    3113                           "VALUES (:CHANID,:STARTTIME,:ENDTIME,:TITLE,"
    3114                           " :SUBTITLE,:RECORDID)");
     3252            query.prepare("REPLACE INTO program (chanid, starttime, endtime,"
     3253                          " title, subtitle, manualid, generic) "
     3254                          "VALUES (:CHANID, :STARTTIME, :ENDTIME, :TITLE,"
     3255                          " :SUBTITLE, :RECORDID, 1)");
    31153256            query.bindValue(":CHANID", chanidlist[i]);
    31163257            query.bindValue(":STARTTIME", startdt);
    31173258            query.bindValue(":ENDTIME", startdt.addSecs(duration * 60));
    void Scheduler::UpdateManuals(int recordid) 
    31283269    }
    31293270}
    31303271
    3131 void Scheduler::BuildNewRecordsQueries(int recordid, QStringList &from,
     3272void Scheduler::BuildNewRecordsQueries(uint recordid, QStringList &from,
    31323273                                       QStringList &where,
    31333274                                       MSqlBindings &bindings)
    31343275{
    void Scheduler::BuildNewRecordsQueries(int recordid, QStringList &from, 
    31383279
    31393280    query = QString("SELECT recordid,search,subtitle,description "
    31403281                    "FROM %1 WHERE search <> %2 AND "
    3141                     "(recordid = %3 OR %4 = -1) ")
     3282                    "(recordid = %3 OR %4 = 0) ")
    31423283        .arg(recordTable).arg(kNoSearch).arg(recordid).arg(recordid);
    31433284
    31443285    result.prepare(query);
    void Scheduler::BuildNewRecordsQueries(int recordid, QStringList &from, 
    32313372        count++;
    32323373    }
    32333374
    3234     if (recordid == -1 || from.count() == 0)
     3375    if (recordid == 0 || from.count() == 0)
    32353376    {
    32363377        QString recidmatch = "";
    3237         if (recordid != -1)
     3378        if (recordid != 0)
    32383379            recidmatch = "RECTABLE.recordid = :NRRECORDID AND ";
    32393380        QString s1 = recidmatch +
    32403381            "RECTABLE.search = :NRST AND "
    void Scheduler::BuildNewRecordsQueries(int recordid, QStringList &from, 
    32533394        from << "";
    32543395        where << s2;
    32553396        bindings[":NRST"] = kNoSearch;
    3256         if (recordid != -1)
     3397        if (recordid != 0)
    32573398            bindings[":NRRECORDID"] = recordid;
    32583399    }
    32593400}
    32603401
    3261 void Scheduler::UpdateMatches(int recordid) {
    3262     struct timeval dbstart, dbend;
     3402static QString progdupinit = QString(
     3403"(CASE "
     3404"  WHEN RECTABLE.type IN (%1, %2, %3) THEN  0 "
     3405"  WHEN RECTABLE.type IN (%4, %5, %6) THEN  -1 "
     3406"  ELSE (program.generic - 1) "
     3407" END) ")
     3408    .arg(kSingleRecord).arg(kOverrideRecord).arg(kDontRecord)
     3409    .arg(kFindOneRecord).arg(kFindDailyRecord).arg(kFindWeeklyRecord);
    32633410
    3264     if (recordid == 0)
    3265         return;
     3411static QString progfindid = QString(
     3412"(CASE RECTABLE.type "
     3413"  WHEN %1 "
     3414"   THEN RECTABLE.findid "
     3415"  WHEN %2 "
     3416"   THEN to_days(date_sub(program.starttime, interval "
     3417"                time_format(RECTABLE.findtime, '%H:%i') hour_minute)) "
     3418"  WHEN %3 "
     3419"   THEN floor((to_days(date_sub(program.starttime, interval "
     3420"               time_format(RECTABLE.findtime, '%H:%i') hour_minute)) - "
     3421"               RECTABLE.findday)/7) * 7 + RECTABLE.findday "
     3422"  WHEN %4 "
     3423"   THEN RECTABLE.findid "
     3424"  ELSE 0 "
     3425" END) ")
     3426        .arg(kFindOneRecord)
     3427        .arg(kFindDailyRecord)
     3428        .arg(kFindWeeklyRecord)
     3429        .arg(kOverrideRecord);
     3430
     3431void Scheduler::UpdateMatches(uint recordid, uint sourceid, uint mplexid,
     3432                              const QDateTime maxstarttime) {
     3433    struct timeval dbstart, dbend;
    32663434
    32673435    MSqlQuery query(dbConn);
     3436    MSqlBindings bindings;
     3437    QString deleteClause;
     3438    QString filterClause = QString(" AND program.endtime > "
     3439                                   "(NOW() - INTERVAL 480 MINUTE)");
    32683440
    3269     if (recordid == -1)
    3270         query.prepare("DELETE FROM recordmatch");
    3271     else
     3441    if (recordid)
    32723442    {
    3273         query.prepare("DELETE FROM recordmatch WHERE recordid = :RECORDID");
    3274         query.bindValue(":RECORDID", recordid);
     3443        deleteClause += " AND recordmatch.recordid = :RECORDID";
     3444        bindings[":RECORDID"] = recordid;
    32753445    }
    3276 
    3277     if (!query.exec())
     3446    if (sourceid)
    32783447    {
    3279         MythDB::DBError("UpdateMatches", query);
    3280         return;
     3448        deleteClause += " AND channel.sourceid = :SOURCEID";
     3449        filterClause += " AND channel.sourceid = :SOURCEID";
     3450        bindings[":SOURCEID"] = sourceid;
    32813451    }
    3282 
    3283     if (recordid == -1)
    3284         query.prepare("DELETE FROM program WHERE manualid <> 0");
    3285     else
     3452    if (mplexid)
    32863453    {
    3287         query.prepare("DELETE FROM program WHERE manualid = :RECORDID");
    3288         query.bindValue(":RECORDID", recordid);
     3454        deleteClause += " AND channel.mplexid = :MPLEXID";
     3455        filterClause += " AND channel.mplexid = :MPLEXID";
     3456        bindings[":MPLEXID"] = mplexid;
    32893457    }
     3458    if (maxstarttime.isValid())
     3459    {
     3460        deleteClause += " AND recordmatch.starttime <= :MAXSTARTTIME";
     3461        filterClause += " AND program.starttime <= :MAXSTARTTIME";
     3462        bindings[":MAXSTARTTIME"] = maxstarttime;
     3463    }
     3464
     3465    query.prepare(QString("DELETE recordmatch FROM recordmatch, channel "
     3466                          "WHERE recordmatch.chanid = channel.chanid")
     3467                  + deleteClause);
     3468    MSqlBindings::const_iterator it;
     3469    for (it = bindings.begin(); it != bindings.end(); ++it)
     3470        query.bindValue(it.key(), it.value());
    32903471    if (!query.exec())
    32913472    {
    3292         MythDB::DBError("UpdateMatches", query);
     3473        MythDB::DBError("UpdateMatches1", query);
    32933474        return;
    32943475    }
     3476    if (recordid)
     3477        bindings.remove(":RECORDID");
    32953478
    3296     QString filterClause;
    32973479    query.prepare("SELECT filterid, clause FROM recordfilter "
    32983480                  "WHERE filterid >= 0 AND filterid < :NUMFILTERS AND "
    32993481                  "      TRIM(clause) <> ''");
    33003482    query.bindValue(":NUMFILTERS", RecordingRule::kNumFilters);
    33013483    if (!query.exec())
    33023484    {
    3303         MythDB::DBError("UpdateMatches", query);
     3485        MythDB::DBError("UpdateMatches2", query);
    33043486        return;
    33053487    }
    33063488    while (query.next())
    void Scheduler::UpdateMatches(int recordid) { 
    33153497    query.bindValue(":FINDONE", kFindOneRecord);
    33163498    if (!query.exec())
    33173499    {
    3318         MythDB::DBError("UpdateMatches", query);
     3500        MythDB::DBError("UpdateMatches3", query);
    33193501        return;
    33203502    }
    33213503    else if (query.size())
    void Scheduler::UpdateMatches(int recordid) { 
    33273509        query.bindValue(":FINDID", findtoday);
    33283510        query.bindValue(":FINDONE", kFindOneRecord);
    33293511        if (!query.exec())
    3330             MythDB::DBError("UpdateMatches", query);
     3512            MythDB::DBError("UpdateMatches4", query);
    33313513    }
    33323514
    33333515    int clause;
    33343516    QStringList fromclauses, whereclauses;
    3335     MSqlBindings bindings;
    33363517
    33373518    BuildNewRecordsQueries(recordid, fromclauses, whereclauses, bindings);
    33383519
    void Scheduler::UpdateMatches(int recordid) { 
    33493530    for (clause = 0; clause < fromclauses.count(); ++clause)
    33503531    {
    33513532        QString query = QString(
    3352 "REPLACE INTO recordmatch (recordid, chanid, starttime, manualid) "
     3533"REPLACE INTO recordmatch (recordid, chanid, starttime, manualid, "
     3534"                          oldrecduplicate, findid) "
    33533535"SELECT RECTABLE.recordid, program.chanid, program.starttime, "
    3354 " IF(search = %1, RECTABLE.recordid, 0) ").arg(kManualSearch) + QString(
     3536" IF(search = %1, RECTABLE.recordid, 0), ").arg(kManualSearch) +
     3537            progdupinit + ", " + progfindid + QString(
    33553538"FROM (RECTABLE, program INNER JOIN channel "
    33563539"      ON channel.chanid = program.chanid) ") + fromclauses[clause] + QString(
    33573540" WHERE ") + whereclauses[clause] +
    void Scheduler::UpdateMatches(int recordid) { 
    33953578            .arg(kWeekslotRecord)
    33963579            .arg(kNotRecording);
    33973580
    3398         while (1)
    3399         {
    3400             int i = query.indexOf("RECTABLE");
    3401             if (i == -1) break;
    3402             query = query.replace(i, strlen("RECTABLE"), recordTable);
    3403         }
     3581        query.replace("RECTABLE", recordTable);
    34043582
    34053583        LOG(VB_SCHEDULE, LOG_INFO, QString(" |-- Start DB Query %1...")
    34063584                .arg(clause));
    void Scheduler::UpdateMatches(int recordid) { 
    34093587        MSqlQuery result(dbConn);
    34103588        result.prepare(query);
    34113589
    3412         MSqlBindings::const_iterator it;
    34133590        for (it = bindings.begin(); it != bindings.end(); ++it)
    34143591        {
    34153592            if (query.contains(it.key()))
    void Scheduler::UpdateMatches(int recordid) { 
    34353612    LOG(VB_SCHEDULE, LOG_INFO, " +-- Done.");
    34363613}
    34373614
     3615void Scheduler::CreateTempTables(void)
     3616{
     3617    MSqlQuery result(dbConn);
     3618
     3619    if (recordTable == "record")
     3620    {
     3621        result.prepare("DROP TABLE IF EXISTS sched_temp_record;");
     3622        if (!result.exec())
     3623        {
     3624            MythDB::DBError("Dropping sched_temp_record table", result);
     3625            return;
     3626        }
     3627        result.prepare("CREATE TEMPORARY TABLE sched_temp_record "
     3628                           "LIKE record;");
     3629        if (!result.exec())
     3630        {
     3631            MythDB::DBError("Creating sched_temp_record table", result);
     3632            return;
     3633        }
     3634        result.prepare("INSERT sched_temp_record SELECT * from record;");
     3635        if (!result.exec())
     3636        {
     3637            MythDB::DBError("Populating sched_temp_record table", result);
     3638            return;
     3639        }
     3640    }
     3641
     3642    result.prepare("DROP TABLE IF EXISTS sched_temp_recorded;");
     3643    if (!result.exec())
     3644    {
     3645        MythDB::DBError("Dropping sched_temp_recorded table", result);
     3646        return;
     3647    }
     3648    result.prepare("CREATE TEMPORARY TABLE sched_temp_recorded "
     3649                       "LIKE recorded;");
     3650    if (!result.exec())
     3651    {
     3652        MythDB::DBError("Creating sched_temp_recorded table", result);
     3653        return;
     3654    }
     3655    result.prepare("INSERT sched_temp_recorded SELECT * from recorded;");
     3656    if (!result.exec())
     3657    {
     3658        MythDB::DBError("Populating sched_temp_recorded table", result);
     3659        return;
     3660    }
     3661}
     3662
     3663void Scheduler::DeleteTempTables(void)
     3664{
     3665    MSqlQuery result(dbConn);
     3666
     3667    if (recordTable == "record")
     3668    {
     3669        result.prepare("DROP TABLE IF EXISTS sched_temp_record;");
     3670        if (!result.exec())
     3671            MythDB::DBError("DeleteTempTables sched_temp_record", result);
     3672    }
     3673
     3674    result.prepare("DROP TABLE IF EXISTS sched_temp_recorded;");
     3675    if (!result.exec())
     3676        MythDB::DBError("DeleteTempTables drop table", result);
     3677}
     3678
     3679void Scheduler::UpdateDuplicates(void)
     3680{
     3681    QString schedTmpRecord = recordTable;
     3682    if (schedTmpRecord == "record")
     3683        schedTmpRecord = "sched_temp_record";
     3684
     3685    QString rmquery = QString(
     3686"UPDATE recordmatch "
     3687" INNER JOIN RECTABLE ON (recordmatch.recordid = RECTABLE.recordid) "
     3688" INNER JOIN program p ON (recordmatch.chanid = p.chanid AND "
     3689"                          recordmatch.starttime = p.starttime AND "
     3690"                          recordmatch.manualid = p.manualid) "
     3691" LEFT JOIN oldrecorded ON "
     3692"  ( "
     3693"    RECTABLE.dupmethod > 1 AND "
     3694"    oldrecorded.duplicate <> 0 AND "
     3695"    p.title = oldrecorded.title AND "
     3696"    p.generic = 0 "
     3697"     AND "
     3698"     ( "
     3699"      (p.programid <> '' "
     3700"       AND p.programid = oldrecorded.programid) "
     3701"      OR "
     3702"      ( ") +
     3703        (ProgramInfo::UsingProgramIDAuthority() ?
     3704"       (p.programid = '' OR oldrecorded.programid = '' OR "
     3705"         LEFT(p.programid, LOCATE('/', p.programid)) <> "
     3706"         LEFT(oldrecorded.programid, LOCATE('/', oldrecorded.programid))) " :
     3707"       (p.programid = '' OR oldrecorded.programid = '') " )
     3708        + QString(
     3709"       AND "
     3710"       (((RECTABLE.dupmethod & 0x02) = 0) OR (p.subtitle <> '' "
     3711"          AND p.subtitle = oldrecorded.subtitle)) "
     3712"       AND "
     3713"       (((RECTABLE.dupmethod & 0x04) = 0) OR (p.description <> '' "
     3714"          AND p.description = oldrecorded.description)) "
     3715"       AND "
     3716"       (((RECTABLE.dupmethod & 0x08) = 0) OR "
     3717"          (p.subtitle <> '' AND "
     3718"             (p.subtitle = oldrecorded.subtitle OR "
     3719"              (oldrecorded.subtitle = '' AND "
     3720"               p.subtitle = oldrecorded.description))) OR "
     3721"          (p.subtitle = '' AND p.description <> '' AND "
     3722"             (p.description = oldrecorded.subtitle OR "
     3723"              (oldrecorded.subtitle = '' AND "
     3724"               p.description = oldrecorded.description)))) "
     3725"      ) "
     3726"     ) "
     3727"  ) "
     3728" LEFT JOIN sched_temp_recorded recorded ON "
     3729"  ( "
     3730"    RECTABLE.dupmethod > 1 AND "
     3731"    recorded.duplicate <> 0 AND "
     3732"    p.title = recorded.title AND "
     3733"    p.generic = 0 AND "
     3734"    recorded.recgroup NOT IN ('LiveTV','Deleted') "
     3735"     AND "
     3736"     ( "
     3737"      (p.programid <> '' "
     3738"       AND p.programid = recorded.programid) "
     3739"      OR "
     3740"      ( ") +
     3741        (ProgramInfo::UsingProgramIDAuthority() ?
     3742"       (p.programid = '' OR recorded.programid = '' OR "
     3743"         LEFT(p.programid, LOCATE('/', p.programid)) <> "
     3744"         LEFT(recorded.programid, LOCATE('/', recorded.programid))) " :
     3745"       (p.programid = '' OR recorded.programid = '') ")
     3746        + QString(
     3747"       AND "
     3748"       (((RECTABLE.dupmethod & 0x02) = 0) OR (p.subtitle <> '' "
     3749"          AND p.subtitle = recorded.subtitle)) "
     3750"       AND "
     3751"       (((RECTABLE.dupmethod & 0x04) = 0) OR (p.description <> '' "
     3752"          AND p.description = recorded.description)) "
     3753"       AND "
     3754"       (((RECTABLE.dupmethod & 0x08) = 0) OR "
     3755"          (p.subtitle <> '' AND "
     3756"             (p.subtitle = recorded.subtitle OR "
     3757"              (recorded.subtitle = '' AND "
     3758"               p.subtitle = recorded.description))) OR "
     3759"          (p.subtitle = '' AND p.description <> '' AND "
     3760"             (p.description = recorded.subtitle OR "
     3761"              (recorded.subtitle = '' AND "
     3762"               p.description = recorded.description)))) "
     3763"      ) "
     3764"     ) "
     3765"  ) "
     3766" LEFT JOIN oldfind ON "
     3767"  (oldfind.recordid = recordmatch.recordid AND "
     3768"   oldfind.findid = recordmatch.findid) "
     3769" SET oldrecduplicate = (oldrecorded.endtime IS NOT NULL), "
     3770"     recduplicate = (recorded.endtime IS NOT NULL), "
     3771"     findduplicate = (oldfind.findid IS NOT NULL), "
     3772"     oldrecstatus = oldrecorded.recstatus "
     3773" WHERE p.endtime >= (NOW() - INTERVAL 480 MINUTE) "
     3774"       AND oldrecduplicate = -1 "
     3775);
     3776    rmquery.replace("RECTABLE", schedTmpRecord);
     3777
     3778    MSqlQuery result(dbConn);
     3779    result.prepare(rmquery);
     3780    if (!result.exec())
     3781    {
     3782        MythDB::DBError("UpdateDuplicates", result);
     3783        return;
     3784    }
     3785}
     3786
    34383787void Scheduler::AddNewRecords(void)
    34393788{
    34403789    struct timeval dbstart, dbend;
    void Scheduler::AddNewRecords(void) 
    35483897        "(FIND_IN_SET('VISUALIMPAIR', program.audioprop) > 0) * %1").arg(adpriority);
    35493898
    35503899    QString schedTmpRecord = recordTable;
    3551 
    3552     MSqlQuery result(dbConn);
    3553 
    35543900    if (schedTmpRecord == "record")
    3555     {
    35563901        schedTmpRecord = "sched_temp_record";
    35573902
    3558         result.prepare("DROP TABLE IF EXISTS sched_temp_record;");
    3559 
    3560         if (!result.exec())
    3561         {
    3562             MythDB::DBError("Dropping sched_temp_record table", result);
    3563             return;
    3564         }
    3565 
    3566         result.prepare("CREATE TEMPORARY TABLE sched_temp_record "
    3567                            "LIKE record;");
    3568 
    3569         if (!result.exec())
    3570         {
    3571             MythDB::DBError("Creating sched_temp_record table",
    3572                                  result);
    3573             return;
    3574         }
    3575 
    3576         result.prepare("INSERT sched_temp_record SELECT * from record;");
    3577 
    3578         if (!result.exec())
    3579         {
    3580             MythDB::DBError("Populating sched_temp_record table",
    3581                                  result);
    3582             return;
    3583         }
    3584     }
    3585 
    3586     result.prepare("DROP TABLE IF EXISTS sched_temp_recorded;");
    3587 
    3588     if (!result.exec())
    3589     {
    3590         MythDB::DBError("Dropping sched_temp_recorded table", result);
    3591         return;
    3592     }
    3593 
    3594     result.prepare("CREATE TEMPORARY TABLE sched_temp_recorded "
    3595                        "LIKE recorded;");
    3596 
    3597     if (!result.exec())
    3598     {
    3599         MythDB::DBError("Creating sched_temp_recorded table", result);
    3600         return;
    3601     }
    3602 
    3603     result.prepare("INSERT sched_temp_recorded SELECT * from recorded;");
    3604 
    3605     if (!result.exec())
    3606     {
    3607         MythDB::DBError("Populating sched_temp_recorded table", result);
    3608         return;
    3609     }
     3903    MSqlQuery result(dbConn);
    36103904
    36113905    result.prepare(QString("SELECT recpriority, selectclause FROM %1;")
    36123906                           .arg(priorityTable));
    void Scheduler::AddNewRecords(void) 
    36303924    }
    36313925    pwrpri += QString(" AS powerpriority ");
    36323926
    3633     QString progfindid = QString(
    3634 "(CASE RECTABLE.type "
    3635 "  WHEN %1 "
    3636 "   THEN RECTABLE.findid "
    3637 "  WHEN %2 "
    3638 "   THEN to_days(date_sub(program.starttime, interval "
    3639 "                time_format(RECTABLE.findtime, '%H:%i') hour_minute)) "
    3640 "  WHEN %3 "
    3641 "   THEN floor((to_days(date_sub(program.starttime, interval "
    3642 "               time_format(RECTABLE.findtime, '%H:%i') hour_minute)) - "
    3643 "               RECTABLE.findday)/7) * 7 + RECTABLE.findday "
    3644 "  WHEN %4 "
    3645 "   THEN RECTABLE.findid "
    3646 "  ELSE 0 "
    3647 " END) ")
    3648         .arg(kFindOneRecord)
    3649         .arg(kFindDailyRecord)
    3650         .arg(kFindWeeklyRecord)
    3651         .arg(kOverrideRecord);
    3652 
    3653     QString rmquery = QString(
    3654 "UPDATE recordmatch "
    3655 " INNER JOIN RECTABLE ON (recordmatch.recordid = RECTABLE.recordid) "
    3656 " INNER JOIN program ON (recordmatch.chanid = program.chanid AND "
    3657 "                        recordmatch.starttime = program.starttime AND "
    3658 "                        recordmatch.manualid = program.manualid) "
    3659 " LEFT JOIN oldrecorded ON "
    3660 "  ( "
    3661 "    RECTABLE.dupmethod > 1 AND "
    3662 "    oldrecorded.duplicate <> 0 AND "
    3663 "    program.title = oldrecorded.title AND "
    3664 "    program.generic = 0 "
    3665 "     AND "
    3666 "     ( "
    3667 "      (program.programid <> '' "
    3668 "       AND program.programid = oldrecorded.programid) "
    3669 "      OR "
    3670 "      ( ") +
    3671         (ProgramInfo::UsingProgramIDAuthority() ?
    3672 "       (program.programid = '' OR oldrecorded.programid = '' OR "
    3673 "         LEFT(program.programid, LOCATE('/', program.programid)) <> "
    3674 "         LEFT(oldrecorded.programid, LOCATE('/', oldrecorded.programid))) " :
    3675 "       (program.programid = '' OR oldrecorded.programid = '') " )
    3676         + QString(
    3677 "       AND "
    3678 "       (((RECTABLE.dupmethod & 0x02) = 0) OR (program.subtitle <> '' "
    3679 "          AND program.subtitle = oldrecorded.subtitle)) "
    3680 "       AND "
    3681 "       (((RECTABLE.dupmethod & 0x04) = 0) OR (program.description <> '' "
    3682 "          AND program.description = oldrecorded.description)) "
    3683 "       AND "
    3684 "       (((RECTABLE.dupmethod & 0x08) = 0) OR "
    3685 "          (program.subtitle <> '' AND "
    3686 "             (program.subtitle = oldrecorded.subtitle OR "
    3687 "              (oldrecorded.subtitle = '' AND "
    3688 "               program.subtitle = oldrecorded.description))) OR "
    3689 "          (program.subtitle = '' AND program.description <> '' AND "
    3690 "             (program.description = oldrecorded.subtitle OR "
    3691 "              (oldrecorded.subtitle = '' AND "
    3692 "               program.description = oldrecorded.description)))) "
    3693 "      ) "
    3694 "     ) "
    3695 "  ) "
    3696 " LEFT JOIN sched_temp_recorded recorded ON "
    3697 "  ( "
    3698 "    RECTABLE.dupmethod > 1 AND "
    3699 "    recorded.duplicate <> 0 AND "
    3700 "    program.title = recorded.title AND "
    3701 "    program.generic = 0 AND "
    3702 "    recorded.recgroup NOT IN ('LiveTV','Deleted') "
    3703 "     AND "
    3704 "     ( "
    3705 "      (program.programid <> '' "
    3706 "       AND program.programid = recorded.programid) "
    3707 "      OR "
    3708 "      ( ") +
    3709         (ProgramInfo::UsingProgramIDAuthority() ?
    3710 "       (program.programid = '' OR recorded.programid = '' OR "
    3711 "         LEFT(program.programid, LOCATE('/', program.programid)) <> "
    3712 "         LEFT(recorded.programid, LOCATE('/', recorded.programid))) " :
    3713 "       (program.programid = '' OR recorded.programid = '') ")
    3714         + QString(
    3715 "       AND "
    3716 "       (((RECTABLE.dupmethod & 0x02) = 0) OR (program.subtitle <> '' "
    3717 "          AND program.subtitle = recorded.subtitle)) "
    3718 "       AND "
    3719 "       (((RECTABLE.dupmethod & 0x04) = 0) OR (program.description <> '' "
    3720 "          AND program.description = recorded.description)) "
    3721 "       AND "
    3722 "       (((RECTABLE.dupmethod & 0x08) = 0) OR "
    3723 "          (program.subtitle <> '' AND "
    3724 "             (program.subtitle = recorded.subtitle OR "
    3725 "              (recorded.subtitle = '' AND "
    3726 "               program.subtitle = recorded.description))) OR "
    3727 "          (program.subtitle = '' AND program.description <> '' AND "
    3728 "             (program.description = recorded.subtitle OR "
    3729 "              (recorded.subtitle = '' AND "
    3730 "               program.description = recorded.description)))) "
    3731 "      ) "
    3732 "     ) "
    3733 "  ) "
    3734 " LEFT JOIN oldfind ON "
    3735 "  (oldfind.recordid = recordmatch.recordid AND "
    3736 "   oldfind.findid = ") + progfindid + QString(") "
    3737 "  SET oldrecduplicate = (oldrecorded.endtime IS NOT NULL), "
    3738 "      recduplicate = (recorded.endtime IS NOT NULL), "
    3739 "      findduplicate = (oldfind.findid IS NOT NULL), "
    3740 "      oldrecstatus = oldrecorded.recstatus "
    3741 " WHERE program.endtime >= NOW() - INTERVAL 9 HOUR "
    3742 );
    3743     rmquery.replace("RECTABLE", schedTmpRecord);
    3744 
    37453927    pwrpri.replace("program.","p.");
    37463928    pwrpri.replace("channel.","c.");
    3747     progfindid.replace("program.","p.");
    3748     progfindid.replace("channel.","c.");
    37493929    QString query = QString(
    37503930        "SELECT "
    37513931        "    c.chanid,         c.sourceid,           p.starttime,       "// 0-2
    void Scheduler::AddNewRecords(void) 
    37633943        "    capturecard.cardid, cardinput.cardinputid,p.seriesid,      "//24-26
    37643944        "    p.programid,       RECTABLE.inetref,    p.category_type,   "//27-29
    37653945        "    p.airdate,         p.stars,             p.originalairdate, "//30-32
    3766         "    RECTABLE.inactive, RECTABLE.parentid,") + progfindid + ", "//33-35
     3946        "    RECTABLE.inactive, RECTABLE.parentid,   recordmatch.findid, "//33-35
    37673947        "    RECTABLE.playgroup, oldrecstatus.recstatus, "//36-37
    37683948        "    oldrecstatus.reactivate, p.videoprop+0,     "//38-39
    37693949        "    p.subtitletypes+0, p.audioprop+0,   RECTABLE.storagegroup, "//40-42
    37703950        "    capturecard.hostname, recordmatch.oldrecstatus, "
    37713951        "                                           RECTABLE.avg_delay, "//43-45
    3772         "    oldrecstatus.future, cardinput.schedorder, "                //46-47
    3773         + pwrpri + QString(
     3952        "    oldrecstatus.future, cardinput.schedorder, ") +             //46-47
     3953        pwrpri + QString(
    37743954        "FROM recordmatch "
    37753955        "INNER JOIN RECTABLE ON (recordmatch.recordid = RECTABLE.recordid) "
    37763956        "INNER JOIN program AS p "
    void Scheduler::AddNewRecords(void) 
    37853965        "ON ( oldrecstatus.station   = c.callsign  AND "
    37863966        "     oldrecstatus.starttime = p.starttime AND "
    37873967        "     oldrecstatus.title     = p.title ) "
    3788         "WHERE p.endtime >= NOW() - INTERVAL 1 DAY "
     3968        "WHERE p.endtime > (NOW() - INTERVAL 480 MINUTE) "
    37893969        "ORDER BY RECTABLE.recordid DESC ");
    37903970    query.replace("RECTABLE", schedTmpRecord);
    37913971
    37923972    LOG(VB_SCHEDULE, LOG_INFO, QString(" |-- Start DB Query..."));
    37933973
    37943974    gettimeofday(&dbstart, NULL);
    3795     result.prepare(rmquery);
    3796     if (!result.exec())
    3797     {
    3798         MythDB::DBError("AddNewRecords recordmatch", result);
    3799         return;
    3800     }
    38013975    result.prepare(query);
    38023976    if (!result.exec())
    38033977    {
    void Scheduler::AddNewRecords(void) 
    39894163    RecIter tmp = tmpList.begin();
    39904164    for ( ; tmp != tmpList.end(); ++tmp)
    39914165        worklist.push_back(*tmp);
    3992 
    3993     if (schedTmpRecord == "sched_temp_record")
    3994     {
    3995         result.prepare("DROP TABLE IF EXISTS sched_temp_record;");
    3996         if (!result.exec())
    3997             MythDB::DBError("AddNewRecords sched_temp_record", result);
    3998     }
    3999 
    4000     result.prepare("DROP TABLE IF EXISTS sched_temp_recorded;");
    4001     if (!result.exec())
    4002         MythDB::DBError("AddNewRecords drop table", result);
    40034166}
    40044167
    40054168void Scheduler::AddNotListed(void) {
  • mythtv/programs/mythbackend/scheduler.h

    diff --git a/mythtv/programs/mythbackend/scheduler.h b/mythtv/programs/mythbackend/scheduler.h
    index 8203c9f..2df7b68 100644
    a b using namespace std; 
    2222#include "mythdeque.h"
    2323#include "mythscheduler.h"
    2424#include "mthread.h"
     25#include "scheduledrecording.h"
    2526
    2627class EncoderLink;
    2728class MainServer;
    class Scheduler : public MThread, public MythScheduler 
    4142
    4243    void SetExpirer(AutoExpire *autoExpirer) { m_expirer = autoExpirer; }
    4344
    44     void Reschedule(int recordid);
     45    void Reschedule(const QStringList &request);
     46    void RescheduleMatch(uint recordid, uint sourceid, uint mplexid,
     47                         const QDateTime &maxstarttime, const QString &why)
     48    { Reschedule(ScheduledRecording::BuildMatchRequest(recordid, sourceid,
     49                                               mplexid, maxstarttime, why)); };
     50    void RescheduleCheck(const RecordingInfo &recinfo, const QString &why)
     51    { Reschedule(ScheduledRecording::BuildCheckRequest(recinfo, why)); };
     52    void ReschedulePlace(const QString &why)
     53    { Reschedule(ScheduledRecording::BuildPlaceRequest(why)); };
     54
    4555    void AddRecording(const RecordingInfo&);
    46     void FillRecordListFromDB(int recordid = -1);
     56    void FillRecordListFromDB(uint recordid = 0);
    4757    void FillRecordListFromMaster(void);
    4858
    4959    void UpdateRecStatus(RecordingInfo *pginfo);
    class Scheduler : public MThread, public MythScheduler 
    92102
    93103    bool VerifyCards(void);
    94104
     105    void CreateTempTables(void);
     106    void DeleteTempTables(void);
     107    void UpdateDuplicates(void);
    95108    bool FillRecordList(void);
    96     void UpdateMatches(int recordid);
    97     void UpdateManuals(int recordid);
     109    void UpdateMatches(uint recordid, uint sourceid, uint mplexid,
     110                       const QDateTime maxstarttime);
     111    void UpdateManuals(uint recordid);
    98112    void BuildWorkList(void);
    99113    bool ClearWorkList(void);
    100114    void AddNewRecords(void);
    101115    void AddNotListed(void);
    102     void BuildNewRecordsQueries(int recordid, QStringList &from, QStringList &where,
    103                                 MSqlBindings &bindings);
     116    void BuildNewRecordsQueries(uint recordid, QStringList &from,
     117                                QStringList &where, MSqlBindings &bindings);
    104118    void PruneOverlaps(void);
    105119    void BuildListMaps(void);
    106120    void ClearListMaps(void);
    class Scheduler : public MThread, public MythScheduler 
    150164        RecConstIter startIter, const RecList &reclist,
    151165        int prerollseconds, int max_sleep /*ms*/);
    152166    void OldRecordedFixups(void);
     167    void ResetDuplicates(uint recordid, uint findid, const QString &title,
     168                         const QString &subtitle, const QString &descrip,
     169                         const QString &programid);
    153170    bool HandleReschedule(void);
    154171    bool HandleRunSchedulerStartup(
    155172        int prerollseconds, int idleWaitForRecordingTime);
    class Scheduler : public MThread, public MythScheduler 
    166183        int idleTimeoutSecs, int idleWaitForRecordingTime,
    167184        bool &statuschanged);
    168185
    169 
    170     MythDeque<int> reschedQueue;
     186    void EnqueueMatch(uint recordid, uint sourceid, uint mplexid,
     187                      const QDateTime maxstarttime, const QString &why)
     188    { reschedQueue.enqueue(ScheduledRecording::BuildMatchRequest(recordid,
     189                                     sourceid, mplexid, maxstarttime, why)); };
     190    void EnqueueCheck(const RecordingInfo &recinfo, const QString &why)
     191    { reschedQueue.enqueue(ScheduledRecording::BuildCheckRequest(recinfo,
     192                                                                 why)); };
     193    void EnqueuePlace(const QString &why)
     194    { reschedQueue.enqueue(ScheduledRecording::BuildPlaceRequest(why)); };
     195
     196    MythDeque<QStringList> reschedQueue;
    171197    mutable QMutex schedLock;
    172198    QMutex recordmatchLock;
    173199    QWaitCondition reschedWait;
    class Scheduler : public MThread, public MythScheduler 
    175201    RecList worklist;
    176202    RecList retrylist;
    177203    RecList conflictlist;
    178     QMap<int, RecList> recordidlistmap;
     204    QMap<uint, RecList> recordidlistmap;
    179205    QMap<QString, RecList> titlelistmap;
    180206    InputGroupMap igrp;
    181207
  • mythtv/programs/mythfilldatabase/main.cpp

    diff --git a/mythtv/programs/mythfilldatabase/main.cpp b/mythtv/programs/mythfilldatabase/main.cpp
    index 57d4709..1552a1a 100644
    a b int main(int argc, char *argv[]) 
    760760            "===============================================================");
    761761
    762762    if (grab_data || mark_repeats)
    763         ScheduledRecording::signalChange(-1);
     763        ScheduledRecording::RescheduleMatch(0, 0, 0, QDateTime(),
     764                                            "MythFillDatabase");
    764765
    765766    gCoreContext->SendMessage("CLEAR_SETTINGS_CACHE");
    766767
  • mythtv/programs/mythfrontend/channelrecpriority.cpp

    diff --git a/mythtv/programs/mythfrontend/channelrecpriority.cpp b/mythtv/programs/mythfrontend/channelrecpriority.cpp
    index 180bd7e..085ed0f 100644
    a b void ChannelRecPriority::saveRecPriority(void) 
    238238            applyChannelRecPriorityChange(QString::number(chanInfo->chanid),
    239239                                          chanInfo->recpriority);
    240240    }
    241     ScheduledRecording::signalChange(0);
     241    ScheduledRecording::ReschedulePlace("SaveChannelPriority");
    242242}
    243243
    244244void ChannelRecPriority::FillList(void)
  • mythtv/programs/mythfrontend/custompriority.cpp

    diff --git a/mythtv/programs/mythfrontend/custompriority.cpp b/mythtv/programs/mythfrontend/custompriority.cpp
    index e595090..4c5c2b0 100644
    a b void CustomPriority::installClicked(void) 
    306306    if (!query.exec())
    307307        MythDB::DBError("Install power search insert", query);
    308308    else
    309         ScheduledRecording::signalChange(0);
     309        ScheduledRecording::ReschedulePlace("InstallCustomPriority");
    310310
    311311    Close();
    312312}
    void CustomPriority::deleteClicked(void) 
    324324    if (!query.exec())
    325325        MythDB::DBError("Delete power search query", query);
    326326    else
    327         ScheduledRecording::signalChange(0);
     327        ScheduledRecording::ReschedulePlace("DeleteCustomPriority");
    328328
    329329    Close();
    330330}
  • mythtv/programs/mythfrontend/main.cpp

    diff --git a/mythtv/programs/mythfrontend/main.cpp b/mythtv/programs/mythfrontend/main.cpp
    index 019bb3a..d9042d6 100644
    a b static void TVMenuCallback(void *data, QString &selection) 
    10441044
    10451045        if (sel == "settings general" ||
    10461046            sel == "settings generalrecpriorities")
    1047             ScheduledRecording::signalChange(0);
     1047            ScheduledRecording::ReschedulePlace("TVMenuCallback");
    10481048        GetMythMainWindow()->ShowPainterWindow();
    10491049    }
    10501050}
  • mythtv/programs/mythfrontend/proglist.cpp

    diff --git a/mythtv/programs/mythfrontend/proglist.cpp b/mythtv/programs/mythfrontend/proglist.cpp
    index ddda2af..f2e10c1 100644
    a b void ProgLister::DeleteOldEpisode(bool ok) 
    675675    if (!query.exec())
    676676        MythDB::DBError("ProgLister::DeleteOldEpisode", query);
    677677
    678     ScheduledRecording::signalChange(0);
     678    ScheduledRecording::RescheduleCheck(*pi, "DeleteOldEpisode");
    679679    FillItemList(true);
    680680}
    681681
    void ProgLister::DeleteOldSeries(bool ok) 
    704704    if (!query.exec())
    705705        MythDB::DBError("ProgLister::DeleteOldSeries -- delete", query);
    706706
    707     ScheduledRecording::signalChange(0);
     707    // Set the programid to the special value of "**any**" which the
     708    // scheduler recognizes to mean the entire series was deleted.
     709    RecordingInfo tempri(*pi);
     710    tempri.SetProgramID("**any**");
     711    ScheduledRecording::RescheduleCheck(tempri, "DeleteOldSeries");
    708712    FillItemList(true);
    709713}
    710714
  • mythtv/programs/mythfrontend/programrecpriority.cpp

    diff --git a/mythtv/programs/mythfrontend/programrecpriority.cpp b/mythtv/programs/mythfrontend/programrecpriority.cpp
    index 1ea874c..a33acf8 100644
    a b void ProgramRecPriority::deactivate(void) 
    10271027            }
    10281028            else
    10291029            {
    1030                 ScheduledRecording::signalChange(0);
     1030                ScheduledRecording::ReschedulePlace(
     1031                    QString("DeactivateRule %1 %2")
     1032                    .arg(pgRecInfo->GetRecordingRuleID())
     1033                    .arg(pgRecInfo->GetTitle()));
    10311034                pgRecInfo->recstatus = inactive ? rsInactive : rsUnknown;
    10321035                item->DisplayState("disabled", "status");
    10331036            }
  • mythtv/programs/mythutil/backendutils.cpp

    diff --git a/mythtv/programs/mythutil/backendutils.cpp b/mythtv/programs/mythutil/backendutils.cpp
    index 151fa7d..f4f43ea 100644
    a b  
    33#include "mythcorecontext.h"
    44#include "mythlogging.h"
    55#include "remoteutil.h"
     6#include "scheduledrecording.h"
    67
    78// local headers
    89#include "backendutils.h"
    910
    10 static int RawSendEvent(const QString &eventString)
     11static int RawSendEvent(const QStringList &eventStringList)
    1112{
    12     if (eventString.isEmpty())
     13    if (eventStringList.isEmpty() || eventStringList[0].isEmpty())
    1314        return GENERIC_EXIT_INVALID_CMDLINE;
    1415
    1516    if (gCoreContext->ConnectToMasterServer(false, false))
    1617    {
    17         gCoreContext->SendMessage(eventString);
     18        QStringList message("MESSAGE");
     19        message << eventStringList;
     20        gCoreContext->SendReceiveStringList(message);
    1821        return GENERIC_EXIT_OK;
    1922    }
    2023    return GENERIC_EXIT_CONNECT_ERROR;
    static int ClearSettingsCache(const MythUtilCommandLineParser &cmdline) 
    3639
    3740static int SendEvent(const MythUtilCommandLineParser &cmdline)
    3841{
    39     return RawSendEvent(cmdline.toString("event"));
     42    return RawSendEvent(cmdline.toStringList("event"));
    4043}
    4144
    4245static int SendSystemEvent(const MythUtilCommandLineParser &cmdline)
    4346{
    44     return RawSendEvent(QString("SYSTEM_EVENT %1 SENDER %2")
    45                                 .arg(cmdline.toString("systemevent"))
    46                                 .arg(gCoreContext->GetHostName()));
     47    return RawSendEvent(QStringList(QString("SYSTEM_EVENT %1 SENDER %2")
     48                                    .arg(cmdline.toString("systemevent"))
     49                                    .arg(gCoreContext->GetHostName())));
    4750}
    4851
    4952static int Reschedule(const MythUtilCommandLineParser &cmdline)
    5053{
    5154    if (gCoreContext->ConnectToMasterServer(false, false))
    5255    {
    53         QStringList slist("RESCHEDULE_RECORDINGS -1");
    54         if (gCoreContext->SendReceiveStringList(slist))
    55         {
    56             LOG(VB_GENERAL, LOG_ERR,
    57                 "Error sending reschedule command to master backend");
    58             return GENERIC_EXIT_CONNECT_ERROR;
    59         }
    60 
     56        ScheduledRecording::RescheduleMatch(0, 0, 0, QDateTime(),
     57                                            "MythUtilCommand");
    6158        LOG(VB_GENERAL, LOG_INFO, "Reschedule command sent to master");
    6259        return GENERIC_EXIT_OK;
    6360    }
  • mythtv/programs/mythutil/commandlineparser.cpp

    diff --git a/mythtv/programs/mythutil/commandlineparser.cpp b/mythtv/programs/mythutil/commandlineparser.cpp
    index 7f00e50..897be65 100644
    a b void MythUtilCommandLineParser::LoadArguments(void) 
    8383                "access those files to do so. If enabled, this will also "
    8484                "trigger the bulk metadata scanner upon completion.")
    8585                ->SetGroup("Backend")
    86         << add("--event", "event", "", "Send a backend event test message.", "")
     86        << add("--event", "event", QVariant::StringList,
     87                "Send a backend event test message.", "")
    8788                ->SetGroup("Backend")
    8889        << add("--systemevent", "systemevent", "",
    8990                "Send a backend SYSTEM_EVENT test message.", "")