Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

QgsFeaturePool documentation and thread safety cleanups #58259

Merged
merged 4 commits into from
Jul 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ A feature pool is based on a vector layer and caches features.
QgsFeaturePool( QgsVectorLayer *layer );
%Docstring
Creates a new feature pool for ``layer``.

Must be created on the same thread as ``layer``.
%End
virtual ~QgsFeaturePool();

Expand All @@ -38,19 +40,36 @@ Creates a new feature pool for ``layer``.
Retrieves the feature with the specified ``id`` into ``feature``.
It will be retrieved from the cache or from the underlying feature source if unavailable.
If the feature is neither available from the cache nor from the source it will return ``False``.

.. note::

This method can safely be called from a different thread vs the object's creation thread or
the original layer's thread.
%End


virtual void updateFeature( QgsFeature &feature ) = 0;
%Docstring
Updates a feature in this pool.
Implementations will update the feature on the layer or on the data provider.

.. warning::

This method can safely be called from a different thread vs the object's creation thread or
the original layer's thread. The update will be delegated to run in the main thread, and care must
be taken to avoid deadlocks if the main thread is busy.
%End

virtual void deleteFeature( QgsFeatureId fid ) = 0;
%Docstring
Removes a feature from this pool.
Implementations will remove the feature from the layer or from the data provider.

.. warning::

This method can safely be called from a different thread vs the object's creation thread or
the original layer's thread. The update will be delegated to run in the main thread, and care must
be taken to avoid deadlocks if the main thread is busy.
%End


Expand All @@ -59,7 +78,10 @@ Implementations will remove the feature from the layer or from the data provider
%Docstring
Gets a pointer to the underlying layer.
May return a ````None```` if the layer has been deleted.
This must only be called from the main thread.

.. warning::

This must be called from the same thread as the vector layer belongs to.
%End


Expand Down Expand Up @@ -92,18 +114,33 @@ the background thread.
%Docstring
Inserts a feature into the cache and the spatial index.
To be used by implementations of ``addFeature``.

.. note::

This method can safely be called from a different thread vs the object's creation thread or
the original layer's thread.
%End

void refreshCache( const QgsFeature &feature );
%Docstring
Changes a feature in the cache and the spatial index.
To be used by implementations of ``updateFeature``.

.. note::

This method can safely be called from a different thread vs the object's creation thread or
the original layer's thread.
%End

void removeFeature( const QgsFeatureId featureId );
%Docstring
Removes a feature from the cache and the spatial index.
To be used by implementations of ``deleteFeature``.

.. note::

This method can safely be called from a different thread vs the object's creation thread or
the original layer's thread.
%End


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ A feature pool is based on a vector layer and caches features.
QgsFeaturePool( QgsVectorLayer *layer );
%Docstring
Creates a new feature pool for ``layer``.

Must be created on the same thread as ``layer``.
%End
virtual ~QgsFeaturePool();

Expand All @@ -38,19 +40,36 @@ Creates a new feature pool for ``layer``.
Retrieves the feature with the specified ``id`` into ``feature``.
It will be retrieved from the cache or from the underlying feature source if unavailable.
If the feature is neither available from the cache nor from the source it will return ``False``.

.. note::

This method can safely be called from a different thread vs the object's creation thread or
the original layer's thread.
%End


virtual void updateFeature( QgsFeature &feature ) = 0;
%Docstring
Updates a feature in this pool.
Implementations will update the feature on the layer or on the data provider.

.. warning::

This method can safely be called from a different thread vs the object's creation thread or
the original layer's thread. The update will be delegated to run in the main thread, and care must
be taken to avoid deadlocks if the main thread is busy.
%End

virtual void deleteFeature( QgsFeatureId fid ) = 0;
%Docstring
Removes a feature from this pool.
Implementations will remove the feature from the layer or from the data provider.

.. warning::

This method can safely be called from a different thread vs the object's creation thread or
the original layer's thread. The update will be delegated to run in the main thread, and care must
be taken to avoid deadlocks if the main thread is busy.
%End


Expand All @@ -59,7 +78,10 @@ Implementations will remove the feature from the layer or from the data provider
%Docstring
Gets a pointer to the underlying layer.
May return a ````None```` if the layer has been deleted.
This must only be called from the main thread.

.. warning::

