From 7c5ee8d83b09c170a5978fa8cc2d2c95d352ab46 Mon Sep 17 00:00:00 2001 From: goldenhawking Date: Wed, 20 Aug 2014 10:39:15 +0800 Subject: [PATCH] Add a thread-quitting cleaning method. when a thread is quitting, its finished signal will be caugth, so that , db resource class can clean the database connections belongs to this thread one by one. this method is very important in some situation, such as Qt-concurrent threading, threads will be created, deleted frequently. --- .../database/databaseresource.cpp | 206 +++++++++++------- .../database/databaseresource.h | 5 +- 2 files changed, 127 insertions(+), 84 deletions(-) diff --git a/ZoomPipeline_FuncSvr/database/databaseresource.cpp b/ZoomPipeline_FuncSvr/database/databaseresource.cpp index c06f418..ba17db2 100644 --- a/ZoomPipeline_FuncSvr/database/databaseresource.cpp +++ b/ZoomPipeline_FuncSvr/database/databaseresource.cpp @@ -11,6 +11,33 @@ namespace ZPDatabase{ { bTerm = false; } + //When a QThread finished, the database for this thread should be removed. + void DatabaseResource::on_finishedThread() + { + QMutexLocker locker(&m_mutex_reg); + QThread * pThread = qobject_cast( sender()); + //Get The quiting thread + if (pThread && m_ThreadOwnedMainDBs.contains(pThread) ) + { + QSet mainNames = m_ThreadOwnedMainDBs[pThread]; + //Remove every thread-owned db names for this thread. + foreach (QString mainName, mainNames) + { + QString threadName = QString("%1_%2").arg(mainName).arg((quint64)pThread); + QSqlDatabase db = QSqlDatabase::database(threadName); + if (db.isOpen()==true) + db.close(); + QSqlDatabase::removeDatabase(threadName); + QString msg = "Database:"+tr(" Connection removed ")+threadName+ tr(" ."); + emit evt_Message(this,msg); + //Remove the key map + m_ThreadsDB[mainName].remove(threadName); + } + //Completly remove this thread's ThreadOwnedMainDBs + m_ThreadOwnedMainDBs.remove(pThread); + + } + } /** * @brief Get an database connection belong to current thread. @@ -28,67 +55,78 @@ namespace ZPDatabase{ emit evt_Message(this,msg); return QSqlDatabase(); } - //We need a thread owner db , instead of the main DB template - QString threadName = QString("%1_%2").arg(strDBName).arg((quint64)currentThreadId()); - if (false==QSqlDatabase::contains(threadName)) - { - QSqlDatabase db = QSqlDatabase::cloneDatabase(QSqlDatabase::database(strDBName),threadName); - if (db.open()==false) - { - QString msg = "Database:"+tr(" Connection name ")+threadName+ - tr(" Can not be cloned from database %1.").arg(strDBName)+ - tr(" Err String:") + db.lastError().text(); - emit evt_Message(this,msg); - return QSqlDatabase(); - } - m_ThreadsDB[strDBName].insert(threadName); - } - //Confirm the thread-owned db is still open - QSqlDatabase db = QSqlDatabase::database(threadName); - tagConnectionPara & para = m_dbNames[strDBName]; - bool bNeedReconnect = false; - if (db.isOpen()==true) - { - if (para.testSQL.length()) - { - QSqlQuery query(db); - query.exec(para.testSQL); - if (query.lastError().type()!=QSqlError::NoError) - { - QString msg = "Database:"+tr(" Connection ")+threadName+ tr(" confirm failed. MSG="); - msg += query.lastError().text(); - emit evt_Message(this,msg); - bNeedReconnect = true; - } - } - if (bNeedReconnect==true) - { - db.close(); - QSqlDatabase::removeDatabase(threadName); - } - } - else - bNeedReconnect = true; - if (bNeedReconnect==true) - { - db = QSqlDatabase::cloneDatabase(QSqlDatabase::database(strDBName),threadName); - if (db.open()==true) - { - QString msg = "Database:"+tr(" Connection ")+threadName+ tr(" Re-Established."); - emit evt_Message(this,msg); - } - else - { - QString msg = "Database:"+tr(" Connection name ")+threadName+ - tr(" Can not be cloned from database %1.").arg(strDBName)+ - tr(" Err String:") + db.lastError().text(); - emit evt_Message(this,msg); - m_ThreadsDB[strDBName].remove(threadName); - return QSqlDatabase(); + //We need a thread owner db , instead of the main DB template + QThread * pThread = currentThread(); + //We will clean the thread's db connections when thread quits. + if (pThread) + connect (pThread,&QThread::finished,this,&DatabaseResource::on_finishedThread); + //Make a process-unique db id + QString threadName = QString("%1_%2").arg(strDBName).arg((quint64)currentThread()); + if (false==QSqlDatabase::contains(threadName)) + { + QSqlDatabase db = QSqlDatabase::cloneDatabase(QSqlDatabase::database(strDBName),threadName); + if (db.open()==false) + { + QString msg = "Database:"+tr(" Connection name ")+threadName+ + tr(" Can not be cloned from database %1.").arg(strDBName)+ + tr(" Err String:") + db.lastError().text(); + emit evt_Message(this,msg); + return QSqlDatabase(); + } + m_ThreadsDB[strDBName].insert(threadName); + m_ThreadOwnedMainDBs[pThread].insert(strDBName); + } + //Confirm the thread-owned db is still open + QSqlDatabase db = QSqlDatabase::database(threadName); + tagConnectionPara & para = m_dbNames[strDBName]; + bool bNeedReconnect = false; + if (db.isOpen()==true) + { + if (para.testSQL.length()) + { + QSqlQuery query(db); + query.exec(para.testSQL); + if (query.lastError().type()!=QSqlError::NoError) + { + QString msg = "Database:"+tr(" Connection ")+threadName+ tr(" confirm failed. MSG="); + msg += query.lastError().text(); + emit evt_Message(this,msg); + bNeedReconnect = true; + } + } + if (bNeedReconnect==true) + { + db.close(); + QSqlDatabase::removeDatabase(threadName); + m_ThreadsDB[strDBName].remove(threadName); + m_ThreadOwnedMainDBs[pThread].remove(strDBName); + } + } + else + bNeedReconnect = true; + if (bNeedReconnect==true) + { + db = QSqlDatabase::cloneDatabase(QSqlDatabase::database(strDBName),threadName); + if (db.open()==true) + { + QString msg = "Database:"+tr(" Connection ")+threadName+ tr(" Re-Established."); + emit evt_Message(this,msg); + m_ThreadsDB[strDBName].insert(threadName); + m_ThreadOwnedMainDBs[pThread].insert(strDBName); + } + else + { + QString msg = "Database:"+tr(" Connection name ")+threadName+ + tr(" Can not be cloned from database %1.").arg(strDBName)+ + tr(" Err String:") + db.lastError().text(); + emit evt_Message(this,msg); + m_ThreadsDB[strDBName].remove(threadName); + m_ThreadOwnedMainDBs[pThread].remove(strDBName); + return QSqlDatabase(); - } - } - return db; + } + } + return db; } void DatabaseResource::remove_connections() { @@ -98,9 +136,9 @@ namespace ZPDatabase{ sets = currentDatabaseConnections(); } foreach (QString name, sets.keys()) - { - this->remove_connection(name); - } + { + this->remove_connection(name); + } } //!Remove Database @@ -115,8 +153,8 @@ namespace ZPDatabase{ QSqlDatabase::removeDatabase(strDBName); QString msg = "Database:"+tr(" Connection removed ")+strDBName+ tr(" ."); emit evt_Message(this,msg); - RemoveTreadsConnections(strDBName); - m_ThreadsDB[strDBName].clear(); + RemoveTreadsConnections(strDBName); + m_ThreadsDB[strDBName].clear(); } else { @@ -126,22 +164,28 @@ namespace ZPDatabase{ m_dbNames.remove(strDBName) ; } - void DatabaseResource::RemoveTreadsConnections(QString mainName) - { - if (m_ThreadsDB.contains(mainName)) - { - QSet & sethreadNames = m_ThreadsDB[mainName]; - foreach(QString str, sethreadNames) - { - QSqlDatabase db = QSqlDatabase::database(str); - if (db.isOpen()==true) - db.close(); - QSqlDatabase::removeDatabase(str); - QString msg = "Database:"+tr(" Connection removed ")+str+ tr(" ."); - emit evt_Message(this,msg); - } - } - } + void DatabaseResource::RemoveTreadsConnections(QString mainName) + { + if (m_ThreadsDB.contains(mainName)) + { + QSet & sethreadNames = m_ThreadsDB[mainName]; + foreach(QString str, sethreadNames) + { + QSqlDatabase db = QSqlDatabase::database(str); + if (db.isOpen()==true) + db.close(); + QSqlDatabase::removeDatabase(str); + QString msg = "Database:"+tr(" Connection removed ")+str+ tr(" ."); + emit evt_Message(this,msg); + } + //Remove thread map. + foreach (QThread * ptr, m_ThreadOwnedMainDBs.keys()) + { + QSet & threadOwnedMainDB = m_ThreadOwnedMainDBs[ptr]; + threadOwnedMainDB.remove(mainName); + } + } + } /** * @brief add a database connection resource diff --git a/ZoomPipeline_FuncSvr/database/databaseresource.h b/ZoomPipeline_FuncSvr/database/databaseresource.h index 2a89783..b03c601 100644 --- a/ZoomPipeline_FuncSvr/database/databaseresource.h +++ b/ZoomPipeline_FuncSvr/database/databaseresource.h @@ -13,9 +13,6 @@ namespace ZPDatabase{ * @brief this class provide an database reource pool.In different thread, workers can get existing db connections * immediately without re-creation operations. The working thread does not maintain db connections, instead of * maintaining, it just using db resources from DatabaseResource - * Important!! When Ever a thread calls DatabaseResource::databse(), a thread-owned dbconnection - * will be cloned from main db connection. be careful, this class does not auto remove connections - * unless main connection has been removed by DatabaseResource::remove_connection(s) * @class DatabaseResource databaseresource.h "ZoomPipeline_FuncSvr/database/databaseresource.h" */ class DatabaseResource : public QThread @@ -71,10 +68,12 @@ namespace ZPDatabase{ QMutex m_mutex_reg; QMap m_dbNames; QMap > m_ThreadsDB; + QMap > m_ThreadOwnedMainDBs; void RemoveTreadsConnections(QString mainName); signals: void evt_Message(QObject *,QString ); public slots: + void on_finishedThread(); }; }; -- GitLab