diff --git a/src/live/channelcache.c b/src/live/channelcache.c index 460eebc..42a7904 100644 --- a/src/live/channelcache.c +++ b/src/live/channelcache.c @@ -154,9 +154,12 @@ void cChannelCache::AddToCache(const cChannel* channel) { std::map::iterator i = m_cache.find(uid); - // channel already in cache - if(i != m_cache.end()) - return; + // valid channel already in cache + if(i != m_cache.end()) { + if(i->second.size() != 0) { + return; + } + } // create new cache item cChannelCache item; @@ -205,7 +208,16 @@ void cChannelCache::AddToCache(const cChannel* channel) { } cChannelCache cChannelCache::GetFromCache(uint32_t channeluid) { + static cChannelCache empty; + Lock(); + + std::map::iterator i = m_cache.find(channeluid); + if(i == m_cache.end()) { + Unlock(); + return empty; + } + cChannelCache result = m_cache[channeluid]; Unlock(); @@ -239,17 +251,48 @@ void cChannelCache::SaveChannelCacheData() { rename(filename, filenamenew); } -void cChannelCache::LoadChannelCacheData() { - m_cache.clear(); +void cChannelCache::gc() { + cMutexLock lock(&m_access); + std::map m_newcache; - // preload cache with VDR channel entries + INFOLOG("channel cache garbage collection ..."); + INFOLOG("before: %i channels in cache", m_cache.size()); + + // remove orphaned cache entries XVDRChannels.Lock(false); cChannels *channels = XVDRChannels.Get(); + for (cChannel *channel = channels->First(); channel; channel = channels->Next(channel)) { - AddToCache(channel); + uint32_t uid = CreateChannelUID(channel); + + // ignore invalid channels + if(uid == 0) + continue; + + // lookup channel in current cache + std::map::iterator i = m_cache.find(uid); + if(i == m_cache.end()) + continue; + + // add to new cache if it exists + m_newcache[uid] = i->second; } XVDRChannels.Unlock(); + // regenerate cache + m_cache.clear(); + std::map::iterator i; + + for(i = m_newcache.begin(); i != m_newcache.end(); i++) { + m_cache[i->first] = i->second; + } + + INFOLOG("after: %i channels in cache", m_cache.size()); +} + +void cChannelCache::LoadChannelCacheData() { + m_cache.clear(); + // load cache std::fstream in; cString filename = AddDirectory(XVDRServerConfig.CacheDirectory, CHANNEL_CACHE_FILE); @@ -288,6 +331,8 @@ void cChannelCache::LoadChannelCacheData() { if(uid != 0) m_cache[uid] = cache; } + + gc(); } diff --git a/src/live/channelcache.h b/src/live/channelcache.h index 0df78ee..728d2de 100644 --- a/src/live/channelcache.h +++ b/src/live/channelcache.h @@ -66,6 +66,8 @@ class cChannelCache : public std::map { static cChannelCache GetFromCache(uint32_t channeluid); + static void gc(); + private: static void Lock() { m_access.Lock(); } diff --git a/src/live/livestreamer.c b/src/live/livestreamer.c index 2da23a2..80d67eb 100644 --- a/src/live/livestreamer.c +++ b/src/live/livestreamer.c @@ -258,18 +258,33 @@ int cLiveStreamer::StreamChannel(const cChannel *channel, int sock, bool waitfor m_PatFilter = new cLivePatFilter(this, channel); // get cached demuxer data - DEBUGLOG("Creating demuxers"); cChannelCache cache = cChannelCache::GetFromCache(m_uid); - if(cache.size() != 0) { + + // channel not found in cache -> add it from vdr + if(cache.size() == 0) { + INFOLOG("adding channel to cache"); + cChannelCache::AddToCache(channel); + cache = cChannelCache::GetFromCache(m_uid); + } + + // channel already in cache + else { INFOLOG("Channel information found in cache"); + } + + // recheck cache item + if(cache.size() != 0) { + INFOLOG("Creating demuxers"); cache.CreateDemuxers(this); - if(!Attach()) { - INFOLOG("Unable to attach receiver !"); - return XVDR_RET_DATALOCKED; - } - RequestStreamChange(); } + if(!Attach()) { + INFOLOG("Unable to attach receiver !"); + return XVDR_RET_DATALOCKED; + } + + RequestStreamChange(); + DEBUGLOG("Starting PAT scanner"); m_Device->AttachFilter(m_PatFilter);