Ticket #1660: asyncdb.2.patch

File asyncdb.2.patch, 15.0 KB (added by ylee@…, 5 years ago)

Fixed version of ajlill@…'s asyncdb.patch for 0.20 with two typos fixed that caused a "malformed patch" error. (In line 5, both ",11"s should be ",9" .)

  • 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/libmythtv/programinfo.cpp

     
    1919#include "remoteutil.h" 
    2020#include "jobqueue.h" 
    2121#include "mythdbcon.h" 
     22#include "asyncdb.h" 
    2223 
    2324using namespace std; 
    2425 
     
    14791480    if (playbackHost == "") 
    14801481        playbackHost = m_hostname; 
    14811482 
     1483    // Get the original path it was recorded on 
    14821484    tmpURL = GetRecordFilename(gContext->GetSettingOnHost("RecordFilePrefix", 
    14831485                                                          hostname)); 
    14841486 
     1487    // if we are playing back on the recording host, just return it 
    14851488    if (playbackHost == hostname) 
    14861489        return tmpURL; 
    14871490 
     1491    // else if we are playing back on this host, check if the path is accessable, if so, use it 
    14881492    if (playbackHost == m_hostname) 
    14891493    { 
    14901494        QFile checkFile(tmpURL); 
     
    15001504            return tmpURL; 
    15011505    } 
    15021506 
     1507    // else contruct a url to use myth file transfer protocol 
    15031508    tmpURL = QString("myth://") + 
    15041509             gContext->GetSettingOnHost("BackendServerIP", hostname) + ":" + 
    15051510             gContext->GetSettingOnHost("BackendServerPort", hostname) + "/" + 
     
    17571762{ 
    17581763    filesize = fsize; 
    17591764 
    1760     MSqlQuery query(MSqlQuery::InitCon()); 
    1761     query.prepare("UPDATE recorded SET filesize = :FILESIZE" 
    1762                   " WHERE chanid = :CHANID" 
    1763                   " AND starttime = :STARTTIME ;"); 
    1764     query.bindValue(":FILESIZE", longLongToString(fsize)); 
    1765     query.bindValue(":CHANID", chanid); 
    1766     query.bindValue(":STARTTIME", recstartts); 
     1765    QString query = QString("UPDATE recorded SET filesize = %1" 
     1766                            " WHERE chanid = %2" 
     1767                            " AND starttime = \"%3\" ;") 
     1768      .arg(longLongToString(fsize)) 
     1769      .arg(chanid) 
     1770      .arg(recstartts.toString("yyyyMMddhhmmss")); 
    17671771     
    1768     if (!query.exec() || !query.isActive()) 
    1769         MythContext::DBError("File size update",  
    1770                              query); 
     1772    gAsyncDB->AddCommand(query); 
    17711773} 
    17721774 
    17731775/** \fn ProgramInfo::GetFilesize(void) 
     
    23882390 
    23892391void ProgramInfo::ClearPositionMap(int type) const 
    23902392{ 
     2393    QString query; 
     2394   
     2395    if (isVideo) 
     2396    { 
     2397        query = QString("DELETE FROM filemarkup" 
     2398                        " WHERE filename = \"%1\"") 
     2399        .arg(pathname); 
     2400    } 
     2401    else 
     2402    { 
     2403        query = QString("DELETE FROM recordedseek" 
     2404                      " WHERE chanid = %1" 
     2405                      " AND starttime = \"%2\"") 
     2406        .arg(chanid) 
     2407        .arg(recstartts.toString("yyyyMMddhhmmss")); 
     2408    } 
     2409    query += QString(" AND type = %1 ;").arg(type); 
     2410                                
     2411    /* Hand it to the async thread */ 
     2412    gAsyncDB->AddCommand(query); 
     2413} 
     2414 
     2415void ProgramInfo::ClearPositionMap(int type, bool sync) const 
     2416{ 
    23912417    MSqlQuery query(MSqlQuery::InitCon()); 
    23922418   
    23932419    if (isVideo) 
     
    25052531} 
    25062532 
    25072533void ProgramInfo::SetPositionMapDelta(frm_pos_map_t &posMap, 
    2508                                       int type) const 
     2534                                      int type) 
    25092535{ 
    25102536    QMap<long long, long long>::Iterator i; 
    2511     MSqlQuery query(MSqlQuery::InitCon()); 
     2537    QString insert; 
    25122538 
     2539    if( posMap.isEmpty() ) 
     2540      return; 
     2541 
     2542    if (isVideo) 
     2543      { 
     2544        insert = QString("INSERT INTO filemarkup" 
     2545                         " (filename, mark, type, offset)" 
     2546                         " VALUES"); 
     2547      }  
     2548    else  
     2549      { 
     2550        insert = QString("INSERT INTO recordedseek" 
     2551                         " (chanid, starttime, mark, type, offset)" 
     2552                         " VALUES"); 
     2553      } 
     2554    QString sep = " "; 
     2555 
     2556    /* Assemble these these updates into a single multi-row insert  
     2557     * statement -- much more efficient */ 
    25132558    for (i = posMap.begin(); i != posMap.end(); ++i) 
    25142559    { 
    25152560        long long frame = i.key(); 
     
    25242569        QString offset_str = tempc; 
    25252570 
    25262571        if (isVideo) 
    2527         { 
    2528             query.prepare("INSERT INTO filemarkup" 
    2529                           " (filename, mark, type, offset)" 
    2530                           " VALUES" 
    2531                           " ( :PATH , :MARK , :TYPE , :OFFSET );"); 
    2532             query.bindValue(":PATH", pathname); 
    2533         } 
    2534         else 
    2535         { 
    2536             query.prepare("INSERT INTO recordedseek" 
    2537                           " (chanid, starttime, mark, type, offset)" 
    2538                           " VALUES" 
    2539                           " ( :CHANID , :STARTTIME , :MARK , :TYPE , :OFFSET );"); 
    2540             query.bindValue(":CHANID", chanid); 
    2541             query.bindValue(":STARTTIME", recstartts); 
    2542         } 
    2543         query.bindValue(":MARK", frame_str); 
    2544         query.bindValue(":TYPE", type); 
    2545         query.bindValue(":OFFSET", offset_str); 
    2546          
    2547         if (!query.exec() || !query.isActive()) 
    2548             MythContext::DBError("delta position map insert",  
    2549                                  query); 
    2550     } 
     2572          { 
     2573            insert += sep + QString("( \"%1\", %2, %3, %4 )") 
     2574              .arg(pathname).arg(i.key()).arg(type).arg(i.data()); 
     2575          } 
     2576          else 
     2577          { 
     2578            insert += sep + QString("( %1 , \"%2\" , %3 , %4 , %5 )") 
     2579              .arg(chanid).arg(recstartts.toString("yyyyMMddhhmmss")) 
     2580              .arg(i.key()).arg(type).arg(i.data()); 
     2581          } 
     2582        sep = ","; 
     2583      } 
     2584 
     2585    insert += QString(";"); 
     2586    /* Hand it to the async thread */ 
     2587    gAsyncDB->AddCommand(insert); 
    25512588} 
    25522589 
    25532590/** \fn ProgramInfo::ReactivateRecording(void) 
  • 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/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 
    2324 
    2425SOURCES += dialogbox.cpp lcddevice.cpp mythcontext.cpp mythwidgets.cpp  
    2526SOURCES += oldsettings.cpp remotefile.cpp settings.cpp 
     
    3233SOURCES += langsettings.cpp mythdbcon.cpp audiooutputnull.cpp 
    3334SOURCES += DisplayResScreen.cpp util-x11.cpp qmdcodec.cpp 
    3435SOURCES += virtualkeyboard.cpp mythobservable.cpp mythsocket.cpp 
     36SOURCES += asyncdb.cpp 
    3537 
    3638INCLUDEPATH += ../libmythsamplerate ../libmythsoundtouch ../.. ../ 
    3739DEPENDPATH += ../libmythsamplerate ../libmythsoundtouch ../ ../libmythui 
     
    5860inc.files += visual.h volumebase.h output.h langsettings.h qmdcodec.h 
    5961inc.files += exitcodes.h mythconfig.h mythconfig.mak virtualkeyboard.h 
    6062inc.files += mythevent.h mythobservable.h mythsocket.h 
     63inc.files += asyncdb.h 
    6164 
    6265using_oss { 
    6366    DEFINES += USING_OSS 
  • 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

     
    3535#include "libmythtv/dbcheck.h" 
    3636#include "libmythtv/jobqueue.h" 
    3737#include "libmythupnp/upnp.h" 
     38#include "libmyth/asyncdb.h" 
    3839 
    3940#include "upnpcdstv.h" 
    4041#include "upnpcdsmusic.h" 
     
    202203 
    203204void cleanup(void)  
    204205{ 
     206    delete gAsyncDB; 
    205207    delete gContext; 
    206208 
    207209    if (sched) 
     
    497499    }     
    498500    gContext->ActivateSettingsCache(true); 
    499501 
     502    gAsyncDB = new AsyncDB(); 
     503    if( gAsyncDB->Init() == false ) 
     504      { 
     505        VERBOSE(VB_IMPORTANT, "Couldn't start async database thread"); 
     506        return BACKEND_EXIT_ASYNCDB_ERROR; 
     507      } 
     508 
    500509    if (printsched || testsched) 
    501510    { 
    502511        gContext->SetBackend(false);