Ticket #1660: asyncdb.12631.patch

File asyncdb.12631.patch, 14.3 KB (added by wilhelm.eger@…, 6 years ago)

Patch for SVN Ver. 12631

  • libs/libmythtv/NuppelVideoPlayer.cpp

     
    52425242    using_null_videoout = true; 
    52435243 
    52445244    // clear out any existing seektables 
    5245     m_playbackinfo->ClearPositionMap(MARK_KEYFRAME); 
    5246     m_playbackinfo->ClearPositionMap(MARK_GOP_START); 
    5247     m_playbackinfo->ClearPositionMap(MARK_GOP_BYFRAME); 
     5245    m_playbackinfo->ClearPositionMap(MARK_KEYFRAME,true); 
     5246    m_playbackinfo->ClearPositionMap(MARK_GOP_START,true); 
     5247    m_playbackinfo->ClearPositionMap(MARK_GOP_BYFRAME,true); 
    52485248 
    52495249    if (OpenFile() < 0) 
    52505250        return(0); 
  • libs/libmythtv/programinfo.h

     
    220220    // Keyframe positions Map 
    221221    void GetPositionMap(frm_pos_map_t &, int type) const; 
    222222    void ClearPositionMap(int type) const; 
     223    void ClearPositionMap(int type, bool sync) const; 
    223224    void SetPositionMap(frm_pos_map_t &, int type, 
    224225                        long long min_frm = -1, long long max_frm = -1) const; 
    225     void SetPositionMapDelta(frm_pos_map_t &, int type) const; 
     226    void SetPositionMapDelta(frm_pos_map_t &, int type); 
    226227 
    227  
    228228    // GUI stuff 
    229229    void showDetails(void) const; 
    230230    void EditRecording(void); 
     
    322322  private: 
    323323    bool ignoreBookmark; 
    324324    mutable class ScheduledRecording* record; 
     325     
     326    QString inUseForWhat; 
    325327 
    326     QString inUseForWhat; 
    327328}; 
    328329 
    329330/** \class ProgramList 
  • libs/libmyth/exitcodes.h

     
    5757#define BACKEND_BUGGY_EXIT_NO_CAP_CARD            GENERIC_EXIT_START-11 
    5858#define BACKEND_BUGGY_EXIT_NO_CHAN_DATA           GENERIC_EXIT_START-12 
    5959#define BACKEND_EXIT_START                        GENERIC_EXIT_START-12 
     60#define BACKEND_EXIT_ASYNCDB_ERROR                GENERIC_EXIT_START-13 
    6061 
    6162// mythtranscode 
    6263#define TRANSCODE_EXIT_OK                         GENERIC_EXIT_OK 
  • libs/libmyth/asyncdb.h

     
     1#ifndef ASYNCDB_H_ 
     2#define ASYNCDB_H_ 
     3 
     4// ANSI C headers 
     5#include <cstdio> 
     6#include <cstdlib> 
     7#include <cerrno> 
     8 
     9#include "mythdbcon.h" 
     10 
     11#include <qstring.h> 
     12 
     13using namespace std; 
     14 
     15typedef struct adb_cmd_list { 
     16    struct adb_cmd_list *next; 
     17    QString cmd; 
     18} adb_cmd_list_t; 
     19 
     20class AsyncDB 
     21{ 
     22 public: 
     23    AsyncDB(void); 
     24    ~AsyncDB(); 
     25    bool Init(void); 
     26    void AddCommand(QString);   
     27 
     28 private: 
     29    pthread_t thread; 
     30    bool threadRunning; 
     31    QStringList list; 
     32//    adb_cmd_list_t *list; 
     33    QMutex listLock; 
     34    MSqlQuery query; 
     35    bool ListRunner(adb_cmd_list_t *); 
     36 
     37 protected: 
     38    static void *StartThread(void *); 
     39    void Worker(void); 
     40}; 
     41 
     42extern AsyncDB *gAsyncDB; 
     43#endif 
  • libs/libmyth/asyncdb.cpp

     
     1#include "asyncdb.h" 
     2#include <unistd.h> 
     3#include <sys/time.h> 
     4#include <sys/resource.h> 
     5#include <sys/mman.h> 
     6 
     7AsyncDB *gAsyncDB = NULL; 
     8#define ADB QString("AsyncDB: ") 
     9 
     10/** \class AsyncDB 
     11 *  \brief This class supports asynchronous database inserts. 
     12 * 
     13 *   This class allows us to toss those database queries for which 
     14 *   we do not require values or status to be run by a separate thread. 
     15 *   This helps the enocder threads to keep up with the datastream. 
     16 */ 
     17 
     18/** \fn AsyncDB 
     19 *  \brief Initialize the class 
     20 */ 
     21AsyncDB::AsyncDB(void): 
     22  query(MSqlQuery::InitCon()), threadRunning(false) 
     23{ 
     24  list.clear(); 
     25} 
     26 
     27/** \fn Init() 
     28 *  \brief Starts the thread 
     29 * 
     30 *   Create a thread and return false if this fails 
     31 */ 
     32bool AsyncDB::Init(void) 
     33{ 
     34  int rv; 
     35  if(  ( rv = pthread_create(&thread, NULL, StartThread, this) ) ) { 
     36    VERBOSE(VB_IMPORTANT, ADB + QString("Can't start thread")); 
     37    return false; 
     38  } 
     39  threadRunning = true; 
     40  return(true); 
     41} 
     42 
     43/** \fn StartThread(AsyncDB *) 
     44 *  \brief Runs the worker function 
     45 * 
     46 *   Drop the priority on this thread and invoke the worker function 
     47 */ 
     48void *AsyncDB::StartThread(void *wotzit) 
     49{ 
     50  AsyncDB *pi = (AsyncDB *)wotzit; 
     51  VERBOSE(VB_IMPORTANT,QString("Starting async db thread")); 
     52  // Loser priority, to avoid problems with recordings. 
     53  setpriority(PRIO_PROCESS, 0, 3); 
     54  pi->Worker(); 
     55  return(NULL); 
     56} 
     57 
     58/** \fn AddCommand(QString) 
     59 *  \brief Adds a database command to the list 
     60 * 
     61 *  \param QString   The sql command 
     62 */ 
     63void AsyncDB::AddCommand(QString cmd) 
     64{ 
     65  listLock.lock(); 
     66  list.append(cmd); 
     67  listLock.unlock(); 
     68//  adb_cmd_list_t *item = new adb_cmd_list_t; 
     69//  item->cmd = cmd; 
     70//  listLock.lock(); 
     71//  item->next = list; 
     72//  list = item; 
     73//  listLock.unlock(); 
     74} 
     75 
     76/** \fn ~AsyncDB 
     77 *  \brief Shut down the thread 
     78 * 
     79 *   Add a "done" command to the list to make the thread  
     80 *   shutdown and reap it. 
     81 */ 
     82AsyncDB::~AsyncDB(void) 
     83{ 
     84  AddCommand(QString("done")); 
     85  pthread_join(thread, NULL); 
     86  VERBOSE(VB_IMPORTANT,QString("Ending async db thread")); 
     87} 
     88 
     89/** \fn Worker() 
     90 *  \brief Run the lists of commands 
     91 * 
     92 *   Swap the list for an empty one and call ListRunner 
     93 *   to execute the commands. 
     94 */ 
     95void AsyncDB::Worker(void) 
     96{ 
     97  bool done = false; 
     98 
     99  while( ! done ) { 
     100    if( list.empty() ) { 
     101      sleep(1); 
     102    } else { 
     103      listLock.lock(); 
     104      QStringList mylist = list; 
     105      list.clear(); 
     106      listLock.unlock(); 
     107      for ( QStringList::Iterator it = mylist.begin(); it != mylist.end(); ++it ) { 
     108        if( *it == QString("done") ) { 
     109          done = true; 
     110          break; 
     111        } 
     112        query.prepare(*it); 
     113        if (!query.exec() || !query.isActive()) 
     114          MythContext::DBError("delta position map insert",  
     115                               query); 
     116      } 
     117      mylist.clear();  
     118    } 
     119  } 
     120//  while( ! done ) { 
     121//    if( list == NULL ) { 
     122//      sleep(1); 
     123//    } else { 
     124//      listLock.lock(); 
     125//      adb_cmd_list_t *mylist = list; 
     126//      list = NULL; 
     127//      listLock.unlock(); 
     128//      done = ListRunner(mylist); 
     129//    } 
     130//  } 
     131} 
     132 
     133/** \fn ListRunner( adb_cmd_list_t * ) 
     134 *  \brief Execute the accumulated commands 
     135 * 
     136 *   Standard recursive routine. Shoot down to the end of the 
     137 *   list and as we return back execute the commands and clean 
     138 *   up the objects. This maintains order, since the newest  
     139 *   commands are at the head of the list. 
     140 * 
     141 *   If we find the command "done" return true. 
     142 * 
     143 *  \param adb_cmd_list_t*  The rest of the list 
     144 */ 
     145bool AsyncDB::ListRunner( adb_cmd_list_t *list ) { 
     146  bool done = false; 
     147  if( list != NULL ) { 
     148    done = ListRunner(list->next); 
     149    if( list->cmd == QString("done") ) { 
     150          done = true; 
     151    } else { 
     152      query.prepare(list->cmd); 
     153      if (!query.exec() || !query.isActive()) 
     154        MythContext::DBError("async command failed",  
     155                             query); 
     156    } 
     157    delete list->cmd; 
     158    delete list; 
     159  } 
     160  return( done ); 
     161} 
     162 
  • programs/mythtranscode/main.cpp

     
    540545{ 
    541546    if (pginfo && ! mapfile) 
    542547    { 
    543         pginfo->ClearPositionMap(MARK_KEYFRAME); 
    544         pginfo->ClearPositionMap(MARK_GOP_START); 
     548        pginfo->ClearPositionMap(MARK_KEYFRAME, true); 
     549        pginfo->ClearPositionMap(MARK_GOP_START, true); 
    545550        pginfo->SetPositionMap(posMap, MARK_GOP_BYFRAME); 
    546551    } 
    547552    else if (mapfile) 
  • programs/mythbackend/main.cpp

     
    3636#include "libmythtv/jobqueue.h" 
    3737#include "libmythtv/storagegroup.h" 
    3838#include "libmythupnp/mediaserver.h" 
     39#include "libmyth/asyncdb.h" 
    3940 
    4041#include "upnpcdstv.h" 
    4142#include "upnpcdsmusic.h" 
  • libs/libmythtv/programinfo.cpp

    @@ -202,6 +203,7 @@
     
     void cleanup(void) 
     {
    +    delete gAsyncDB;
         delete gContext;
     
         if (sched)
    @@ -497,6 +499,13 @@
         }    
         gContext->ActivateSettingsCache(true);
     
    +    gAsyncDB = new AsyncDB();
    +    if( gAsyncDB->Init() == false )
    +      {
    +	VERBOSE(VB_IMPORTANT, "Couldn't start async database thread");
    +	return BACKEND_EXIT_ASYNCDB_ERROR;
    +      }
    +
         if (printsched || testsched)
         {
             gContext->SetBackend(false);
    
     
    1717#include "util.h" 
    1818#include "mythcontext.h" 
    1919#include "dialogbox.h" 
     20#include "asyncdb.h" 
    2021#include "remoteutil.h" 
    2122#include "jobqueue.h" 
    2223#include "mythdbcon.h" 
     
    18121813{ 
    18131814    filesize = fsize; 
    18141815 
    1815     MSqlQuery query(MSqlQuery::InitCon()); 
    1816     query.prepare("UPDATE recorded SET filesize = :FILESIZE" 
    1817                   " WHERE chanid = :CHANID" 
    1818                   " AND starttime = :STARTTIME ;"); 
    1819     query.bindValue(":FILESIZE", longLongToString(fsize)); 
    1820     query.bindValue(":CHANID", chanid); 
    1821     query.bindValue(":STARTTIME", recstartts); 
     1816    QString query = QString("UPDATE recorded SET filesize = %1" 
     1817                            " WHERE chanid = %2" 
     1818                            " AND starttime = \"%3\" ;") 
     1819      .arg(longLongToString(fsize)) 
     1820      .arg(chanid) 
     1821      .arg(recstartts.toString("yyyyMMddhhmmss")); 
    18221822     
    1823     if (!query.exec() || !query.isActive()) 
    1824         MythContext::DBError("File size update",  
    1825                              query); 
     1823    gAsyncDB->AddCommand(query); 
    18261824} 
    18271825 
    18281826/** \fn ProgramInfo::GetFilesize(void) 
     
    25952593 
    25962594void ProgramInfo::ClearPositionMap(int type) const 
    25972595{ 
     2596    QString query; 
     2597   
     2598    if (isVideo) 
     2599    { 
     2600        query = QString("DELETE FROM filemarkup" 
     2601                        " WHERE filename = \"%1\"") 
     2602        .arg(pathname); 
     2603    } 
     2604    else 
     2605    { 
     2606        query = QString("DELETE FROM recordedseek" 
     2607                      " WHERE chanid = %1" 
     2608                      " AND starttime = \"%2\"") 
     2609        .arg(chanid) 
     2610        .arg(recstartts.toString("yyyyMMddhhmmss")); 
     2611    } 
     2612    query += QString(" AND type = %1 ;").arg(type); 
     2613                                
     2614    /* Hand it to the async thread */ 
     2615    gAsyncDB->AddCommand(query); 
     2616} 
     2617 
     2618void ProgramInfo::ClearPositionMap(int type, bool sync) const 
     2619{ 
    25982620    MSqlQuery query(MSqlQuery::InitCon()); 
    25992621   
    26002622    if (isVideo) 
     
    27122734} 
    27132735 
    27142736void ProgramInfo::SetPositionMapDelta(frm_pos_map_t &posMap, 
    2715                                       int type) const 
     2737                                      int type) 
    27162738{ 
    27172739    QMap<long long, long long>::Iterator i; 
    2718     MSqlQuery query(MSqlQuery::InitCon()); 
     2740    QString insert; 
     2741 
     2742    if( posMap.isEmpty() ) 
     2743      return; 
     2744 
     2745    if (isVideo) 
     2746      { 
     2747        insert = QString("INSERT INTO filemarkup" 
     2748                         " (filename, mark, type, offset)" 
     2749                         " VALUES"); 
     2750      }  
     2751    else  
     2752      { 
     2753        insert = QString("INSERT INTO recordedseek" 
     2754                         " (chanid, starttime, mark, type, offset)" 
     2755                         " VALUES"); 
     2756      } 
     2757    QString sep = " "; 
    27192758 
     2759    /* Assemble these these updates into a single multi-row insert  
     2760     * statement -- much more efficient */ 
    27202761    for (i = posMap.begin(); i != posMap.end(); ++i) 
    27212762    { 
    27222763        long long frame = i.key(); 
     
    27312772        QString offset_str = tempc; 
    27322773 
    27332774        if (isVideo) 
    2734         { 
    2735             query.prepare("INSERT INTO filemarkup" 
    2736                           " (filename, mark, type, offset)" 
    2737                           " VALUES" 
    2738                           " ( :PATH , :MARK , :TYPE , :OFFSET );"); 
    2739             query.bindValue(":PATH", pathname); 
    2740         } 
    2741         else 
    2742         { 
    2743             query.prepare("INSERT INTO recordedseek" 
    2744                           " (chanid, starttime, mark, type, offset)" 
    2745                           " VALUES" 
    2746                           " ( :CHANID , :STARTTIME , :MARK , :TYPE , :OFFSET );"); 
    2747             query.bindValue(":CHANID", chanid); 
    2748             query.bindValue(":STARTTIME", recstartts); 
    2749         } 
    2750         query.bindValue(":MARK", frame_str); 
    2751         query.bindValue(":TYPE", type); 
    2752         query.bindValue(":OFFSET", offset_str); 
    2753          
    2754         if (!query.exec() || !query.isActive()) 
    2755             MythContext::DBError("delta position map insert",  
    2756                                  query); 
    2757     } 
     2775          { 
     2776            insert += sep + QString("( \"%1\", %2, %3, %4 )") 
     2777              .arg(pathname).arg(i.key()).arg(type).arg(i.data()); 
     2778          } 
     2779          else 
     2780          { 
     2781            insert += sep + QString("( %1 , \"%2\" , %3 , %4 , %5 )") 
     2782              .arg(chanid).arg(recstartts.toString("yyyyMMddhhmmss")) 
     2783              .arg(i.key()).arg(type).arg(i.data()); 
     2784          } 
     2785        sep = ","; 
     2786      } 
     2787 
     2788    insert += QString(";"); 
     2789    /* Hand it to the async thread */ 
     2790    gAsyncDB->AddCommand(insert); 
    27582791} 
    27592792 
    27602793/** \fn ProgramInfo::ReactivateRecording(void) 
  • libs/libmyth/libmyth.pro

     
    2020HEADERS += langsettings.h audiooutputnull.h mythsocket.h 
    2121HEADERS += DisplayResScreen.h util-x11.h mythdeque.h qmdcodec.h 
    2222HEADERS += exitcodes.h virtualkeyboard.h mythobservable.h mythevent.h 
     23HEADERS += asyncdb.h 
    2324HEADERS += mythexp.h mythpluginapi.h 
    2425 
    2526SOURCES += dialogbox.cpp lcddevice.cpp mythcontext.cpp mythwidgets.cpp  
     
    3334SOURCES += langsettings.cpp mythdbcon.cpp audiooutputnull.cpp 
    3435SOURCES += DisplayResScreen.cpp util-x11.cpp qmdcodec.cpp 
    3536SOURCES += virtualkeyboard.cpp mythobservable.cpp mythsocket.cpp 
     37SOURCES += asyncdb.cpp 
    3638 
    3739INCLUDEPATH += ../libmythsamplerate ../libmythsoundtouch ../.. ../ 
    3840DEPENDPATH += ../libmythsamplerate ../libmythsoundtouch ../ ../libmythui 
     
    5961inc.files += visual.h volumebase.h output.h langsettings.h qmdcodec.h 
    6062inc.files += exitcodes.h mythconfig.h mythconfig.mak virtualkeyboard.h 
    6163inc.files += mythevent.h mythobservable.h mythsocket.h 
     64inc.files += asyncdb.h 
    6265inc.files += mythexp.h mythpluginapi.h 
    6366 
    6467cygwin:QMAKE_LFLAGS_SHLIB += -Wl,--noinhibit-exec