Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge pull request #5443 from m-kuhn/iteratorTimeout
[feature] Allow to specify timeout when requesting features
  • Loading branch information
m-kuhn committed Oct 26, 2017
2 parents dc5eefb + ace8b06 commit ba75123
Show file tree
Hide file tree
Showing 10 changed files with 138 additions and 6 deletions.
26 changes: 26 additions & 0 deletions python/core/qgsfeatureiterator.sip
Expand Up @@ -63,6 +63,19 @@ end of iterating: free the resources / lock
:rtype: CompileStatus
%End

virtual bool isValid() const;
%Docstring
Returns if this iterator is valid.
An invalid feature iterator is not able to provide a reliable source for data.
If an iterator is invalid, either give up or try to send the request again (preferably
after a timeout to give the system some time to stay responsive).

If you want to check if the iterator successfully completed, better use QgsFeatureIterator.isClosed().

.. versionadded:: 3.0
:rtype: bool
%End

protected:

virtual bool fetchFeature( QgsFeature &f ) = 0;
Expand Down Expand Up @@ -145,6 +158,7 @@ Setup the simplification of geometries to fetch using the specified simplify met
:rtype: bool
%End


};


Expand Down Expand Up @@ -233,6 +247,18 @@ destructor deletes the iterator if it has no more references
:rtype: bool
%End

virtual bool isValid() const;
%Docstring
Will return if this iterator is valid.
An invalid iterator was probably introduced by a failed attempt to acquire a connection
or is a default constructed iterator.

.. seealso:: isClosed to check if the iterator successfully completed and returned all the features.

.. versionadded:: 3.0
:rtype: bool
%End

bool isClosed() const;
%Docstring
find out whether the iterator is still valid or closed already
Expand Down
13 changes: 13 additions & 0 deletions python/core/qgsfeaturerequest.sip
Expand Up @@ -625,6 +625,19 @@ Set a subset of attributes by names that will be fetched
:rtype: bool
%End

int connectionTimeout() const;
%Docstring
The timeout for how long we should wait for a connection if none is available from the pool
at this moment. A negative value (which is set by default) will wait forever.
:rtype: int
%End

void setConnectionTimeout( int connectionTimeout );
%Docstring
The timeout for how long we should wait for a connection if none is available from the pool
at this moment. A negative value (which is set by default) will wait forever.
%End

protected:
};

Expand Down
2 changes: 2 additions & 0 deletions python/core/qgsvectorlayerfeatureiterator.sip
Expand Up @@ -107,6 +107,8 @@ end of iterating: free the resources / lock
};


virtual bool isValid() const;

protected:
virtual bool fetchFeature( QgsFeature &feature );
%Docstring
Expand Down
23 changes: 17 additions & 6 deletions src/core/qgsconnectionpool.h
Expand Up @@ -85,10 +85,18 @@ class QgsConnectionPoolGroup
//! QgsConnectionPoolGroup cannot be copied
QgsConnectionPoolGroup &operator=( const QgsConnectionPoolGroup &other ) = delete;

T acquire()
/**
* Try to acquire a connection for a maximum of \a timeout milliseconds.
* 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 acquire( int timeout )
{
// we are going to acquire a resource - if no resource is available, we will block here
sem.acquire();
if ( !sem.tryAcquire( 1, timeout ) )
return nullptr;

// quick (preferred) way - use cached connection
{
Expand Down Expand Up @@ -259,10 +267,13 @@ class QgsConnectionPool
}

/**
* Try to acquire a connection: if no connections are available, the thread will get blocked.
* \returns initialized connection or null on error
* Try to acquire a connection for a maximum of \a timeout milliseconds.
* 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 )
T acquireConnection( const QString &connInfo, int timeout = -1 )
{
mMutex.lock();
typename T_Groups::iterator it = mGroups.find( connInfo );
Expand All @@ -273,7 +284,7 @@ class QgsConnectionPool
T_Group *group = *it;
mMutex.unlock();

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

//! Release an existing connection so it will get back into the pool and can be reused
Expand Down
5 changes: 5 additions & 0 deletions src/core/qgsfeatureiterator.cpp
Expand Up @@ -235,3 +235,8 @@ QgsFeatureIterator &QgsFeatureIterator::operator=( const QgsFeatureIterator &oth
}
return *this;
}

bool QgsFeatureIterator::isValid() const
{
return mIter && mIter->isValid();
}
36 changes: 36 additions & 0 deletions src/core/qgsfeatureiterator.h
Expand Up @@ -82,6 +82,21 @@ class CORE_EXPORT QgsAbstractFeatureIterator
*/
CompileStatus compileStatus() const { return mCompileStatus; }

