@@ -93,12 +93,13 @@ class QgsConnectionPoolGroup
93
93
*
94
94
* \returns initialized connection or nullptr if unsuccessful
95
95
*/
96
- T acquire ( int timeout, int freeConnectionRequirement )
96
+ T acquire ( int timeout, bool requestMayBeNested )
97
97
{
98
+ const int requiredFreeConnectionCount = requestMayBeNested ? 1 : 3 ;
98
99
// we are going to acquire a resource - if no resource is available, we will block here
99
100
if ( timeout >= 0 )
100
101
{
101
- if ( !sem.tryAcquire ( freeConnectionRequirement , timeout ) )
102
+ if ( !sem.tryAcquire ( requiredFreeConnectionCount , timeout ) )
102
103
return nullptr ;
103
104
}
104
105
else
@@ -107,9 +108,9 @@ class QgsConnectionPoolGroup
107
108
// tryAcquire is broken on Qt > 5.8 with negative timeouts - see
108
109
// https://bugreports.qt.io/browse/QTBUG-64413
109
110
// https://lists.osgeo.org/pipermail/qgis-developer/2017-November/050456.html
110
- sem.acquire ( freeConnectionRequirement );
111
+ sem.acquire ( requiredFreeConnectionCount );
111
112
}
112
- sem.release ( freeConnectionRequirement - 1 );
113
+ sem.release ( requiredFreeConnectionCount - 1 );
113
114
114
115
// quick (preferred) way - use cached connection
115
116
{
@@ -122,218 +123,218 @@ class QgsConnectionPoolGroup
122
123
{
123
124
qgsConnectionPool_ConnectionDestroy ( i.c );
124
125
qgsConnectionPool_ConnectionCreate ( connInfo, i.c );
125
- }
126
126
127
- // no need to run if nothing can expire
128
- if ( conns.isEmpty () )
129
- {
130
- // will call the slot directly or queue the call (if the object lives in a different thread)
131
- QMetaObject::invokeMethod ( expirationTimer->parent (), " stopExpirationTimer" );
132
- }
133
127
134
- acquiredConns.append ( i.c );
128
+ // no need to run if nothing can expire
129
+ if ( conns.isEmpty () )
130
+ {
131
+ // will call the slot directly or queue the call (if the object lives in a different thread)
132
+ QMetaObject::invokeMethod ( expirationTimer->parent (), " stopExpirationTimer" );
133
+ }
135
134
136
- return i.c ;
137
- }
138
- }
135
+ acquiredConns.append ( i.c );
139
136
140
- T c;
141
- qgsConnectionPool_ConnectionCreate ( connInfo, c );
142
- if ( !c )
143
- {
144
- // we didn't get connection for some reason, so release the lock
145
- sem.release ();
146
- return nullptr ;
147
- }
137
+ return i.c ;
138
+ }
139
+ }
148
140
149
- connMutex.lock ();
150
- acquiredConns.append ( c );
151
- connMutex.unlock ();
152
- return c;
153
- }
141
+ T c;
142
+ qgsConnectionPool_ConnectionCreate ( connInfo, c );
143
+ if ( !c )
144
+ {
145
+ // we didn't get connection for some reason, so release the lock
146
+ sem.release ();
147
+ return nullptr ;
148
+ }
154
149
155
- void release ( T conn )
156
- {
157
- connMutex.lock ();
158
- acquiredConns.removeAll ( conn );
159
- if ( !qgsConnectionPool_ConnectionIsValid ( conn ) )
160
- {
161
- qgsConnectionPool_ConnectionDestroy ( conn );
150
+ connMutex.lock ();
151
+ acquiredConns.append ( c );
152
+ connMutex.unlock ();
153
+ return c;
162
154
}
163
- else
164
- {
165
- Item i;
166
- i.c = conn;
167
- i.lastUsedTime = QTime::currentTime ();
168
- conns.push ( i );
169
155
170
- if ( !expirationTimer->isActive () )
156
+ void release ( T conn )
157
+ {
158
+ connMutex.lock ();
159
+ acquiredConns.removeAll ( conn );
160
+ if ( !qgsConnectionPool_ConnectionIsValid ( conn ) )
171
161
{
172
- // will call the slot directly or queue the call (if the object lives in a different thread)
173
- QMetaObject::invokeMethod ( expirationTimer->parent (), " startExpirationTimer" );
162
+ qgsConnectionPool_ConnectionDestroy ( conn );
163
+ }
164
+ else
165
+ {
166
+ Item i;
167
+ i.c = conn;
168
+ i.lastUsedTime = QTime::currentTime ();
169
+ conns.push ( i );
170
+
171
+ if ( !expirationTimer->isActive () )
172
+ {
173
+ // will call the slot directly or queue the call (if the object lives in a different thread)
174
+ QMetaObject::invokeMethod ( expirationTimer->parent (), " startExpirationTimer" );
175
+ }
174
176
}
175
- }
176
177
177
- connMutex.unlock ();
178
+ connMutex.unlock ();
178
179
179
- sem.release (); // this can unlock a thread waiting in acquire()
180
- }
180
+ sem.release (); // this can unlock a thread waiting in acquire()
181
+ }
181
182
182
- void invalidateConnections ()
183
- {
184
- connMutex.lock ();
185
- for ( const Item &i : qgis::as_const ( conns ) )
183
+ void invalidateConnections ()
186
184
{
187
- qgsConnectionPool_ConnectionDestroy ( i.c );
185
+ connMutex.lock ();
186
+ for ( const Item &i : qgis::as_const ( conns ) )
187
+ {
188
+ qgsConnectionPool_ConnectionDestroy ( i.c );
189
+ }
190
+ conns.clear ();
191
+ for ( T c : qgis::as_const ( acquiredConns ) )
192
+ qgsConnectionPool_InvalidateConnection ( c );
193
+ connMutex.unlock ();
188
194
}
189
- conns.clear ();
190
- for ( T c : qgis::as_const ( acquiredConns ) )
191
- qgsConnectionPool_InvalidateConnection ( c );
192
- connMutex.unlock ();
193
- }
194
-
195
- protected:
196
195
197
- void initTimer ( QObject *parent )
198
- {
199
- expirationTimer = new QTimer ( parent );
200
- expirationTimer->setInterval ( CONN_POOL_EXPIRATION_TIME * 1000 );
201
- QObject::connect ( expirationTimer, SIGNAL ( timeout () ), parent, SLOT ( handleConnectionExpired () ) );
196
+ protected:
202
197
203
- // just to make sure the object belongs to main thread and thus will get events
204
- if ( qApp )
205
- parent->moveToThread ( qApp->thread () );
206
- }
207
-
208
- void onConnectionExpired ()
209
- {
210
- connMutex.lock ();
211
-
212
- QTime now = QTime::currentTime ();
213
-
214
- // what connections have expired?
215
- QList<int > toDelete;
216
- for ( int i = 0 ; i < conns.count (); ++i )
198
+ void initTimer ( QObject * parent )
217
199
{
218
- if ( conns.at ( i ).lastUsedTime .secsTo ( now ) >= CONN_POOL_EXPIRATION_TIME )
219
- toDelete.append ( i );
200
+ expirationTimer = new QTimer ( parent );
201
+ expirationTimer->setInterval ( CONN_POOL_EXPIRATION_TIME * 1000 );
202
+ QObject::connect ( expirationTimer, SIGNAL ( timeout () ), parent, SLOT ( handleConnectionExpired () ) );
203
+
204
+ // just to make sure the object belongs to main thread and thus will get events
205
+ if ( qApp )
206
+ parent->moveToThread ( qApp->thread () );
220
207
}
221
208
222
- // delete expired connections
223
- for ( int j = toDelete.count () - 1 ; j >= 0 ; --j )
209
+ void onConnectionExpired ()
224
210
{
225
- int index = toDelete[j];
226
- qgsConnectionPool_ConnectionDestroy ( conns[index].c );
227
- conns.remove ( index );
228
- }
211
+ connMutex.lock ();
229
212
230
- if ( conns.isEmpty () )
231
- expirationTimer->stop ();
213
+ QTime now = QTime::currentTime ();
232
214
233
- connMutex.unlock ();
234
- }
215
+ // what connections have expired?
216
+ QList<int > toDelete;
217
+ for ( int i = 0 ; i < conns.count (); ++i )
218
+ {
219
+ if ( conns.at ( i ).lastUsedTime .secsTo ( now ) >= CONN_POOL_EXPIRATION_TIME )
220
+ toDelete.append ( i );
221
+ }
235
222
236
- protected:
223
+ // delete expired connections
224
+ for ( int j = toDelete.count () - 1 ; j >= 0 ; --j )
225
+ {
226
+ int index = toDelete[j];
227
+ qgsConnectionPool_ConnectionDestroy ( conns[index].c );
228
+ conns.remove ( index );
229
+ }
237
230
238
- QString connInfo;
239
- QStack<Item> conns;
240
- QList<T> acquiredConns;
241
- QMutex connMutex;
242
- QSemaphore sem;
243
- QTimer *expirationTimer = nullptr ;
231
+ if ( conns.isEmpty () )
232
+ expirationTimer->stop ();
244
233
245
- };
234
+ connMutex.unlock ();
235
+ }
246
236
237
+ protected:
247
238
248
- /* *
249
- * \ingroup core
250
- * Template class responsible for keeping a pool of open connections.
251
- * This is desired to avoid the overhead of creation of new connection every time.
252
- *
253
- * The methods are thread safe.
254
- *
255
- * The connection pool has a limit on maximum number of concurrent connections
256
- * (per server), once the limit is reached, the acquireConnection() function
257
- * will block. All connections that have been acquired must be then released
258
- * with releaseConnection() function.
259
- *
260
- * When the connections are not used for some time, they will get closed automatically
261
- * to save resources.
262
- * \note not available in Python bindings
263
- */
264
- template <typename T, typename T_Group>
265
- class QgsConnectionPool
266
- {
267
- public:
239
+ QString connInfo;
240
+ QStack<Item> conns;
241
+ QList<T> acquiredConns;
242
+ QMutex connMutex;
243
+ QSemaphore sem;
244
+ QTimer *expirationTimer = nullptr ;
268
245
269
- typedef QMap<QString, T_Group *> T_Groups ;
246
+ } ;
270
247
271
- virtual ~QgsConnectionPool ()
272
- {
273
- mMutex .lock ();
274
- for ( T_Group *group : qgis::as_const ( mGroups ) )
275
- {
276
- delete group;
277
- }
278
- mGroups .clear ();
279
- mMutex .unlock ();
280
- }
281
248
282
249
/* *
283
- * Try to acquire a connection for a maximum of \a timeout milliseconds.
284
- * If \a timeout is a negative value the calling thread will be blocked
285
- * until a connection becomes available. This is the default behavior .
250
+ * \ingroup core
251
+ * Template class responsible for keeping a pool of open connections.
252
+ * This is desired to avoid the overhead of creation of new connection every time .
286
253
*
254
+ * The methods are thread safe.
287
255
*
256
+ * The connection pool has a limit on maximum number of concurrent connections
257
+ * (per server), once the limit is reached, the acquireConnection() function
258
+ * will block. All connections that have been acquired must be then released
259
+ * with releaseConnection() function.
288
260
*
289
- * \returns initialized connection or nullptr if unsuccessful
261
+ * When the connections are not used for some time, they will get closed automatically
262
+ * to save resources.
263
+ * \note not available in Python bindings
290
264
*/
291
- T acquireConnection ( const QString &connInfo, int timeout = -1 , int freeConnectionRequirement = 3 )
265
+ template <typename T, typename T_Group>
266
+ class QgsConnectionPool
292
267
{
293
- mMutex .lock ();
294
- typename T_Groups::iterator it = mGroups .find ( connInfo );
295
- if ( it == mGroups .end () )
296
- {
297
- it = mGroups .insert ( connInfo, new T_Group ( connInfo ) );
298
- }
299
- T_Group *group = *it;
300
- mMutex .unlock ();
268
+ public:
301
269
302
- return group->acquire ( timeout, freeConnectionRequirement );
303
- }
270
+ typedef QMap<QString, T_Group *> T_Groups;
304
271
305
- // ! Release an existing connection so it will get back into the pool and can be reused
306
- void releaseConnection ( T conn )
307
- {
308
- mMutex .lock ();
309
- typename T_Groups::iterator it = mGroups .find ( qgsConnectionPool_ConnectionToName ( conn ) );
310
- Q_ASSERT ( it != mGroups .end () );
311
- T_Group *group = *it;
312
- mMutex .unlock ();
272
+ virtual ~QgsConnectionPool ()
273
+ {
274
+ mMutex .lock ();
275
+ for ( T_Group *group : qgis::as_const ( mGroups ) )
276
+ {
277
+ delete group;
278
+ }
279
+ mGroups .clear ();
280
+ mMutex .unlock ();
281
+ }
313
282
314
- group->release ( conn );
315
- }
283
+ /* *
284
+ * Try to acquire a connection for a maximum of \a timeout milliseconds.
285
+ * If \a timeout is a negative value the calling thread will be blocked
286
+ * until a connection becomes available. This is the default behavior.
287
+ *
288
+ *
289
+ *
290
+ * \returns initialized connection or nullptr if unsuccessful
291
+ */
292
+ T acquireConnection ( const QString &connInfo, int timeout = -1 , bool requestMayBeNested = false )
293
+ {
294
+ mMutex .lock ();
295
+ typename T_Groups::iterator it = mGroups .find ( connInfo );
296
+ if ( it == mGroups .end () )
297
+ {
298
+ it = mGroups .insert ( connInfo, new T_Group ( connInfo ) );
299
+ }
300
+ T_Group *group = *it;
301
+ mMutex .unlock ();
316
302
317
- /* *
318
- * Invalidates all connections to the specified resource.
319
- * The internal state of certain handles (for instance OGR) are altered
320
- * when a dataset is modified. Consquently, all open handles need to be
321
- * invalidated when such datasets are changed to ensure the handles are
322
- * refreshed. See the OGR provider for an example where this is needed.
323
- */
324
- void invalidateConnections ( const QString &connInfo )
325
- {
326
- mMutex .lock ();
327
- if ( mGroups .contains ( connInfo ) )
328
- mGroups [connInfo]->invalidateConnections ();
329
- mMutex .unlock ();
330
- }
303
+ return group->acquire ( timeout, requestMayBeNested );
304
+ }
331
305
306
+ // ! Release an existing connection so it will get back into the pool and can be reused
307
+ void releaseConnection ( T conn )
308
+ {
309
+ mMutex .lock ();
310
+ typename T_Groups::iterator it = mGroups .find ( qgsConnectionPool_ConnectionToName ( conn ) );
311
+ Q_ASSERT ( it != mGroups .end () );
312
+ T_Group *group = *it;
313
+ mMutex .unlock ();
314
+
315
+ group->release ( conn );
316
+ }
332
317
333
- protected:
334
- T_Groups mGroups ;
335
- QMutex mMutex ;
336
- };
318
+ /* *
319
+ * Invalidates all connections to the specified resource.
320
+ * The internal state of certain handles (for instance OGR) are altered
321
+ * when a dataset is modified. Consquently, all open handles need to be
322
+ * invalidated when such datasets are changed to ensure the handles are
323
+ * refreshed. See the OGR provider for an example where this is needed.
324
+ */
325
+ void invalidateConnections ( const QString &connInfo )
326
+ {
327
+ mMutex .lock ();
328
+ if ( mGroups .contains ( connInfo ) )
329
+ mGroups [connInfo]->invalidateConnections ();
330
+ mMutex .unlock ();
331
+ }
332
+
333
+
334
+ protected:
335
+ T_Groups mGroups ;
336
+ QMutex mMutex ;
337
+ };
337
338
338
339
339
340
#endif // QGSCONNECTIONPOOL_H
0 commit comments