Skip to content

Commit

Permalink
Allow specifying the number of required connections
Browse files Browse the repository at this point in the history
for a request. Most requests should reserve more
than a single connection (default: 3) and only
requests that are executed as nested expressions
should specify 1.
  • Loading branch information
m-kuhn committed Aug 2, 2018
1 parent 7033b54 commit 14643ad
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 7 deletions.
34 changes: 34 additions & 0 deletions python/core/auto_generated/qgsfeaturerequest.sip.in
Expand Up @@ -657,6 +657,40 @@ at this moment. A negative value (which is set by default) will wait forever.
Only works if the provider supports this option.

.. versionadded:: 3.0
%End

int freeConnectionsRequirement() const;
%Docstring
The amount of free connections required to start this request.
The system will block the request until the specified amount of connections
is available for usage.

By default this amount is 3. This makes sure, that we have 2 spare connections
that might be used by "nested" requests which are executed while iterating
over the results of this request.

This number should be changed to one, when we know that no nested requests happen
and that this request might happen in a nested way. This is for example given for
expression functions that do internal requests.

.. versionadded:: 3.4
%End

void setFreeConnectionsRequirement( int freeConnectionsRequirement );
%Docstring
The amount of free connections required to start this request.
The system will block the request until the specified amount of connections
is available for usage.

By default this amount is 3. This makes sure, that we have 2 spare connections
that might be used by "nested" requests which are executed while iterating
over the results of this request.

This number should be changed to one, when we know that no nested requests happen
and that this request might happen in a nested way. This is for example given for
expression functions that do internal requests.

.. versionadded:: 3.4
%End

protected:
Expand Down
15 changes: 9 additions & 6 deletions src/core/qgsconnectionpool.h
Expand Up @@ -29,7 +29,7 @@
#include <QThread>


#define CONN_POOL_MAX_CONCURRENT_CONNS 4
#define CONN_POOL_MAX_CONCURRENT_CONNS 6
#define CONN_POOL_EXPIRATION_TIME 60 // in seconds


Expand Down Expand Up @@ -93,12 +93,12 @@ class QgsConnectionPoolGroup
*
* \returns initialized connection or nullptr if unsuccessful
*/
T acquire( int timeout )
T acquire( int timeout, int freeConnectionRequirement )
{
// we are going to acquire a resource - if no resource is available, we will block here
if ( timeout >= 0 )
{
if ( !sem.tryAcquire( 1, timeout ) )
if ( !sem.tryAcquire( freeConnectionRequirement, timeout ) )
return nullptr;
}
else
Expand All @@ -107,8 +107,9 @@ class QgsConnectionPoolGroup
// tryAcquire is broken on Qt > 5.8 with negative timeouts - see
// https://bugreports.qt.io/browse/QTBUG-64413
// https://lists.osgeo.org/pipermail/qgis-developer/2017-November/050456.html
sem.acquire( 1 );
sem.acquire( freeConnectionRequirement );
}
sem.release( freeConnectionRequirement - 1 );

// quick (preferred) way - use cached connection
{
Expand Down Expand Up @@ -283,9 +284,11 @@ class QgsConnectionPool
* If \a timeout is a negative value the calling thread will be blocked
* until a connection becomes available. This is the default behavior.
*
*
*
* \returns initialized connection or nullptr if unsuccessful
*/
T acquireConnection( const QString &connInfo, int timeout = -1 )
T acquireConnection( const QString &connInfo, int timeout = -1, int freeConnectionRequirement = 3 )
{
mMutex.lock();
typename T_Groups::iterator it = mGroups.find( connInfo );
Expand All @@ -296,7 +299,7 @@ class QgsConnectionPool
T_Group *group = *it;
mMutex.unlock();

return group->acquire( timeout );
return group->acquire( timeout, freeConnectionRequirement );
}

//! Release an existing connection so it will get back into the pool and can be reused
Expand Down
11 changes: 11 additions & 0 deletions src/core/qgsfeaturerequest.cpp
Expand Up @@ -86,6 +86,7 @@ QgsFeatureRequest &QgsFeatureRequest::operator=( const QgsFeatureRequest &rh )
mCrs = rh.mCrs;
mTransformErrorCallback = rh.mTransformErrorCallback;
mConnectionTimeout = rh.mConnectionTimeout;
mFreeConnectionsRequirement = rh.mFreeConnectionsRequirement;
return *this;
}

Expand Down Expand Up @@ -298,6 +299,16 @@ void QgsFeatureRequest::setConnectionTimeout( int connectionTimeout )
mConnectionTimeout = connectionTimeout;
}

int QgsFeatureRequest::freeConnectionsRequirement() const
{
return mFreeConnectionsRequirement;
}

void QgsFeatureRequest::setFreeConnectionsRequirement( int freeConnectionsRequirement )
{
mFreeConnectionsRequirement = freeConnectionsRequirement;
}


#include "qgsfeatureiterator.h"
#include "qgslogger.h"
Expand Down
35 changes: 35 additions & 0 deletions src/core/qgsfeaturerequest.h
Expand Up @@ -636,6 +636,40 @@ class CORE_EXPORT QgsFeatureRequest
*/
void setConnectionTimeout( int connectionTimeout );

/**
* The amount of free connections required to start this request.
* The system will block the request until the specified amount of connections
* is available for usage.
*
* By default this amount is 3. This makes sure, that we have 2 spare connections
* that might be used by "nested" requests which are executed while iterating
* over the results of this request.
*
* This number should be changed to one, when we know that no nested requests happen
* and that this request might happen in a nested way. This is for example given for
* expression functions that do internal requests.
*
* \since QGIS 3.4
*/
int freeConnectionsRequirement() const;

/**
* The amount of free connections required to start this request.
* The system will block the request until the specified amount of connections
* is available for usage.
*
* By default this amount is 3. This makes sure, that we have 2 spare connections
* that might be used by "nested" requests which are executed while iterating
* over the results of this request.
*
* This number should be changed to one, when we know that no nested requests happen
* and that this request might happen in a nested way. This is for example given for
* expression functions that do internal requests.
*
* \since QGIS 3.4
*/
void setFreeConnectionsRequirement( int freeConnectionsRequirement );

protected:
FilterType mFilter = FilterNone;
QgsRectangle mFilterRect;
Expand All @@ -654,6 +688,7 @@ class CORE_EXPORT QgsFeatureRequest
QgsCoordinateReferenceSystem mCrs;
QgsCoordinateTransformContext mTransformContext;
int mConnectionTimeout = -1;
int mFreeConnectionsRequirement = 3;
};

Q_DECLARE_OPERATORS_FOR_FLAGS( QgsFeatureRequest::Flags )
Expand Down
2 changes: 1 addition & 1 deletion src/providers/postgres/qgspostgresfeatureiterator.cpp
Expand Up @@ -38,7 +38,7 @@ QgsPostgresFeatureIterator::QgsPostgresFeatureIterator( QgsPostgresFeatureSource

if ( !source->mTransactionConnection )
{
mConn = QgsPostgresConnPool::instance()->acquireConnection( mSource->mConnInfo );
mConn = QgsPostgresConnPool::instance()->acquireConnection( mSource->mConnInfo, request.connectionTimeout(), request.freeConnectionsRequirement() );
mIsTransactionConnection = false;
}
else
Expand Down

0 comments on commit 14643ad

Please sign in to comment.