Skip to content

Commit 273e998

Browse files
authored
Merge pull request #7805 from m-kuhn/vectordataproviderfeaturepool
Refactor QgsFeaturePool
2 parents 2d1dbe7 + 84cdff1 commit 273e998

18 files changed

+624
-122
lines changed
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/************************************************************************
2+
* This file has been generated automatically from *
3+
* *
4+
* src/core/qgsreadwritelocker.h *
5+
* *
6+
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
7+
************************************************************************/
8+
9+
10+
11+
12+
13+
class QgsReadWriteLocker
14+
{
15+
%Docstring
16+
The QgsReadWriteLocker class is a convenience class that simplifies locking and unlocking QReadWriteLocks.
17+
18+
Locking and unlocking a QReadWriteLocks in complex functions and statements or in exception handling code
19+
is error-prone and difficult to debug.
20+
QgsReadWriteLocker can be used in such situations to ensure that the state of the lock is always well-defined.
21+
22+
QgsReadWriteLocker should be created within a function where a QReadWriteLock needs to be locked.
23+
The lock may be locked when QgsReadWriteLocker is created or when changeMode is called.
24+
You can unlock and relock the lock with unlock() and changeMode().
25+
If locked, the lock will be unlocked when the QgsReadWriteLocker is destroyed.
26+
27+
.. versionadded:: 3.4
28+
%End
29+
30+
%TypeHeaderCode
31+
#include "qgsreadwritelocker.h"
32+
%End
33+
public:
34+
35+
enum Mode
36+
{
37+
Read,
38+
Write,
39+
Unlocked
40+
};
41+
42+
QgsReadWriteLocker( QReadWriteLock &lock, Mode mode );
43+
%Docstring
44+
Create a new QgsReadWriteLocker for ``lock`` and initialize in ``mode``.
45+
%End
46+
47+
void changeMode( Mode mode );
48+
%Docstring
49+
Change the mode of the lock to ``mode``.
50+
The lock will be unlocked and relocked as required.
51+
%End
52+
53+
void unlock();
54+
%Docstring
55+
Unlocks the lock.
56+
Equivalent to doing ``changeMode( QgsReadWriteLocker.Unlock );``
57+
%End
58+
59+
~QgsReadWriteLocker();
60+
61+
};
62+
63+
/************************************************************************
64+
* This file has been generated automatically from *
65+
* *
66+
* src/core/qgsreadwritelocker.h *
67+
* *
68+
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
69+
************************************************************************/

python/core/core_auto.sip

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@
107107
%Include auto_generated/qgspythonrunner.sip
108108
%Include auto_generated/qgsrange.sip
109109
%Include auto_generated/qgsreadwritecontext.sip
110+
%Include auto_generated/qgsreadwritelocker.sip
110111
%Include auto_generated/qgsrenderchecker.sip
111112
%Include auto_generated/qgsrendercontext.sip
112113
%Include auto_generated/qgsrulebasedlabeling.sip

