Skip to content

Commit 0addae5

Browse files
committed
[WFS provider] Fix excessive memory consumption on big layers (refs #1870)
There was a pseudo memory leak in qgsgml.cpp And the WFS downloader could also have to process big replies, causing a lot of features to be instanciated at once. Was seen on the 'portugal_addresses' layer of http://www.naturalgis.pt/cgi-bin/opendata/mapserv?
1 parent 19b3325 commit 0addae5

File tree

3 files changed

+17
-3
lines changed

3 files changed

+17
-3
lines changed

src/core/qgsgml.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -844,7 +844,7 @@ void QgsGmlStreamingParser::endElement( const XML_Char *el )
844844
const int localNameLen = ( pszSep ) ? ( int )( elLen - nsLen ) - 1 : elLen;
845845
ParseMode parseMode( mParseModeStack.isEmpty() ? None : mParseModeStack.top() );
846846

847-
mDimension = mDimensionStack.isEmpty() ? 0 : mDimensionStack.top();
847+
mDimension = mDimensionStack.isEmpty() ? 0 : mDimensionStack.pop();
848848

849849
const bool isGMLNS = ( nsLen == mGMLNameSpaceURI.size() && mGMLNameSpaceURIPtr && memcmp( el, mGMLNameSpaceURIPtr, nsLen ) == 0 );
850850

src/providers/wfs/qgswfsfeatureiterator.cpp

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,7 @@ void QgsWFSFeatureDownloader::run( bool serializeFeatures, int maxFeatures )
456456
int pagingIter = 1;
457457
QString gmlIdFirstFeatureFirstIter;
458458
bool disablePaging = false;
459+
// Top level loop to do feature paging in WFS 2
459460
while ( true )
460461
{
461462
success = true;
@@ -476,9 +477,14 @@ void QgsWFSFeatureDownloader::run( bool serializeFeatures, int maxFeatures )
476477
false /* cache */ );
477478

478479
int featureCountForThisResponse = 0;
480+
bool bytesStillAvailableInReply = false;
481+
// Loop until there is no data coming from the current requst
479482
while ( true )
480483
{
481-
loop.exec( QEventLoop::ExcludeUserInputEvents );
484+
if ( !bytesStillAvailableInReply )
485+
{
486+
loop.exec( QEventLoop::ExcludeUserInputEvents );
487+
}
482488
if ( mStop )
483489
{
484490
interrupted = true;
@@ -495,7 +501,10 @@ void QgsWFSFeatureDownloader::run( bool serializeFeatures, int maxFeatures )
495501
bool finished = false;
496502
if ( mReply )
497503
{
498-
data = mReply->readAll();
504+
// Limit the number of bytes to process at once, to avoid the GML parser to
505+
// create too many objects.
506+
data = mReply->read( 10 * 1024 * 1024 );
507+
bytesStillAvailableInReply = mReply->bytesAvailable() > 0;
499508
}
500509
else
501510
{

src/providers/wfs/qgswfsrequest.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
#include <QNetworkCacheMetaData>
2626
#include <QCryptographicHash> // just for testin file:// fake_qgis_http_endpoint hack
2727

28+
const qint64 READ_BUFFER_SIZE_HINT = 1024 * 1024;
29+
2830
QgsWfsRequest::QgsWfsRequest( const QgsWFSDataSourceURI &uri )
2931
: mUri( uri )
3032
, mErrorCode( QgsWfsRequest::NoError )
@@ -125,6 +127,7 @@ bool QgsWfsRequest::sendGET( const QUrl &url, bool synchronous, bool forceRefres
125127
}
126128

127129
mReply = QgsNetworkAccessManager::instance()->get( request );
130+
mReply->setReadBufferSize( READ_BUFFER_SIZE_HINT );
128131
if ( !mUri.auth().setAuthorizationReply( mReply ) )
129132
{
130133
mErrorCode = QgsWfsRequest::NetworkError;
@@ -176,6 +179,7 @@ bool QgsWfsRequest::sendPOST( const QUrl &url, const QString &contentTypeHeader,
176179
request.setHeader( QNetworkRequest::ContentTypeHeader, contentTypeHeader );
177180

178181
mReply = QgsNetworkAccessManager::instance()->post( request, data );
182+
mReply->setReadBufferSize( READ_BUFFER_SIZE_HINT );
179183
if ( !mUri.auth().setAuthorizationReply( mReply ) )
180184
{
181185
mErrorCode = QgsWfsRequest::NetworkError;
@@ -266,6 +270,7 @@ void QgsWfsRequest::replyFinished()
266270

267271
QgsDebugMsg( QString( "redirected: %1 forceRefresh=%2" ).arg( redirect.toString() ).arg( mForceRefresh ) );
268272
mReply = QgsNetworkAccessManager::instance()->get( request );
273+
mReply->setReadBufferSize( READ_BUFFER_SIZE_HINT );
269274
if ( !mUri.auth().setAuthorizationReply( mReply ) )
270275
{
271276
mResponse.clear();

0 commit comments

Comments
 (0)