Ticket #1660: asyncdb.13130.patch
File asyncdb.13130.patch, 13.3 KB (added by , 17 years ago) |
---|
-
libs/libmythtv/NuppelVideoPlayer.cpp
5429 5429 using_null_videoout = true; 5430 5430 5431 5431 // clear out any existing seektables 5432 m_playbackinfo->ClearPositionMap(MARK_KEYFRAME );5433 m_playbackinfo->ClearPositionMap(MARK_GOP_START );5434 m_playbackinfo->ClearPositionMap(MARK_GOP_BYFRAME );5432 m_playbackinfo->ClearPositionMap(MARK_KEYFRAME,true); 5433 m_playbackinfo->ClearPositionMap(MARK_GOP_START,true); 5434 m_playbackinfo->ClearPositionMap(MARK_GOP_BYFRAME,true); 5435 5435 5436 5436 if (OpenFile() < 0) 5437 5437 return(0); -
libs/libmythtv/programinfo.h
237 237 // Keyframe positions Map 238 238 void GetPositionMap(frm_pos_map_t &, int type) const; 239 239 void ClearPositionMap(int type) const; 240 void ClearPositionMap(int type, bool sync) const; 240 241 void SetPositionMap(frm_pos_map_t &, int type, 241 242 long long min_frm = -1, long long max_frm = -1) const; 242 void SetPositionMapDelta(frm_pos_map_t &, int type) const;243 void SetPositionMapDelta(frm_pos_map_t &, int type); 243 244 244 245 245 // GUI stuff 246 246 void showDetails(void) const; 247 247 void EditRecording(void); … … 344 344 private: 345 345 bool ignoreBookmark; 346 346 mutable class ScheduledRecording* record; 347 348 QString inUseForWhat; 347 349 348 QString inUseForWhat;349 350 }; 350 351 351 352 /** \class ProgramList -
libs/libmythtv/programinfo.cpp
17 17 #include "util.h" 18 18 #include "mythcontext.h" 19 19 #include "dialogbox.h" 20 #include "asyncdb.h" 20 21 #include "remoteutil.h" 21 22 #include "jobqueue.h" 22 23 #include "mythdbcon.h" … … 1828 1829 { 1829 1830 filesize = fsize; 1830 1831 1831 MSqlQuery query(MSqlQuery::InitCon()); 1832 query.prepare("UPDATE recorded SET filesize = :FILESIZE" 1833 " WHERE chanid = :CHANID" 1834 " AND starttime = :STARTTIME ;"); 1835 query.bindValue(":FILESIZE", longLongToString(fsize)); 1836 query.bindValue(":CHANID", chanid); 1837 query.bindValue(":STARTTIME", recstartts); 1832 QString query = QString("UPDATE recorded SET filesize = %1" 1833 " WHERE chanid = %2" 1834 " AND starttime = \"%3\" ;") 1835 .arg(longLongToString(fsize)) 1836 .arg(chanid) 1837 .arg(recstartts.toString("yyyyMMddhhmmss")); 1838 1838 1839 if (!query.exec() || !query.isActive()) 1840 MythContext::DBError("File size update", 1841 query); 1839 gAsyncDB->AddCommand(query); 1842 1840 } 1843 1841 1844 1842 /** \fn ProgramInfo::GetFilesize(void) … … 2605 2603 2606 2604 void ProgramInfo::ClearPositionMap(int type) const 2607 2605 { 2606 QString query; 2607 2608 if (isVideo) 2609 { 2610 query = QString("DELETE FROM filemarkup" 2611 " WHERE filename = \"%1\"") 2612 .arg(pathname); 2613 } 2614 else 2615 { 2616 query = QString("DELETE FROM recordedseek" 2617 " WHERE chanid = %1" 2618 " AND starttime = \"%2\"") 2619 .arg(chanid) 2620 .arg(recstartts.toString("yyyyMMddhhmmss")); 2621 } 2622 query += QString(" AND type = %1 ;").arg(type); 2623 2624 /* Hand it to the async thread */ 2625 gAsyncDB->AddCommand(query); 2626 } 2627 2628 void ProgramInfo::ClearPositionMap(int type, bool sync) const 2629 { 2608 2630 MSqlQuery query(MSqlQuery::InitCon()); 2609 2631 2610 2632 if (isVideo) … … 2710 2732 } 2711 2733 2712 2734 void ProgramInfo::SetPositionMapDelta(frm_pos_map_t &posMap, 2713 int type) const2735 int type) 2714 2736 { 2715 2737 QMap<long long, long long>::Iterator i; 2716 MSqlQuery query(MSqlQuery::InitCon());2738 QString insert; 2717 2739 2740 if( posMap.isEmpty() ) 2741 return; 2742 2743 if (isVideo) 2744 { 2745 insert = QString("INSERT INTO filemarkup" 2746 " (filename, mark, type, offset)" 2747 " VALUES"); 2748 } 2749 else 2750 { 2751 insert = QString("INSERT INTO recordedseek" 2752 " (chanid, starttime, mark, type, offset)" 2753 " VALUES"); 2754 } 2755 QString sep = " "; 2756 2757 /* Assemble these these updates into a single multi-row insert 2758 * statement -- much more efficient */ 2718 2759 for (i = posMap.begin(); i != posMap.end(); ++i) 2719 2760 { 2720 2761 long long frame = i.key(); 2721 2762 long long offset = i.data(); 2722 2763 2723 2764 if (isVideo) 2724 { 2725 query.prepare("INSERT INTO filemarkup" 2726 " (filename, mark, type, offset)" 2727 " VALUES" 2728 " ( :PATH , :MARK , :TYPE , :OFFSET );"); 2729 query.bindValue(":PATH", pathname); 2730 } 2731 else 2732 { 2733 query.prepare("INSERT INTO recordedseek" 2734 " (chanid, starttime, mark, type, offset)" 2735 " VALUES" 2736 " ( :CHANID , :STARTTIME , :MARK , :TYPE , :OFFSET );"); 2737 query.bindValue(":CHANID", chanid); 2738 query.bindValue(":STARTTIME", recstartts); 2739 } 2740 query.bindValue(":MARK", frame); 2741 query.bindValue(":TYPE", type); 2742 query.bindValue(":OFFSET", offset); 2743 2744 if (!query.exec() || !query.isActive()) 2745 MythContext::DBError("delta position map insert", 2746 query); 2747 } 2765 { 2766 insert += sep + QString("( \"%1\", %2, %3, %4 )") 2767 .arg(pathname).arg(frame).arg(type).arg(offset); 2768 } 2769 else 2770 { 2771 insert += sep + QString("( %1 , \"%2\" , %3 , %4 , %5 )") 2772 .arg(chanid).arg(recstartts.toString("yyyyMMddhhmmss")) 2773 .arg(frame).arg(type).arg(offset); 2774 } 2775 sep = ","; 2776 } 2777 2778 insert += QString(";"); 2779 /* Hand it to the async thread */ 2780 gAsyncDB->AddCommand(insert); 2748 2781 } 2749 2782 2750 2783 /** \fn ProgramInfo::ReactivateRecording(void) -
libs/libmyth/exitcodes.h
57 57 #define BACKEND_BUGGY_EXIT_NO_CAP_CARD GENERIC_EXIT_START-11 58 58 #define BACKEND_BUGGY_EXIT_NO_CHAN_DATA GENERIC_EXIT_START-12 59 59 #define BACKEND_EXIT_START GENERIC_EXIT_START-12 60 #define BACKEND_EXIT_ASYNCDB_ERROR GENERIC_EXIT_START-13 60 61 61 62 // mythtranscode 62 63 #define TRANSCODE_EXIT_OK GENERIC_EXIT_OK -
libs/libmyth/libmyth.pro
20 20 HEADERS += langsettings.h audiooutputnull.h mythsocket.h 21 21 HEADERS += DisplayResScreen.h util-x11.h mythdeque.h qmdcodec.h 22 22 HEADERS += exitcodes.h virtualkeyboard.h mythobservable.h mythevent.h 23 HEADERS += asyncdb.h 23 24 HEADERS += mythexp.h mythpluginapi.h 24 25 25 26 SOURCES += dialogbox.cpp lcddevice.cpp mythcontext.cpp mythwidgets.cpp … … 33 34 SOURCES += langsettings.cpp mythdbcon.cpp audiooutputnull.cpp 34 35 SOURCES += DisplayResScreen.cpp util-x11.cpp qmdcodec.cpp 35 36 SOURCES += virtualkeyboard.cpp mythobservable.cpp mythsocket.cpp 37 SOURCES += asyncdb.cpp 36 38 37 39 INCLUDEPATH += ../libmythsamplerate ../libmythsoundtouch ../.. ../ 38 40 DEPENDPATH += ../libmythsamplerate ../libmythsoundtouch ../ ../libmythui … … 59 61 inc.files += visual.h volumebase.h output.h langsettings.h qmdcodec.h 60 62 inc.files += exitcodes.h mythconfig.h mythconfig.mak virtualkeyboard.h 61 63 inc.files += mythevent.h mythobservable.h mythsocket.h 64 inc.files += asyncdb.h 62 65 inc.files += mythexp.h mythpluginapi.h 63 66 64 67 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 13 using namespace std; 14 15 class AsyncDB 16 { 17 public: 18 AsyncDB(void); 19 ~AsyncDB(); 20 bool Init(void); 21 void AddCommand(QString); 22 23 private: 24 pthread_t thread; 25 QStringList list; 26 QMutex listLock; 27 int retry; 28 bool threadRunning; 29 30 protected: 31 static void *StartThread(void *); 32 void Worker(void); 33 }; 34 35 extern AsyncDB *gAsyncDB; 36 #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 7 AsyncDB *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 */ 21 AsyncDB::AsyncDB(void): 22 retry(0), 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 */ 32 bool 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 return(true); 40 } 41 42 /** \fn StartThread(AsyncDB *) 43 * \brief Runs the worker function 44 * 45 * Drop the priority on this thread and invoke the worker function 46 */ 47 void *AsyncDB::StartThread(void *wotzit) 48 { 49 AsyncDB *pi = (AsyncDB *)wotzit; 50 VERBOSE(VB_IMPORTANT,QString("Starting async db thread")); 51 // Loser priority, to avoid problems with recordings. 52 pi->threadRunning = true; 53 setpriority(PRIO_PROCESS, 0, 3); 54 do { 55 pi->Worker(); 56 } while(pi->retry <= 1 ); // A second retry means we're hosed 57 pi->threadRunning = false; 58 return(NULL); 59 } 60 61 /** \fn AddCommand(QString) 62 * \brief Adds a database command to the list 63 * 64 * \param QString The sql command 65 */ 66 void AsyncDB::AddCommand(QString cmd) 67 { 68 if( threadRunning ) { 69 listLock.lock(); 70 list.append(cmd); 71 listLock.unlock(); 72 } 73 } 74 75 /** \fn ~AsyncDB 76 * \brief Shut down the thread 77 * 78 * Add a "done" command to the list to make the thread 79 * shutdown and reap it. 80 */ 81 AsyncDB::~AsyncDB(void) 82 { 83 AddCommand(QString("done")); 84 pthread_join(thread, NULL); 85 VERBOSE(VB_IMPORTANT,QString("Ending async db thread")); 86 } 87 88 /** \fn Worker() 89 * \brief Run the lists of commands 90 * 91 * Swap the list for an empty one and call ListRunner 92 * to execute the commands. 93 */ 94 void AsyncDB::Worker(void) 95 { 96 bool done = false; 97 bool errored = false; 98 MSqlQuery query(MSqlQuery::InitCon()); 99 100 while( ! done && ! errored ) { 101 if( list.empty() ) { 102 sleep(1); 103 } else { 104 listLock.lock(); 105 QStringList mylist = list; 106 list.clear(); 107 listLock.unlock(); 108 for ( QStringList::Iterator it = mylist.begin(); it != mylist.end(); ++it ) { 109 if( *it == QString("done") ) { 110 done = true; 111 retry = 2; // Make calling function exit. 112 break; 113 } 114 if( errored ) { 115 /* If we experienece a database error, we stuff the commands back onto the list, 116 and exit this function. We get called again which refreshes the DB connection. 117 We count these retries, so we don't loop, but only do it once without some 118 success */ 119 AddCommand(*it); 120 } else { 121 query.prepare(*it); 122 if (!query.exec() || !query.isActive()) { 123 MythContext::DBError("delta position map insert", 124 query); 125 retry++; 126 errored = true; 127 AddCommand(*it); 128 } else 129 retry = 0; 130 } 131 } 132 mylist.clear(); 133 } 134 } 135 } 136 137 -
programs/mythtranscode/main.cpp
561 561 { 562 562 if (pginfo && ! mapfile) 563 563 { 564 pginfo->ClearPositionMap(MARK_KEYFRAME );565 pginfo->ClearPositionMap(MARK_GOP_START );564 pginfo->ClearPositionMap(MARK_KEYFRAME, true); 565 pginfo->ClearPositionMap(MARK_GOP_START, true); 566 566 pginfo->SetPositionMap(posMap, MARK_GOP_BYFRAME); 567 567 } 568 568 else if (mapfile) -
programs/mythbackend/main.cpp
35 35 #include "libmythtv/dbcheck.h" 36 36 #include "libmythtv/jobqueue.h" 37 37 #include "libmythtv/storagegroup.h" 38 #include "libmyth/asyncdb.h" 38 39 39 40 #include "mediaserver.h" 40 41 #include "httpstatus.h" … … 199 200 200 201 void cleanup(void) 201 202 { 203 delete gAsyncDB; 202 204 delete gContext; 203 205 204 206 if (sched) … … 518 520 } 519 521 gContext->ActivateSettingsCache(true); 520 522 523 gAsyncDB = new AsyncDB(); 524 if( gAsyncDB->Init() == false ) 525 { 526 VERBOSE(VB_IMPORTANT, "Couldn't start async database thread"); 527 return BACKEND_EXIT_ASYNCDB_ERROR; 528 } 529 521 530 if (printsched || testsched) 522 531 { 523 532 gContext->SetBackend(false);