Skip to content

Commit

Permalink
Merge pull request #7520 from m-kuhn/get_feature_thread_safety
Browse files Browse the repository at this point in the history
Thread safety for get_feature
  • Loading branch information
m-kuhn committed Aug 4, 2018
2 parents b55a8a3 + 11b2683 commit 9db2022
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 5 deletions.
Expand Up @@ -52,6 +52,13 @@ this source.
Returns the coordinate reference system for features retrieved from this source.

.. versionadded:: 3.0
%End

QString id() const;
%Docstring
Returns the layer id of the source layer.

.. versionadded:: 3.4
%End

protected:
Expand All @@ -63,6 +70,7 @@ Returns the coordinate reference system for features retrieved from this source.




};


Expand Down
12 changes: 7 additions & 5 deletions src/core/expression/qgsexpressionfunction.cpp
Expand Up @@ -43,6 +43,7 @@
#include "qgscolorramp.h"
#include "qgsfieldformatterregistry.h"
#include "qgsfieldformatter.h"
#include "qgsvectorlayerfeatureiterator.h"

const QString QgsExpressionFunction::helpText() const
{
Expand Down Expand Up @@ -3582,24 +3583,25 @@ static QVariant fcnGetFeatureById( const QVariantList &values, const QgsExpressi
static QVariant fcnGetFeature( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
{
//arguments: 1. layer id / name, 2. key attribute, 3. eq value
QgsVectorLayer *vl = QgsExpressionUtils::getVectorLayer( values.at( 0 ), parent );

std::unique_ptr<QgsVectorLayerFeatureSource> featureSource = QgsExpressionUtils::getFeatureSource( values.at( 0 ), parent );

//no layer found
if ( !vl )
if ( !featureSource )
{
return QVariant();
}

QString attribute = QgsExpressionUtils::getStringValue( values.at( 1 ), parent );
int attributeId = vl->fields().lookupField( attribute );
int attributeId = featureSource->fields().lookupField( attribute );
if ( attributeId == -1 )
{
return QVariant();
}

const QVariant &attVal = values.at( 2 );

const QString cacheValueKey = QStringLiteral( "getfeature:%1:%2:%3" ).arg( vl->id(), QString::number( attributeId ), attVal.toString() );
const QString cacheValueKey = QStringLiteral( "getfeature:%1:%2:%3" ).arg( featureSource->id(), QString::number( attributeId ), attVal.toString() );
if ( context && context->hasCachedValue( cacheValueKey ) )
{
return context->cachedValue( cacheValueKey );
Expand All @@ -3613,7 +3615,7 @@ static QVariant fcnGetFeature( const QVariantList &values, const QgsExpressionCo
{
req.setFlags( QgsFeatureRequest::NoGeometry );
}
QgsFeatureIterator fIt = vl->getFeatures( req );
QgsFeatureIterator fIt = featureSource->getFeatures( req );

QgsFeature fet;
QVariant res;
Expand Down
29 changes: 29 additions & 0 deletions src/core/expression/qgsexpressionutils.h
Expand Up @@ -23,6 +23,7 @@
#include "qgsexpression.h"
#include "qgscolorramp.h"
#include "qgsvectorlayer.h"
#include "qgsvectorlayerfeatureiterator.h"
#include "qgsrasterlayer.h"
#include "qgsproject.h"
#include "qgsrelationmanager.h"
Expand Down Expand Up @@ -351,6 +352,34 @@ class QgsExpressionUtils
return ml;
}

static std::unique_ptr<QgsVectorLayerFeatureSource> getFeatureSource( const QVariant &value, QgsExpression *e )
{
std::unique_ptr<QgsVectorLayerFeatureSource> featureSource;

auto getFeatureSource = [ &value, e, &featureSource ]
{
QgsVectorLayer *layer = getVectorLayer( value, e );

if ( layer )
{
featureSource.reset( new QgsVectorLayerFeatureSource( layer ) );
}
};

#if QT_VERSION >= QT_VERSION_CHECK( 5, 10, 0 )
// Make sure we only deal with the vector layer on the main thread where it lives.
// Anything else risks a crash.
if ( QThread::currentThread() == qApp->thread() )
getFeatureSource();
else
QMetaObject::invokeMethod( qApp, getFeatureSource, Qt::BlockingQueuedConnection );
#else
getFeatureSource();
#endif

return featureSource;
}

static QgsVectorLayer *getVectorLayer( const QVariant &value, QgsExpression *e )
{
return qobject_cast<QgsVectorLayer *>( getMapLayer( value, e ) );
Expand Down
6 changes: 6 additions & 0 deletions src/core/qgsvectorlayerfeatureiterator.cpp
Expand Up @@ -32,6 +32,7 @@ QgsVectorLayerFeatureSource::QgsVectorLayerFeatureSource( const QgsVectorLayer *
QMutexLocker locker( &layer->mFeatureSourceConstructorMutex );
mProviderFeatureSource = layer->dataProvider()->featureSource();
mFields = layer->fields();
mId = layer->id();

// update layer's join caches if necessary
if ( layer->mJoinBuffer->containsJoins() )
Expand Down Expand Up @@ -107,6 +108,11 @@ QgsCoordinateReferenceSystem QgsVectorLayerFeatureSource::crs() const
return mCrs;
}

QString QgsVectorLayerFeatureSource::id() const
{
return mId;
}


QgsVectorLayerFeatureIterator::QgsVectorLayerFeatureIterator( QgsVectorLayerFeatureSource *source, bool ownSource, const QgsFeatureRequest &request )
: QgsAbstractFeatureIteratorFromSource<QgsVectorLayerFeatureSource>( source, ownSource, request )
Expand Down
9 changes: 9 additions & 0 deletions src/core/qgsvectorlayerfeatureiterator.h
Expand Up @@ -78,6 +78,13 @@ class CORE_EXPORT QgsVectorLayerFeatureSource : public QgsAbstractFeatureSource
*/
QgsCoordinateReferenceSystem crs() const;

/**
* Returns the layer id of the source layer.
*
* \since QGIS 3.4
*/
QString id() const;

protected:

QgsAbstractFeatureSource *mProviderFeatureSource = nullptr;
Expand All @@ -88,6 +95,8 @@ class CORE_EXPORT QgsVectorLayerFeatureSource : public QgsAbstractFeatureSource

QgsFields mFields;

QString mId;

QgsExpressionContextScope mLayerScope;

bool mHasEditBuffer;
Expand Down

0 comments on commit 9db2022

Please sign in to comment.