Ticket #1660: asyncdb.2.patch

File asyncdb.2.patch, 15.0 KB (added by ylee@…, 17 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);