diff options
author | Lars Op den Kamp <opdenkamp@gmail.com> | 2012-11-30 18:01:24 -0800 |
---|---|---|
committer | Lars Op den Kamp <opdenkamp@gmail.com> | 2012-11-30 18:01:24 -0800 |
commit | 32b3d87d4e6afd157a00221e66a89da06884ee21 (patch) | |
tree | 1b7f304d5f17d0eb79d84bc7093278a1a61fc4a1 | |
parent | eb9eecdfc11feff35115b189b021aac871025298 (diff) | |
parent | 2fe0e24ef86e1a54efcc9ef6200386f1d7fd60f1 (diff) |
Merge pull request #1834 from opdenkamp/bg_db_updates
speed up EPG data import
-rw-r--r-- | xbmc/epg/Epg.cpp | 230 | ||||
-rw-r--r-- | xbmc/epg/Epg.h | 14 | ||||
-rw-r--r-- | xbmc/epg/EpgContainer.cpp | 40 | ||||
-rw-r--r-- | xbmc/epg/EpgDatabase.cpp | 2 |
4 files changed, 105 insertions, 181 deletions
diff --git a/xbmc/epg/Epg.cpp b/xbmc/epg/Epg.cpp index de6ad66665..353f968b9b 100644 --- a/xbmc/epg/Epg.cpp +++ b/xbmc/epg/Epg.cpp @@ -32,7 +32,7 @@ #include "pvr/channels/PVRChannelGroupsContainer.h" #include "utils/StringUtils.h" -#include "../addons/include/xbmc_pvr_types.h" // TODO extract the epg specific stuff +#include "../addons/include/xbmc_epg_types.h" using namespace PVR; using namespace EPG; @@ -45,7 +45,8 @@ CEpg::CEpg(int iEpgID, const CStdString &strName /* = "" */, const CStdString &s m_bUpdatePending(false), m_iEpgID(iEpgID), m_strName(strName), - m_strScraperName(strScraperName) + m_strScraperName(strScraperName), + m_bUpdateLastScanTime(false) { CPVRChannelPtr empty; m_pvrChannel = empty; @@ -59,7 +60,8 @@ CEpg::CEpg(CPVRChannelPtr channel, bool bLoadedFromDb /* = false */) : m_iEpgID(channel->EpgID()), m_strName(channel->ChannelName()), m_strScraperName(channel->EPGScraper()), - m_pvrChannel(channel) + m_pvrChannel(channel), + m_bUpdateLastScanTime(false) { } @@ -68,7 +70,8 @@ CEpg::CEpg(void) : m_bTagsChanged(false), m_bLoaded(false), m_bUpdatePending(false), - m_iEpgID(0) + m_iEpgID(0), + m_bUpdateLastScanTime(false) { CPVRChannelPtr empty; m_pvrChannel = empty; @@ -330,35 +333,30 @@ void CEpg::AddEntry(const CEpgInfoTag &tag) bool CEpg::UpdateEntry(const CEpgInfoTag &tag, bool bUpdateDatabase /* = false */, bool bSort /* = true */) { CEpgInfoTagPtr infoTag; - bool bReturn(false); + CSingleLock lock(m_critSection); + map<CDateTime, CEpgInfoTagPtr>::iterator it = m_tags.find(tag.StartAsUTC()); + bool bNewTag(false); + if (it != m_tags.end()) { - CSingleLock lock(m_critSection); - map<CDateTime, CEpgInfoTagPtr>::iterator it = m_tags.find(tag.StartAsUTC()); - bool bNewTag(false); - if (it != m_tags.end()) - { - infoTag = it->second; - } - else - { - /* create a new tag if no tag with this ID exists */ - infoTag = CEpgInfoTagPtr(new CEpgInfoTag(this, m_pvrChannel, m_strName, m_pvrChannel ? m_pvrChannel->IconPath() : StringUtils::EmptyString)); - infoTag->SetUniqueBroadcastID(tag.UniqueBroadcastID()); - m_tags.insert(make_pair(tag.StartAsUTC(), infoTag)); - bNewTag = true; - } - - infoTag->Update(tag, bNewTag); - infoTag->m_epg = this; - infoTag->m_pvrChannel = m_pvrChannel; + infoTag = it->second; } + else + { + /* create a new tag if no tag with this ID exists */ + infoTag = CEpgInfoTagPtr(new CEpgInfoTag(this, m_pvrChannel, m_strName, m_pvrChannel ? m_pvrChannel->IconPath() : StringUtils::EmptyString)); + infoTag->SetUniqueBroadcastID(tag.UniqueBroadcastID()); + m_tags.insert(make_pair(tag.StartAsUTC(), infoTag)); + bNewTag = true; + } + + infoTag->Update(tag, bNewTag); + infoTag->m_epg = this; + infoTag->m_pvrChannel = m_pvrChannel; if (bUpdateDatabase) - bReturn = infoTag->Persist(); - else - bReturn = true; + m_changedTags.insert(make_pair<int, CEpgInfoTagPtr>(infoTag->UniqueBroadcastID(), infoTag)); - return bReturn; + return true; } bool CEpg::Load(void) @@ -395,64 +393,29 @@ bool CEpg::Load(void) bool CEpg::UpdateEntries(const CEpg &epg, bool bStoreInDb /* = true */) { - bool bReturn(false); - CEpgDatabase *database = g_EpgContainer.GetDatabase(); - - if (epg.m_tags.size() > 0) - { - if (bStoreInDb) - { - if (!database || !database->IsOpen()) - { - CLog::Log(LOGERROR, "EPG -%s - could not open the database", __FUNCTION__); - return bReturn; - } - database->BeginTransaction(); - } - - { - CSingleLock lock(m_critSection); + CSingleLock lock(m_critSection); #if EPG_DEBUGGING - CLog::Log(LOGDEBUG, "EPG - %s - %zu entries in memory before merging", __FUNCTION__, m_tags.size()); + CLog::Log(LOGDEBUG, "EPG - %s - %zu entries in memory before merging", __FUNCTION__, m_tags.size()); #endif - /* copy over tags */ - for (map<CDateTime, CEpgInfoTagPtr>::const_iterator it = epg.m_tags.begin(); it != epg.m_tags.end(); it++) - UpdateEntry(*it->second, bStoreInDb, false); + /* copy over tags */ + for (map<CDateTime, CEpgInfoTagPtr>::const_iterator it = epg.m_tags.begin(); it != epg.m_tags.end(); it++) + UpdateEntry(*it->second, bStoreInDb, false); #if EPG_DEBUGGING - CLog::Log(LOGDEBUG, "EPG - %s - %zu entries in memory after merging and before fixing", __FUNCTION__, m_tags.size()); + CLog::Log(LOGDEBUG, "EPG - %s - %zu entries in memory after merging and before fixing", __FUNCTION__, m_tags.size()); #endif - FixOverlappingEvents(bStoreInDb); + FixOverlappingEvents(bStoreInDb); #if EPG_DEBUGGING - CLog::Log(LOGDEBUG, "EPG - %s - %zu entries in memory after fixing", __FUNCTION__, m_tags.size()); + CLog::Log(LOGDEBUG, "EPG - %s - %zu entries in memory after fixing", __FUNCTION__, m_tags.size()); #endif - /* update the last scan time of this table */ - m_lastScanTime = CDateTime::GetCurrentDateTime().GetAsUTCDateTime(); - - SetChanged(); - } - /* persist changes */ - if (bStoreInDb) - { - bReturn = database->CommitTransaction(); - if (bReturn) - Persist(true); - } - else - bReturn = true; - } - else - { - if (bStoreInDb) - bReturn = Persist(true); - else - bReturn = true; - } + /* update the last scan time of this table */ + m_lastScanTime = CDateTime::GetCurrentDateTime().GetAsUTCDateTime(); + m_bUpdateLastScanTime = true; NotifyObservers(ObservableMessageEpg); - return bReturn; + return true; } CDateTime CEpg::GetLastScanTime(void) @@ -566,52 +529,48 @@ int CEpg::Get(CFileItemList &results, const EpgSearchFilter &filter) const return results.Size() - iInitialSize; } -bool CEpg::Persist(bool bUpdateLastScanTime /* = false */) +bool CEpg::Persist(void) { - if (g_guiSettings.GetBool("epg.ignoredbforclient")) + if (g_guiSettings.GetBool("epg.ignoredbforclient") || !NeedsSave()) return true; - CEpgDatabase *database = g_EpgContainer.GetDatabase(); +#if EPG_DEBUGGING + CLog::Log(LOGDEBUG, "persist table '%s' (#%d) changed=%d deleted=%d", Name().c_str(), m_iEpgID, m_changedTags.size(), m_deletedTags.size()); +#endif + CEpgDatabase *database = g_EpgContainer.GetDatabase(); if (!database || !database->IsOpen()) { CLog::Log(LOGERROR, "EPG - %s - could not open the database", __FUNCTION__); return false; } - CEpg epgCopy; { CSingleLock lock(m_critSection); - epgCopy = *this; - m_bChanged = false; - m_bTagsChanged = false; - } - - database->BeginTransaction(); - - if (epgCopy.m_iEpgID <= 0 || epgCopy.m_bChanged) - { - int iId = database->Persist(epgCopy); - if (iId > 0) + if (m_iEpgID <= 0 || m_bChanged) { - epgCopy.m_iEpgID = iId; - epgCopy.m_bChanged = false; - if (m_iEpgID != epgCopy.m_iEpgID) - { - CSingleLock lock(m_critSection); - m_iEpgID = epgCopy.m_iEpgID; - } + int iId = database->Persist(*this, m_iEpgID > 0); + if (iId > 0) + m_iEpgID = iId; } - } - bool bReturn(true); + for (std::map<int, CEpgInfoTagPtr>::iterator it = m_deletedTags.begin(); it != m_deletedTags.end(); it++) + database->Delete(*it->second); - if (bUpdateLastScanTime) - bReturn = database->PersistLastEpgScanTime(epgCopy.m_iEpgID); + for (std::map<int, CEpgInfoTagPtr>::iterator it = m_changedTags.begin(); it != m_changedTags.end(); it++) + it->second->Persist(false); - database->CommitTransaction(); + if (m_bUpdateLastScanTime) + database->PersistLastEpgScanTime(m_iEpgID, true); - return bReturn; + m_deletedTags.clear(); + m_changedTags.clear(); + m_bChanged = false; + m_bTagsChanged = false; + m_bUpdateLastScanTime = false; + } + + return database->CommitInsertQueries(); } CDateTime CEpg::GetFirstDate(void) const @@ -666,16 +625,6 @@ bool CEpg::FixOverlappingEvents(bool bUpdateDb /* = false */) { bool bReturn(true); CEpgInfoTagPtr previousTag, currentTag; - CEpgDatabase *database(NULL); - if (bUpdateDb) - { - database = g_EpgContainer.GetDatabase(); - if (!database || !database->IsOpen()) - { - CLog::Log(LOGERROR, "EPG - %s - could not open the database", __FUNCTION__); - return false; - } - } for (map<CDateTime, CEpgInfoTagPtr>::iterator it = m_tags.begin(); it != m_tags.end(); it != m_tags.end() ? it++ : it) { @@ -690,7 +639,7 @@ bool CEpg::FixOverlappingEvents(bool bUpdateDb /* = false */) { // delete the current tag. it's completely overlapped if (bUpdateDb) - bReturn &= database->Delete(*currentTag); + m_deletedTags.insert(make_pair<int, CEpgInfoTagPtr>(currentTag->UniqueBroadcastID(), currentTag)); if (m_nowActiveStart == it->first) m_nowActiveStart.SetValid(false); @@ -702,7 +651,7 @@ bool CEpg::FixOverlappingEvents(bool bUpdateDb /* = false */) { currentTag->SetStartFromUTC(previousTag->EndAsUTC()); if (bUpdateDb) - bReturn &= currentTag->Persist(); + m_changedTags.insert(make_pair<int, CEpgInfoTagPtr>(currentTag->UniqueBroadcastID(), currentTag)); previousTag = it->second; } @@ -722,8 +671,8 @@ bool CEpg::FixOverlappingEvents(bool bUpdateDb /* = false */) if (bUpdateDb) { - bReturn &= currentTag->Persist(); - bReturn &= previousTag->Persist(); + m_changedTags.insert(make_pair<int, CEpgInfoTagPtr>(currentTag->UniqueBroadcastID(), currentTag)); + m_changedTags.insert(make_pair<int, CEpgInfoTagPtr>(previousTag->UniqueBroadcastID(), previousTag)); } previousTag = it->second; @@ -783,47 +732,6 @@ bool CEpg::UpdateFromScraper(time_t start, time_t end) return bGrabSuccess; } -bool CEpg::PersistTags(void) const -{ - bool bReturn = false; - CEpgDatabase *database = g_EpgContainer.GetDatabase(); - - if (!database || !database->IsOpen()) - { - CLog::Log(LOGERROR, "EPG - %s - could not load the database", __FUNCTION__); - return bReturn; - } - - CDateTime first = GetFirstDate(); - CDateTime last = GetLastDate(); - - time_t iStart(0), iEnd(0); - if (first.IsValid()) - first.GetAsTime(iStart); - if (last.IsValid()) - last.GetAsTime(iEnd); - database->Delete(*this, iStart, iEnd); - - if (m_tags.size() > 0) - { - for (map<CDateTime, CEpgInfoTagPtr>::const_iterator it = m_tags.begin(); it != m_tags.end(); it++) - { - if (!it->second->Persist()) - { - CLog::Log(LOGERROR, "EPG - failed to persist epg tag %d", it->second->UniqueBroadcastID()); - bReturn = false; - } - } - } - else - { - /* Return true if we have no tags, so that no error is logged */ - bReturn = true; - } - - return bReturn; -} - //@} const CStdString &CEpg::ConvertGenreIdToString(int iID, int iSubID) @@ -987,3 +895,9 @@ size_t CEpg::Size(void) const CSingleLock lock(m_critSection); return m_tags.size(); } + +bool CEpg::NeedsSave(void) const +{ + CSingleLock lock(m_critSection); + return !m_changedTags.empty() || !m_deletedTags.empty() || m_bChanged; +} diff --git a/xbmc/epg/Epg.h b/xbmc/epg/Epg.h index 5f6d536260..b22206351e 100644 --- a/xbmc/epg/Epg.h +++ b/xbmc/epg/Epg.h @@ -246,10 +246,9 @@ namespace EPG /*! * @brief Persist this table in the database. - * @param bUpdateLastScanTime True to update the last scan time in the db, false otherwise. * @return True if the table was persisted, false otherwise. */ - bool Persist(bool bUpdateLastScanTime = false); + bool Persist(void); /*! * @brief Get the start time of the first entry in this table. @@ -298,6 +297,8 @@ namespace EPG CEpgInfoTagPtr GetPreviousEvent(const CEpgInfoTag& tag) const; size_t Size(void) const; + + bool NeedsSave(void) const; protected: CEpg(void); @@ -311,12 +312,6 @@ namespace EPG bool UpdateFromScraper(time_t start, time_t end); /*! - * @brief Persist all tags in this container. - * @return True if all tags were persisted, false otherwise. - */ - bool PersistTags(void) const; - - /*! * @brief Fix overlapping events from the tables. * @param bUpdateDb If set to yes, any changes to tags during fixing will be persisted to database * @return True if anything changed, false otherwise. @@ -348,6 +343,8 @@ namespace EPG bool IsRemovableTag(const EPG::CEpgInfoTag &tag) const; std::map<CDateTime, CEpgInfoTagPtr> m_tags; + std::map<int, CEpgInfoTagPtr> m_changedTags; + std::map<int, CEpgInfoTagPtr> m_deletedTags; bool m_bChanged; /*!< true if anything changed that needs to be persisted, false otherwise */ bool m_bTagsChanged; /*!< true when any tags are changed and not persisted, false otherwise */ bool m_bLoaded; /*!< true when the initial entries have been loaded */ @@ -362,5 +359,6 @@ namespace EPG PVR::CPVRChannelPtr m_pvrChannel; /*!< the channel this EPG belongs to */ CCriticalSection m_critSection; /*!< critical section for changes in this table */ + bool m_bUpdateLastScanTime; }; } diff --git a/xbmc/epg/EpgContainer.cpp b/xbmc/epg/EpgContainer.cpp index d387059a36..3e8c84b454 100644 --- a/xbmc/epg/EpgContainer.cpp +++ b/xbmc/epg/EpgContainer.cpp @@ -136,6 +136,9 @@ void CEpgContainer::Start(void) m_iNextEpgUpdate = 0; m_iNextEpgActiveTagCheck = 0; + LoadFromDB(); + CheckPlayingEvents(); + Create(); SetPriority(-1); CLog::Log(LOGNOTICE, "%s - EPG thread started", __FUNCTION__); @@ -165,9 +168,15 @@ void CEpgContainer::Notify(const Observable &obs, const ObservableMessage msg) void CEpgContainer::LoadFromDB(void) { + if (m_bLoaded || m_bIgnoreDbForClient) + return; + + if (!m_database.IsOpen()) + m_database.Open(); + bool bLoaded(true); unsigned int iCounter(0); - if (!m_bIgnoreDbForClient && m_database.IsOpen()) + if (m_database.IsOpen()) { ShowProgressDialog(false); @@ -196,13 +205,15 @@ bool CEpgContainer::PersistAll(void) { bool bReturn(true); CSingleLock lock(m_critSection); - for (map<unsigned int, CEpg *>::iterator it = m_epgs.begin(); it != m_epgs.end(); it++) + for (map<unsigned int, CEpg *>::iterator it = m_epgs.begin(); it != m_epgs.end() && !m_bStop; it++) { CEpg *epg = it->second; - lock.Leave(); - if (epg) - bReturn &= epg->Persist(false); - lock.Enter(); + if (epg && epg->NeedsSave()) + { + lock.Leave(); + bReturn &= epg->Persist(); + lock.Enter(); + } } return bReturn; @@ -210,17 +221,10 @@ bool CEpgContainer::PersistAll(void) void CEpgContainer::Process(void) { - time_t iNow = 0; - + time_t iNow(0), iLastSave(0); bool bUpdateEpg(true); bool bHasPendingUpdates(false); - if (!m_bLoaded) - { - LoadFromDB(); - CheckPlayingEvents(); - } - while (!m_bStop && !g_application.m_bStop) { CDateTime::GetCurrentDateTime().GetAsUTCDateTime().GetAsTime(iNow); @@ -253,6 +257,13 @@ void CEpgContainer::Process(void) if (!m_bStop) CheckPlayingEvents(); + /* check for changes that need to be saved every 60 seconds */ + if (iNow - iLastSave > 60) + { + PersistAll(); + iLastSave = iNow; + } + Sleep(1000); } @@ -306,6 +317,7 @@ CEpg *CEpgContainer::CreateChannelEpg(CPVRChannelPtr channel) WaitForUpdateFinish(true); CSingleLock lock(m_critSection); + LoadFromDB(); CEpg *epg(NULL); if (channel->EpgID() > 0) diff --git a/xbmc/epg/EpgDatabase.cpp b/xbmc/epg/EpgDatabase.cpp index 21e42b8c33..97854ed305 100644 --- a/xbmc/epg/EpgDatabase.cpp +++ b/xbmc/epg/EpgDatabase.cpp @@ -383,7 +383,7 @@ int CEpgDatabase::Persist(const CEpgInfoTag &tag, bool bSingleUpdate /* = true * if (iBroadcastId < 0) { - strQuery = FormatSQL("INSERT INTO epgtags (idEpg, iStartTime, " + strQuery = FormatSQL("REPLACE INTO epgtags (idEpg, iStartTime, " "iEndTime, sTitle, sPlotOutline, sPlot, iGenreType, iGenreSubType, sGenre, " "iFirstAired, iParentalRating, iStarRating, bNotify, iSeriesId, " "iEpisodeId, iEpisodePart, sEpisodeName, iBroadcastUid) " |