Ticket #1660: asyncdb.2.patch
File asyncdb.2.patch, 15.0 KB (added by , 17 years ago) |
---|
-
libs/libmythtv/NuppelVideoPlayer.cpp
5242 5242 using_null_videoout = true; 5243 5243 5244 5244 // 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); 5248 5248 5249 5249 if (OpenFile() < 0) 5250 5250 return(0); -
libs/libmythtv/programinfo.h
220 220 // Keyframe positions Map 221 221 void GetPositionMap(frm_pos_map_t &, int type) const; 222 222 void ClearPositionMap(int type) const; 223 void ClearPositionMap(int type, bool sync) const; 223 224 void SetPositionMap(frm_pos_map_t &, int type, 224 225 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); 226 227 227 228 228 // GUI stuff 229 229 void showDetails(void) const; 230 230 void EditRecording(void); … … 322 322 private: 323 323 bool ignoreBookmark; 324 324 mutable class ScheduledRecording* record; 325 326 QString inUseForWhat; 325 327 326 QString inUseForWhat;327 328 }; 328 329 329 330 /** \class ProgramList -
libs/libmythtv/programinfo.cpp
19 19 #include "remoteutil.h" 20 20 #include "jobqueue.h" 21 21 #include "mythdbcon.h" 22 #include "asyncdb.h" 22 23 23 24 using namespace std; 24 25 … … 1479 1480 if (playbackHost == "") 1480 1481 playbackHost = m_hostname; 1481 1482 1483 // Get the original path it was recorded on 1482 1484 tmpURL = GetRecordFilename(gContext->GetSettingOnHost("RecordFilePrefix", 1483 1485 hostname)); 1484 1486 1487 // if we are playing back on the recording host, just return it 1485 1488 if (playbackHost == hostname) 1486 1489 return tmpURL; 1487 1490 1491 // else if we are playing back on this host, check if the path is accessable, if so, use it 1488 1492 if (playbackHost == m_hostname) 1489 1493 { 1490 1494 QFile checkFile(tmpURL); … … 1500 1504 return tmpURL; 1501 1505 } 1502 1506 1507 // else contruct a url to use myth file transfer protocol 1503 1508 tmpURL = QString("myth://") + 1504 1509 gContext->GetSettingOnHost("BackendServerIP", hostname) + ":" + 1505 1510 gContext->GetSettingOnHost("BackendServerPort", hostname) + "/" + … … 1757 1762 { 1758 1763 filesize = fsize; 1759 1764 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")); 1767 1771 1768 if (!query.exec() || !query.isActive()) 1769 MythContext::DBError("File size update", 1770 query); 1772 gAsyncDB->AddCommand(query); 1771 1773 } 1772 1774 1773 1775 /** \fn ProgramInfo::GetFilesize(void) … … 2388 2390 2389 2391 void ProgramInfo::ClearPositionMap(int type) const 2390 2392 { 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 2415 void ProgramInfo::ClearPositionMap(int type, bool sync) const 2416 { 2391 2417 MSqlQuery query(MSqlQuery::InitCon()); 2392 2418 2393 2419 if (isVideo) … … 2505 2531 } 2506 2532 2507 2533 void ProgramInfo::SetPositionMapDelta(frm_pos_map_t &posMap, 2508 int type) const2534 int type) 2509 2535 { 2510 2536 QMap<long long, long long>::Iterator i; 2511 MSqlQuery query(MSqlQuery::InitCon());2537 QString insert; 2512 2538 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 */ 2513 2558 for (i = posMap.begin(); i != posMap.end(); ++i) 2514 2559 { 2515 2560 long long frame = i.key(); … … 2524 2569 QString offset_str = tempc; 2525 2570 2526 2571 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); 2551 2588 } 2552 2589 2553 2590 /** \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 24 25 SOURCES += dialogbox.cpp lcddevice.cpp mythcontext.cpp mythwidgets.cpp 25 26 SOURCES += oldsettings.cpp remotefile.cpp settings.cpp … … 32 33 SOURCES += langsettings.cpp mythdbcon.cpp audiooutputnull.cpp 33 34 SOURCES += DisplayResScreen.cpp util-x11.cpp qmdcodec.cpp 34 35 SOURCES += virtualkeyboard.cpp mythobservable.cpp mythsocket.cpp 36 SOURCES += asyncdb.cpp 35 37 36 38 INCLUDEPATH += ../libmythsamplerate ../libmythsoundtouch ../.. ../ 37 39 DEPENDPATH += ../libmythsamplerate ../libmythsoundtouch ../ ../libmythui … … 58 60 inc.files += visual.h volumebase.h output.h langsettings.h qmdcodec.h 59 61 inc.files += exitcodes.h mythconfig.h mythconfig.mak virtualkeyboard.h 60 62 inc.files += mythevent.h mythobservable.h mythsocket.h 63 inc.files += asyncdb.h 61 64 62 65 using_oss { 63 66 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 13 using namespace std; 14 15 typedef struct adb_cmd_list { 16 struct adb_cmd_list *next; 17 QString cmd; 18 } adb_cmd_list_t; 19 20 class 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 42 extern 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 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 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 */ 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 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 */ 48 void *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 */ 63 void 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 */ 82 AsyncDB::~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 */ 95 void 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 */ 145 bool 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
540 545 { 541 546 if (pginfo && ! mapfile) 542 547 { 543 pginfo->ClearPositionMap(MARK_KEYFRAME );544 pginfo->ClearPositionMap(MARK_GOP_START );548 pginfo->ClearPositionMap(MARK_KEYFRAME, true); 549 pginfo->ClearPositionMap(MARK_GOP_START, true); 545 550 pginfo->SetPositionMap(posMap, MARK_GOP_BYFRAME); 546 551 } 547 552 else if (mapfile) -
programs/mythbackend/main.cpp
35 35 #include "libmythtv/dbcheck.h" 36 36 #include "libmythtv/jobqueue.h" 37 37 #include "libmythupnp/upnp.h" 38 #include "libmyth/asyncdb.h" 38 39 39 40 #include "upnpcdstv.h" 40 41 #include "upnpcdsmusic.h" … … 202 203 203 204 void cleanup(void) 204 205 { 206 delete gAsyncDB; 205 207 delete gContext; 206 208 207 209 if (sched) … … 497 499 } 498 500 gContext->ActivateSettingsCache(true); 499 501 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 500 509 if (printsched || testsched) 501 510 { 502 511 gContext->SetBackend(false);