This must be called from the same thread as the vector layer belongs to.
%End


Expand Down Expand Up @@ -92,18 +114,33 @@ the background thread.
%Docstring
Inserts a feature into the cache and the spatial index.
To be used by implementations of ``addFeature``.

.. note::

This method can safely be called from a different thread vs the object's creation thread or
the original layer's thread.
%End

void refreshCache( const QgsFeature &feature );
%Docstring
Changes a feature in the cache and the spatial index.
To be used by implementations of ``updateFeature``.

.. note::

This method can safely be called from a different thread vs the object's creation thread or
the original layer's thread.
%End

void removeFeature( const QgsFeatureId featureId );
%Docstring
Removes a feature from the cache and the spatial index.
To be used by implementations of ``deleteFeature``.

.. note::

This method can safely be called from a different thread vs the object's creation thread or
the original layer's thread.
%End


Expand Down
18 changes: 10 additions & 8 deletions src/analysis/vector/geometry_checker/qgsfeaturepool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,11 @@ QgsFeaturePool::QgsFeaturePool( QgsVectorLayer *layer )
, mLayer( layer )
, mGeometryType( layer->geometryType() )
, mFeatureSource( std::make_unique<QgsVectorLayerFeatureSource>( layer ) )
, mLayerId( layer->id() )
, mLayerName( layer->name() )
, mCrs( layer->crs() )
{

Q_ASSERT( QThread::currentThread() == mLayer->thread() );
}

bool QgsFeaturePool::getFeature( QgsFeatureId id, QgsFeature &feature )
Expand Down Expand Up @@ -71,9 +73,10 @@ bool QgsFeaturePool::getFeature( QgsFeatureId id, QgsFeature &feature )

