Ticket #8962: 8962_0.27_v1.patch

File 8962_0.27_v1.patch, 10.0 KB (added by Jim Stichnoth, 4 years ago)

Untested backport to fixes/0.27

  • mythtv/libs/libmythtv/jobqueue.cpp

    commit b43b11ca3062086d20ee0072368e9dd3646a5faa
    Author: Jim Stichnoth <jstichnoth@mythtv.org>
    Date:   Sat Apr 25 10:04:16 2015 -0700
    
        Reduce "Watch Recordings" sluggishness by caching jobqueue state.
        
        Refs #8962, refs #7990.
        
        Currently, when navigating the Watch Recordings screen, every time the
        cursor position is moved, 4 jobqueue queries are issued for each item
        visible on the screen (the actual number being controlled by the
        theme).  These queries are done within the UI thread, which makes
        navigation noticeably sluggish on most any setup that isn't a
        moderately powerful combined frontend/backend.
        
        Ideally, any time a job's status changes (including queue addition and
        removal), we would call ProgramInfo::SendUpdateEvent() to get the
        Watch Recordings entry updated, along with any other
        ProgramInfoUpdater subscribers.  Also,
        ProgramInfo::LoadProgramFromRecorded() and LoadFromRecorded() would
        set up the necessary commflag and transcode flags in the ProgramInfo
        object.
        
        However, in the current jobqueue implementation, this is not very
        practical because of functions like:
          JobQueue::DeleteJob(int jobID)
          JobQueue::ChangeJobCmds(int jobID, int newCmds)
          JobQueue::ChangeJobFlags(int jobID, int newFlags)
          JobQueue::ChangeJobStatus(int jobID, int newStatus, QString comment)
          JobQueue::ChangeJobComment(int jobID, QString comment)
          JobQueue::ChangeJobArgs(int jobID, QString args)
          JobQueue::ChangeJobHost(int jobID, QString newHostname)
          JobQueue::CleanupOldJobsInQueue()
        where the ProgramInfo isn't readily available (though it could be
        found given another query on jobID for all but the last function).
        
        Instead, in this approach, the PlaybackBox locally caches the jobqueue
        contents, reloading every 15 seconds as needed.  The reload blocks the
        UI thread, but only for a small fraction of the time that the current
        implementation was blocking it, so it's unlikely a user pay much
        attention to this once-in-15-seconds query.
        
        This code should be removed once #7990 makes jobs more autonomous.
    
    diff --git a/mythtv/libs/libmythtv/jobqueue.cpp b/mythtv/libs/libmythtv/jobqueue.cpp
    index b465bfb..f94d73f 100644
    a b int JobQueue::GetRunningJobID(uint chanid, const QDateTime &recstartts) 
    10621062    return 0;
    10631063}
    10641064
    1065 bool JobQueue::IsJobRunning(int jobType,
    1066                             uint chanid, const QDateTime &recstartts)
     1065bool JobQueue::IsJobStatusQueued(int status)
    10671066{
    1068     int tmpStatus = GetJobStatus(jobType, chanid, recstartts);
     1067    return (status & JOB_QUEUED);
     1068}
    10691069
    1070     if ((tmpStatus != JOB_UNKNOWN) && (tmpStatus != JOB_QUEUED) &&
    1071         (!(tmpStatus & JOB_DONE)))
    1072         return true;
     1070bool JobQueue::IsJobStatusRunning(int status)
     1071{
     1072    return ((status != JOB_UNKNOWN) && (status != JOB_QUEUED) &&
     1073            (!(status & JOB_DONE)));
     1074}
    10731075
    1074     return false;
     1076bool JobQueue::IsJobRunning(int jobType,
     1077                            uint chanid, const QDateTime &recstartts)
     1078{
     1079    return IsJobStatusRunning(GetJobStatus(jobType, chanid, recstartts));
    10751080}
    10761081
    10771082bool JobQueue::IsJobRunning(int jobType, const ProgramInfo &pginfo)
    bool JobQueue::IsJobQueuedOrRunning( 
    10941099bool JobQueue::IsJobQueued(
    10951100    int jobType, uint chanid, const QDateTime &recstartts)
    10961101{
    1097     int tmpStatus = GetJobStatus(jobType, chanid, recstartts);
    1098 
    1099     if (tmpStatus & JOB_QUEUED)
    1100         return true;
    1101 
    1102     return false;
     1102    return IsJobStatusQueued(GetJobStatus(jobType, chanid, recstartts));
    11031103}
    11041104
    11051105QString JobQueue::JobText(int jobType)
  • mythtv/libs/libmythtv/jobqueue.h

    diff --git a/mythtv/libs/libmythtv/jobqueue.h b/mythtv/libs/libmythtv/jobqueue.h
    index e799912..ee7dcaa 100644
    a b class MTV_PUBLIC JobQueue : public QObject, public QRunnable 
    161161    static bool IsJobRunning(int jobType, const ProgramInfo &pginfo);
    162162    static bool IsJobQueued(int jobType,
    163163                            uint chanid, const QDateTime &recstartts);
     164    static bool IsJobStatusQueued(int status);
     165    static bool IsJobStatusRunning(int status);
    164166    static bool PauseJob(int jobID);
    165167    static bool ResumeJob(int jobID);
    166168    static bool RestartJob(int jobID);
  • mythtv/programs/mythfrontend/playbackbox.cpp

    diff --git a/mythtv/programs/mythfrontend/playbackbox.cpp b/mythtv/programs/mythfrontend/playbackbox.cpp
    index 6d69ef3..548c014 100644
    a b static QString extract_main_state(const ProgramInfo &pginfo, const TV *player) 
    288288    return state;
    289289}
    290290
    291 static QString extract_job_state(const ProgramInfo &pginfo)
     291QString PlaybackBox::extract_job_state(const ProgramInfo &pginfo)
    292292{
    293293    QString job = "default";
    294294
    295295    if (pginfo.GetRecordingStatus() == rsRecording)
    296296        job = "recording";
    297     else if (JobQueue::IsJobQueuedOrRunning(
     297    else if (m_jobQueue.IsJobQueuedOrRunning(
    298298                 JOB_TRANSCODE, pginfo.GetChanID(),
    299299                 pginfo.GetRecordingStartTime()))
    300300        job = "transcoding";
    301     else if (JobQueue::IsJobQueuedOrRunning(
     301    else if (m_jobQueue.IsJobQueuedOrRunning(
    302302                 JOB_COMMFLAG,  pginfo.GetChanID(),
    303303                 pginfo.GetRecordingStartTime()))
    304304        job = "commflagging";
    static QString extract_job_state(const ProgramInfo &pginfo) 
    307307    return job;
    308308}
    309309
    310 static QString extract_commflag_state(const ProgramInfo &pginfo)
     310QString PlaybackBox::extract_commflag_state(const ProgramInfo &pginfo)
    311311{
    312312    QString job = "default";
    313313
    314314    // commflagged can be yes, no or processing
    315     if (JobQueue::IsJobRunning(JOB_COMMFLAG, pginfo))
     315    if (m_jobQueue.IsJobRunning(JOB_COMMFLAG, pginfo.GetChanID(),
     316                                pginfo.GetRecordingStartTime()))
    316317        return "running";
    317     if (JobQueue::IsJobQueued(JOB_COMMFLAG, pginfo.GetChanID(),
    318                               pginfo.GetRecordingStartTime()))
     318    if (m_jobQueue.IsJobQueued(JOB_COMMFLAG, pginfo.GetChanID(),
     319                               pginfo.GetRecordingStartTime()))
    319320        return "queued";
    320321
    321322    return (pginfo.GetProgramFlags() & FL_COMMFLAG ? "yes" : "no");
    void HelpPopup::addItem(const QString &state, const QString &text) 
    55445545    item->DisplayState(state, "icons");
    55455546}
    55465547
     5548void PlaybackBox::PbbJobQueue::Update()
     5549{
     5550    QDateTime now = QDateTime::currentDateTime();
     5551    if (!m_lastUpdated.isValid() ||
     5552        m_lastUpdated.msecsTo(now) >= kInvalidateTimeMs)
     5553    {
     5554        QMap<int, JobQueueEntry> jobs;
     5555        JobQueue::GetJobsInQueue(jobs, JOB_LIST_ALL);
     5556        m_jobs.clear();
     5557        for (int i = 0; i < jobs.size(); ++i)
     5558        {
     5559            JobQueueEntry &entry = jobs[i];
     5560            m_jobs.insert(qMakePair(entry.chanid, entry.recstartts), entry);
     5561        }
     5562        m_lastUpdated = now;
     5563    }
     5564}
     5565
     5566bool PlaybackBox::PbbJobQueue::IsJobQueued(int jobType, uint chanid,
     5567                                           const QDateTime &recstartts)
     5568{
     5569    Update();
     5570    MapType::const_iterator iter = m_jobs.find(qMakePair(chanid, recstartts));
     5571    for (; iter != m_jobs.end(); ++iter)
     5572    {
     5573        if (iter->type == jobType)
     5574            return JobQueue::IsJobStatusQueued(iter->status);
     5575    }
     5576    return false;
     5577}
     5578
     5579bool PlaybackBox::PbbJobQueue::IsJobRunning(int jobType, uint chanid,
     5580                                            const QDateTime &recstartts)
     5581{
     5582    Update();
     5583    MapType::const_iterator iter = m_jobs.find(qMakePair(chanid, recstartts));
     5584    for (; iter != m_jobs.end(); ++iter)
     5585    {
     5586        if (iter->type == jobType)
     5587            return JobQueue::IsJobStatusRunning(iter->status);
     5588    }
     5589    return false;
     5590}
     5591
     5592bool PlaybackBox::PbbJobQueue::IsJobQueuedOrRunning(int jobType, uint chanid,
     5593                                                    const QDateTime &recstartts)
     5594{
     5595    return IsJobQueued(jobType, chanid, recstartts) ||
     5596        IsJobRunning(jobType, chanid, recstartts);
     5597}
     5598
    55475599/* vim: set expandtab tabstop=4 shiftwidth=4: */
  • mythtv/programs/mythfrontend/playbackbox.h

    diff --git a/mythtv/programs/mythfrontend/playbackbox.h b/mythtv/programs/mythfrontend/playbackbox.h
    index 44a41e2..19255ec 100644
    a b using namespace std; 
    1313
    1414#include <QStringList>
    1515#include <QDateTime>
     16#include <QMultiMap>
    1617#include <QObject>
    1718#include <QMutex>
    1819#include <QMap>
    class PlaybackBox : public ScheduleCommon 
    333334
    334335    QString CreateProgramInfoString(const ProgramInfo &program) const;
    335336
     337    QString extract_job_state(const ProgramInfo &pginfo);
     338    QString extract_commflag_state(const ProgramInfo &pginfo);
     339
    336340
    337341    QRegExp m_prefixes;   ///< prefixes to be ignored when sorting
    338342    QRegExp m_titleChaff; ///< stuff to remove for search rules
    class PlaybackBox : public ScheduleCommon 
    442446    bool                m_usingGroupSelector;
    443447    bool                m_groupSelected;
    444448    bool                m_passwordEntered;
     449
     450    // This class caches the contents of the jobqueue table to avoid excessive
     451    // DB queries each time the PBB selection changes (currently 4 queries per
     452    // displayed item).  The cache remains valid for 15 seconds
     453    // (kInvalidateTimeMs).
     454    class PbbJobQueue
     455    {
     456    public:
     457        PbbJobQueue() {}
     458        bool IsJobQueued(int jobType, uint chanid,
     459                         const QDateTime &recstartts);
     460        bool IsJobRunning(int jobType, uint chanid,
     461                          const QDateTime &recstartts);
     462        bool IsJobQueuedOrRunning(int jobType, uint chanid,
     463                                  const QDateTime &recstartts);
     464    private:
     465        static const qint64 kInvalidateTimeMs = 15000;
     466        void Update();
     467        QDateTime m_lastUpdated;
     468        // Maps <chanid, recstartts> to a set of JobQueueEntry values.
     469        typedef QMultiMap<QPair<uint, QDateTime>, JobQueueEntry> MapType;
     470        MapType m_jobs;
     471    } m_jobQueue;
    445472};
    446473
    447474class GroupSelector : public MythScreenType