Skip to content

Commit 1121565

Browse files
committedMay 22, 2018
[WFS provider] Fix excessive memory consumption on big layers (refs #18740)
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? Backport of 0addae5 c3c5c97 6cf1c50
1 parent e8e15d5 commit 1121565

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
@@ -856,7 +856,7 @@ void QgsGmlStreamingParser::endElement( const XML_Char* el )
856856
const int localNameLen = ( pszSep ) ? ( int )( elLen - nsLen ) - 1 : elLen;
857857
ParseMode theParseMode( mParseModeStack.isEmpty() ? none : mParseModeStack.top() );
858858

859-
mDimension = mDimensionStack.isEmpty() ? 0 : mDimensionStack.top() ;
859+
mDimension = mDimensionStack.isEmpty() ? 0 : mDimensionStack.pop() ;
860860

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

‎src/providers/wfs/qgswfsfeatureiterator.cpp

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,7 @@ void QgsWFSFeatureDownloader::run( bool serializeFeatures, int maxFeatures )
436436
int pagingIter = 1;
437437
QString gmlIdFirstFeatureFirstIter;
438438
bool disablePaging = false;
439+
// Top level loop to do feature paging in WFS 2
439440
while ( true )
440441
{
441442
success = true;
@@ -456,9 +457,14 @@ void QgsWFSFeatureDownloader::run( bool serializeFeatures, int maxFeatures )
456457
false /* cache */ );
457458

458459
int featureCountForThisResponse = 0;
460+
bool bytesStillAvailableInReply = false;
461+
// Loop until there is no data coming from the current request
459462
while ( true )
460463
{
461-
loop.exec( QEventLoop::ExcludeUserInputEvents );
464+
if ( !bytesStillAvailableInReply )
465+
{
466+
loop.exec( QEventLoop::ExcludeUserInputEvents );
467+
}
462468
if ( mStop )
463469
{
464470
interrupted = true;
@@ -475,7 +481,10 @@ void QgsWFSFeatureDownloader::run( bool serializeFeatures, int maxFeatures )
475481
bool finished = false;
476482
if ( mReply )
477483
{
478-
data = mReply->readAll();
484+
// Limit the number of bytes to process at once, to avoid the GML parser to
485+
// create too many objects.
486+
data = mReply->read( 10 * 1024 * 1024 );
487+
bytesStillAvailableInReply = mReply->bytesAvailable() > 0;
479488
}
480489
else
481490
{

‎src/providers/wfs/qgswfsrequest.cpp

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

27+
const qint64 READ_BUFFER_SIZE_HINT = 1024 * 1024;
28+
2729
QgsWFSRequest::QgsWFSRequest( const QString& theUri )
2830
: mUri( theUri )
2931
, mReply( nullptr )
@@ -116,6 +118,7 @@ bool QgsWFSRequest::sendGET( const QUrl& url, bool synchronous, bool forceRefres
116118
}
117119

118120
mReply = QgsNetworkAccessManager::instance()->get( request );
121+
mReply->setReadBufferSize( READ_BUFFER_SIZE_HINT );
119122
if ( !mUri.auth().setAuthorizationReply( mReply ) )
120123
{
121124
mErrorCode = QgsWFSRequest::NetworkError;
@@ -167,6 +170,7 @@ bool QgsWFSRequest::sendPOST( const QUrl& url, const QString& contentTypeHeader,
167170
request.setHeader( QNetworkRequest::ContentTypeHeader, contentTypeHeader );
168171

169172
mReply = QgsNetworkAccessManager::instance()->post( request, data );
173+
mReply->setReadBufferSize( READ_BUFFER_SIZE_HINT );
170174
if ( !mUri.auth().setAuthorizationReply( mReply ) )
171175
{
172176
mErrorCode = QgsWFSRequest::NetworkError;
@@ -257,6 +261,7 @@ void QgsWFSRequest::replyFinished()
257261

258262
QgsDebugMsg( QString( "redirected: %1 forceRefresh=%2" ).arg( redirect.toString() ).arg( mForceRefresh ) );
259263
mReply = QgsNetworkAccessManager::instance()->get( request );
264+
mReply->setReadBufferSize( READ_BUFFER_SIZE_HINT );
260265
if ( !mUri.auth().setAuthorizationReply( mReply ) )
261266
{
262267
mResponse.clear();

0 commit comments

Comments
 (0)
Please sign in to comment.