Skip to content
Permalink
Browse files

Heavier use of feature caching for fully populated caches

When a feature cache is set to "FullCache" mode, it will answer
requests from this cache instead of querying the backend.

Some more documentation for writing custom feature iterators
based on QgsAbstractFeatureIterator

Fix #9099
  • Loading branch information
m-kuhn committed Nov 20, 2013
1 parent 9d8d3cf commit 584aba7672e1c000a031de750713cd9a8e58ca8d
@@ -24,19 +24,39 @@ QgsCachedFeatureIterator::QgsCachedFeatureIterator( QgsVectorLayerCache *vlCache
mFeatureIdIterator = featureIds.begin();
}

QgsCachedFeatureIterator::QgsCachedFeatureIterator( QgsVectorLayerCache *vlCache, QgsFeatureRequest featureRequest )
: QgsAbstractFeatureIterator( featureRequest )
, mVectorLayerCache( vlCache )
{
switch ( featureRequest.filterType() )
{
case QgsFeatureRequest::FilterFids:
mFeatureIds = featureRequest.filterFids();
break;

case QgsFeatureRequest::FilterFid:
mFeatureIds = QgsFeatureIds() << featureRequest.filterFid();
break;

default:
mFeatureIds = mVectorLayerCache->mCache.keys().toSet();
break;
}

mFeatureIdIterator = mFeatureIds.begin();
}

bool QgsCachedFeatureIterator::fetchFeature( QgsFeature& f )
{
mFeatureIdIterator++;

if ( mFeatureIdIterator == mFeatureIds.end() )
{
return false;
}
else
while ( mFeatureIdIterator != mFeatureIds.end() )
{
f = QgsFeature( *mVectorLayerCache->mCache[*mFeatureIdIterator]->feature() );
return true;
if ( mRequest.acceptFeature( f ) )
return true;
}
return false;
}

