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
15 #include "libmyth/programinfo.h"
16 #include "libmyth/remoteutil.h"
19 #include "libmythbase/mythdb.h"
20 #include "libmythbase/mythevent.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  MythDB::DBError("Watched progress", query);
120  }
121 
122  locker.relock();
123 
125  m_nextCache = tmp;
126 
127  if (updateUI)
128  QCoreApplication::postEvent(
129  m_listener, new MythEvent("UPDATE_UI_LIST"));
130 
132  m_loadWait.wakeAll();
133 }
134 
136 {
137  QMutexLocker locker(&m_lock);
138  return m_loadsInProgress != 0U;
139 }
140 
142 {
143  QMutexLocker locker(&m_lock);
144  while (m_loadsInProgress)
145  m_loadWait.wait(&m_lock);
146 }
147 
159 {
160  QMutexLocker locker(&m_lock);
161  if (m_nextCache)
162  {
163  Clear();
164  for (auto & it : *m_nextCache)
165  {
166  if (!it->GetChanID())
167  continue;
168 
169  m_cache[it->GetRecordingID()] = it;
170  }
171  delete m_nextCache;
172  m_nextCache = nullptr;
173  return;
174  }
175 
176  for (auto it = m_cache.begin(); it != m_cache.end(); )
177  {
178  if ((*it)->GetAvailableStatus() == asDeleted)
179  {
180  delete (*it);
181  it = m_cache.erase(it);
182  }
183  else
184  {
185  it++;
186  }
187  }
188 }
189 
194 ProgramInfoCache::UpdateStates ProgramInfoCache::Update(const ProgramInfo &pginfo)
195 {
196  QMutexLocker locker(&m_lock);
197 
198  uint recordingId = pginfo.GetRecordingID();
199  Cache::iterator it = m_cache.find(recordingId);
200 
201  if (it == m_cache.end())
202  return PIC_NO_ACTION;
203 
204  ProgramInfo& pg = **it;
205  UpdateStates flags { PIC_NONE };
206 
207  if (pginfo.GetBookmarkUpdate() != pg.m_previewUpdate)
208  flags |= PIC_MARK_CHANGED;
209 
210  if (pginfo.GetRecordingGroup() != pg.GetRecordingGroup())
211  flags |= PIC_RECGROUP_CHANGED;
212 
213  pg.clone(pginfo, true);
214 
215  if (flags & PIC_MARK_CHANGED)
216  {
217  // Delegate this update to a background task
219  recordingId, 0, flags);
220 
221  // Ignore this update
222  flags = PIC_NO_ACTION;
223  }
224 
225  LOG(VB_GUI, LOG_DEBUG, QString("Pg %1 %2 update state %3")
226  .arg(recordingId).arg(pg.GetTitle()).arg(flags));
227  return flags;
228 }
229 
234 void ProgramInfoCache::UpdateFileSize(uint recordingID, uint64_t filesize,
235  UpdateStates flags)
236 {
237  Cache::iterator it = m_cache.find(recordingID);
238  if (it == m_cache.end())
239  return;
240 
241  ProgramInfo *pg = *it;
242 
244 
245  if (filesize > 0)
246  {
247  // Filesize update
248  pg->SetFilesize(filesize);
249  pg->SetAvailableStatus(asAvailable, "PIC::UpdateFileSize");
250  }
251  else // Info update
252  {
253  // Don't keep regenerating previews of files being played
254  QString byWhom;
255  if (pg->QueryIsInUse(byWhom) && byWhom.contains(QObject::tr("Playing")))
256  flags &= ~PIC_MARK_CHANGED;
257  }
258 
259  // Time of preview picture generation request for next comparison
260  if (flags & PIC_MARK_CHANGED)
262 
263  QString mesg = QString("UPDATE_UI_ITEM %1 %2").arg(recordingID).arg(flags);
264  QCoreApplication::postEvent(m_listener, new MythEvent(mesg));
265 
266  LOG(VB_GUI, LOG_DEBUG, mesg);
267 }
268 
273 {
274  if (!pginfo.GetRecordingID() || (Update(pginfo) != PIC_NO_ACTION))
275  return;
276 
277  m_cache[pginfo.GetRecordingID()] = new ProgramInfo(pginfo);
278 }
279 
286 {
287  Cache::iterator it = m_cache.find(recordingID);
288 
289  if (it != m_cache.end())
290  (*it)->SetAvailableStatus(asDeleted, "PIC::Remove");
291 
292  return it != m_cache.end();
293 }
294 
295 // two helper functions that are used only in this file
296 namespace {
297  // Sorting functions for ProgramInfoCache::GetOrdered()
298  bool PISort(const ProgramInfo *a, const ProgramInfo *b)
299  {
301  return a->GetChanID() < b->GetChanID();
302  return (a->GetRecordingStartTime() < b->GetRecordingStartTime());
303  }
304 
305  bool reversePISort(const ProgramInfo *a, const ProgramInfo *b)
306  {
308  return a->GetChanID() > b->GetChanID();
309  return (a->GetRecordingStartTime() > b->GetRecordingStartTime());
310  }
311 }
312 
313 void ProgramInfoCache::GetOrdered(std::vector<ProgramInfo*> &list, bool newest_first)
314 {
315  std::copy(m_cache.cbegin(), m_cache.cend(), std::back_inserter(list));
316 
317  if (newest_first)
318  std::sort(list.begin(), list.end(), reversePISort);
319  else
320  std::sort(list.begin(), list.end(), PISort);
321 
322 }
323 
325 {
326  Cache::const_iterator it = m_cache.find(recordingID);
327 
328  if (it != m_cache.end())
329  return *it;
330 
331  return nullptr;
332 }
333 
336 {
337  for (const auto & pi : qAsConst(m_cache))
338  delete pi;
339  m_cache.clear();
340 }
ProgramInfoCache::Add
void Add(const ProgramInfo &pginfo)
Adds a ProgramInfo to the cache.
Definition: programinfocache.cpp:272
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:807
ProgramInfo::SetAvailableStatus
void SetAvailableStatus(AvailableStatusType status, const QString &where)
Definition: programinfo.cpp:2451
MSqlQuery
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:128
mythevent.h
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
asAvailable
@ asAvailable
Definition: programtypes.h:178
ProgramInfo::m_previewUpdate
QDateTime m_previewUpdate
Definition: programinfo.h:858
ProgramInfoCache
Definition: programinfocache.h:20
ProgramInfoCache::GetOrdered
void GetOrdered(std::vector< ProgramInfo * > &list, bool newest_first=false)
Definition: programinfocache.cpp:313
ProgramInfoCache::PIC_RECGROUP_CHANGED
@ PIC_RECGROUP_CHANGED
Definition: programinfocache.h:28
ProgramInfo::GetRecordingID
uint GetRecordingID(void) const
Definition: programinfo.h:446
ProgramInfo::clone
virtual void clone(const ProgramInfo &other, bool ignore_non_serialized_data=false)
Copies important fields from other ProgramInfo.
Definition: programinfo.cpp:836
MythEvent
This class is used as a container for messages.
Definition: mythevent.h:16
MSqlQuery::value
QVariant value(int i) const
Definition: mythdbcon.h:205
asDeleted
@ asDeleted
Definition: programtypes.h:183
MSqlQuery::exec
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:608
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
ProgramInfo::GetRecordingGroup
QString GetRecordingGroup(void) const
Definition: programinfo.h:419
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:404
tmp
static guint32 * tmp
Definition: goom_core.cpp:26
ProgramInfoCache::m_loadsInProgress
uint m_loadsInProgress
Definition: programinfocache.h:69
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:264
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:361
MSqlQuery::InitCon
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:540
MythDB::DBError
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:227
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:194
ProgramInfoCache::GetRecordingInfo
ProgramInfo * GetRecordingInfo(uint recordingID) const
Definition: programinfocache.cpp:324
ProgramInfoCache::Refresh
void Refresh(void)
Refreshed the cache.
Definition: programinfocache.cpp:158
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:79
ProgramInfo::SetFilesize
virtual void SetFilesize(uint64_t sz)
Definition: programinfo.cpp:6304
ProgramInfo::CalculateProgress
void CalculateProgress(uint64_t pos)
Definition: programinfo.cpp:6440
ProgramInfoCache::WaitForLoadToComplete
void WaitForLoadToComplete(void) const
Definition: programinfocache.cpp:141
ProgramInfoCache::PIC_NO_ACTION
@ PIC_NO_ACTION
Definition: programinfocache.h:29
ProgramInfoCache::IsLoadInProgress
bool IsLoadInProgress(void) const
Definition: programinfocache.cpp:135
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:372
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
MARK_UTIL_LASTPLAYPOS
@ MARK_UTIL_LASTPLAYPOS
Definition: programtypes.h:78
MSqlQuery::bindValue
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:883
ProgramInfoCache::m_loadWait
QWaitCondition m_loadWait
Definition: programinfocache.h:70
ProgramInfoCache::PIC_MARK_CHANGED
@ PIC_MARK_CHANGED
Definition: programinfocache.h:27
ProgramInfoCache::UpdateFileSize
void UpdateFileSize(uint recordingID, uint64_t filesize, UpdateStates flags)
Updates a ProgramInfo in the cache.
Definition: programinfocache.cpp:234
ProgramInfoCache::~ProgramInfoCache
~ProgramInfoCache()
Definition: programinfocache.cpp:53
ProgramInfoCache::Remove
bool Remove(uint recordingID)
Marks a ProgramInfo in the cache for deletion on the next call to Refresh().
Definition: programinfocache.cpp:285
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:3183
ProgramInfo::QueryLastPlayPos
uint64_t QueryLastPlayPos(void) const
Gets any lastplaypos position in database, unless the ignore lastplaypos flag is set.
Definition: programinfo.cpp:2828
RemoteGetRecordedList
std::vector< ProgramInfo * > * RemoteGetRecordedList(int sort)
Definition: remoteutil.cpp:17
MThreadPool::globalInstance
static MThreadPool * globalInstance(void)
Definition: mthreadpool.cpp:317
ProgramInfoCache::Clear
void Clear(void)
Clears the cache, m_lock must be held when this is called.
Definition: programinfocache.cpp:335
ProgramInfoCache::PIC_NONE
@ PIC_NONE
Definition: programinfocache.h:26
MThreadPool::start
void start(QRunnable *runnable, const QString &debugName, int priority=0)
Definition: mthreadpool.cpp:352
ProgramInfo::GetBookmarkUpdate
QDateTime GetBookmarkUpdate(void) const
Definition: programinfo.h:474
MSqlQuery::prepare
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:832
ProgramInfoCache::m_nextCache
std::vector< ProgramInfo * > * m_nextCache
Definition: programinfocache.h:66