Ticket #1728: eitcache_db.2.diff

File eitcache_db.2.diff, 13.9 KB (added by Janne <janne-mythtv@…>, 14 years ago)

correct one tiny error in the previous patch

  • libs/libmythtv/dbcheck.cpp

    old new using namespace std; 
    1010#include "mythdbcon.h"
    1111
    1212/// This is the DB schema version expected by the running MythTV instance.
    13 const QString currentDatabaseVersion = "1138";
     13const QString currentDatabaseVersion = "1139";
    1414
    1515static bool UpdateDBVersionNumber(const QString &newnumber);
    1616static bool performActualUpdate(const QString updates[], QString version,
    static bool doUpgradeTVDatabaseSchema(vo 
    22132213            return false;
    22142214    }
    22152215
     2216    if (dbver == "1138")
     2217    {
     2218        const QString updates[] = {
     2219"CREATE TABLE eit_cache ("
     2220"  chanid  INT(10) NOT NULL, "
     2221"  eventid SMALLINT UNSIGNED NOT NULL, "
     2222"  tableid TINYINT UNSIGNED NOT NULL, "
     2223"  version TINYINT UNSIGNED NOT NULL, "
     2224"  endtime INT UNSIGNED NOT NULL, "
     2225"  PRIMARY KEY  (chanid, eventid) "
     2226");",
     2227"",
     2228};
     2229
     2230       if (!performActualUpdate(updates, "1139", dbver))
     2231            return false;
     2232    }
     2233
    22162234//"ALTER TABLE capturecard DROP COLUMN dvb_recordts;" in 0.21
    22172235//"ALTER TABLE capturecard DROP COLUMN dvb_hw_decoder;" in 0.21
    22182236//"ALTER TABLE cardinput DROP COLUMN  preference;" in 0.22
  • libs/libmythtv/eitcache.cpp

    old new  
    1010
    1111#include "eitcache.h"
    1212#include "mythcontext.h"
     13#include "mythdbcon.h"
    1314
    1415#define LOC QString("EITCache: ")
    1516
     
    1718const uint EITCache::kVersionMax = 31;
    1819
    1920EITCache::EITCache()
    20     : accessCnt(0), hitCnt(0),   tblChgCnt(0),
    21       verChgCnt(0), pruneCnt(0), prunedHitCnt(0)
     21    : accessCnt(0), hitCnt(0),   tblChgCnt(0),   verChgCnt(0),
     22      entryCnt(0), pruneCnt(0), prunedHitCnt(0), wrongChannelHitCnt(0)
    2223{
    2324    // 24 hours ago
    2425    lastPruneTime = QDateTime::currentDateTime(Qt::UTC).toTime_t() - 86400;
    2526}
    2627
     28EITCache::~EITCache()
     29{
     30    WriteToDB();
     31}
     32
    2733void EITCache::ResetStatistics(void)
    2834{
    2935    accessCnt = 0;
    3036    hitCnt    = 0;
    3137    tblChgCnt = 0;
    3238    verChgCnt = 0;
     39    entryCnt  = 0;
    3340    pruneCnt  = 0;
    3441    prunedHitCnt = 0;
     42    wrongChannelHitCnt = 0;
    3543}
    3644
    3745QString EITCache::GetStatistics(void) const
    QString EITCache::GetStatistics(void) co 
    4048    return QString(
    4149        "EITCache::statistics: Accesses: %1, Hits: %2, "
    4250        "Table Upgrades %3, New Versions: %4, Entries: %5 "
    43         "Pruned entries: %6, pruned Hits: %7.")
     51        "Pruned entries: %6, pruned Hits: %7 Discard channel Hit %8 "
     52        "Hit Ratio %9.")
    4453        .arg(accessCnt).arg(hitCnt).arg(tblChgCnt).arg(verChgCnt)
    45         .arg(eventMap.size()).arg(pruneCnt).arg(prunedHitCnt);
     54        .arg(entryCnt).arg(pruneCnt).arg(prunedHitCnt)
     55        .arg(wrongChannelHitCnt)
     56        .arg((hitCnt+prunedHitCnt+wrongChannelHitCnt)/(double)accessCnt);
     57}
     58
     59static inline uint64_t construct_channel(uint networkid, uint tsid, uint serviceid)
     60{
     61    return (((uint64_t) networkid << 32) | ((uint64_t) tsid    << 16) |
     62            ((uint64_t) serviceid));
     63}
     64
     65static inline uint extract_onid(uint64_t channel)
     66{
     67    return (channel >> 32) & 0xffff;
     68}
     69
     70static inline uint extract_tsid(uint64_t channel)
     71{
     72    return (channel >> 16) & 0xffff;
    4673}
    4774
    48 static uint64_t construct_key(uint networkid, uint tsid,
    49                               uint serviceid, uint eventid)
     75static inline uint extrac_sid(uint64_t channel)
    5076{
    51     return (((uint64_t) networkid << 48) | ((uint64_t) tsid    << 32) |
    52             ((uint64_t) serviceid << 16) | ((uint64_t) eventid      ));
     77    return channel & 0xffff;
    5378}
    5479
    55 static uint64_t construct_sig(uint tableid, uint version, uint endtime)
     80static inline uint64_t construct_sig(uint tableid, uint version, uint endtime,
     81                              bool modified)
    5682{
    57     return (((uint64_t) tableid   << 40) | ((uint64_t) version   << 32) |
    58             ((uint64_t) endtime));
     83    return (((uint64_t) modified  << 63) | ((uint64_t) tableid   << 40) |
     84            ((uint64_t) version   << 32) | ((uint64_t) endtime));
    5985}
    6086
    61 static uint extract_table_id(uint64_t sig)
     87static inline uint extract_table_id(uint64_t sig)
    6288{
    6389    return (sig >> 40) & 0xff;
    6490}
    6591
    66 static uint extract_version(uint64_t sig)
     92static inline uint extract_version(uint64_t sig)
    6793{
    6894    return (sig >> 32) & 0x1f;
    6995}
    7096
    71 static uint extract_endtime(uint64_t sig)
     97static inline uint extract_endtime(uint64_t sig)
    7298{
    7399    return sig & 0xffffffff;
    74100}
    75101
     102static inline bool modified(uint64_t sig)
     103{
     104    return sig >> 63;
     105}
     106
     107static int get_chanid_from_db(uint networkid, uint tsid, uint serviceid)
     108{
     109    MSqlQuery query(MSqlQuery::InitCon());
     110
     111    // DVB Link to chanid
     112    QString qstr =
     113        "SELECT chanid, useonairguide "
     114        "FROM channel, dtv_multiplex "
     115        "WHERE serviceid        = :SERVICEID   AND "
     116        "      networkid        = :NETWORKID   AND "
     117        "      transportid      = :TRANSPORTID AND "
     118        "      channel.mplexid  = dtv_multiplex.mplexid";
     119
     120    query.prepare(qstr);
     121    query.bindValue(":SERVICEID",   serviceid);
     122    query.bindValue(":NETWORKID",   networkid);
     123    query.bindValue(":TRANSPORTID", tsid);
     124
     125    if (!query.exec() || !query.isActive())
     126        MythContext::DBError("Looking up chanID", query);
     127    else if (query.next())
     128    {
     129        bool useOnAirGuide = query.value(1).toBool();
     130        return (useOnAirGuide) ? query.value(0).toInt() : -1;
     131    }
     132    return -1;
     133}
     134
     135static void replace_in_db(int chanid, uint eventid, uint64_t sig)
     136{
     137
     138    MSqlQuery query(MSqlQuery::InitCon());
     139
     140    QString qstr =
     141        "REPLACE INTO eit_cache "
     142        "       ( chanid,  eventid,  tableid,  version,  endtime) "
     143        "VALUES (:CHANID, :EVENTID, :TABLEID, :VERSION, :ENDTIME)";
     144
     145    query.prepare(qstr);
     146    query.bindValue(":CHANID",   chanid);
     147    query.bindValue(":EVENTID",  eventid);
     148    query.bindValue(":TABLEID",  extract_table_id(sig));
     149    query.bindValue(":VERSION",  extract_version(sig));
     150    query.bindValue(":ENDTIME",  extract_endtime(sig));
     151
     152    if (!query.exec())
     153        MythContext::DBError("Error updating eitcache", query);
     154
     155    return;
     156}
     157
     158
     159event_map_t * EITCache::LoadChannel(uint networkid, uint tsid, uint serviceid)
     160{
     161    int chanid = get_chanid_from_db(networkid, tsid, serviceid);
     162
     163    if (chanid < 1)
     164        return NULL;
     165
     166    MSqlQuery query(MSqlQuery::InitCon());
     167
     168    QString qstr =
     169        "SELECT eventid,tableid,version,endtime "
     170        "FROM eit_cache "
     171        "WHERE chanid        = :CHANID   AND "
     172        "      endtime       > :ENDTIME";
     173
     174    query.prepare(qstr);
     175    query.bindValue(":CHANID",   chanid);
     176    query.bindValue(":ENDTIME",  lastPruneTime);
     177
     178    if (!query.exec() || !query.isActive())
     179    {
     180        MythContext::DBError("Error loading eitcache", query);
     181        return NULL;
     182    }
     183
     184    event_map_t * eventMap = new event_map_t();
     185
     186    while (query.next())
     187    {
     188        uint eventid = query.value(0).toUInt();
     189        uint tableid = query.value(1).toUInt();
     190        uint version = query.value(2).toUInt();
     191        uint endtime = query.value(3).toUInt();
     192
     193        (*eventMap)[eventid] = construct_sig(tableid, version, endtime, false);
     194    }
     195
     196    VERBOSE(VB_EIT, LOC + QString("Loaded %1 entries for channel %2")
     197            .arg(eventMap->size()).arg(chanid));
     198
     199    entryCnt += eventMap->size();
     200    return eventMap;
     201}
     202
     203
     204void EITCache::DropChannel(uint64_t channel)
     205{
     206    int chanid = get_chanid_from_db(extract_onid(channel),
     207                                    extract_tsid(channel),
     208                                    extrac_sid(channel));
     209
     210    if (chanid < 1)
     211        return;
     212
     213    event_map_t * eventMap = channelMap[channel];
     214
     215    uint size    = eventMap->size();
     216    uint written = 0;
     217
     218    event_map_t::iterator it = eventMap->begin();
     219    while (it != eventMap->end())
     220    {
     221        if (modified(*it) && extract_endtime(*it) > lastPruneTime)
     222        {
     223            replace_in_db(chanid, it.key(), *it);
     224            written++;
     225        }
     226
     227        event_map_t::iterator tmp = it;
     228        ++tmp;
     229        eventMap->erase(it);
     230        it = tmp;
     231    }
     232    channelMap.erase(channel);
     233
     234    VERBOSE(VB_EIT, LOC + QString("Writed %1 modified entries of %2 "
     235                                  "for channel %3 to database.")
     236            .arg(written).arg(size).arg(chanid));
     237    entryCnt -= size;
     238}
     239
     240void EITCache::WriteToDB(void)
     241{
     242    QMutexLocker locker(&eventMapLock);
     243
     244    key_map_t::iterator it = channelMap.begin();
     245    while (it != channelMap.end())
     246    {
     247        key_map_t::iterator tmp = it;
     248        ++tmp;
     249        DropChannel(it.key());
     250        it = tmp;
     251    }
     252    entryCnt = 0;
     253}
     254
     255
     256
    76257bool EITCache::IsNewEIT(uint networkid, uint tsid,    uint serviceid,
    77258                        uint tableid,   uint version,
    78259                        uint eventid,   uint endtime)
    79260{
    80261    accessCnt++;
    81262
     263    if (accessCnt % 500000 == 50000)
     264    {
     265        cerr << GetStatistics() << endl;
     266        WriteToDB();
     267    }
     268
    82269    // don't readd pruned entries
    83270    if (endtime < lastPruneTime)
    84271    {
    bool EITCache::IsNewEIT(uint networkid,  
    86273        return false;
    87274    }
    88275
    89     uint64_t key = construct_key(networkid, tsid, serviceid, eventid);
     276    uint64_t channel = construct_channel(networkid, tsid, serviceid);
    90277
    91278    QMutexLocker locker(&eventMapLock);
    92     key_map_t::const_iterator it = eventMap.find(key);
     279    if (!channelMap.contains(channel))
     280    {
     281        channelMap[channel] = LoadChannel(networkid, tsid, serviceid);
     282    }
    93283
    94     if (it != eventMap.end())
     284    if (!channelMap[channel])
     285    {
     286        wrongChannelHitCnt++;
     287        return false;
     288    }
     289
     290    event_map_t * eventMap = channelMap[channel];
     291    event_map_t::iterator it = eventMap->find(eventid);
     292    if (it != eventMap->end())
    95293    {
    96294        if (extract_table_id(*it) > tableid)
    97295        {
    bool EITCache::IsNewEIT(uint networkid,  
    113311            return false;
    114312        }
    115313    }
    116 
    117     eventMap[key] = construct_sig(tableid, version, endtime);
     314    eventMap->insert(eventid, construct_sig(tableid, version, endtime, true));
     315    entryCnt++;
    118316
    119317    return true;
    120318}
    uint EITCache::PruneOldEntries(uint time 
    133331                tmptime.toString(Qt::ISODate));
    134332    }
    135333
    136     QMutexLocker locker(&eventMapLock);
    137     uint orig_size = eventMap.size();
    138 
    139     key_map_t::iterator it = eventMap.begin();
    140     while (it != eventMap.end())
    141     {
    142         if (extract_endtime(*it) < timestamp)
    143         {
    144             key_map_t::iterator tmp = it;
    145             ++tmp;
    146             eventMap.erase(it);
    147             it = tmp;
    148             continue;
    149         }
    150         ++it;
    151     }
    152 
    153     uint pruned    = orig_size - eventMap.size();
    154     prunedHitCnt  += pruned;
    155334    lastPruneTime  = timestamp;
     335    //Write all modified entries to DB and start with a clean cache
     336    WriteToDB();
     337    // TODO: prune old entries in the DB
    156338
    157     return pruned;
     339    return 0;
    158340}
    159341
    160342/* vim: set expandtab tabstop=4 shiftwidth=4: */
  • libs/libmythtv/eitcache.h

    old new  
    1313#include <qmutex.h>
    1414#include <qstring.h>
    1515
    16 typedef QMap<uint64_t, uint64_t> key_map_t;
     16typedef QMap<uint, uint64_t> event_map_t;
     17typedef QMap<uint64_t, event_map_t*> key_map_t;
    1718
    1819class EITCache
    1920{
    2021  public:
    2122    EITCache();
    22    ~EITCache() {};
     23   ~EITCache();
    2324
    2425    bool IsNewEIT(uint networkid, uint tsid,    uint serviceid,
    2526                  uint tableid,   uint version,
    class EITCache 
    3132    QString GetStatistics(void) const;
    3233
    3334  private:
     35    event_map_t * LoadChannel(uint networkid, uint tsid, uint serviceid);
     36    void DropChannel(uint64_t channel);
     37    void WriteToDB(void);
     38
    3439    // event key cache
    35     key_map_t   eventMap;
     40    key_map_t   channelMap;
    3641
    3742    mutable QMutex eventMapLock;
    3843    uint            lastPruneTime;
    class EITCache 
    4247    uint        hitCnt;
    4348    uint        tblChgCnt;
    4449    uint        verChgCnt;
     50    uint        entryCnt;
    4551    uint        pruneCnt;
    4652    uint        prunedHitCnt;
     53    uint        wrongChannelHitCnt;
    4754
    4855    static const uint kVersionMax;
    4956};
  • libs/libmythtv/eithelper.h

    old new class EITHelper 
    6969
    7070    void AddEIT(const DVBEventInformationTable *eit);
    7171
     72    void PruneCache(uint timestamp);
     73
    7274  private:
    7375    uint GetChanID(uint atscsrcid);
    7476    uint GetChanID(uint serviceid, uint networkid, uint transportid);
  • libs/libmythtv/eitscanner.cpp

    old new void EITScanner::RunEventLoop(void) 
    135135            activeScanNextTrig = QDateTime::currentDateTime()
    136136                .addSecs(activeScanTrigTime);
    137137            activeScanNextChan++;
     138
     139            // 24 hours ago
     140            eitHelper->PruneCache(activeScanNextTrig.toTime_t() - 86400);
    138141        }
    139142
    140143        exitThreadCond.wait(200); // sleep up to 200 ms.
  • libs/libmythtv/eithelper.cpp

    old new void EITHelper::AddEIT(const DVBEventInf 
    336336    }
    337337}
    338338
     339void EITHelper::PruneCache(uint timestamp)
     340{
     341    eitcache->PruneOldEntries(timestamp);
     342}
     343
    339344//////////////////////////////////////////////////////////////////////
    340345// private methods and functions below this line                    //
    341346//////////////////////////////////////////////////////////////////////