Index: libs/libmyth/asyncdb.h =================================================================== --- libs/libmyth/asyncdb.h (revision 0) +++ libs/libmyth/asyncdb.h (revision 0) @@ -0,0 +1,36 @@ +#ifndef ASYNCDB_H_ +#define ASYNCDB_H_ + +// ANSI C headers +#include +#include +#include + +#include "mythdbcon.h" + +#include + +using namespace std; + +class AsyncDB +{ + public: + AsyncDB(void); + ~AsyncDB(); + bool Init(void); + void AddCommand(QString); + + private: + pthread_t thread; + QStringList list; + QMutex listLock; + int retry; + bool threadRunning; + + protected: + static void *StartThread(void *); + void Worker(void); +}; + +extern AsyncDB *gAsyncDB; +#endif Index: libs/libmyth/asyncdb.cpp =================================================================== --- libs/libmyth/asyncdb.cpp (revision 0) +++ libs/libmyth/asyncdb.cpp (revision 0) @@ -0,0 +1,137 @@ +#include "asyncdb.h" +#include +#include +#include +#include + +AsyncDB *gAsyncDB = NULL; +#define ADB QString("AsyncDB: ") + +/** \class AsyncDB + * \brief This class supports asynchronous database inserts. + * + * This class allows us to toss those database queries for which + * we do not require values or status to be run by a separate thread. + * This helps the enocder threads to keep up with the datastream. + */ + +/** \fn AsyncDB + * \brief Initialize the class + */ +AsyncDB::AsyncDB(void): + retry(0), threadRunning(false) +{ + list.clear(); +} + +/** \fn Init() + * \brief Starts the thread + * + * Create a thread and return false if this fails + */ +bool AsyncDB::Init(void) +{ + int rv; + if( ( rv = pthread_create(&thread, NULL, StartThread, this) ) ) { + VERBOSE(VB_IMPORTANT, ADB + QString("Can't start thread")); + return false; + } + return(true); +} + +/** \fn StartThread(AsyncDB *) + * \brief Runs the worker function + * + * Drop the priority on this thread and invoke the worker function + */ +void *AsyncDB::StartThread(void *wotzit) +{ + AsyncDB *pi = (AsyncDB *)wotzit; + VERBOSE(VB_IMPORTANT,QString("Starting async db thread")); + // Loser priority, to avoid problems with recordings. + pi->threadRunning = true; + setpriority(PRIO_PROCESS, 0, 3); + do { + pi->Worker(); + } while(pi->retry <= 1 ); // A second retry means we're hosed + pi->threadRunning = false; + return(NULL); +} + +/** \fn AddCommand(QString) + * \brief Adds a database command to the list + * + * \param QString The sql command + */ +void AsyncDB::AddCommand(QString cmd) +{ + if( threadRunning ) { + listLock.lock(); + list.append(cmd); + listLock.unlock(); + } +} + +/** \fn ~AsyncDB + * \brief Shut down the thread + * + * Add a "done" command to the list to make the thread + * shutdown and reap it. + */ +AsyncDB::~AsyncDB(void) +{ + AddCommand(QString("done")); + pthread_join(thread, NULL); + VERBOSE(VB_IMPORTANT,QString("Ending async db thread")); +} + +/** \fn Worker() + * \brief Run the lists of commands + * + * Swap the list for an empty one and call ListRunner + * to execute the commands. + */ +void AsyncDB::Worker(void) +{ + bool done = false; + bool errored = false; + MSqlQuery query(MSqlQuery::InitCon()); + + while( ! done && ! errored ) { + if( list.empty() ) { + sleep(1); + } else { + listLock.lock(); + QStringList mylist = list; + list.clear(); + listLock.unlock(); + for ( QStringList::Iterator it = mylist.begin(); it != mylist.end(); ++it ) { + if( *it == QString("done") ) { + done = true; + retry = 2; // Make calling function exit. + break; + } + if( errored ) { + /* If we experienece a database error, we stuff the commands back onto the list, + and exit this function. We get called again which refreshes the DB connection. + We count these retries, so we don't loop, but only do it once without some + success */ + AddCommand(*it); + } else { + query.prepare(*it); + if (!query.exec() || !query.isActive()) { + MythContext::DBError("delta position map insert", + query); + retry++; + errored = true; + AddCommand(*it); + } else + retry = 0; + } + } + mylist.clear(); + } + } +} + +