Ticket #10533: schedopt3.patch

File schedopt3.patch, 73.7 KB (added by gigem, 14 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..1d2740f 100644
    a b int handle_command(const MythBackendCommandLineParser &cmdline)  
    370370        }
    371371
    372372        verboseMask |= VB_SCHEDULE;
     373        LogLevel_t oldLogLevel = logLevel;
     374        logLevel = LOG_DEBUG;
    373375        sched->PrintList(true);
     376        logLevel = oldLogLevel;
    374377        delete sched;
    375378        return GENERIC_EXIT_OK;
    376379    }
    int handle_command(const MythBackendCommandLineParser &cmdline)  
    381384        if (gCoreContext->ConnectToMasterServer())
    382385        {
    383386            LOG(VB_GENERAL, LOG_INFO, "Connected to master for reschedule");
    384             ScheduledRecording::signalChange(-1);
     387            ScheduledRecording::RescheduleMatch(0, 0, 0, QDateTime(),
     388                                                "MythBackendCommand");
    385389            ok = true;
    386390        }
    387391        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..827aa5a 100644
    a b static bool comp_redundant(RecordingInfo *a, RecordingInfo *b)  
    287287                                              Qt::CaseInsensitive);
    288288    if (cmp != 0)
    289289        return cmp < 0;
    290     return a->GetRecordingStatus() < b->GetRecordingStatus();
     290    if (a->GetRecordingStatus() != b->GetRecordingStatus())
     291        return a->GetRecordingStatus() < b->GetRecordingStatus();
     292    cmp = a->GetChanNum().compare(b->GetChanNum(), Qt::CaseInsensitive);
     293    return cmp < 0;
    291294}
    292295
    293296static bool comp_recstart(RecordingInfo *a, RecordingInfo *b)
    bool Scheduler::FillRecordList(void)  
    400403
    401404/** \fn Scheduler::FillRecordListFromDB(int)
    402405 *  \param recordid Record ID of recording that has changed,
    403  *                  or -1 if anything might have been changed.
     406 *                  or 0 if anything might have been changed.
    404407 */
    405 void Scheduler::FillRecordListFromDB(int recordid)
     408void Scheduler::FillRecordListFromDB(uint recordid)
    406409{
    407410    struct timeval fillstart, fillend;
    408     float matchTime, placeTime;
     411    float matchTime, checkTime, placeTime;
    409412
    410413    MSqlQuery query(dbConn);
    411414    QString thequery;
    412415    QString where = "";
    413416
    414417    // This will cause our temp copy of recordmatch to be empty
    415     if (recordid == -1)
     418    if (recordid == 0)
    416419        where = "WHERE recordid IS NULL ";
    417420
    418421    thequery = QString("CREATE TEMPORARY TABLE recordmatch ") +
    void Scheduler::FillRecordListFromDB(int recordid)  
    449452    QMutexLocker locker(&schedLock);
    450453
    451454    gettimeofday(&fillstart, NULL);
    452     UpdateMatches(recordid);
     455    UpdateMatches(recordid, 0, 0, QDateTime());
    453456    gettimeofday(&fillend, NULL);
    454457    matchTime = ((fillend.tv_sec - fillstart.tv_sec ) * 1000000 +
    455458                 (fillend.tv_usec - fillstart.tv_usec)) / 1000000.0;
    456459
     460    LOG(VB_SCHEDULE, LOG_INFO, "CreateTempTables...");
     461    CreateTempTables();
     462
     463    gettimeofday(&fillstart, NULL);
     464    LOG(VB_SCHEDULE, LOG_INFO, "UpdateDuplicates...");
     465    UpdateDuplicates();
     466    gettimeofday(&fillend, NULL);
     467    checkTime = ((fillend.tv_sec - fillstart.tv_sec ) * 1000000 +
     468                 (fillend.tv_usec - fillstart.tv_usec)) / 1000000.0;
     469
    457470    gettimeofday(&fillstart, NULL);
    458471    FillRecordList();
    459472    gettimeofday(&fillend, NULL);
    460473    placeTime = ((fillend.tv_sec - fillstart.tv_sec ) * 1000000 +
    461474                 (fillend.tv_usec - fillstart.tv_usec)) / 1000000.0;
    462475
     476    LOG(VB_SCHEDULE, LOG_INFO, "DeleteTempTables...");
     477    DeleteTempTables();
     478
    463479    MSqlQuery queryDrop(dbConn);
    464480    queryDrop.prepare("DROP TABLE recordmatch;");
    465481    if (!queryDrop.exec())
    void Scheduler::FillRecordListFromDB(int recordid)  
    469485    }
    470486
    471487    QString msg;
    472     msg.sprintf("Speculative scheduled %d items in "
    473                 "%.1f = %.2f match + %.2f place", (int)reclist.size(),
    474                 matchTime + placeTime, matchTime, placeTime);
     488    msg.sprintf("Speculative scheduled %d items in %.1f "
     489                "= %.2f match + %.2f check + %.2f place",
     490                (int)reclist.size(),
     491                matchTime + checkTime + placeTime,
     492                matchTime, checkTime, placeTime);
    475493    LOG(VB_GENERAL, LOG_INFO, msg);
    476494}
    477495
    void Scheduler::FillRecordListFromMaster(void)  
    490508
    491509void Scheduler::PrintList(RecList &list, bool onlyFutureRecordings)
    492510{
    493     if (!VERBOSE_LEVEL_CHECK(VB_SCHEDULE, LOG_INFO))
     511    if (!VERBOSE_LEVEL_CHECK(VB_SCHEDULE, LOG_DEBUG))
    494512        return;
    495513
    496514    QDateTime now = QDateTime::currentDateTime();
    void Scheduler::PrintList(RecList &list, bool onlyFutureRecordings)  
    518536
    519537void Scheduler::PrintRec(const RecordingInfo *p, const char *prefix)
    520538{
    521     if (!VERBOSE_LEVEL_CHECK(VB_SCHEDULE, LOG_INFO))
     539    if (!VERBOSE_LEVEL_CHECK(VB_SCHEDULE, LOG_DEBUG))
    522540        return;
    523541
    524542    QString outstr;
    void Scheduler::UpdateRecStatus(RecordingInfo *pginfo)  
    593611                p->AddHistory(false);
    594612                if (resched)
    595613                {
    596                     reschedQueue.enqueue(0);
     614                    EnqueueCheck(*p, "UpdateRecStatus1");
    597615                    reschedWait.wakeOne();
    598616                }
    599617                else
    void Scheduler::UpdateRecStatus(uint cardid, uint chanid,  
    643661                p->AddHistory(false);
    644662                if (resched)
    645663                {
    646                     reschedQueue.enqueue(0);
     664                    EnqueueCheck(*p, "UpdateRecStatus2");
    647665                    reschedWait.wakeOne();
    648666                }
    649667                else
    bool Scheduler::ChangeRecordingEnd(RecordingInfo *oldp, RecordingInfo *newp)  
    665683        return false;
    666684
    667685    RecordingType oldrectype = oldp->GetRecordingRuleType();
    668     int oldrecordid = oldp->GetRecordingRuleID();
     686    uint oldrecordid = oldp->GetRecordingRuleID();
    669687    QDateTime oldrecendts = oldp->GetRecordingEndTime();
    670688
    671689    oldp->SetRecordingRuleType(newp->GetRecordingRuleType());
    bool Scheduler::TryAnotherShowing(RecordingInfo *p, bool samePriority,  
    12251243
    12261244void Scheduler::SchedNewRecords(void)
    12271245{
    1228     LOG(VB_SCHEDULE, LOG_INFO, "Scheduling:");
    1229 
    1230     if (VERBOSE_LEVEL_CHECK(VB_SCHEDULE, LOG_INFO))
     1246    if (VERBOSE_LEVEL_CHECK(VB_SCHEDULE, LOG_DEBUG))
    12311247    {
    1232         LOG(VB_SCHEDULE, LOG_INFO,
     1248        LOG(VB_SCHEDULE, LOG_DEBUG,
    12331249            "+ = schedule this showing to be recorded");
    1234         LOG(VB_SCHEDULE, LOG_INFO,
     1250        LOG(VB_SCHEDULE, LOG_DEBUG,
    12351251            "# = could not schedule this showing, retry later");
    1236         LOG(VB_SCHEDULE, LOG_INFO,
     1252        LOG(VB_SCHEDULE, LOG_DEBUG,
    12371253            "! = conflict caused by this showing");
    1238         LOG(VB_SCHEDULE, LOG_INFO,
     1254        LOG(VB_SCHEDULE, LOG_DEBUG,
    12391255            "/ = retry this showing, same priority pass");
    1240         LOG(VB_SCHEDULE, LOG_INFO,
     1256        LOG(VB_SCHEDULE, LOG_DEBUG,
    12411257            "? = retry this showing, lower priority pass");
    1242         LOG(VB_SCHEDULE, LOG_INFO,
     1258        LOG(VB_SCHEDULE, LOG_DEBUG,
    12431259            "> = try another showing for this program");
    1244         LOG(VB_SCHEDULE, LOG_INFO,
     1260        LOG(VB_SCHEDULE, LOG_DEBUG,
    12451261            "% = found another showing, same priority required");
    1246         LOG(VB_SCHEDULE, LOG_INFO,
     1262        LOG(VB_SCHEDULE, LOG_DEBUG,
    12471263            "$ = found another showing, lower priority allowed");
    1248         LOG(VB_SCHEDULE, LOG_INFO,
     1264        LOG(VB_SCHEDULE, LOG_DEBUG,
    12491265            "- = unschedule a showing in favor of another one");
    12501266    }
    12511267
    void Scheduler::GetAllScheduled(QStringList &strList)  
    16131629    }
    16141630}
    16151631
    1616 void Scheduler::Reschedule(int recordid)
     1632void Scheduler::Reschedule(const QStringList &request)
    16171633{
    16181634    QMutexLocker locker(&schedLock);
    1619 
    1620     if (recordid == -1)
    1621         reschedQueue.clear();
    1622 
    1623     if (recordid != 0 || reschedQueue.empty())
    1624         reschedQueue.enqueue(recordid);
    1625 
     1635    reschedQueue.enqueue(request);
    16261636    reschedWait.wakeOne();
    16271637}
    16281638
    void Scheduler::AddRecording(const RecordingInfo &pi)  
    16611671    new_pi->GetRecordingRule();
    16621672
    16631673    // Trigger reschedule..
    1664     reschedQueue.enqueue(pi.GetRecordingRuleID());
     1674    EnqueueMatch(pi.GetRecordingRuleID(), 0, 0, QDateTime(),
     1675                 QString("AddRecording %1").arg(pi.GetTitle()));
    16651676    reschedWait.wakeOne();
    16661677}
    16671678
    void Scheduler::OldRecordedFixups(void)  
    17431754    // during normal processing.
    17441755    query.prepare("UPDATE oldrecorded SET future = 0 "
    17451756                  "WHERE future > 0 AND "
    1746                   "      endtime < (NOW() - INTERVAL 8 HOUR)");
     1757                  "      endtime < (NOW() - INTERVAL 475 MINUTE)");
    17471758    if (!query.exec())
    17481759        MythDB::DBError("UpdateFuture", query);
    17491760}
    void Scheduler::run(void)  
    17681779    QMutexLocker lockit(&schedLock);
    17691780
    17701781    reschedQueue.clear();
    1771     reschedQueue.enqueue(-1);
     1782    EnqueueMatch(0, 0, 0, QDateTime(), "SchedulerInit");
    17721783
    17731784    int       prerollseconds  = 0;
    17741785    int       wakeThreshold   = 300;
    int Scheduler::CalcTimeToNextHandleRecordingEvent(  
    19922003    return min(msecs, max_sleep);
    19932004}
    19942005
     2006void Scheduler::ResetDuplicates(uint recordid, uint findid,
     2007                                const QString &title, const QString &subtitle,
     2008                                const QString &descrip,
     2009                                const QString &programid)
     2010{
     2011    MSqlQuery query(dbConn);
     2012    QString filterClause;
     2013    MSqlBindings bindings;
     2014
     2015    // "**any**" is special value set in ProgLister::DeleteOldSeries()
     2016    if (programid != "**any**")
     2017    {
     2018        filterClause = "AND (0 ";
     2019        if (!subtitle.isEmpty())
     2020        {
     2021            // Need to check both for kDupCheckSubThenDesc
     2022            filterClause += "OR p.subtitle = :SUBTITLE "
     2023                            "OR p.description = :SUBTITLE ";
     2024            bindings[":SUBTITLE"] = subtitle;
     2025        }
     2026        if (!descrip.isEmpty())
     2027        {
     2028            // Need to check both for kDupCheckSubThenDesc
     2029            filterClause += "OR p.description = :DESCRIP "
     2030                            "OR p.subtitle = :DESCRIP ";
     2031            bindings[":DESCRIP"] = descrip;
     2032        }
     2033        if (!programid.isEmpty())
     2034        {
     2035            filterClause += "OR p.programid = :PROGRAMID ";
     2036            bindings[":PROGRAMID"] = programid;
     2037        }
     2038        filterClause += ") ";
     2039    }
     2040
     2041    query.prepare(QString("UPDATE recordmatch rm "
     2042                          "INNER JOIN %1 r "
     2043                          "      ON rm.recordid = r.recordid "
     2044                          "INNER JOIN program p "
     2045                          "      ON rm.chanid = p.chanid "
     2046                          "         AND rm.starttime = p.starttime "
     2047                          "         AND rm.manualid = p.manualid "
     2048                          "SET oldrecduplicate = -1 "
     2049                          "WHERE p.title = :TITLE"
     2050                          "      AND p.generic = 0 "
     2051                          "      AND r.type NOT IN (%2, %3, %4) ")
     2052                  .arg(recordTable)
     2053                  .arg(kSingleRecord)
     2054                  .arg(kOverrideRecord)
     2055                  .arg(kDontRecord)
     2056                  + filterClause);
     2057    query.bindValue(":TITLE", title);
     2058    MSqlBindings::const_iterator it;
     2059    for (it = bindings.begin(); it != bindings.end(); ++it)
     2060        query.bindValue(it.key(), it.value());
     2061    if (!query.exec())
     2062        MythDB::DBError("ResetDuplicates1", query);
     2063
     2064    if (findid && programid != "**any**")
     2065    {
     2066        query.prepare("UPDATE recordmatch rm "
     2067                      "SET oldrecduplicate = -1 "
     2068                      "WHERE rm.recordid = :RECORDID "
     2069                      "      AND rm.findid = :FINDID");
     2070        query.bindValue("RECORDID", recordid);
     2071        query.bindValue("FINDID", findid);
     2072        if (!query.exec())
     2073            MythDB::DBError("ResetDuplicates2", query);
     2074    }
     2075 }
     2076
    19952077bool Scheduler::HandleReschedule(void)
    19962078{
    19972079    // We might have been inactive for a long time, so make
    19982080    // sure our DB connection is fresh before continuing.
    19992081    dbConn = MSqlQuery::SchedCon();
    20002082
    2001     struct timeval fillstart;
     2083    struct timeval fillstart, fillend;
     2084    float matchTime, checkTime, placeTime;
     2085
    20022086    gettimeofday(&fillstart, NULL);
    20032087    QString msg;
    20042088    bool deleteFuture = false;
     2089    bool runCheck = false;
    20052090
    20062091    while (!reschedQueue.empty())
    20072092    {
    2008         int recordid = reschedQueue.dequeue();
     2093        QStringList request = reschedQueue.dequeue();
     2094        QStringList tokens;
     2095        if (request.size() >= 1)
     2096            tokens = request[0].split(' ', QString::SkipEmptyParts);
    20092097
    2010         LOG(VB_GENERAL, LOG_INFO, QString("Reschedule requested for id %1.")
    2011                 .arg(recordid));
     2098        if (request.size() < 1 || tokens.size() < 1)
     2099        {
     2100            LOG(VB_GENERAL, LOG_ERR, "Empty Reschedule request received");
     2101            return false;
     2102        }
    20122103
    2013         if (recordid != 0)
     2104        LOG(VB_GENERAL, LOG_INFO, QString("Reschedule requested for %1 %2")
     2105            .arg(request[0]).arg((request.size() > 1) ? request[1] : ""));
     2106
     2107        if (tokens[0] == "MATCH")
    20142108        {
    2015             if (recordid == -1)
    2016                 reschedQueue.clear();
     2109            if (tokens.size() < 5)
     2110            {
     2111                LOG(VB_GENERAL, LOG_ERR,
     2112                    QString("Invalid RescheduleMatch request received (%1)")
     2113                    .arg(request[0]));
     2114                continue;
     2115            }
    20172116
     2117            uint recordid = tokens[1].toUInt();
     2118            uint sourceid = tokens[2].toUInt();
     2119            uint mplexid = tokens[3].toUInt();
     2120            QDateTime maxstarttime =
     2121                QDateTime::fromString(tokens[4], Qt::ISODate);
    20182122            deleteFuture = true;
     2123            runCheck = true;
    20192124            schedLock.unlock();
    20202125            recordmatchLock.lock();
    2021             UpdateMatches(recordid);
     2126            UpdateMatches(recordid, sourceid, mplexid, maxstarttime);
    20222127            recordmatchLock.unlock();
    20232128            schedLock.lock();
    20242129        }
     2130        else if (tokens[0] == "CHECK")
     2131        {
     2132            if (tokens.size() < 4 || request.size() < 5)
     2133            {
     2134                LOG(VB_GENERAL, LOG_ERR,
     2135                    QString("Invalid RescheduleCheck request received (%1)")
     2136                    .arg(request[0]));
     2137                continue;
     2138            }
     2139
     2140            uint recordid = tokens[2].toUInt();
     2141            uint findid = tokens[3].toUInt();
     2142            QString title = request[1];
     2143            QString subtitle = request[2];
     2144            QString descrip = request[3];
     2145            QString programid = request[4];
     2146            runCheck = true;
     2147            schedLock.unlock();
     2148            recordmatchLock.lock();
     2149            ResetDuplicates(recordid, findid, title, subtitle, descrip,
     2150                            programid);
     2151            recordmatchLock.unlock();
     2152            schedLock.lock();
     2153        }
     2154        else if (tokens[0] != "PLACE")
     2155        {
     2156            LOG(VB_GENERAL, LOG_ERR,
     2157                QString("Unknown Reschedule request received (%1)")
     2158                .arg(request[0]));
     2159        }
    20252160    }
    20262161
    20272162    // Delete future oldrecorded entries that no longer
    bool Scheduler::HandleReschedule(void)  
    20392174            MythDB::DBError("DeleteFuture", query);
    20402175    }
    20412176
    2042     struct timeval fillend;
    20432177    gettimeofday(&fillend, NULL);
     2178    matchTime = ((fillend.tv_sec - fillstart.tv_sec ) * 1000000 +
     2179                 (fillend.tv_usec - fillstart.tv_usec)) / 1000000.0;
    20442180
    2045     float matchTime = ((fillend.tv_sec - fillstart.tv_sec ) * 1000000 +
    2046                        (fillend.tv_usec - fillstart.tv_usec)) / 1000000.0;
     2181    LOG(VB_SCHEDULE, LOG_INFO, "CreateTempTables...");
     2182    CreateTempTables();
     2183
     2184    gettimeofday(&fillstart, NULL);
     2185    if (runCheck)
     2186    {
     2187        LOG(VB_SCHEDULE, LOG_INFO, "UpdateDuplicates...");
     2188        UpdateDuplicates();
     2189    }
     2190    gettimeofday(&fillend, NULL);
     2191    checkTime = ((fillend.tv_sec - fillstart.tv_sec ) * 1000000 +
     2192                 (fillend.tv_usec - fillstart.tv_usec)) / 1000000.0;
    20472193
    20482194    gettimeofday(&fillstart, NULL);
    20492195    bool worklistused = FillRecordList();
    20502196    gettimeofday(&fillend, NULL);
     2197    placeTime = ((fillend.tv_sec - fillstart.tv_sec ) * 1000000 +
     2198                 (fillend.tv_usec - fillstart.tv_usec)) / 1000000.0;
     2199
     2200    LOG(VB_SCHEDULE, LOG_INFO, "DeleteTempTables...");
     2201    DeleteTempTables();
     2202
    20512203    if (worklistused)
    20522204    {
    20532205        UpdateNextRecord();
    bool Scheduler::HandleReschedule(void)  
    20562208    else
    20572209    {
    20582210        LOG(VB_GENERAL, LOG_INFO, "Reschedule interrupted, will retry");
    2059         reschedQueue.enqueue(0);
     2211        EnqueuePlace("Interrupted");
    20602212        return false;
    20612213    }
    20622214
    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);
     2215    msg.sprintf("Scheduled %d items in %.1f "
     2216                "= %.2f match + %.2f check + %.2f place",
     2217                (int)reclist.size(), matchTime + checkTime + placeTime,
     2218                matchTime, checkTime, placeTime);
    20692219    LOG(VB_GENERAL, LOG_INFO, msg);
    20702220
    20712221    fsInfoCacheFillTime = QDateTime::currentDateTime().addSecs(-1000);
    void Scheduler::HandleWakeSlave(RecordingInfo &ri, int prerollseconds)  
    22162366                .arg(nexttv->GetHostName()).arg(ri.GetTitle()));
    22172367
    22182368        if (!WakeUpSlave(nexttv->GetHostName()))
    2219             reschedQueue.enqueue(0);
     2369            EnqueuePlace("HandleWakeSlave1");
    22202370    }
    22212371    else if ((nexttv->IsWaking()) &&
    22222372             ((secsleft - prerollseconds) < 210) &&
    void Scheduler::HandleWakeSlave(RecordingInfo &ri, int prerollseconds)  
    22292379                .arg(nexttv->GetHostName()));
    22302380
    22312381        if (!WakeUpSlave(nexttv->GetHostName(), false))
    2232             reschedQueue.enqueue(0);
     2382            EnqueuePlace("HandleWakeSlave2");
    22332383    }
    22342384    else if ((nexttv->IsWaking()) &&
    22352385             ((secsleft - prerollseconds) < 150) &&
    void Scheduler::HandleWakeSlave(RecordingInfo &ri, int prerollseconds)  
    22492399                (*it)->SetSleepStatus(sStatus_Undefined);
    22502400        }
    22512401
    2252         reschedQueue.enqueue(0);
     2402        EnqueuePlace("HandleWakeSlave3");
    22532403    }
    22542404}
    22552405
    bool Scheduler::HandleRecording(  
    22872437            livetvTime = (livetvTime < nextrectime) ?
    22882438                nextrectime : livetvTime;
    22892439
    2290             reschedQueue.enqueue(0);
     2440            EnqueuePlace("PrepareToRecord");
    22912441        }
    22922442    }
    22932443
    bool Scheduler::HandleRecording(  
    23702520                    enc->SetSleepStatus(sStatus_Undefined);
    23712521            }
    23722522
    2373             reschedQueue.enqueue(0);
     2523            EnqueuePlace("SlaveNotAwake");
    23742524        }
    23752525
    23762526        return false;
    void Scheduler::WakeUpSlaves(void)  
    30293179    }
    30303180}
    30313181
    3032 void Scheduler::UpdateManuals(int recordid)
     3182void Scheduler::UpdateManuals(uint recordid)
    30333183{
    30343184    MSqlQuery query(dbConn);
    30353185
    void Scheduler::UpdateManuals(int recordid)  
    31083258            if (weekday && startdt.date().dayOfWeek() >= 6)
    31093259                continue;
    31103260
    3111             query.prepare("REPLACE INTO program (chanid,starttime,endtime,"
    3112                           " title,subtitle,manualid) "
    3113                           "VALUES (:CHANID,:STARTTIME,:ENDTIME,:TITLE,"
    3114                           " :SUBTITLE,:RECORDID)");
     3261            query.prepare("REPLACE INTO program (chanid, starttime, endtime,"
     3262                          " title, subtitle, manualid, generic) "
     3263                          "VALUES (:CHANID, :STARTTIME, :ENDTIME, :TITLE,"
     3264                          " :SUBTITLE, :RECORDID, 1)");
    31153265            query.bindValue(":CHANID", chanidlist[i]);
    31163266            query.bindValue(":STARTTIME", startdt);
    31173267            query.bindValue(":ENDTIME", startdt.addSecs(duration * 60));
    void Scheduler::UpdateManuals(int recordid)  
    31283278    }
    31293279}
    31303280
    3131 void Scheduler::BuildNewRecordsQueries(int recordid, QStringList &from,
     3281void Scheduler::BuildNewRecordsQueries(uint recordid, QStringList &from,
    31323282                                       QStringList &where,
    31333283                                       MSqlBindings &bindings)
    31343284{
    void Scheduler::BuildNewRecordsQueries(int recordid, QStringList &from,  
    31383288
    31393289    query = QString("SELECT recordid,search,subtitle,description "
    31403290                    "FROM %1 WHERE search <> %2 AND "
    3141                     "(recordid = %3 OR %4 = -1) ")
     3291                    "(recordid = %3 OR %4 = 0) ")
    31423292        .arg(recordTable).arg(kNoSearch).arg(recordid).arg(recordid);
    31433293
    31443294    result.prepare(query);
    void Scheduler::BuildNewRecordsQueries(int recordid, QStringList &from,  
    32313381        count++;
    32323382    }
    32333383
    3234     if (recordid == -1 || from.count() == 0)
     3384    if (recordid == 0 || from.count() == 0)
    32353385    {
    32363386        QString recidmatch = "";
    3237         if (recordid != -1)
     3387        if (recordid != 0)
    32383388            recidmatch = "RECTABLE.recordid = :NRRECORDID AND ";
    32393389        QString s1 = recidmatch +
    32403390            "RECTABLE.search = :NRST AND "
    void Scheduler::BuildNewRecordsQueries(int recordid, QStringList &from,  
    32533403        from << "";
    32543404        where << s2;
    32553405        bindings[":NRST"] = kNoSearch;
    3256         if (recordid != -1)
     3406        if (recordid != 0)
    32573407            bindings[":NRRECORDID"] = recordid;
    32583408    }
    32593409}
    32603410
    3261 void Scheduler::UpdateMatches(int recordid) {
    3262     struct timeval dbstart, dbend;
     3411static QString progdupinit = QString(
     3412"(CASE "
     3413"  WHEN RECTABLE.type IN (%1, %2, %3) THEN  0 "
     3414"  WHEN RECTABLE.type IN (%4, %5, %6) THEN  -1 "
     3415"  ELSE (program.generic - 1) "
     3416" END) ")
     3417    .arg(kSingleRecord).arg(kOverrideRecord).arg(kDontRecord)
     3418    .arg(kFindOneRecord).arg(kFindDailyRecord).arg(kFindWeeklyRecord);
    32633419
    3264     if (recordid == 0)
    3265         return;
     3420static QString progfindid = QString(
     3421"(CASE RECTABLE.type "
     3422"  WHEN %1 "
     3423"   THEN RECTABLE.findid "
     3424"  WHEN %2 "
     3425"   THEN to_days(date_sub(program.starttime, interval "
     3426"                time_format(RECTABLE.findtime, '%H:%i') hour_minute)) "
     3427"  WHEN %3 "
     3428"   THEN floor((to_days(date_sub(program.starttime, interval "
     3429"               time_format(RECTABLE.findtime, '%H:%i') hour_minute)) - "
     3430"               RECTABLE.findday)/7) * 7 + RECTABLE.findday "
     3431"  WHEN %4 "
     3432"   THEN RECTABLE.findid "
     3433"  ELSE 0 "
     3434" END) ")
     3435        .arg(kFindOneRecord)
     3436        .arg(kFindDailyRecord)
     3437        .arg(kFindWeeklyRecord)
     3438        .arg(kOverrideRecord);
     3439
     3440void Scheduler::UpdateMatches(uint recordid, uint sourceid, uint mplexid,
     3441                              const QDateTime maxstarttime)
     3442{
     3443    struct timeval dbstart, dbend;
    32663444
    32673445    MSqlQuery query(dbConn);
     3446    MSqlBindings bindings;
     3447    QString deleteClause;
     3448    QString filterClause = QString(" AND program.endtime > "
     3449                                   "(NOW() - INTERVAL 480 MINUTE)");
    32683450
    3269     if (recordid == -1)
    3270         query.prepare("DELETE FROM recordmatch");
    3271     else
     3451    if (recordid)
    32723452    {
    3273         query.prepare("DELETE FROM recordmatch WHERE recordid = :RECORDID");
    3274         query.bindValue(":RECORDID", recordid);
     3453        deleteClause += " AND recordmatch.recordid = :RECORDID";
     3454        bindings[":RECORDID"] = recordid;
    32753455    }
    3276 
    3277     if (!query.exec())
     3456    if (sourceid)
    32783457    {
    3279         MythDB::DBError("UpdateMatches", query);
    3280         return;
     3458        deleteClause += " AND channel.sourceid = :SOURCEID";
     3459        filterClause += " AND channel.sourceid = :SOURCEID";
     3460        bindings[":SOURCEID"] = sourceid;
    32813461    }
    3282 
    3283     if (recordid == -1)
    3284         query.prepare("DELETE FROM program WHERE manualid <> 0");
    3285     else
     3462    if (mplexid)
     3463    {
     3464        deleteClause += " AND channel.mplexid = :MPLEXID";
     3465        filterClause += " AND channel.mplexid = :MPLEXID";
     3466        bindings[":MPLEXID"] = mplexid;
     3467    }
     3468    if (maxstarttime.isValid())
    32863469    {
    3287         query.prepare("DELETE FROM program WHERE manualid = :RECORDID");
    3288         query.bindValue(":RECORDID", recordid);
     3470        deleteClause += " AND recordmatch.starttime <= :MAXSTARTTIME";
     3471        filterClause += " AND program.starttime <= :MAXSTARTTIME";
     3472        bindings[":MAXSTARTTIME"] = maxstarttime;
    32893473    }
     3474
     3475    query.prepare(QString("DELETE recordmatch FROM recordmatch, channel "
     3476                          "WHERE recordmatch.chanid = channel.chanid")
     3477                  + deleteClause);
     3478    MSqlBindings::const_iterator it;
     3479    for (it = bindings.begin(); it != bindings.end(); ++it)
     3480        query.bindValue(it.key(), it.value());
    32903481    if (!query.exec())
    32913482    {
    3292         MythDB::DBError("UpdateMatches", query);
     3483        MythDB::DBError("UpdateMatches1", query);
    32933484        return;
    32943485    }
     3486    if (recordid)
     3487        bindings.remove(":RECORDID");
    32953488
    3296     QString filterClause;
    32973489    query.prepare("SELECT filterid, clause FROM recordfilter "
    32983490                  "WHERE filterid >= 0 AND filterid < :NUMFILTERS AND "
    32993491                  "      TRIM(clause) <> ''");
    33003492    query.bindValue(":NUMFILTERS", RecordingRule::kNumFilters);
    33013493    if (!query.exec())
    33023494    {
    3303         MythDB::DBError("UpdateMatches", query);
     3495        MythDB::DBError("UpdateMatches2", query);
    33043496        return;
    33053497    }
    33063498    while (query.next())
    void Scheduler::UpdateMatches(int recordid) {  
    33153507    query.bindValue(":FINDONE", kFindOneRecord);
    33163508    if (!query.exec())
    33173509    {
    3318         MythDB::DBError("UpdateMatches", query);
     3510        MythDB::DBError("UpdateMatches3", query);
    33193511        return;
    33203512    }
    33213513    else if (query.size())
    void Scheduler::UpdateMatches(int recordid) {  
    33273519        query.bindValue(":FINDID", findtoday);
    33283520        query.bindValue(":FINDONE", kFindOneRecord);
    33293521        if (!query.exec())
    3330             MythDB::DBError("UpdateMatches", query);
     3522            MythDB::DBError("UpdateMatches4", query);
    33313523    }
    33323524
    33333525    int clause;
    33343526    QStringList fromclauses, whereclauses;
    3335     MSqlBindings bindings;
    33363527
    33373528    BuildNewRecordsQueries(recordid, fromclauses, whereclauses, bindings);
    33383529
    void Scheduler::UpdateMatches(int recordid) {  
    33493540    for (clause = 0; clause < fromclauses.count(); ++clause)
    33503541    {
    33513542        QString query = QString(
    3352 "REPLACE INTO recordmatch (recordid, chanid, starttime, manualid) "
     3543"REPLACE INTO recordmatch (recordid, chanid, starttime, manualid, "
     3544"                          oldrecduplicate, findid) "
    33533545"SELECT RECTABLE.recordid, program.chanid, program.starttime, "
    3354 " IF(search = %1, RECTABLE.recordid, 0) ").arg(kManualSearch) + QString(
     3546" IF(search = %1, RECTABLE.recordid, 0), ").arg(kManualSearch) +
     3547            progdupinit + ", " + progfindid + QString(
    33553548"FROM (RECTABLE, program INNER JOIN channel "
    33563549"      ON channel.chanid = program.chanid) ") + fromclauses[clause] + QString(
    33573550" WHERE ") + whereclauses[clause] +
    void Scheduler::UpdateMatches(int recordid) {  
    33953588            .arg(kWeekslotRecord)
    33963589            .arg(kNotRecording);
    33973590
    3398         while (1)
    3399         {
    3400             int i = query.indexOf("RECTABLE");
    3401             if (i == -1) break;
    3402             query = query.replace(i, strlen("RECTABLE"), recordTable);
    3403         }
     3591        query.replace("RECTABLE", recordTable);
    34043592
    34053593        LOG(VB_SCHEDULE, LOG_INFO, QString(" |-- Start DB Query %1...")
    34063594                .arg(clause));
    void Scheduler::UpdateMatches(int recordid) {  
    34093597        MSqlQuery result(dbConn);
    34103598        result.prepare(query);
    34113599
    3412         MSqlBindings::const_iterator it;
    34133600        for (it = bindings.begin(); it != bindings.end(); ++it)
    34143601        {
    34153602            if (query.contains(it.key()))
    void Scheduler::UpdateMatches(int recordid) {  
    34353622    LOG(VB_SCHEDULE, LOG_INFO, " +-- Done.");
    34363623}
    34373624
     3625void Scheduler::CreateTempTables(void)
     3626{
     3627    MSqlQuery result(dbConn);
     3628
     3629    if (recordTable == "record")
     3630    {
     3631        result.prepare("DROP TABLE IF EXISTS sched_temp_record;");
     3632        if (!result.exec())
     3633        {
     3634            MythDB::DBError("Dropping sched_temp_record table", result);
     3635            return;
     3636        }
     3637        result.prepare("CREATE TEMPORARY TABLE sched_temp_record "
     3638                           "LIKE record;");
     3639        if (!result.exec())
     3640        {
     3641            MythDB::DBError("Creating sched_temp_record table", result);
     3642            return;
     3643        }
     3644        result.prepare("INSERT sched_temp_record SELECT * from record;");
     3645        if (!result.exec())
     3646        {
     3647            MythDB::DBError("Populating sched_temp_record table", result);
     3648            return;
     3649        }
     3650    }
     3651
     3652    result.prepare("DROP TABLE IF EXISTS sched_temp_recorded;");
     3653    if (!result.exec())
     3654    {
     3655        MythDB::DBError("Dropping sched_temp_recorded table", result);
     3656        return;
     3657    }
     3658    result.prepare("CREATE TEMPORARY TABLE sched_temp_recorded "
     3659                       "LIKE recorded;");
     3660    if (!result.exec())
     3661    {
     3662        MythDB::DBError("Creating sched_temp_recorded table", result);
     3663        return;
     3664    }
     3665    result.prepare("INSERT sched_temp_recorded SELECT * from recorded;");
     3666    if (!result.exec())
     3667    {
     3668        MythDB::DBError("Populating sched_temp_recorded table", result);
     3669        return;
     3670    }
     3671}
     3672
     3673void Scheduler::DeleteTempTables(void)
     3674{
     3675    MSqlQuery result(dbConn);
     3676
     3677    if (recordTable == "record")
     3678    {
     3679        result.prepare("DROP TABLE IF EXISTS sched_temp_record;");
     3680        if (!result.exec())
     3681            MythDB::DBError("DeleteTempTables sched_temp_record", result);
     3682    }
     3683
     3684    result.prepare("DROP TABLE IF EXISTS sched_temp_recorded;");
     3685    if (!result.exec())
     3686        MythDB::DBError("DeleteTempTables drop table", result);
     3687}
     3688
     3689void Scheduler::UpdateDuplicates(void)
     3690{
     3691    QString schedTmpRecord = recordTable;
     3692    if (schedTmpRecord == "record")
     3693        schedTmpRecord = "sched_temp_record";
     3694
     3695    QString rmquery = QString(
     3696"UPDATE recordmatch "
     3697" INNER JOIN RECTABLE ON (recordmatch.recordid = RECTABLE.recordid) "
     3698" INNER JOIN program p ON (recordmatch.chanid = p.chanid AND "
     3699"                          recordmatch.starttime = p.starttime AND "
     3700"                          recordmatch.manualid = p.manualid) "
     3701" LEFT JOIN oldrecorded ON "
     3702"  ( "
     3703"    RECTABLE.dupmethod > 1 AND "
     3704"    oldrecorded.duplicate <> 0 AND "
     3705"    p.title = oldrecorded.title AND "
     3706"    p.generic = 0 "
     3707"     AND "
     3708"     ( "
     3709"      (p.programid <> '' "
     3710"       AND p.programid = oldrecorded.programid) "
     3711"      OR "
     3712"      ( ") +
     3713        (ProgramInfo::UsingProgramIDAuthority() ?
     3714"       (p.programid = '' OR oldrecorded.programid = '' OR "
     3715"         LEFT(p.programid, LOCATE('/', p.programid)) <> "
     3716"         LEFT(oldrecorded.programid, LOCATE('/', oldrecorded.programid))) " :
     3717"       (p.programid = '' OR oldrecorded.programid = '') " )
     3718        + QString(
     3719"       AND "
     3720"       (((RECTABLE.dupmethod & 0x02) = 0) OR (p.subtitle <> '' "
     3721"          AND p.subtitle = oldrecorded.subtitle)) "
     3722"       AND "
     3723"       (((RECTABLE.dupmethod & 0x04) = 0) OR (p.description <> '' "
     3724"          AND p.description = oldrecorded.description)) "
     3725"       AND "
     3726"       (((RECTABLE.dupmethod & 0x08) = 0) OR "
     3727"          (p.subtitle <> '' AND "
     3728"             (p.subtitle = oldrecorded.subtitle OR "
     3729"              (oldrecorded.subtitle = '' AND "
     3730"               p.subtitle = oldrecorded.description))) OR "
     3731"          (p.subtitle = '' AND p.description <> '' AND "
     3732"             (p.description = oldrecorded.subtitle OR "
     3733"              (oldrecorded.subtitle = '' AND "
     3734"               p.description = oldrecorded.description)))) "
     3735"      ) "
     3736"     ) "
     3737"  ) "
     3738" LEFT JOIN sched_temp_recorded recorded ON "
     3739"  ( "
     3740"    RECTABLE.dupmethod > 1 AND "
     3741"    recorded.duplicate <> 0 AND "
     3742"    p.title = recorded.title AND "
     3743"    p.generic = 0 AND "
     3744"    recorded.recgroup NOT IN ('LiveTV','Deleted') "
     3745"     AND "
     3746"     ( "
     3747"      (p.programid <> '' "
     3748"       AND p.programid = recorded.programid) "
     3749"      OR "
     3750"      ( ") +
     3751        (ProgramInfo::UsingProgramIDAuthority() ?
     3752"       (p.programid = '' OR recorded.programid = '' OR "
     3753"         LEFT(p.programid, LOCATE('/', p.programid)) <> "
     3754"         LEFT(recorded.programid, LOCATE('/', recorded.programid))) " :
     3755"       (p.programid = '' OR recorded.programid = '') ")
     3756        + QString(
     3757"       AND "
     3758"       (((RECTABLE.dupmethod & 0x02) = 0) OR (p.subtitle <> '' "
     3759"          AND p.subtitle = recorded.subtitle)) "
     3760"       AND "
     3761"       (((RECTABLE.dupmethod & 0x04) = 0) OR (p.description <> '' "
     3762"          AND p.description = recorded.description)) "
     3763"       AND "
     3764"       (((RECTABLE.dupmethod & 0x08) = 0) OR "
     3765"          (p.subtitle <> '' AND "
     3766"             (p.subtitle = recorded.subtitle OR "
     3767"              (recorded.subtitle = '' AND "
     3768"               p.subtitle = recorded.description))) OR "
     3769"          (p.subtitle = '' AND p.description <> '' AND "
     3770"             (p.description = recorded.subtitle OR "
     3771"              (recorded.subtitle = '' AND "
     3772"               p.description = recorded.description)))) "
     3773"      ) "
     3774"     ) "
     3775"  ) "
     3776" LEFT JOIN oldfind ON "
     3777"  (oldfind.recordid = recordmatch.recordid AND "
     3778"   oldfind.findid = recordmatch.findid) "
     3779" SET oldrecduplicate = (oldrecorded.endtime IS NOT NULL), "
     3780"     recduplicate = (recorded.endtime IS NOT NULL), "
     3781"     findduplicate = (oldfind.findid IS NOT NULL), "
     3782"     oldrecstatus = oldrecorded.recstatus "
     3783" WHERE p.endtime >= (NOW() - INTERVAL 480 MINUTE) "
     3784"       AND oldrecduplicate = -1 "
     3785);
     3786    rmquery.replace("RECTABLE", schedTmpRecord);
     3787
     3788    MSqlQuery result(dbConn);
     3789    result.prepare(rmquery);
     3790    if (!result.exec())
     3791    {
     3792        MythDB::DBError("UpdateDuplicates", result);
     3793        return;
     3794    }
     3795}
     3796
    34383797void Scheduler::AddNewRecords(void)
    34393798{
     3799    QString schedTmpRecord = recordTable;
     3800    if (schedTmpRecord == "record")
     3801        schedTmpRecord = "sched_temp_record";
     3802
    34403803    struct timeval dbstart, dbend;
    34413804
    34423805    QMap<RecordingType, int> recTypeRecPriorityMap;
    void Scheduler::AddNewRecords(void)  
    34563819    schedAfterStartMap.clear();
    34573820
    34583821    MSqlQuery rlist(dbConn);
    3459     rlist.prepare(QString("SELECT recordid,title,maxepisodes,maxnewest FROM %1;").arg(recordTable));
     3822    rlist.prepare(QString("SELECT recordid, title, maxepisodes, maxnewest "
     3823                          "FROM %1").arg(schedTmpRecord));
    34603824
    34613825    if (!rlist.exec())
    34623826    {
    void Scheduler::AddNewRecords(void)  
    35473911        pwrpri += QString(" + "
    35483912        "(FIND_IN_SET('VISUALIMPAIR', program.audioprop) > 0) * %1").arg(adpriority);
    35493913
    3550     QString schedTmpRecord = recordTable;
    3551 
    35523914    MSqlQuery result(dbConn);
    35533915
    3554     if (schedTmpRecord == "record")
    3555     {
    3556         schedTmpRecord = "sched_temp_record";
    3557 
    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     }
    3610 
    36113916    result.prepare(QString("SELECT recpriority, selectclause FROM %1;")
    36123917                           .arg(priorityTable));
    36133918
    void Scheduler::AddNewRecords(void)  
    36303935    }
    36313936    pwrpri += QString(" AS powerpriority ");
    36323937
    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 
    37453938    pwrpri.replace("program.","p.");
    37463939    pwrpri.replace("channel.","c.");
    3747     progfindid.replace("program.","p.");
    3748     progfindid.replace("channel.","c.");
    37493940    QString query = QString(
    37503941        "SELECT "
    37513942        "    c.chanid,         c.sourceid,           p.starttime,       "// 0-2
    void Scheduler::AddNewRecords(void)  
    37633954        "    capturecard.cardid, cardinput.cardinputid,p.seriesid,      "//24-26
    37643955        "    p.programid,       RECTABLE.inetref,    p.category_type,   "//27-29
    37653956        "    p.airdate,         p.stars,             p.originalairdate, "//30-32
    3766         "    RECTABLE.inactive, RECTABLE.parentid,") + progfindid + ", "//33-35
     3957        "    RECTABLE.inactive, RECTABLE.parentid,   recordmatch.findid, "//33-35
    37673958        "    RECTABLE.playgroup, oldrecstatus.recstatus, "//36-37
    37683959        "    oldrecstatus.reactivate, p.videoprop+0,     "//38-39
    37693960        "    p.subtitletypes+0, p.audioprop+0,   RECTABLE.storagegroup, "//40-42
    37703961        "    capturecard.hostname, recordmatch.oldrecstatus, "
    37713962        "                                           RECTABLE.avg_delay, "//43-45
    3772         "    oldrecstatus.future, cardinput.schedorder, "                //46-47
    3773         + pwrpri + QString(
     3963        "    oldrecstatus.future, cardinput.schedorder, ") +             //46-47
     3964        pwrpri + QString(
    37743965        "FROM recordmatch "
    37753966        "INNER JOIN RECTABLE ON (recordmatch.recordid = RECTABLE.recordid) "
    37763967        "INNER JOIN program AS p "
    void Scheduler::AddNewRecords(void)  
    37853976        "ON ( oldrecstatus.station   = c.callsign  AND "
    37863977        "     oldrecstatus.starttime = p.starttime AND "
    37873978        "     oldrecstatus.title     = p.title ) "
    3788         "WHERE p.endtime >= NOW() - INTERVAL 1 DAY "
    3789         "ORDER BY RECTABLE.recordid DESC ");
     3979        "WHERE p.endtime > (NOW() - INTERVAL 480 MINUTE) "
     3980        "ORDER BY RECTABLE.recordid DESC, p.starttime, p.title, c.callsign, "
     3981        "         c.channum ");
    37903982    query.replace("RECTABLE", schedTmpRecord);
    37913983
    37923984    LOG(VB_SCHEDULE, LOG_INFO, QString(" |-- Start DB Query..."));
    37933985
    37943986    gettimeofday(&dbstart, NULL);
    3795     result.prepare(rmquery);
    3796     if (!result.exec())
    3797     {
    3798         MythDB::DBError("AddNewRecords recordmatch", result);
    3799         return;
    3800     }
    38013987    result.prepare(query);
    38023988    if (!result.exec())
    38033989    {
    void Scheduler::AddNewRecords(void)  
    38123998            .arg(((dbend.tv_sec  - dbstart.tv_sec) * 1000000 +
    38133999                  (dbend.tv_usec - dbstart.tv_usec)) / 1000000.0));
    38144000
     4001    RecordingInfo *lastp = NULL;
     4002
    38154003    while (result.next())
    38164004    {
     4005        // If this is the same program we saw in the last pass and it
     4006        // wasn't a viable candidate, then neither is this one so
     4007        // don't bother with it.  This is essentially an early call to
     4008        // PruneRedundants().
     4009        uint recordid = result.value(17).toUInt();
     4010        QDateTime startts = result.value(2).toDateTime();
     4011        QString title = result.value(4).toString();
     4012        QString callsign = result.value(8).toString();
     4013        if (lastp && lastp->GetRecordingStatus() != rsUnknown
     4014            && recordid == lastp->GetRecordingRuleID()
     4015            && startts == lastp->GetScheduledStartTime()
     4016            && title == lastp->GetTitle()
     4017            && callsign == lastp->GetChannelSchedulingID())
     4018            continue;
     4019
    38174020        RecordingInfo *p = new RecordingInfo(
    3818             result.value(4).toString(),//title
     4021            title,
    38194022            result.value(5).toString(),//subtitle
    38204023            result.value(6).toString(),//description
    38214024            0, // season
    void Scheduler::AddNewRecords(void)  
    38244027
    38254028            result.value(0).toUInt(),//chanid
    38264029            result.value(7).toString(),//channum
    3827             result.value(8).toString(),//chansign
     4030            callsign,
    38284031            result.value(9).toString(),//channame
    38294032
    38304033            result.value(21).toString(),//recgroup
    void Scheduler::AddNewRecords(void)  
    38424045
    38434046            result.value(12).toInt(),//recpriority
    38444047
    3845             result.value(2).toDateTime(),//startts
     4048            startts,
    38464049            result.value(3).toDateTime(),//endts
    38474050            result.value(18).toDateTime(),//recstartts
    38484051            result.value(19).toDateTime(),//recendts
    void Scheduler::AddNewRecords(void)  
    38574060            RecStatusType(result.value(37).toInt()),//oldrecstatus
    38584061            result.value(38).toInt(),//reactivate
    38594062
    3860             result.value(17).toUInt(),//recordid
     4063            recordid,
    38614064            result.value(34).toUInt(),//parentid
    38624065            RecordingType(result.value(16).toInt()),//rectype
    38634066            RecordingDupInType(result.value(13).toInt()),//dupin
    void Scheduler::AddNewRecords(void)  
    39194122        if (p == NULL)
    39204123            continue;
    39214124
     4125        lastp = p;
     4126
    39224127        if (p->GetRecordingStatus() != rsUnknown)
    39234128        {
    39244129            tmpList.push_back(p);
    void Scheduler::AddNewRecords(void)  
    39894194    RecIter tmp = tmpList.begin();
    39904195    for ( ; tmp != tmpList.end(); ++tmp)
    39914196        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);
    40034197}
    40044198
    40054199void 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.", "")