create postgres RO connection in the thread where the provider live

This commit is contained in:
vcloarec 2023-07-13 10:20:52 +02:00 committed by Vincent Cloarec
parent 9719883721
commit c3611c60a1
5 changed files with 18 additions and 3 deletions

View File

@ -79,6 +79,7 @@ Abstract base class for spatial data provider implementations.
SkipFullScan,
ForceReadOnly,
SkipCredentialsRequest,
ParallelThreadLoading,
};
typedef QFlags<QgsDataProvider::ReadFlag> ReadFlags;

View File

@ -1368,6 +1368,7 @@ void QgsProject::preloadProviders( const QVector<QDomNode> &parallelLayerNodes,
// Requesting credential from worker thread could lead to deadlocks because the main thread is waiting for worker thread to fininsh
layerToLoad.flags.setFlag( QgsDataProvider::SkipCredentialsRequest, true );
layerToLoad.flags.setFlag( QgsDataProvider::ParallelThreadLoading, true );
layersToLoad.insert( layerToLoad.layerId, layerToLoad );
}
@ -1426,6 +1427,7 @@ void QgsProject::preloadProviders( const QVector<QDomNode> &parallelLayerNodes,
const LayerToLoad &lay = it.value();
QgsDataProvider::ReadFlags providerFlags = lay.flags;
providerFlags.setFlag( QgsDataProvider::SkipCredentialsRequest, false );
providerFlags.setFlag( QgsDataProvider::ParallelThreadLoading, false );
QgsScopedRuntimeProfile profile( "Create data providers/" + lay.layerId, QStringLiteral( "projectload" ) );
std::unique_ptr<QgsDataProvider> provider( QgsProviderRegistry::instance()->createProvider( lay.provider, lay.dataSource, lay.options, providerFlags ) );
i++;

View File

@ -128,6 +128,7 @@ class CORE_EXPORT QgsDataProvider : public QObject
SkipFullScan = 1 << 4, //!< Skip expensive full scan on files (i.e. on delimited text) (since QGIS 3.24)
ForceReadOnly = 1 << 5, //!< Open layer in a read-only mode (since QGIS 3.28)
SkipCredentialsRequest = 1 << 6, //! Skip credentials if the provided one are not valid, let the provider be invalid, avoiding to block the thread creating the provider if it is not the main thread (since QGIS 3.32).
ParallelThreadLoading = 1 << 7, //! Provider is created in a parallel thread than the one where it will live (since QGIS 3.32.1).
};
Q_DECLARE_FLAGS( ReadFlags, ReadFlag )

View File

@ -303,6 +303,11 @@ QgsPostgresProvider::QgsPostgresProvider( QString const &uri, const ProviderOpti
mLayerMetadata.setType( QStringLiteral( "dataset" ) );
mLayerMetadata.setCrs( crs() );
// Constructor is called in another thread than the thread where the provider will live,
// so we disconnect the DB, connection will be done later in the provider thread when needed
if ( flags.testFlag( QgsDataProvider::ParallelThreadLoading ) )
disconnectDb();
}
QgsPostgresProvider::~QgsPostgresProvider()
@ -320,7 +325,13 @@ QgsAbstractFeatureSource *QgsPostgresProvider::featureSource() const
QgsPostgresConn *QgsPostgresProvider::connectionRO() const
{
return mTransaction ? mTransaction->connection() : mConnectionRO;
if ( mTransaction )
return mTransaction->connection();
if ( !mConnectionRO )
mConnectionRO = QgsPostgresConn::connectDb( mUri, true, true, false, !mReadFlags.testFlag( QgsDataProvider::SkipCredentialsRequest ) );
return mConnectionRO;
}
void QgsPostgresProvider::setListening( bool isListening )
@ -3887,7 +3898,7 @@ QgsRectangle QgsPostgresProvider::extent() const
quotedValue( mSchemaName ),
quotedValue( mTableName ),
quotedValue( mGeometryColumn ) );
result = mConnectionRO->LoggedPQexec( "QgsPostgresProvider", sql );
result = connectionRO()->LoggedPQexec( "QgsPostgresProvider", sql );
if ( result.PQresultStatus() == PGRES_TUPLES_OK && result.PQntuples() == 1 && !result.PQgetisnull( 0, 0 ) )
{
ext = result.PQgetvalue( 0, 0 );

View File

@ -450,7 +450,7 @@ class QgsPostgresProvider final: public QgsVectorDataProvider
QString paramValue( const QString &fieldvalue, const QString &defaultValue ) const;
QgsPostgresConn *mConnectionRO = nullptr ; //!< Read-only database connection (initially)
mutable QgsPostgresConn *mConnectionRO = nullptr ; //!< Read-only database connection (initially)
QgsPostgresConn *mConnectionRW = nullptr ; //!< Read-write database connection (on update)
QgsPostgresConn *connectionRO() const;