Skip to content

Commit

Permalink
EIT cache persistency optional
Browse files Browse the repository at this point in the history
Make it optional to save the content of the EIT cache in the database.
Saving the content of the EIT cache in the database and using that at
the next start of the backend is the existing behavior.
This reduces EIT event processing at a restart of the backend but only when
there is only a short time period in between. Also, this comes at the cost
of updating the copy of the EIT cache in the database continuously.
When the time period is significant, think of more than a few hours,
the copied EIT cache may be obsolete already as indicated by the table version.
Given that the version field is only 5 bits, the value does wrap around
which means that, if the backend has been offline for a few days, there is
the possibility that invalid cached EIT cache data is seen as valid.
The default behavior is to have the persistency enabled because that
is how it has been since 2006.
  • Loading branch information
kmdewaal committed Jan 1, 2024
1 parent c7426fc commit 90201f0
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 27 deletions.
75 changes: 50 additions & 25 deletions mythtv/libs/libmythtv/eitcache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,6 @@ static void delete_in_db(uint endtime)
MythDB::DBError("Error deleting old eitcache entries.", query);
}


enum channel_status
{
EITDATA = 0,
Expand Down Expand Up @@ -208,9 +207,14 @@ static void unlock_channel(uint chanid, uint updated)
MythDB::DBError("Error inserting eit statistics", query);
}


event_map_t * EITCache::LoadChannel(uint chanid)
{
// Event map is empty when we do not backup the cache in the database
if (!m_persistent)
{
return new event_map_t();
}

if (!lock_channel(chanid, m_lastPruneTime))
return nullptr;

Expand Down Expand Up @@ -272,9 +276,13 @@ bool EITCache::WriteChannelToDB(QStringList &value_clauses, uint chanid)
{
if (modified(*it))
{
replace_in_db(value_clauses, chanid, it.key(), *it);
if (m_persistent)
{
replace_in_db(value_clauses, chanid, it.key(), *it);
}

updated++;
*it &= ~(uint64_t)0 >> 1; // mark as synced
*it &= ~(uint64_t)0 >> 1; // Mark as synced
}
++it;
}
Expand All @@ -285,13 +293,26 @@ bool EITCache::WriteChannelToDB(QStringList &value_clauses, uint chanid)
removed++;
}
}
unlock_channel(chanid, updated);

if (m_persistent)
{
unlock_channel(chanid, updated);
}

if (updated)
{
LOG(VB_EIT, LOG_INFO, LOC + QString("Writing %1 modified entries of %2 "
"for chanid %3 to database.")
.arg(updated).arg(size).arg(chanid));
if (m_persistent)
{
LOG(VB_EIT, LOG_INFO, LOC +
QString("Writing %1 modified entries of %2 for chanid %3 to database.")
.arg(updated).arg(size).arg(chanid));
}
else
{
LOG(VB_EIT, LOG_INFO, LOC +
QString("Updated %1 modified entries of %2 for chanid %3 in cache.")
.arg(updated).arg(size).arg(chanid));
}
}
if (removed)
{
Expand All @@ -318,18 +339,21 @@ void EITCache::WriteToDB(void)
++it;
}

if(value_clauses.isEmpty())
if (m_persistent)
{
return;
}
if(value_clauses.isEmpty())
{
return;
}

MSqlQuery query(MSqlQuery::InitCon());
query.prepare(QString("REPLACE INTO eit_cache "
"(chanid, eventid, tableid, version, endtime) "
"VALUES %1").arg(value_clauses.join(",")));
if (!query.exec())
{
MythDB::DBError("Error updating eitcache", query);
MSqlQuery query(MSqlQuery::InitCon());
query.prepare(QString("REPLACE INTO eit_cache "
"(chanid, eventid, tableid, version, endtime) "
"VALUES %1").arg(value_clauses.join(",")));
if (!query.exec())
{
MythDB::DBError("Error updating eitcache", query);
}
}
}