QgsFeatureIds QgsFeaturePool::getFeatures( const QgsFeatureRequest &request, QgsFeedback *feedback )
{
QgsReadWriteLocker( mCacheLock, QgsReadWriteLocker::Write );
QgsReadWriteLocker locker( mCacheLock, QgsReadWriteLocker::Write );
Q_UNUSED( feedback )
Q_ASSERT( QThread::currentThread() == qApp->thread() );
Q_ASSERT( mLayer );
Q_ASSERT( QThread::currentThread() == mLayer->thread() );

mFeatureCache.clear();
mIndex = QgsSpatialIndex();
Expand Down Expand Up @@ -107,7 +110,8 @@ QgsFeatureIds QgsFeaturePool::getIntersects( const QgsRectangle &rect ) const

QgsVectorLayer *QgsFeaturePool::layer() const
{
Q_ASSERT( QThread::currentThread() == qApp->thread() );
if ( mLayer )
Q_ASSERT( QThread::currentThread() == mLayer->thread() );

return mLayer.data();
}
Expand Down Expand Up @@ -169,8 +173,7 @@ QString QgsFeaturePool::layerName() const

QgsCoordinateReferenceSystem QgsFeaturePool::crs() const
{
QgsReadWriteLocker( mCacheLock, QgsReadWriteLocker::Read );
return mFeatureSource->crs();
return mCrs;
}

Qgis::GeometryType QgsFeaturePool::geometryType() const
Expand All @@ -180,6 +183,5 @@ Qgis::GeometryType QgsFeaturePool::geometryType() const

QString QgsFeaturePool::layerId() const
{
QgsReadWriteLocker( mCacheLock, QgsReadWriteLocker::Read );
return mFeatureSource->id();
return mLayerId;
}
40 changes: 37 additions & 3 deletions src/analysis/vector/geometry_checker/qgsfeaturepool.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ class ANALYSIS_EXPORT QgsFeaturePool : public QgsFeatureSink SIP_ABSTRACT

/**
* Creates a new feature pool for \a layer.
*
* Must be created on the same thread as \a layer.
*/
QgsFeaturePool( QgsVectorLayer *layer );
virtual ~QgsFeaturePool() = default;
Expand All @@ -49,6 +51,9 @@ class ANALYSIS_EXPORT QgsFeaturePool : public QgsFeatureSink SIP_ABSTRACT
* Retrieves the feature with the specified \a id into \a feature.
* It will be retrieved from the cache or from the underlying feature source if unavailable.
* If the feature is neither available from the cache nor from the source it will return FALSE.
*
* \note This method can safely be called from a different thread vs the object's creation thread or
* the original layer's thread.
*/
bool getFeature( QgsFeatureId id, QgsFeature &feature );

Expand All @@ -59,27 +64,40 @@ class ANALYSIS_EXPORT QgsFeaturePool : public QgsFeatureSink SIP_ABSTRACT
* are returned. This is used to warm the cache for a particular area of interest
* (bounding box) or other set of features.
* This will get a new feature source from the source vector layer.
* This needs to be called from the main thread.
*
* If \a feedback is specified, the call may return if the feedback is canceled.
*
* \warning This must be called from the same thread as the vector layer belongs to.
*/
QgsFeatureIds getFeatures( const QgsFeatureRequest &request, QgsFeedback *feedback = nullptr ) SIP_SKIP;

/**
* Updates a feature in this pool.
* Implementations will update the feature on the layer or on the data provider.
*
* \warning This method can safely be called from a different thread vs the object's creation thread or
* the original layer's thread. The update will be delegated to run in the main thread, and care must
* be taken to avoid deadlocks if the main thread is busy.
*/
virtual void updateFeature( QgsFeature &feature ) = 0;

/**
* Removes a feature from this pool.
* Implementations will remove the feature from the layer or from the data provider.
*
* \warning This method can safely be called from a different thread vs the object's creation thread or
* the original layer's thread. The update will be delegated to run in the main thread, and care must
* be taken to avoid deadlocks if the main thread is busy.
*/
virtual void deleteFeature( QgsFeatureId fid ) = 0;

/**
* Returns the complete set of feature ids in this pool.
* Note that this concerns the features governed by this pool, which are not necessarily all cached.
*
* \note This method can safely be called from a different thread vs the object's creation thread or
* the original layer's thread.
*
* \note not available in Python bindings
*/
QgsFeatureIds allFeatureIds() const SIP_SKIP;
Expand All @@ -88,20 +106,25 @@ class ANALYSIS_EXPORT QgsFeaturePool : public QgsFeatureSink SIP_ABSTRACT
* Gets all feature ids in the bounding box \a rect. It will use a spatial index to
* determine the ids.
*
* \note This method can safely be called from a different thread vs the object's creation thread or
* the original layer's thread.
*
* \note not available in Python bindings
*/
QgsFeatureIds getIntersects( const QgsRectangle &rect ) const SIP_SKIP;

/**
* Gets a pointer to the underlying layer.
* May return a ``NULLPTR`` if the layer has been deleted.
* This must only be called from the main thread.
*
* \warning This must be called from the same thread as the vector layer belongs to.
*/
QgsVectorLayer *layer() const;

/**
* Gets a QPointer to the underlying layer.
* Note that access to any methods of the object
*
* \warning Access to any methods of the object
* will need to be done on the main thread and
* the pointer will need to be checked for validity
* before usage.
Expand Down Expand Up @@ -138,18 +161,27 @@ class ANALYSIS_EXPORT QgsFeaturePool : public QgsFeatureSink SIP_ABSTRACT
/**
* Inserts a feature into the cache and the spatial index.
* To be used by implementations of ``addFeature``.
*
* \note This method can safely be called from a different thread vs the object's creation thread or
* the original layer's thread.
*/
void insertFeature( const QgsFeature &feature, bool skipLock = false );

/**
* Changes a feature in the cache and the spatial index.
* To be used by implementations of ``updateFeature``.
*
* \note This method can safely be called from a different thread vs the object's creation thread or
* the original layer's thread.
*/
void refreshCache( const QgsFeature &feature );

/**
* Removes a feature from the cache and the spatial index.
* To be used by implementations of ``deleteFeature``.
*
* \note This method can safely be called from a different thread vs the object's creation thread or
* the original layer's thread.
*/
void removeFeature( const QgsFeatureId featureId );

Expand Down Expand Up @@ -184,7 +216,9 @@ class ANALYSIS_EXPORT QgsFeaturePool : public QgsFeatureSink SIP_ABSTRACT
QgsSpatialIndex mIndex;
Qgis::GeometryType mGeometryType;
std::unique_ptr<QgsVectorLayerFeatureSource> mFeatureSource;
QString mLayerId;
QString mLayerName;
QgsCoordinateReferenceSystem mCrs;
};

#endif // QGS_FEATUREPOOL_H
Loading