QgsConnectionPoolGroup类分析

基本

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 conns;QList acquiredConns;对连接进行维护。conns为栈结构,存放未使用的连接,当连接使用完毕后会入栈,等待被再次使用。acquiredConns为列表结构,被获取的连接会进入该列表。

数据流

你可能感兴趣的:(QgsConnectionPoolGroup类分析)