Expand All @@ -338,22 +362,20 @@ bool EITCache::IsNewEIT(uint chanid, uint tableid, uint version,
{
m_accessCnt++;

if ((m_accessCnt < 100000 && (m_accessCnt % 10000 == 0)) ||
(m_accessCnt < 1000000 && (m_accessCnt % 100000 == 0)) ||
(m_accessCnt % 1000000 == 0))
if ((m_accessCnt < 100000 && (m_accessCnt % 10000 == 0)) ||
(m_accessCnt % 100000 == 0))
{
LOG(VB_EIT, LOG_INFO, LOC + GetStatistics());
WriteToDB();
}

// don't re-add pruned entries
// Don't re-add pruned entries
if (endtime < m_lastPruneTime)
{
m_prunedHitCnt++;
return false;
}

// validity check, reject events with endtime over 7 weeks in the future
// Validity check, reject events with endtime over 7 weeks in the future
if (endtime > m_lastPruneTime + 50 * 86400)
{
m_futureHitCnt++;
Expand Down Expand Up @@ -426,7 +448,10 @@ uint EITCache::PruneOldEntries(uint timestamp)
WriteToDB();

// Prune old entries in the DB
delete_in_db(timestamp);
if (m_persistent)
{
delete_in_db(timestamp);
}

return 0;
}
Expand Down
8 changes: 6 additions & 2 deletions mythtv/libs/libmythtv/eitcache.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,16 @@ class EITCache
event_map_t * LoadChannel(uint chanid);
bool WriteChannelToDB(QStringList &value_clauses, uint chanid);

// event key cache
// Event key cache
key_map_t m_channelMap;

mutable QMutex m_eventMapLock;
uint m_lastPruneTime;

// statistics
// Cache persistency in database table eit_cache
bool m_persistent {true};

// Statistics
uint m_accessCnt {0};
uint m_hitCnt {0};
uint m_tblChgCnt {0};
Expand All @@ -60,6 +63,7 @@ class EITCache

public:
static MTV_PUBLIC void ClearChannelLocks(void);
void SetPersistent(bool persistent) { m_persistent = persistent; }
};

#endif // EIT_CACHE_H
Expand Down
4 changes: 4 additions & 0 deletions mythtv/libs/libmythtv/eithelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ static void init_fixup(FixupMap &fix);
EITHelper::EITHelper(uint cardnum) :
m_cardnum(cardnum)
{
// Save EIT cache in database table eit_cache iff true
bool persistent = gCoreContext->GetBoolSetting("EITCachePersistent", true);
s_eitCache->SetPersistent(persistent);

init_fixup(m_fixup);
}

Expand Down
15 changes: 15 additions & 0 deletions mythtv/programs/mythtv-setup/backendsettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,20 @@ static GlobalSpinBoxSetting *EITScanPeriod()
return gc;
}


static GlobalCheckBoxSetting *EITCachePersistent()
{
auto *gc = new GlobalCheckBoxSetting("EITCachePersistent");
gc->setLabel(QObject::tr("EIT cache persistent"));
gc->setValue(true);
QString helpText = QObject::tr(
"Save the content of the EIT cache in the database "
"and use that at the next start of the backend. "
"This reduces EIT event processing at a restart of the backend but at the "
"cost of updating the copy of the EIT cache in the database continuously.");
gc->setHelpText(helpText);
return gc;
}
static GlobalSpinBoxSetting *WOLbackendReconnectWaitTime()
{
auto *gc = new GlobalSpinBoxSetting("WOLbackendReconnectWaitTime", 0, 1200, 5);
Expand Down Expand Up @@ -970,6 +984,7 @@ BackendSettings::BackendSettings()
group2a1->addChild(EITTransportTimeout());
group2a1->addChild(EITCrawIdleStart());
group2a1->addChild(EITScanPeriod());
group2a1->addChild(EITCachePersistent());
addChild(group2a1);

auto* group3 = new GroupSetting();
Expand Down

0 comments on commit 90201f0

Please sign in to comment.