From 90201f06e8781dad8d14fb09237836015483c7dd Mon Sep 17 00:00:00 2001 From: Klaas de Waal Date: Mon, 1 Jan 2024 22:38:38 +0100 Subject: [PATCH] EIT cache persistency optional 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. --- mythtv/libs/libmythtv/eitcache.cpp | 75 ++++++++++++------- mythtv/libs/libmythtv/eitcache.h | 8 +- mythtv/libs/libmythtv/eithelper.cpp | 4 + .../programs/mythtv-setup/backendsettings.cpp | 15 ++++ 4 files changed, 75 insertions(+), 27 deletions(-) diff --git a/mythtv/libs/libmythtv/eitcache.cpp b/mythtv/libs/libmythtv/eitcache.cpp index 4a720da78a5..486f1e0837b 100644 --- a/mythtv/libs/libmythtv/eitcache.cpp +++ b/mythtv/libs/libmythtv/eitcache.cpp @@ -117,7 +117,6 @@ static void delete_in_db(uint endtime) MythDB::DBError("Error deleting old eitcache entries.", query); } - enum channel_status { EITDATA = 0, @@ -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; @@ -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; } @@ -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) { @@ -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); + } } } @@ -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++; @@ -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; } diff --git a/mythtv/libs/libmythtv/eitcache.h b/mythtv/libs/libmythtv/eitcache.h index ef639528014..800c01c0e14 100644 --- a/mythtv/libs/libmythtv/eitcache.h +++ b/mythtv/libs/libmythtv/eitcache.h @@ -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}; @@ -60,6 +63,7 @@ class EITCache public: static MTV_PUBLIC void ClearChannelLocks(void); + void SetPersistent(bool persistent) { m_persistent = persistent; } }; #endif // EIT_CACHE_H diff --git a/mythtv/libs/libmythtv/eithelper.cpp b/mythtv/libs/libmythtv/eithelper.cpp index c506b11fc5c..64b9ec893f2 100644 --- a/mythtv/libs/libmythtv/eithelper.cpp +++ b/mythtv/libs/libmythtv/eithelper.cpp @@ -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); } diff --git a/mythtv/programs/mythtv-setup/backendsettings.cpp b/mythtv/programs/mythtv-setup/backendsettings.cpp index 38828c6c03c..3b0f9d3a352 100644 --- a/mythtv/programs/mythtv-setup/backendsettings.cpp +++ b/mythtv/programs/mythtv-setup/backendsettings.cpp @@ -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); @@ -970,6 +984,7 @@ BackendSettings::BackendSettings() group2a1->addChild(EITTransportTimeout()); group2a1->addChild(EITCrawIdleStart()); group2a1->addChild(EITScanPeriod()); + group2a1->addChild(EITCachePersistent()); addChild(group2a1); auto* group3 = new GroupSetting();