/**
* Returns if this iterator is valid.
* An invalid feature iterator is not able to provide a reliable source for data.
* If an iterator is invalid, either give up or try to send the request again (preferably
* after a timeout to give the system some time to stay responsive).
*
* If you want to check if the iterator successfully completed, better use QgsFeatureIterator::isClosed().
*
* \since QGIS 3.0
*/
virtual bool isValid() const
{
return mValid;
}

protected:

/**
Expand Down Expand Up @@ -175,6 +190,16 @@ class CORE_EXPORT QgsAbstractFeatureIterator
//! Setup the simplification of geometries to fetch using the specified simplify method
virtual bool prepareSimplification( const QgsSimplifyMethod &simplifyMethod );

/**
* An invalid state of a feature iterator indicates that there was a problem with
* even getting it up and running.
* This should be set to false by subclasses if they have problems connecting to
* the provider.
* Do NOT set this to false when the feature iterator closes or has no features but
* we are sure, that it's just an empty dataset.
*/
bool mValid = true;

private:
bool mUseCachedFeatures;
QList<QgsIndexedFeature> mCachedFeatures;
Expand Down Expand Up @@ -279,6 +304,17 @@ class CORE_EXPORT QgsFeatureIterator
bool rewind();
bool close();

/**
* Will return if this iterator is valid.
* An invalid iterator was probably introduced by a failed attempt to acquire a connection
* or is a default constructed iterator.
*
* \see isClosed to check if the iterator successfully completed and returned all the features.
*
* \since QGIS 3.0
*/
virtual bool isValid() const;

//! find out whether the iterator is still valid or closed already
bool isClosed() const;

Expand Down
11 changes: 11 additions & 0 deletions src/core/qgsfeaturerequest.cpp
Expand Up @@ -85,6 +85,7 @@ QgsFeatureRequest &QgsFeatureRequest::operator=( const QgsFeatureRequest &rh )
mOrderBy = rh.mOrderBy;
mCrs = rh.mCrs;
mTransformErrorCallback = rh.mTransformErrorCallback;
mConnectionTimeout = rh.mConnectionTimeout;
return *this;
}

Expand Down Expand Up @@ -281,6 +282,16 @@ bool QgsFeatureRequest::acceptFeature( const QgsFeature &feature )
return true;
}

int QgsFeatureRequest::connectionTimeout() const
{
return mConnectionTimeout;
}

void QgsFeatureRequest::setConnectionTimeout( int connectionTimeout )
{
mConnectionTimeout = connectionTimeout;
}


#include "qgsfeatureiterator.h"
#include "qgslogger.h"
Expand Down
21 changes: 21 additions & 0 deletions src/core/qgsfeaturerequest.h
Expand Up @@ -601,6 +601,26 @@ class CORE_EXPORT QgsFeatureRequest
*/
bool acceptFeature( const QgsFeature &feature );

/**
* The timeout for how long we should wait for a connection if none is available from the pool
* at this moment. A negative value (which is set by default) will wait forever.
*
* \note Only works if the provider supports this option.
*
* \since QGIS 3.0
*/
int connectionTimeout() const;

/**
* The timeout for how long we should wait for a connection if none is available from the pool
* at this moment. A negative value (which is set by default) will wait forever.
*
* \note Only works if the provider supports this option.
*
* \since QGIS 3.0
*/
void setConnectionTimeout( int connectionTimeout );

protected:
FilterType mFilter = FilterNone;
QgsRectangle mFilterRect;
Expand All @@ -617,6 +637,7 @@ class CORE_EXPORT QgsFeatureRequest
std::function< void( const QgsFeature & ) > mInvalidGeometryCallback;
std::function< void( const QgsFeature & ) > mTransformErrorCallback;
QgsCoordinateReferenceSystem mCrs;
int mConnectionTimeout = -1;
};

Q_DECLARE_OPERATORS_FOR_FLAGS( QgsFeatureRequest::Flags )
Expand Down
5 changes: 5 additions & 0 deletions src/core/qgsvectorlayerfeatureiterator.cpp
Expand Up @@ -408,6 +408,11 @@ void QgsVectorLayerFeatureIterator::setInterruptionChecker( QgsInterruptionCheck
mInterruptionChecker = interruptionChecker;
}

bool QgsVectorLayerFeatureIterator::isValid() const
{
return mProviderIterator.isValid();
}

bool QgsVectorLayerFeatureIterator::fetchNextAddedFeature( QgsFeature &f )
{
while ( mFetchAddedFeaturesIt-- != mSource->mAddedFeatures.constBegin() )
Expand Down
2 changes: 2 additions & 0 deletions src/core/qgsvectorlayerfeatureiterator.h
Expand Up @@ -139,6 +139,8 @@ class CORE_EXPORT QgsVectorLayerFeatureIterator : public QgsAbstractFeatureItera
};


virtual bool isValid() const override;

protected:
//! fetch next feature, return true on success
virtual bool fetchFeature( QgsFeature &feature ) override;
Expand Down

0 comments on commit ba75123

Please sign in to comment.