MythTV  master
programinfocache.cpp
Go to the documentation of this file.
1 // -*- Mode: c++ -*-
2 // vim:set sw=4 ts=4 expandtab:
3 // Copyright (c) 2009, Daniel Thor Kristjansson
4 // Distributed as part of MythTV under GPL version 2
5 // (or at your option a later version)
6 
7 // C++
8 #include <algorithm>
9 
10 // Qt
11 #include <QCoreApplication>
12 #include <QRunnable>
13 
14 // MythTV
17 #include "libmythbase/mythdb.h"
18 #include "libmythbase/mythevent.h"
21 #include "libmythbase/remoteutil.h"
22 
23 // MythFrontend
24 #include "programinfocache.h"
25 
26 using VPI_ptr = std::vector<ProgramInfo *> *;
27 static void free_vec(VPI_ptr &v)
28 {
29  if (v)
30  {
31  for (auto & it : *v)
32  delete it;
33  delete v;
34  v = nullptr;
35  }
36 }
37 
38 class ProgramInfoLoader : public QRunnable
39 {
40  public:
41  ProgramInfoLoader(ProgramInfoCache &c, const bool updateUI)
42  : m_cache(c), m_updateUI(updateUI) {}
43 
44  void run(void) override // QRunnable
45  {
47  }
48 
50  bool m_updateUI;
51 };
52 
54 {
55  QMutexLocker locker(&m_lock);
56 
57  while (m_loadsInProgress)
58  m_loadWait.wait(&m_lock);
59 
60  Clear();
62 }
63 
64 void ProgramInfoCache::ScheduleLoad(const bool updateUI)
65 {
66  QMutexLocker locker(&m_lock);
67  if (!m_loadIsQueued)
68  {
69  m_loadIsQueued = true;
72  new ProgramInfoLoader(*this, updateUI), "ProgramInfoLoader");
73  }
74 }
75 
76 void ProgramInfoCache::Load(const bool updateUI)
77 {
78  QMutexLocker locker(&m_lock);
79  m_loadIsQueued = false;
80 
81  locker.unlock();
82 
83  // Get an unsorted list (sort = 0) from RemoteGetRecordedList
84  // we sort the list later anyway.
85  std::vector<ProgramInfo*> *tmp = RemoteGetRecordedList(0);
86 
87  // Calculate play positions for UI
88  if (tmp)
89  {
90  // Played progress
91  using ProgId = QPair<uint, QDateTime>;
92  QHash<ProgId, uint> lastPlayFrames;
93 
94  // Get all lastplaypos marks in a single lookup
96  query.prepare("SELECT chanid, starttime, mark "
97  "FROM recordedmarkup "
98  "WHERE type = :TYPE ");
99  query.bindValue(":TYPE", MARK_UTIL_LASTPLAYPOS);
100 
101  if (query.exec())
102  {
103  while (query.next())
104  {
105  ProgId id = qMakePair(query.value(0).toUInt(),
106  MythDate::as_utc(query.value(1).toDateTime()));
107  lastPlayFrames[id] = query.value(2).toUInt();
108  }
109 
110  // Determine progress of each prog
111  for (ProgramInfo* pg : *tmp)
112  {
113  ProgId id = qMakePair(pg->GetChanID(),
114  pg->GetRecordingStartTime());
115  pg->CalculateProgress(lastPlayFrames.value(id));
116  }
117  }
118  else
119  {
120  MythDB::DBError("Watched progress", query);
121  }
122  }
123 
124  locker.relock();
125 
127  m_nextCache = tmp;
128 
129  if (updateUI)
130  QCoreApplication::postEvent(
131  m_listener, new MythEvent("UPDATE_UI_LIST"));
132 
134  m_loadWait.wakeAll();
135 }
136 
138 {
139  QMutexLocker locker(&m_lock);
140  return m_loadsInProgress != 0U;
141 }
142 
144 {
145  QMutexLocker locker(&m_lock);
146  while (m_loadsInProgress)
147  m_loadWait.wait(&m_lock);
148 }
149 
161 {
162  QMutexLocker locker(&m_lock);
163  if (m_nextCache)
164  {
165  Clear();
166  for (auto & it : *m_nextCache)
167  {
168  if (!it->GetChanID())
169  continue;
170 
171  m_cache[it->GetRecordingID()] = it;
172  }
173  delete m_nextCache;
174  m_nextCache = nullptr;
175  return;
176  }
177 
178  for (auto it = m_cache.begin(); it != m_cache.end(); )
179  {
180  if ((*it)->GetAvailableStatus() == asDeleted)
181  {
182  delete (*it);
183  it = m_cache.erase(it);
184  }
185  else
186  {
187  it++;
188  }
189  }
190 }
191 
196 ProgramInfoCache::UpdateStates ProgramInfoCache::Update(const ProgramInfo &pginfo)
197 {
198  QMutexLocker locker(&m_lock);
199 
200  uint recordingId = pginfo.GetRecordingID();
201  Cache::iterator it = m_cache.find(recordingId);
202 
203  if (it == m_cache.end())
204  return PIC_NO_ACTION;
205 
206  ProgramInfo& pg = **it;
207  UpdateStates flags { PIC_NONE };
208 
209  if (pginfo.GetBookmarkUpdate() != pg.m_previewUpdate)
210  flags |= PIC_MARK_CHANGED;
211 
212  if (pginfo.GetRecordingGroup() != pg.GetRecordingGroup())
213  flags |= PIC_RECGROUP_CHANGED;
214 
215  pg.clone(pginfo, true);
216 
217  if (flags & PIC_MARK_CHANGED)
218  {
219  // Delegate this update to a background task
221  recordingId, 0, flags);
222 
223  // Ignore this update
224  flags = PIC_NO_ACTION;
225  }
226 
227  LOG(VB_GUI, LOG_DEBUG, QString("Pg %1 %2 update state %3")
228  .arg(recordingId).arg(pg.GetTitle()).arg(flags));
229  return flags;
230 }
231 
236 void ProgramInfoCache::UpdateFileSize(uint recordingID, uint64_t filesize,
237  UpdateStates flags)
238 {
239  Cache::iterator it = m_cache.find(recordingID);
240  if (it == m_cache.end())
241  return;
242 
243  ProgramInfo *pg = *it;
244 
246 
247  if (filesize > 0)
248  {
249  // Filesize update
250  pg->SetFilesize(filesize);
251  pg->SetAvailableStatus(asAvailable, "PIC::UpdateFileSize");
252  }
253  else // Info update
254  {
255  // Don't keep regenerating previews of files being played
256  QString byWhom;
257  if (pg->QueryIsInUse(byWhom) && byWhom.contains(QObject::tr("Playing")))
258  flags &= ~PIC_MARK_CHANGED;
259  }
260 
261  // Time of preview picture generation request for next comparison
262  if (flags & PIC_MARK_CHANGED)
264 
265  QString mesg = QString("UPDATE_UI_ITEM %1 %2").arg(recordingID).arg(flags);
266  QCoreApplication::postEvent(m_listener, new MythEvent(mesg));
267 
268  LOG(VB_GUI, LOG_DEBUG, mesg);
269 }
270 
275 {
276  if (!pginfo.GetRecordingID() || (Update(pginfo) != PIC_NO_ACTION))
277  return;
278 
279  m_cache[pginfo.GetRecordingID()] = new ProgramInfo(pginfo);
280 }
281 
288 {
289  Cache::iterator it = m_cache.find(recordingID);
290 
291  if (it != m_cache.end())
292  (*it)->SetAvailableStatus(asDeleted, "PIC::Remove");
293 
294  return it != m_cache.end();
295 }
296 
297 // two helper functions that are used only in this file
298 namespace {
299  // Sorting functions for ProgramInfoCache::GetOrdered()
300  bool PISort(const ProgramInfo *a, const ProgramInfo *b)
301  {
303  return a->GetChanID() < b->GetChanID();
304  return (a->GetRecordingStartTime() < b->GetRecordingStartTime());
305  }
306 
307  bool reversePISort(const ProgramInfo *a, const ProgramInfo *b)
308  {
310  return a->GetChanID() > b->GetChanID();
311  return (a->GetRecordingStartTime() > b->GetRecordingStartTime());
312  }
313 }
314 
315 void ProgramInfoCache::GetOrdered(std::vector<ProgramInfo*> &list, bool newest_first)
316 {
317  std::copy(m_cache.cbegin(), m_cache.cend(), std::back_inserter(list));
318 
319  if (newest_first)
320  std::sort(list.begin(), list.end(), reversePISort);
321  else
322  std::sort(list.begin(), list.end(), PISort);
323 
324 }
325 
327 {
328  Cache::const_iterator it = m_cache.find(recordingID);
329 
330  if (it != m_cache.end())
331  return *it;
332 
333  return nullptr;
334 }
335 
338 {
339  for (const auto & pi : std::as_const(m_cache))
340  delete pi;
341  m_cache.clear();
342 }
ProgramInfoCache::Add
void Add(const ProgramInfo &pginfo)
Adds a ProgramInfo to the cache.
Definition: programinfocache.cpp:274
ProgramInfoCache::m_cache
Cache m_cache
Definition: programinfocache.h:65
MSqlQuery::next
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:812
ProgramInfo::SetAvailableStatus
void SetAvailableStatus(AvailableStatusType status, const QString &where)
Definition: programinfo.cpp:2456
MSqlQuery
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:127
mythevent.h
ProgramInfoCache::PIC_RECGROUP_CHANGED
@ PIC_RECGROUP_CHANGED
Definition: programinfocache.h:28
ProgramInfoCache::m_loadIsQueued
bool m_loadIsQueued
Definition: programinfocache.h:68
ProgramInfoLoader::ProgramInfoLoader
ProgramInfoLoader(ProgramInfoCache &c, const bool updateUI)
Definition: programinfocache.cpp:41
mythdb.h
MythDate::as_utc
QDateTime as_utc(const QDateTime &old_dt)
Returns copy of QDateTime with TimeSpec set to UTC.
Definition: mythdate.cpp:27
ProgramInfo::m_previewUpdate
QDateTime m_previewUpdate
Definition: programinfo.h:862
ProgramInfoCache
Definition: programinfocache.h:20
ProgramInfoCache::GetOrdered
void GetOrdered(std::vector< ProgramInfo * > &list, bool newest_first=false)
Definition: programinfocache.cpp:315
ProgramInfo::GetRecordingID
uint GetRecordingID(void) const
Definition: programinfo.h:450
ProgramInfo::clone
virtual void clone(const ProgramInfo &other, bool ignore_non_serialized_data=false)
Copies important fields from other ProgramInfo.
Definition: programinfo.cpp:839
MythEvent
This class is used as a container for messages.
Definition: mythevent.h:16
MSqlQuery::value
QVariant value(int i) const
Definition: mythdbcon.h:204
MSqlQuery::exec
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:618
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
ProgramInfo::GetRecordingGroup
QString GetRecordingGroup(void) const
Definition: programinfo.h:420
remoteutil.h
ProgramInfoCache::ProgramInfoLoader
friend class ProgramInfoLoader
Definition: programinfocache.h:22
ProgramInfoCache::m_listener
QObject * m_listener
Definition: programinfocache.h:67
ProgramInfo::GetRecordingStartTime
QDateTime GetRecordingStartTime(void) const
Approximate time the recording started.
Definition: programinfo.h:405
tmp
static guint32 * tmp
Definition: goom_core.cpp:26
ProgramInfoCache::m_loadsInProgress
uint m_loadsInProgress
Definition: programinfocache.h:69
ProgramInfoCache::PIC_MARK_CHANGED
@ PIC_MARK_CHANGED
Definition: programinfocache.h:27
ProgramInfoCache::PIC_NONE
@ PIC_NONE
Definition: programinfocache.h:26
programinfo.h
mythlogging.h
MythFile::copy
MBASE_PUBLIC long long copy(QFile &dst, QFile &src, uint block_size=0)
Copies src file to dst file.
Definition: mythmiscutil.cpp:263
ProgramInfoLoader::run
void run(void) override
Definition: programinfocache.cpp:44
ProgramInfoLoader::m_updateUI
bool m_updateUI
Definition: programinfocache.cpp:50
ProgramInfo::GetTitle
QString GetTitle(void) const
Definition: programinfo.h:362
MSqlQuery::InitCon
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:550
MythDB::DBError
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:225
ProgramInfoCache::ScheduleLoad
void ScheduleLoad(bool updateUI=true)
Definition: programinfocache.cpp:64
ProgramInfoCache::Update
ProgramInfoCache::UpdateStates Update(const ProgramInfo &pginfo)
Updates a ProgramInfo in the cache.
Definition: programinfocache.cpp:196
ProgramInfoCache::GetRecordingInfo
ProgramInfo * GetRecordingInfo(uint recordingID) const
Definition: programinfocache.cpp:326
ProgramInfoCache::Refresh
void Refresh(void)
Refreshed the cache.
Definition: programinfocache.cpp:160
free_vec
static void free_vec(VPI_ptr &v)
Definition: programinfocache.cpp:27
MConcurrent::run
void run(const QString &name, Class *object, void(Class::*fn)())
Definition: mconcurrent.h:137
uint
unsigned int uint
Definition: compat.h:81
ProgramInfo::SetFilesize
virtual void SetFilesize(uint64_t sz)
Definition: programinfo.cpp:6399
ProgramInfo::CalculateProgress
void CalculateProgress(uint64_t pos)
Definition: programinfo.cpp:6551
ProgramInfoCache::WaitForLoadToComplete
void WaitForLoadToComplete(void) const
Definition: programinfocache.cpp:143
ProgramInfoCache::IsLoadInProgress
bool IsLoadInProgress(void) const
Definition: programinfocache.cpp:137
ProgramInfoCache::Load
void Load(bool updateUI=true)
Definition: programinfocache.cpp:76
mthreadpool.h
ProgramInfoLoader::m_cache
ProgramInfoCache & m_cache
Definition: programinfocache.cpp:49
ProgramInfo::GetChanID
uint GetChanID(void) const
This is the unique key used in the database to locate tuning information.
Definition: programinfo.h:373
ProgramInfoCache::m_lock
QMutex m_lock
Definition: programinfocache.h:64
ProgramInfoLoader
Definition: programinfocache.cpp:38
programinfocache.h
ProgramInfo
Holds information on recordings and videos.
Definition: programinfo.h:67
asAvailable
@ asAvailable
Definition: programtypes.h:177
anonymous_namespace{programinfocache.cpp}::PISort
bool PISort(const ProgramInfo *a, const ProgramInfo *b)
Definition: programinfocache.cpp:300
MSqlQuery::bindValue
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:888
ProgramInfoCache::m_loadWait
QWaitCondition m_loadWait
Definition: programinfocache.h:70
ProgramInfoCache::UpdateFileSize
void UpdateFileSize(uint recordingID, uint64_t filesize, UpdateStates flags)
Updates a ProgramInfo in the cache.
Definition: programinfocache.cpp:236
ProgramInfoCache::~ProgramInfoCache
~ProgramInfoCache()
Definition: programinfocache.cpp:53
MARK_UTIL_LASTPLAYPOS
@ MARK_UTIL_LASTPLAYPOS
Definition: programtypes.h:77
ProgramInfoCache::PIC_NO_ACTION
@ PIC_NO_ACTION
Definition: programinfocache.h:29
ProgramInfoCache::Remove
bool Remove(uint recordingID)
Marks a ProgramInfo in the cache for deletion on the next call to Refresh().
Definition: programinfocache.cpp:287
VPI_ptr
std::vector< ProgramInfo * > * VPI_ptr
Definition: programinfocache.cpp:26
mconcurrent.h
ProgramInfo::QueryIsInUse
bool QueryIsInUse(QStringList &byWho) const
Returns true if Program is in use.
Definition: programinfo.cpp:3187
ProgramInfo::QueryLastPlayPos
uint64_t QueryLastPlayPos(void) const
Gets any lastplaypos position in database, unless the ignore lastplaypos flag is set.
Definition: programinfo.cpp:2825
asDeleted
@ asDeleted
Definition: programtypes.h:182
RemoteGetRecordedList
std::vector< ProgramInfo * > * RemoteGetRecordedList(int sort)
Definition: remoteutil.cpp:19
MThreadPool::globalInstance
static MThreadPool * globalInstance(void)
Definition: mthreadpool.cpp:307
anonymous_namespace{programinfocache.cpp}::reversePISort
bool reversePISort(const ProgramInfo *a, const ProgramInfo *b)
Definition: programinfocache.cpp:307
ProgramInfoCache::Clear
void Clear(void)
Clears the cache, m_lock must be held when this is called.
Definition: programinfocache.cpp:337
MThreadPool::start
void start(QRunnable *runnable, const QString &debugName, int priority=0)
Definition: mthreadpool.cpp:342
ProgramInfo::GetBookmarkUpdate
QDateTime GetBookmarkUpdate(void) const
Definition: programinfo.h:478
MSqlQuery::prepare
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:837
ProgramInfoCache::m_nextCache
std::vector< ProgramInfo * > * m_nextCache
Definition: programinfocache.h:66