src/analysis/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ SET(QGIS_ANALYSIS_SRCS
132132
network/qgsgraphanalyzer.cpp
133133

134134
vector/geometry_checker/qgsfeaturepool.cpp
135+
vector/geometry_checker/qgsvectordataproviderfeaturepool.cpp
135136
vector/geometry_checker/qgsgeometrychecker.cpp
136137
vector/geometry_checker/qgsgeometryanglecheck.cpp
137138
vector/geometry_checker/qgsgeometryareacheck.cpp
@@ -232,6 +233,7 @@ SET(QGIS_ANALYSIS_HDRS
232233
vector/qgszonalstatistics.h
233234
vector/geometry_checker/qgsgeometrycheckerutils.h
234235
vector/geometry_checker/qgsfeaturepool.h
236+
vector/geometry_checker/qgsvectordataproviderfeaturepool.h
235237

236238
interpolation/qgsinterpolator.h
237239
interpolation/qgsgridfilewriter.h

src/analysis/vector/geometry_checker/qgsfeaturepool.cpp

Lines changed: 58 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -20,44 +20,26 @@
2020
#include "qgsgeometry.h"
2121
#include "qgsvectorlayer.h"
2222
#include "qgsvectordataprovider.h"
23+
#include "qgsvectorlayerutils.h"
24+
#include "qgsreadwritelocker.h"
2325

2426
#include <QMutexLocker>
2527

26-
QgsFeaturePool::QgsFeaturePool( QgsVectorLayer *layer, double layerToMapUnits, const QgsCoordinateTransform &layerToMapTransform, bool selectedOnly )
28+
29+
QgsFeaturePool::QgsFeaturePool( QgsVectorLayer *layer, double layerToMapUnits, const QgsCoordinateTransform &layerToMapTransform )
2730
: mFeatureCache( CACHE_SIZE )
2831
, mLayer( layer )
2932
, mLayerToMapUnits( layerToMapUnits )
3033
, mLayerToMapTransform( layerToMapTransform )
31-
, mSelectedOnly( selectedOnly )
34+
, mLayerId( layer->id() )
35+
, mGeometryType( layer->geometryType() )
3236
{
33-
// Build spatial index
34-
QgsFeature feature;
35-
QgsFeatureRequest req;
36-
req.setSubsetOfAttributes( QgsAttributeList() );
37-
if ( selectedOnly )
38-
{
39-
mFeatureIds = layer->selectedFeatureIds();
40-
req.setFilterFids( mFeatureIds );
41-
}
4237

43-
QgsFeatureIterator it = layer->getFeatures( req );
44-
while ( it.nextFeature( feature ) )
45-
{
46-
if ( feature.geometry() )
47-
{
48-
mIndex.insertFeature( feature );
49-
mFeatureIds.insert( feature.id() );
50-
}
51-
else
52-
{
53-
mFeatureIds.remove( feature.id() );
54-
}
55-
}
5638
}
5739

5840
bool QgsFeaturePool::get( QgsFeatureId id, QgsFeature &feature )
5941
{
60-
QMutexLocker lock( &mLayerMutex );
42+
QgsReadWriteLocker locker( mCacheLock, QgsReadWriteLocker::Read );
6143
QgsFeature *cachedFeature = mFeatureCache.object( id );
6244
if ( cachedFeature )
6345
{
@@ -66,78 +48,82 @@ bool QgsFeaturePool::get( QgsFeatureId id, QgsFeature &feature )
6648
}
6749
else
6850
{
51+
std::unique_ptr<QgsVectorLayerFeatureSource> source = QgsVectorLayerUtils::getFeatureSource( mLayer );
52+
6953
// Feature not in cache, retrieve from layer
7054
// TODO: avoid always querying all attributes (attribute values are needed when merging by attribute)
71-
if ( !mLayer->getFeatures( QgsFeatureRequest( id ) ).nextFeature( feature ) )
55+
if ( !source->getFeatures( QgsFeatureRequest( id ) ).nextFeature( feature ) )
7256
{
7357
return false;
7458
}
59+
locker.changeMode( QgsReadWriteLocker::Write );
7560
mFeatureCache.insert( id, new QgsFeature( feature ) );
61+
mIndex.insertFeature( feature );
7662
}
7763
return true;
7864
}
7965

80-
void QgsFeaturePool::addFeature( QgsFeature &feature )
66+
QgsFeatureIds QgsFeaturePool::getFeatureIds() const
8167
{
82-
QgsFeatureList features;
83-
features.append( feature );
84-
mLayerMutex.lock();
85-
mLayer->dataProvider()->addFeatures( features );
86-
feature.setId( features.front().id() );
87-
if ( mSelectedOnly )
88-
{
89-
QgsFeatureIds selectedFeatureIds = mLayer->selectedFeatureIds();
90-
selectedFeatureIds.insert( feature.id() );
91-
mLayer->selectByIds( selectedFeatureIds );
92-
}
93-
mLayerMutex.unlock();
94-
mIndexMutex.lock();
95-
mIndex.insertFeature( feature );
96-
mIndexMutex.unlock();
68+
return mFeatureIds;
9769
}
9870

99-
void QgsFeaturePool::updateFeature( QgsFeature &feature )
71+
QgsFeatureIds QgsFeaturePool::getIntersects( const QgsRectangle &rect ) const
10072
{
101-
QgsFeature origFeature;
102-
get( feature.id(), origFeature );
73+
QgsReadWriteLocker locker( mCacheLock, QgsReadWriteLocker::Read );
74+
QgsFeatureIds ids = QgsFeatureIds::fromList( mIndex.intersects( rect ) );
75+
return ids;
76+
}
10377

104-
QgsGeometryMap geometryMap;
105-
geometryMap.insert( feature.id(), feature.geometry() );
106-
QgsChangedAttributesMap changedAttributesMap;
107-
QgsAttributeMap attribMap;
108-
for ( int i = 0, n = feature.attributes().size(); i < n; ++i )
109-
{
110-
attribMap.insert( i, feature.attributes().at( i ) );
111-
}
112-
changedAttributesMap.insert( feature.id(), attribMap );
113-
mLayerMutex.lock();
114-
mFeatureCache.remove( feature.id() ); // Remove to force reload on next get()
115-
mLayer->dataProvider()->changeGeometryValues( geometryMap );
116-
mLayer->dataProvider()->changeAttributeValues( changedAttributesMap );
117-
mLayerMutex.unlock();
118-
mIndexMutex.lock();
119-
mIndex.deleteFeature( origFeature );
78+
QgsVectorLayer *QgsFeaturePool::layer() const
79+
{
80+
Q_ASSERT( QThread::currentThread() == qApp->thread() );
81+
82+
return mLayer.data();
83+
}
84+
85+
void QgsFeaturePool::insertFeature( const QgsFeature &feature )
86+
{
87+
QgsReadWriteLocker locker( mCacheLock, QgsReadWriteLocker::Write );
88+
mFeatureCache.insert( feature.id(), new QgsFeature( feature ) );
12089
mIndex.insertFeature( feature );
121-
mIndexMutex.unlock();
12290
}
12391

124-
void QgsFeaturePool::deleteFeature( QgsFeatureId fid )
92+
void QgsFeaturePool::refreshCache( const QgsFeature &feature )
93+
{
94+
QgsReadWriteLocker locker( mCacheLock, QgsReadWriteLocker::Write );
95+
mFeatureCache.remove( feature.id() );
96+
mIndex.deleteFeature( feature );
97+
locker.unlock();
98+
99+
QgsFeature tempFeature;
100+
get( feature.id(), tempFeature );
101+
}
102+
103+
void QgsFeaturePool::removeFeature( const QgsFeatureId featureId )
125104
{
126105
QgsFeature origFeature;
127-
if ( get( fid, origFeature ) )
106+
QgsReadWriteLocker locker( mCacheLock, QgsReadWriteLocker::Unlocked );
107+
if ( get( featureId, origFeature ) )
128108
{
129-
mIndexMutex.lock();
109+
locker.changeMode( QgsReadWriteLocker::Write );
130110
mIndex.deleteFeature( origFeature );
131-
mIndexMutex.unlock();
132111
}
133-
mLayerMutex.lock();
112+
locker.changeMode( QgsReadWriteLocker::Write );
134113
mFeatureCache.remove( origFeature.id() );
135-
mLayer->dataProvider()->deleteFeatures( QgsFeatureIds() << fid );
136-
mLayerMutex.unlock();
137114
}
138115

139-
QgsFeatureIds QgsFeaturePool::getIntersects( const QgsRectangle &rect ) const
116+
void QgsFeaturePool::setFeatureIds( const QgsFeatureIds &ids )
117+
{
118+
mFeatureIds = ids;
119+
}
120+
121+
QgsWkbTypes::GeometryType QgsFeaturePool::geometryType() const
122+
{
123+
return mGeometryType;
124+
}
125+
126+
QString QgsFeaturePool::layerId() const
140127
{
141-
QMutexLocker lock( &mIndexMutex );
142-
return QgsFeatureIds::fromList( mIndex.intersects( rect ) );
128+
return mLayerId;
143129
}

0 commit comments

Comments
 (0)