aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLars Op den Kamp <opdenkamp@gmail.com>2012-11-30 18:01:24 -0800
committerLars Op den Kamp <opdenkamp@gmail.com>2012-11-30 18:01:24 -0800
commit32b3d87d4e6afd157a00221e66a89da06884ee21 (patch)
tree1b7f304d5f17d0eb79d84bc7093278a1a61fc4a1
parenteb9eecdfc11feff35115b189b021aac871025298 (diff)
parent2fe0e24ef86e1a54efcc9ef6200386f1d7fd60f1 (diff)
Merge pull request #1834 from opdenkamp/bg_db_updates
speed up EPG data import
-rw-r--r--xbmc/epg/Epg.cpp230
-rw-r--r--xbmc/epg/Epg.h14
-rw-r--r--xbmc/epg/EpgContainer.cpp40
-rw-r--r--xbmc/epg/EpgDatabase.cpp2
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) "