From 538204380763c2f3c97d0cf7a67e974bb9548d1d Mon Sep 17 00:00:00 2001 From: phunkyfish Date: Sun, 1 Nov 2020 20:28:27 +0000 Subject: [pvr] bulk commit epg queries when deleting a channel --- xbmc/pvr/epg/Epg.cpp | 6 +++--- xbmc/pvr/epg/Epg.h | 6 +++--- xbmc/pvr/epg/EpgContainer.cpp | 12 +++++++++++- xbmc/pvr/epg/EpgDatabase.cpp | 19 +++++++++++++++++-- xbmc/pvr/epg/EpgDatabase.h | 15 +++++++++++---- xbmc/pvr/epg/EpgTagsContainer.cpp | 4 ++-- xbmc/pvr/epg/EpgTagsContainer.h | 4 ++-- 7 files changed, 49 insertions(+), 17 deletions(-) diff --git a/xbmc/pvr/epg/Epg.cpp b/xbmc/pvr/epg/Epg.cpp index 8fce752b2c..1c8972994c 100644 --- a/xbmc/pvr/epg/Epg.cpp +++ b/xbmc/pvr/epg/Epg.cpp @@ -330,7 +330,7 @@ bool CPVREpg::QueuePersistQuery(const std::shared_ptr& database return true; } -bool CPVREpg::Delete(const std::shared_ptr& database) +bool CPVREpg::QueueDeleteQueries(const std::shared_ptr& database) { if (!database) { @@ -339,10 +339,10 @@ bool CPVREpg::Delete(const std::shared_ptr& database) } // delete own epg db entry - database->Delete(*this); + database->QueueDeleteEpgQuery(*this); // delete all tags for this epg from db - m_tags.Delete(); + m_tags.QueueDelete(); Clear(); diff --git a/xbmc/pvr/epg/Epg.h b/xbmc/pvr/epg/Epg.h index 09577c378f..6b3f18da64 100644 --- a/xbmc/pvr/epg/Epg.h +++ b/xbmc/pvr/epg/Epg.h @@ -217,11 +217,11 @@ namespace PVR bool QueuePersistQuery(const std::shared_ptr& database); /*! - * @brief Delete this table from the given database + * @brief Write the delete queries into the given database's queue * @param database The database. - * @return True if the table was deleted, false otherwise. + * @return True on success, false otherwise. */ - bool Delete(const std::shared_ptr& database); + bool QueueDeleteQueries(const std::shared_ptr& database); /*! * @brief Get the start time of the first entry in this table. diff --git a/xbmc/pvr/epg/EpgContainer.cpp b/xbmc/pvr/epg/EpgContainer.cpp index 5aff3f3df3..00ca07e522 100644 --- a/xbmc/pvr/epg/EpgContainer.cpp +++ b/xbmc/pvr/epg/EpgContainer.cpp @@ -631,6 +631,13 @@ bool CPVREpgContainer::DeleteEpg(const std::shared_ptr& epg) if (!epg || epg->EpgID() < 0) return false; + const std::shared_ptr database = GetEpgDatabase(); + if (!database) + { + CLog::LogF(LOGERROR, "No EPG database"); + return false; + } + std::shared_ptr epgToDelete; { CSingleLock lock(m_critSection); @@ -646,7 +653,10 @@ bool CPVREpgContainer::DeleteEpg(const std::shared_ptr& epg) CLog::LogFC(LOGDEBUG, LOGEPG, "Deleting EPG table {} ({})", epg->Name(), epg->EpgID()); - epgEntry->second->Delete(GetEpgDatabase()); + database->Lock(); + epgEntry->second->QueueDeleteQueries(database); + database->CommitDeleteQueries(); + database->Unlock(); epgToDelete = epgEntry->second; m_epgIdToEpgMap.erase(epgEntry); diff --git a/xbmc/pvr/epg/EpgDatabase.cpp b/xbmc/pvr/epg/EpgDatabase.cpp index 383872d6a1..9fb62c5020 100644 --- a/xbmc/pvr/epg/EpgDatabase.cpp +++ b/xbmc/pvr/epg/EpgDatabase.cpp @@ -274,7 +274,7 @@ bool CPVREpgDatabase::DeleteEpg() return bReturn; } -bool CPVREpgDatabase::Delete(const CPVREpg& table) +bool CPVREpgDatabase::QueueDeleteEpgQuery(const CPVREpg& table) { /* invalid channel */ if (table.EpgID() <= 0) @@ -287,7 +287,10 @@ bool CPVREpgDatabase::Delete(const CPVREpg& table) CSingleLock lock(m_critSection); filter.AppendWhere(PrepareSQL("idEpg = %u", table.EpgID())); - return DeleteValues("epg", filter); + + std::string strQuery; + BuildSQL(PrepareSQL("DELETE FROM %s ", "epg"), filter, strQuery); + return QueueDeleteQuery(strQuery); } bool CPVREpgDatabase::QueueDeleteTagQuery(const CPVREpgInfoTag& tag) @@ -1052,6 +1055,18 @@ bool CPVREpgDatabase::DeleteEpgTags(int iEpgId) return DeleteValues("epgtags", filter); } +bool CPVREpgDatabase::QueueDeleteEpgTags(int iEpgId) +{ + Filter filter; + + CSingleLock lock(m_critSection); + filter.AppendWhere(PrepareSQL("idEpg = %u", iEpgId)); + + std::string strQuery; + BuildSQL(PrepareSQL("DELETE FROM %s ", "epg"), filter, strQuery); + return QueueDeleteQuery(strQuery); +} + bool CPVREpgDatabase::QueuePersistQuery(const CPVREpgInfoTag& tag) { if (tag.EpgID() <= 0) diff --git a/xbmc/pvr/epg/EpgDatabase.h b/xbmc/pvr/epg/EpgDatabase.h index 1e02e6f90b..c9b28842fd 100644 --- a/xbmc/pvr/epg/EpgDatabase.h +++ b/xbmc/pvr/epg/EpgDatabase.h @@ -81,11 +81,11 @@ namespace PVR bool DeleteEpg(); /*! - * @brief Delete an EPG table. - * @param table The table to remove. - * @return True if the table was removed successfully, false otherwise. + * @brief Queue deletionof an EPG table. + * @param tag The table to queue for deletion. + * @return True on success, false otherwise. */ - bool Delete(const CPVREpg& table); + bool QueueDeleteEpgQuery(const CPVREpg& table); /*! * @brief Write the query to delete the given EPG tag to db query queue. @@ -257,6 +257,13 @@ namespace PVR */ bool DeleteEpgTags(int iEpgId); + /*! + * @brief Queue the erase all EPG tags with the given epg ID. + * @param iEpgId The ID of the EPG. + * @return True if the entries were queued successfully, false otherwise. + */ + bool QueueDeleteEpgTags(int iEpgId); + /*! * @brief Write the query to persist the given EPG tag to db query queue. * @param tag The tag to persist. diff --git a/xbmc/pvr/epg/EpgTagsContainer.cpp b/xbmc/pvr/epg/EpgTagsContainer.cpp index 797f0c10c7..c1a8123959 100644 --- a/xbmc/pvr/epg/EpgTagsContainer.cpp +++ b/xbmc/pvr/epg/EpgTagsContainer.cpp @@ -643,10 +643,10 @@ void CPVREpgTagsContainer::QueuePersistQuery() } } -void CPVREpgTagsContainer::Delete() +void CPVREpgTagsContainer::QueueDelete() { if (m_database) - m_database->DeleteEpgTags(m_iEpgID); + m_database->QueueDeleteEpgTags(m_iEpgID); Clear(); } diff --git a/xbmc/pvr/epg/EpgTagsContainer.h b/xbmc/pvr/epg/EpgTagsContainer.h index 75ed5029b9..99b06b946f 100644 --- a/xbmc/pvr/epg/EpgTagsContainer.h +++ b/xbmc/pvr/epg/EpgTagsContainer.h @@ -171,9 +171,9 @@ public: void QueuePersistQuery(); /*! - * @brief Delete this container from its database. + * @brief Queue the deletion of this container from its database. */ - void Delete(); + void QueueDelete(); private: /*! -- cgit v1.2.3 From 4cf954f6695bf0cfece1a41e49f98e3aaa70d080 Mon Sep 17 00:00:00 2001 From: phunkyfish Date: Sat, 7 Nov 2020 13:44:43 +0000 Subject: [pvr] bulk commit channel queries when removing channels no longer on the backend --- xbmc/pvr/PVRDatabase.cpp | 20 ++++++++++++++++---- xbmc/pvr/PVRDatabase.h | 12 +++++++++++- xbmc/pvr/channels/PVRChannel.cpp | 4 ++-- xbmc/pvr/channels/PVRChannel.h | 2 +- xbmc/pvr/channels/PVRChannelGroupInternal.cpp | 24 +++++++++++++++++++++--- 5 files changed, 51 insertions(+), 11 deletions(-) diff --git a/xbmc/pvr/PVRDatabase.cpp b/xbmc/pvr/PVRDatabase.cpp index afba3956b5..77895e4e4e 100644 --- a/xbmc/pvr/PVRDatabase.cpp +++ b/xbmc/pvr/PVRDatabase.cpp @@ -75,6 +75,16 @@ void CPVRDatabase::Close() CDatabase::Close(); } +void CPVRDatabase::Lock() +{ + m_critSection.lock(); +} + +void CPVRDatabase::Unlock() +{ + m_critSection.unlock(); +} + void CPVRDatabase::CreateTables() { CSingleLock lock(m_critSection); @@ -289,19 +299,21 @@ bool CPVRDatabase::DeleteChannels() return DeleteValues("channels"); } -bool CPVRDatabase::Delete(const CPVRChannel& channel) +bool CPVRDatabase::QueueDeleteQuery(const CPVRChannel& channel) { /* invalid channel */ if (channel.ChannelID() <= 0) return false; - CLog::LogFC(LOGDEBUG, LOGPVR, "Deleting channel '{}' from the database", channel.ChannelName()); + CLog::LogFC(LOGDEBUG, LOGPVR, "Queueing delete for channel '{}' from the database", + channel.ChannelName()); Filter filter; filter.AppendWhere(PrepareSQL("idChannel = %u", channel.ChannelID())); - CSingleLock lock(m_critSection); - return DeleteValues("channels", filter); + std::string strQuery; + BuildSQL(PrepareSQL("DELETE FROM %s ", "channels"), filter, strQuery); + return CDatabase::QueueDeleteQuery(strQuery); } int CPVRDatabase::Get(CPVRChannelGroup& results, bool bCompressDB) diff --git a/xbmc/pvr/PVRDatabase.h b/xbmc/pvr/PVRDatabase.h index d0cb5cc879..b2b73db319 100644 --- a/xbmc/pvr/PVRDatabase.h +++ b/xbmc/pvr/PVRDatabase.h @@ -45,6 +45,16 @@ namespace PVR */ void Close() override; + /*! + * @brief Lock the database. + */ + void Lock(); + + /*! + * @brief Unlock the database. + */ + void Unlock(); + /*! * @brief Get the minimal database version that is required to operate correctly. * @return The minimal database version. @@ -109,7 +119,7 @@ namespace PVR * @param channel The channel to remove. * @return True if the channel was removed, false otherwise. */ - bool Delete(const CPVRChannel& channel); + bool QueueDeleteQuery(const CPVRChannel& channel); /*! * @brief Get the list of channels from the database diff --git a/xbmc/pvr/channels/PVRChannel.cpp b/xbmc/pvr/channels/PVRChannel.cpp index 5187b1647d..271d1b336e 100644 --- a/xbmc/pvr/channels/PVRChannel.cpp +++ b/xbmc/pvr/channels/PVRChannel.cpp @@ -101,7 +101,7 @@ void CPVRChannel::Serialize(CVariant& value) const /********** XBMC related channel methods **********/ -bool CPVRChannel::Delete() +bool CPVRChannel::QueueDelete() { bool bReturn = false; const std::shared_ptr database = CServiceBroker::GetPVRManager().GetTVDatabase(); @@ -117,7 +117,7 @@ bool CPVRChannel::Delete() m_epg.reset(); } - bReturn = database->Delete(*this); + bReturn = database->QueueDeleteQuery(*this); return bReturn; } diff --git a/xbmc/pvr/channels/PVRChannel.h b/xbmc/pvr/channels/PVRChannel.h index f678ed4661..ff489197f6 100644 --- a/xbmc/pvr/channels/PVRChannel.h +++ b/xbmc/pvr/channels/PVRChannel.h @@ -50,7 +50,7 @@ namespace PVR * @brief Delete this channel from the database and delete the corresponding EPG table if it exists. * @return True if it was deleted successfully, false otherwise. */ - bool Delete(); + bool QueueDelete(); /*! * @brief Update this channel tag with the data of the given channel tag. diff --git a/xbmc/pvr/channels/PVRChannelGroupInternal.cpp b/xbmc/pvr/channels/PVRChannelGroupInternal.cpp index 96e065d9dd..5b51c4ca2d 100644 --- a/xbmc/pvr/channels/PVRChannelGroupInternal.cpp +++ b/xbmc/pvr/channels/PVRChannelGroupInternal.cpp @@ -282,10 +282,28 @@ std::vector> CPVRChannelGroupInternal::RemoveDelete { std::vector> removedChannels = CPVRChannelGroup::RemoveDeletedChannels(channels); - for (const auto& channel : removedChannels) + bool channelsDeleted = false; + + const std::shared_ptr database = CServiceBroker::GetPVRManager().GetTVDatabase(); + if (!database) + { + CLog::LogF(LOGERROR, "No TV database"); + } + else { - // since channel was not found in the internal group, it was deleted from the backend - channel->Delete(); + // Note: We must lock the db the whole time, otherwise races may occur. + database->Lock(); + + for (const auto& channel : removedChannels) + { + // since channel was not found in the internal group, it was deleted from the backend + channelsDeleted |= channel->QueueDelete(); + } + + if (channelsDeleted) + database->CommitDeleteQueries(); + + database->Unlock(); } return removedChannels; -- cgit v1.2.3