基本
QgsConnectionPoolGroup类保存了指向Server或数据源的连接。它是一个模板类,并且需要提供几个与传入的模板参数相关的函数。
* It is assumed that following functions exist:
*
* - void qgsConnectionPool_ConnectionCreate(QString name, T& c) ... create a new connection
* - void qgsConnectionPool_ConnectionDestroy(T c) ... destroy the connection
* - QString qgsConnectionPool_ConnectionToName(T c) ... lookup connection's name (path)
* - void qgsConnectionPool_InvalidateConnection(T c) ... flag a connection as invalid
* - bool qgsConnectionPool_ConnectionIsValid(T c) ... return whether a connection is valid
以上函数分别用于创建连接、销毁连接、查找连接名、连接是否有效。
* Because of issues with templates and QObject's signals and slots, this class only provides helper functions for QObject-related
* functionality - the place which uses the template is resonsible for:
*
* - being derived from QObject
* - calling initTimer( this ) in constructor
* - having handleConnectionExpired() slot that calls onConnectionExpired()
* - having startExpirationTimer(), stopExpirationTimer() slots to start/stop the expiration timer
*
* For an example on how to use the template class, have a look at the implementation in Postgres/SpatiaLite providers.
* \note not available in Python bindings
*/
template
class QgsConnectionPoolGroup
{
public:
struct Item
{
T c;
QTime lastUsedTime;
};
protected:
QStack- conns;
QList
acquiredConns;
根据类的注释可知,使用该模板类的地方需要:
- 继承自QObject以使用信号槽。
- 在构造函数中调用
initTimer(this)
以启动计时器。 - 有槽函数
handleConnectionExpired()
并在内部调用onConnectionExpired() - 有
startExpirartionTimer()
、stopExpirationTimer()
槽函数用以启动计时器的开始和结束。
initTimer()
void initTimer( QObject *parent )
expirationTimer = new QTimer( parent );
expirationTimer->setInterval( CONN_POOL_EXPIRATION_TIME * 1000 );
QObject::connect( expirationTimer, SIGNAL( timeout() ), parent, SLOT( handleConnectionExpired() ) );
// just to make sure the object belongs to main thread and thus will get events
if ( qApp )
parent->moveToThread( qApp->thread() );
initTimer()初始化计时器,并且将计时的触发绑定到parent
的槽函数中。以定时触发对连接的失效检查。
onConnectionExpired()
对连接的定时检查会进入该函数。
QList toDelete;
for ( int i = 0; i < conns.count(); ++i )
{
if ( conns.at( i ).lastUsedTime.secsTo( now ) >= CONN_POOL_EXPIRATION_TIME )
toDelete.append( i );
}
首先遍历连接栈,获取每个连接的上次使用时间,如果超过了失效时间,则先放入QList等待删除。
// delete expired connections
for ( int j = toDelete.count() - 1; j >= 0; --j )
{
int index = toDelete[j];
qgsConnectionPool_ConnectionDestroy( conns[index].c );
conns.remove( index );
}
if ( conns.isEmpty() )
expirationTimer->stop();
遍历待删除的列表,调用qgsConnectionPool_ConnectionDestroy()
将连接销毁,并从栈中移除。处理完后,如果连接栈为空,则停止计时器。
acquire()
T acquire( int timeout, bool requestMayBeNested )
acquire()用于获取连接,并传入超时时间,超时将返回nullptr。
if ( !conns.isEmpty() )
{
Item i = conns.pop();
if ( !qgsConnectionPool_ConnectionIsValid( i.c ) )
{
qgsConnectionPool_ConnectionDestroy( i.c );
qgsConnectionPool_ConnectionCreate( connInfo, i.c );
}
// no need to run if nothing can expire
if ( conns.isEmpty() )
{
// will call the slot directly or queue the call (if the object lives in a different thread)
QMetaObject::invokeMethod( expirationTimer->parent(), "stopExpirationTimer" );
}
acquiredConns.append( i.c );
return i.c;
}
先看一下获取连接时对成员变量conns
的处理,当conns
不为空时,则将顶部的连接出栈,如果判断出连接无效,会创建到的连接。之后将连接放到acquiredConns
后返回。
T c;
qgsConnectionPool_ConnectionCreate( connInfo, c );
if ( !c )
{
// we didn't get connection for some reason, so release the lock
sem.release();
return nullptr;
}
connMutex.lock();
acquiredConns.append( c );
connMutex.unlock();
return c;
如果conns
中没有连接时,则继续往下运行,创建新的连接,同样放入acquiredConns
后返回。
release(T conn)
连接使用完毕后调用release(T conn)
,将连接放回连接池。
connMutex.lock();
acquiredConns.removeAll( conn ); // (1)
if ( !qgsConnectionPool_ConnectionIsValid( conn ) )
{
qgsConnectionPool_ConnectionDestroy( conn );
}
else
{
Item i;
i.c = conn;
i.lastUsedTime = QTime::currentTime(); // (2)
conns.push( i ); // (3)
if ( !expirationTimer->isActive() )
{
// will call the slot directly or queue the call (if the object lives in a different thread)
QMetaObject::invokeMethod( expirationTimer->parent(), "startExpirationTimer" );
}
}
connMutex.unlock();
- (1) 将该连接从
acquiredConns
列表中移除。 - (2) 赋值给该连接当前时间为使用时间。
- (3) 将连接放入
conns
栈。
连接池数据结构
通过对acquire()
和release()
接口的分析可知,QgsConnectionPool内部通过成员变量QStack
和QList
对连接进行维护。conns
为栈结构,存放未使用的连接,当连接使用完毕后会入栈,等待被再次使用。acquiredConns
为列表结构,被获取的连接会进入该列表。