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
This commit is contained in:
Matthias Kuhn 2013-11-20 19:36:20 +01:00
parent 9d8d3cff08
commit 584aba7672
5 changed files with 129 additions and 47 deletions

View File

@ -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()

View File

@ -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,27 +107,31 @@ class CORE_EXPORT QgsCachedFeatureWriterIterator : public QgsAbstractFeatureIter
QgsCachedFeatureWriterIterator( QgsVectorLayerCache* vlCache, QgsFeatureRequest featureRequest );
/**
* @brief
* Rewind to the beginning of the iterator
*
* @param f
* @return bool
*/
virtual bool fetchFeature( QgsFeature& f );
/**
* @brief
*
* @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();
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 );
private:
QgsFeatureIterator mFeatIt;
QgsVectorLayerCache* mVectorLayerCache;

View File

@ -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;
}
}

View File

@ -39,21 +39,51 @@ class CORE_EXPORT QgsAbstractFeatureIterator
//! end of iterating: free the resources / lock
virtual bool close() = 0;
protected:
virtual bool nextFeatureFilterExpression( QgsFeature &f );
virtual bool nextFeatureFilterFids( QgsFeature & f );
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 );
/** 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;
};

View File

@ -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;
}
}
}
}