bool QgsCachedFeatureIterator::rewind()
@@ -30,38 +30,60 @@ class CORE_EXPORT QgsCachedFeatureIterator : public QgsAbstractFeatureIterator
{
public:
/**
* @brief
* This constructor creates a feature iterator, that delivers only cached information, based on the
* @link QgsFeatureIds @endlink. No request is made to the backend.
*
* @param vlCache The vector layer cache to use
* @param featureRequest The feature request to answer
* @param featureIds The feature ids to return
*
* @deprecated Use QgsCachedFeatureIterator( QgsVectorLayerCache* vlCache, QgsFeatureRequest featureRequest )
* instead
*/
QgsCachedFeatureIterator( QgsVectorLayerCache* vlCache, QgsFeatureRequest featureRequest, QgsFeatureIds featureIds );

/**
* @brief
* This constructor creates a feature iterator, that delivers all cached features. No request is made to the backend.
*
* @param f
* @return bool
* @param vlCache The vector layer cache to use
* @param featureRequest The feature request to answer
*/
virtual bool fetchFeature( QgsFeature& f );
QgsCachedFeatureIterator( QgsVectorLayerCache* vlCache, QgsFeatureRequest featureRequest );

/**
* @brief
* Rewind to the beginning of the iterator
*
* @return bool
* @return bool true if the operation was ok
*/
virtual bool rewind();

/**
* @brief
* Close this iterator. No further features will be available.
*
* @return bool
* @return true if successful
*/
virtual bool close();

// QgsAbstractFeatureIterator interface
protected:
/**
* Implementation for fetching a feature.
*
* @param f Will write to this feature
* @return bool true if the operation was ok
*
* @see bool getFeature( QgsFeature& f )
*/
virtual bool fetchFeature( QgsFeature& f );

/**
* We have a local special iterator for FilterFids, no need to run the generic.
*
* @param f Will write to this feature
* @return bool true if the operation was ok
*/
virtual bool nextFeatureFilterFids( QgsFeature& f ) { return fetchFeature( f ); }

private:
QgsFeatureIds mFeatureIds;
QgsVectorLayerCache* mVectorLayerCache;
@@ -77,7 +99,6 @@ class CORE_EXPORT QgsCachedFeatureWriterIterator : public QgsAbstractFeatureIter
{
public:
/**
* @brief
* This constructor creates a feature iterator, which queries the backend and caches retrieved features.
*
* @param vlCache The vector layer cache to use
@@ -86,26 +107,30 @@ class CORE_EXPORT QgsCachedFeatureWriterIterator : public QgsAbstractFeatureIter
QgsCachedFeatureWriterIterator( QgsVectorLayerCache* vlCache, QgsFeatureRequest featureRequest );

/**
* @brief
* Rewind to the beginning of the iterator
*
* @param f
* @return bool
* @return bool true if the operation was ok
*/
virtual bool fetchFeature( QgsFeature& f );
virtual bool rewind();

/**
* @brief
* Close this iterator. No further features will be available.
*
* @return bool
* @return true if successful
*/
virtual bool rewind();
virtual bool close();

protected:

/**
* @brief
* Implementation for fetching a feature.
*
* @param f Will write to this feature
* @return bool true if the operation was ok
*
* @return bool
* @see bool getFeature( QgsFeature& f )
*/
virtual bool close();
virtual bool fetchFeature( QgsFeature& f );

private:
QgsFeatureIterator mFeatIt;
@@ -46,9 +46,7 @@ bool QgsCacheIndexFeatureId::getCacheIterator( QgsFeatureIterator &featureIterat
{
if ( C->isFidCached( featureRequest.filterFid() ) )
{
QgsFeatureIds fids;
fids << featureRequest.filterFid();
featureIterator = QgsFeatureIterator( new QgsCachedFeatureIterator( C, featureRequest, fids ) );
featureIterator = QgsFeatureIterator( new QgsCachedFeatureIterator( C, featureRequest ) );
return true;
}
}
@@ -39,21 +39,51 @@ class CORE_EXPORT QgsAbstractFeatureIterator
//! end of iterating: free the resources / lock
virtual bool close() = 0;

protected:
protected:
/**
* If you write a feature iterator for your provider, this is the method you
* need to implement!!
*
* @param f The feature to write to
* @return true if a feature was written to f
*/
virtual bool fetchFeature( QgsFeature& f ) = 0;

/**
* By default, the iterator will fetch all features and check if the feature
* matches the expression.
* If you have a more sophisticated metodology (SQL request for the features...)
* and you check for the expression in your fetchFeature method, you can just
* redirect this call to fetchFeature so the default check will be omitted.
*
* @param f The feature to write to
* @return true if a feature was written to f
*/
virtual bool nextFeatureFilterExpression( QgsFeature &f );

/**
* By default, the iterator will fetch all features and check if the id
* is in the request.
* If you have a more sophisticated metodology (SQL request for the features...)
* and you are sure, that any feature you return from fetchFeature will match
* if the request was FilterFids you can just redirect this call to fetchFeature
* so the default check will be omitted.
*
* @param f The feature to write to
* @return true if a feature was written to f
*/
virtual bool nextFeatureFilterFids( QgsFeature & f );

virtual bool fetchFeature( QgsFeature& f ) = 0;

/** A copy of the feature request. */
QgsFeatureRequest mRequest;

/** Set to true, as soon as the iterator is closed. */
bool mClosed;

// reference counting (to allow seamless copying of QgsFeatureIterator instances)
//! reference counting (to allow seamless copying of QgsFeatureIterator instances)
int refs;
void ref(); // add reference
void deref(); // remove reference, delete if refs == 0
void ref(); //!< add reference
void deref(); //!< remove reference, delete if refs == 0
friend class QgsFeatureIterator;
};

@@ -76,9 +76,9 @@ void QgsVectorLayerCache::setFullCache( bool fullCache )
setCacheSize( mLayer->featureCount() + 100 );

// Initialize the cache...
QgsFeatureIterator it = getFeatures( QgsFeatureRequest()
.setSubsetOfAttributes( mCachedAttributes )
.setFlags( !mCacheGeometry ? QgsFeatureRequest::NoGeometry : QgsFeatureRequest::Flags( 0 ) ) );
QgsFeatureIterator it ( new QgsCachedFeatureWriterIterator( this, QgsFeatureRequest()
.setSubsetOfAttributes( mCachedAttributes )
.setFlags( !mCacheGeometry ? QgsFeatureRequest::NoGeometry : QgsFeatureRequest::Flags( 0 ) ) ) );

int i = 0;

@@ -258,13 +258,22 @@ QgsFeatureIterator QgsVectorLayerCache::getFeatures( const QgsFeatureRequest &fe

if ( checkInformationCovered( featureRequest ) )
{
// Check if an index is able to deliver the requested features
foreach ( QgsAbstractCacheIndex *idx, mCacheIndices )
// If we have a full cache available, run on this
if ( mFullCache )
{
if ( idx->getCacheIterator( it, featureRequest ) )
it = QgsFeatureIterator( new QgsCachedFeatureIterator( this, featureRequest ) );
requiresWriterIt = false;
}
else
{
// Check if an index is able to deliver the requested features
foreach ( QgsAbstractCacheIndex *idx, mCacheIndices )
{
requiresWriterIt = false;
break;
if ( idx->getCacheIterator( it, featureRequest ) )
{
requiresWriterIt = false;
break;
}
}
}
}

0 comments on commit 584aba7

Please sign in to comment.
You can’t perform that action at this time.