@@ -7,6 +7,7 @@ use crate::rt::JoinHandle;
7
7
use crate :: Error ;
8
8
use ease_off:: EaseOff ;
9
9
use event_listener:: { Event , EventListener } ;
10
+ use std:: fmt:: { Display , Formatter } ;
10
11
use std:: future:: Future ;
11
12
use std:: pin:: Pin ;
12
13
use std:: ptr;
@@ -246,20 +247,24 @@ impl<DB: Database> PoolConnector<DB> for DefaultConnector<DB> {
246
247
247
248
/// Metadata passed to [`PoolConnector::connect()`] for every connection attempt.
248
249
#[ derive( Debug ) ]
250
+ #[ non_exhaustive]
249
251
pub struct PoolConnectMetadata {
250
252
/// The instant at which the current connection task was started, including all attempts.
251
253
///
252
254
/// May be used for reporting purposes, or to implement a custom backoff.
253
255
pub start : Instant ,
254
256
/// The number of attempts that have occurred so far.
255
257
pub num_attempts : usize ,
258
+ /// The current size of the pool.
256
259
pub pool_size : usize ,
260
+ /// The ID of the connection, unique for the pool.
261
+ pub connection_id : ConnectionId ,
257
262
}
258
263
259
264
pub struct DynConnector < DB : Database > {
260
265
// We want to spawn the connection attempt as a task anyway
261
266
connect : Box <
262
- dyn Fn ( ConnectPermit < DB > , usize ) -> JoinHandle < crate :: Result < PoolConnection < DB > > >
267
+ dyn Fn ( ConnectionId , ConnectPermit < DB > ) -> JoinHandle < crate :: Result < PoolConnection < DB > > >
263
268
+ Send
264
269
+ Sync
265
270
+ ' static ,
@@ -271,53 +276,92 @@ impl<DB: Database> DynConnector<DB> {
271
276
let connector = Arc :: new ( connector) ;
272
277
273
278
Self {
274
- connect : Box :: new ( move |permit , size | {
275
- crate :: rt:: spawn ( connect_with_backoff ( permit, connector. clone ( ) , size ) )
279
+ connect : Box :: new ( move |id , permit | {
280
+ crate :: rt:: spawn ( connect_with_backoff ( id , permit, connector. clone ( ) ) )
276
281
} ) ,
277
282
}
278
283
}
279
284
280
285
pub fn connect (
281
286
& self ,
287
+ id : ConnectionId ,
282
288
permit : ConnectPermit < DB > ,
283
- size : usize ,
284
289
) -> JoinHandle < crate :: Result < PoolConnection < DB > > > {
285
- ( self . connect ) ( permit , size )
290
+ ( self . connect ) ( id , permit )
286
291
}
287
292
}
288
293
289
294
pub struct ConnectionCounter {
290
- connections : AtomicUsize ,
295
+ count : AtomicUsize ,
296
+ next_id : AtomicUsize ,
291
297
connect_available : Event ,
292
298
}
293
299
300
+ /// An opaque connection ID, unique for every connection attempt with the same pool.
301
+ #[ derive( Debug , Copy , Clone , PartialEq , Eq ) ]
302
+ pub struct ConnectionId ( usize ) ;
303
+
294
304
impl ConnectionCounter {
295
305
pub fn new ( ) -> Self {
296
306
Self {
297
- connections : AtomicUsize :: new ( 0 ) ,
307
+ count : AtomicUsize :: new ( 0 ) ,
308
+ next_id : AtomicUsize :: new ( 1 ) ,
298
309
connect_available : Event :: new ( ) ,
299
310
}
300
311
}
301
312
302
313
pub fn connections ( & self ) -> usize {
303
- self . connections . load ( Ordering :: Acquire )
314
+ self . count . load ( Ordering :: Acquire )
304
315
}
305
316
306
317
pub async fn drain ( & self ) {
307
- while self . connections . load ( Ordering :: Acquire ) > 0 {
318
+ while self . count . load ( Ordering :: Acquire ) > 0 {
308
319
self . connect_available . listen ( ) . await ;
309
320
}
310
321
}
311
322
323
+ /// Attempt to acquire a permit from both this instance, and the parent pool, if applicable.
324
+ ///
325
+ /// Returns the permit, and the ID of the new connection.
326
+ pub fn try_acquire_permit < DB : Database > (
327
+ & self ,
328
+ pool : & Arc < PoolInner < DB > > ,
329
+ ) -> Option < ( ConnectionId , ConnectPermit < DB > ) > {
330
+ debug_assert ! ( ptr:: addr_eq( self , & pool. counter) ) ;
331
+
332
+ // Don't skip the queue.
333
+ if pool. options . fair && self . connect_available . total_listeners ( ) > 0 {
334
+ return None ;
335
+ }
336
+
337
+ let prev_size = self
338
+ . count
339
+ . fetch_update ( Ordering :: Release , Ordering :: Acquire , |connections| {
340
+ ( connections < pool. options . max_connections ) . then_some ( connections + 1 )
341
+ } )
342
+ . ok ( ) ?;
343
+
344
+ let size = prev_size + 1 ;
345
+
346
+ tracing:: trace!( target: "sqlx::pool::connect" , size, "increased size" ) ;
347
+
348
+ Some ( (
349
+ ConnectionId ( self . next_id . fetch_add ( 1 , Ordering :: SeqCst ) ) ,
350
+ ConnectPermit {
351
+ pool : Some ( Arc :: clone ( pool) ) ,
352
+ } ,
353
+ ) )
354
+ }
355
+
312
356
/// Attempt to acquire a permit from both this instance, and the parent pool, if applicable.
313
357
///
314
358
/// Returns the permit, and the current size of the pool.
315
359
pub async fn acquire_permit < DB : Database > (
316
360
& self ,
317
361
pool : & Arc < PoolInner < DB > > ,
318
- ) -> ( usize , ConnectPermit < DB > ) {
362
+ ) -> ( ConnectionId , ConnectPermit < DB > ) {
319
363
// Check that `self` can increase size first before we check the parent.
320
- let ( size , permit ) = self . acquire_permit_self ( pool) . await ;
364
+ let acquired = self . acquire_permit_self ( pool) . await ;
321
365
322
366
if let Some ( parent) = & pool. options . parent_pool {
323
367
let ( _, permit) = parent. 0 . counter . acquire_permit_self ( & parent. 0 ) . await ;
@@ -326,46 +370,21 @@ impl ConnectionCounter {
326
370
permit. consume ( ) ;
327
371
}
328
372
329
- ( size , permit )
373
+ acquired
330
374
}
331
375
332
376
// Separate method because `async fn`s cannot be recursive.
333
377
/// Attempt to acquire a [`ConnectPermit`] from this instance and this instance only.
334
378
async fn acquire_permit_self < DB : Database > (
335
379
& self ,
336
380
pool : & Arc < PoolInner < DB > > ,
337
- ) -> ( usize , ConnectPermit < DB > ) {
338
- debug_assert ! ( ptr:: addr_eq( self , & pool. counter) ) ;
339
-
340
- let mut should_wait = pool. options . fair && self . connect_available . total_listeners ( ) > 0 ;
341
-
381
+ ) -> ( ConnectionId , ConnectPermit < DB > ) {
342
382
for attempt in 1usize .. {
343
- if should_wait {
344
- self . connect_available . listen ( ) . await ;
383
+ if let Some ( acquired ) = self . try_acquire_permit ( pool ) {
384
+ return acquired ;
345
385
}
346
386
347
- let res = self . connections . fetch_update (
348
- Ordering :: Release ,
349
- Ordering :: Acquire ,
350
- |connections| {
351
- ( connections < pool. options . max_connections ) . then_some ( connections + 1 )
352
- } ,
353
- ) ;
354
-
355
- if let Ok ( prev_size) = res {
356
- let size = prev_size + 1 ;
357
-
358
- tracing:: trace!( target: "sqlx::pool::connect" , size, "increased size" ) ;
359
-
360
- return (
361
- prev_size + 1 ,
362
- ConnectPermit {
363
- pool : Some ( Arc :: clone ( pool) ) ,
364
- } ,
365
- ) ;
366
- }
367
-
368
- should_wait = true ;
387
+ self . connect_available . listen ( ) . await ;
369
388
370
389
if attempt == 2 {
371
390
tracing:: warn!(
@@ -380,7 +399,7 @@ impl ConnectionCounter {
380
399
pub fn release_permit < DB : Database > ( & self , pool : & PoolInner < DB > ) {
381
400
debug_assert ! ( ptr:: addr_eq( self , & pool. counter) ) ;
382
401
383
- self . connections . fetch_sub ( 1 , Ordering :: Release ) ;
402
+ self . count . fetch_sub ( 1 , Ordering :: Release ) ;
384
403
self . connect_available . notify ( 1usize ) ;
385
404
386
405
if let Some ( parent) = & pool. options . parent_pool {
@@ -415,16 +434,22 @@ impl<DB: Database> Drop for ConnectPermit<DB> {
415
434
}
416
435
}
417
436
437
+ impl Display for ConnectionId {
438
+ fn fmt ( & self , f : & mut Formatter < ' _ > ) -> std:: fmt:: Result {
439
+ Display :: fmt ( & self . 0 , f)
440
+ }
441
+ }
442
+
418
443
#[ tracing:: instrument(
419
444
target = "sqlx::pool::connect" ,
420
- skip_all,
421
- fields( connection = size ) ,
445
+ skip_all,
446
+ fields( %connection_id ) ,
422
447
err
423
448
) ]
424
449
async fn connect_with_backoff < DB : Database > (
450
+ connection_id : ConnectionId ,
425
451
permit : ConnectPermit < DB > ,
426
452
connector : Arc < impl PoolConnector < DB > > ,
427
- size : usize ,
428
453
) -> crate :: Result < PoolConnection < DB > > {
429
454
if permit. pool ( ) . is_closed ( ) {
430
455
return Err ( Error :: PoolClosed ) ;
@@ -436,7 +461,8 @@ async fn connect_with_backoff<DB: Database>(
436
461
let meta = PoolConnectMetadata {
437
462
start : ease_off. started_at ( ) ,
438
463
num_attempts : attempt,
439
- pool_size : size,
464
+ pool_size : permit. pool ( ) . size ( ) ,
465
+ connection_id,
440
466
} ;
441
467
442
468
let conn = ease_off
@@ -445,7 +471,7 @@ async fn connect_with_backoff<DB: Database>(
445
471
. or_retry_if ( |e| can_retry_error ( e. inner ( ) ) ) ?;
446
472
447
473
if let Some ( conn) = conn {
448
- return Ok ( Floating :: new_live ( conn, permit) . reattach ( ) ) ;
474
+ return Ok ( Floating :: new_live ( conn, connection_id , permit) . reattach ( ) ) ;
449
475
}
450
476
}
451
477
0 commit comments