@@ -22,10 +22,7 @@ use crate::{
22
22
conn:: { pool:: futures:: * , Conn } ,
23
23
error:: * ,
24
24
opts:: { Opts , PoolOptions } ,
25
- queryable:: {
26
- transaction:: { Transaction , TransactionOptions } ,
27
- Queryable ,
28
- } ,
25
+ queryable:: transaction:: TxStatus ,
29
26
} ;
30
27
31
28
mod recycler;
@@ -97,7 +94,7 @@ pub struct Inner {
97
94
#[ derive( Clone ) ]
98
95
/// Asynchronous pool of MySql connections.
99
96
///
100
- /// Note that you will probably want to await `Pool::disconnect` before dropping the runtime, as
97
+ /// Note that you will probably want to await [ `Pool::disconnect`] before dropping the runtime, as
101
98
/// otherwise you may end up with a number of connections that are not cleanly terminated.
102
99
pub struct Pool {
103
100
opts : Opts ,
@@ -112,7 +109,7 @@ impl fmt::Debug for Pool {
112
109
}
113
110
114
111
impl Pool {
115
- /// Creates new pool of connections.
112
+ /// Creates a new pool of connections.
116
113
pub fn new < O : Into < Opts > > ( opts : O ) -> Pool {
117
114
let opts = opts. into ( ) ;
118
115
let pool_options = opts. get_pool_options ( ) . clone ( ) ;
@@ -133,29 +130,21 @@ impl Pool {
133
130
}
134
131
}
135
132
136
- /// Creates new pool of connections.
133
+ /// Creates a new pool of connections.
137
134
pub fn from_url < T : AsRef < str > > ( url : T ) -> Result < Pool > {
138
135
let opts = Opts :: from_str ( url. as_ref ( ) ) ?;
139
136
Ok ( Pool :: new ( opts) )
140
137
}
141
138
142
- /// Returns future that resolves to `Conn`.
139
+ /// Returns a future that resolves to [ `Conn`] .
143
140
pub fn get_conn ( & self ) -> GetConn {
144
141
new_get_conn ( self )
145
142
}
146
143
147
- /// Shortcut for `get_conn` followed by `start_transaction`.
148
- pub async fn start_transaction (
149
- & self ,
150
- options : TransactionOptions ,
151
- ) -> Result < Transaction < Conn > > {
152
- Queryable :: start_transaction ( self . get_conn ( ) . await ?, options) . await
153
- }
154
-
155
- /// Returns future that disconnects this pool from server and resolves to `()`.
144
+ /// Returns a future that disconnects this pool from the server and resolves to `()`.
156
145
///
157
- /// Active connections taken from this pool should be disconnected manually.
158
- /// Also all pending and new `GetConn`'s will resolve to error.
146
+ /// **Note:** This Future won't resolve until all active connections, taken from it,
147
+ /// are dropped or disonnected. Also all pending and new `GetConn`'s will resolve to error.
159
148
pub fn disconnect ( self ) -> DisconnectPool {
160
149
let was_closed = self . inner . close . swap ( true , atomic:: Ordering :: AcqRel ) ;
161
150
if !was_closed {
@@ -166,7 +155,7 @@ impl Pool {
166
155
let _ = self . drop . send ( None ) . is_ok ( ) ;
167
156
}
168
157
169
- new_disconnect_pool ( self )
158
+ DisconnectPool :: new ( self )
170
159
}
171
160
172
161
/// A way to return connection taken from a pool.
@@ -178,7 +167,7 @@ impl Pool {
178
167
if conn. inner . stream . is_some ( )
179
168
&& !conn. inner . disconnected
180
169
&& !conn. expired ( )
181
- && ! conn. inner . in_transaction
170
+ && conn. inner . tx_status == TxStatus :: None
182
171
&& conn. inner . has_result . is_none ( )
183
172
&& !self . inner . close . load ( atomic:: Ordering :: Acquire )
184
173
{
@@ -277,6 +266,10 @@ impl Pool {
277
266
278
267
impl Drop for Conn {
279
268
fn drop ( & mut self ) {
269
+ if std:: thread:: panicking ( ) {
270
+ return ;
271
+ }
272
+
280
273
if let Some ( mut pool) = self . inner . pool . take ( ) {
281
274
pool. return_conn ( self . take ( ) ) ;
282
275
} else if self . inner . stream . is_some ( ) && !self . inner . disconnected {
@@ -377,31 +370,31 @@ mod test {
377
370
. await ?
378
371
. drop_query ( "CREATE TABLE IF NOT EXISTS tmp(id int)" )
379
372
. await ?;
380
- let _ = pool
373
+ let mut conn = pool. get_conn ( ) . await ?;
374
+ let mut tx = conn
381
375
. start_transaction ( TransactionOptions :: default ( ) )
382
- . await ?
383
- . batch_exec ( "INSERT INTO tmp (id) VALUES (?)" , vec ! [ ( 1 , ) , ( 2 , ) ] )
384
- . await ?
385
- . prep_exec ( "SELECT * FROM tmp" , ( ) )
386
376
. await ?;
377
+ tx. batch_exec ( "INSERT INTO tmp (id) VALUES (?)" , vec ! [ ( 1_u8 , ) , ( 2_u8 , ) ] )
378
+ . await ?;
379
+ tx. prep_exec ( "SELECT * FROM tmp" , ( ) ) . await ?;
380
+ drop ( tx) ;
381
+ drop ( conn) ;
387
382
let row_opt = pool
388
383
. get_conn ( )
389
384
. await ?
390
385
. first ( "SELECT COUNT(*) FROM tmp" )
391
- . await ?
392
- . 1 ;
386
+ . await ?;
393
387
assert_eq ! ( row_opt, Some ( ( 0u8 , ) ) ) ;
394
388
pool. get_conn ( ) . await ?. drop_query ( "DROP TABLE tmp" ) . await ?;
395
389
pool. disconnect ( ) . await ?;
396
390
Ok ( ( ) )
397
391
}
398
392
399
393
#[ tokio:: test]
400
- async fn aa_should_hold_bounds2 ( ) -> super :: Result < ( ) > {
401
- use std:: cmp:: min;
402
-
394
+ async fn should_check_inactive_connection_ttl ( ) -> super :: Result < ( ) > {
403
395
const POOL_MIN : usize = 5 ;
404
396
const POOL_MAX : usize = 10 ;
397
+
405
398
const INACTIVE_CONNECTION_TTL : Duration = Duration :: from_millis ( 500 ) ;
406
399
const TTL_CHECK_INTERVAL : Duration = Duration :: from_secs ( 1 ) ;
407
400
@@ -417,6 +410,44 @@ mod test {
417
410
let pool_clone = pool. clone ( ) ;
418
411
let conns = ( 0 ..POOL_MAX ) . map ( |_| pool. get_conn ( ) ) . collect :: < Vec < _ > > ( ) ;
419
412
413
+ let conns = try_join_all ( conns) . await ?;
414
+
415
+ assert_eq ! ( ex_field!( pool_clone, exist) , POOL_MAX ) ;
416
+ drop ( conns) ;
417
+
418
+ // wait for a bit to let the connections be reclaimed
419
+ tokio:: time:: delay_for ( std:: time:: Duration :: from_millis ( 100 ) ) . await ;
420
+
421
+ // check that connections are still in the pool because of inactive_connection_ttl
422
+ assert_eq ! ( ex_field!( pool_clone, available) . len( ) , POOL_MAX ) ;
423
+
424
+ // then, wait for ttl_check_interval
425
+ tokio:: time:: delay_for ( TTL_CHECK_INTERVAL ) . await ;
426
+
427
+ // check that we have the expected number of connections
428
+ assert_eq ! ( ex_field!( pool_clone, available) . len( ) , POOL_MIN ) ;
429
+
430
+ Ok ( ( ) )
431
+ }
432
+
433
+ #[ tokio:: test]
434
+ async fn aa_should_hold_bounds2 ( ) -> super :: Result < ( ) > {
435
+ use std:: cmp:: min;
436
+
437
+ const POOL_MIN : usize = 5 ;
438
+ const POOL_MAX : usize = 10 ;
439
+
440
+ let constraints = PoolConstraints :: new ( POOL_MIN , POOL_MAX ) . unwrap ( ) ;
441
+ let pool_options = PoolOptions :: with_constraints ( constraints) ;
442
+
443
+ // Clean
444
+ let mut opts = get_opts ( ) ;
445
+ opts. pool_options ( pool_options) ;
446
+
447
+ let pool = Pool :: new ( opts) ;
448
+ let pool_clone = pool. clone ( ) ;
449
+ let conns = ( 0 ..POOL_MAX ) . map ( |_| pool. get_conn ( ) ) . collect :: < Vec < _ > > ( ) ;
450
+
420
451
let mut conns = try_join_all ( conns) . await ?;
421
452
422
453
// we want to continuously drop connections
@@ -444,15 +475,6 @@ mod test {
444
475
let idle = min ( dropped, POOL_MIN ) ;
445
476
let expected = conns. len ( ) + idle;
446
477
447
- if dropped > POOL_MIN {
448
- // check that connection is still in the pool because of inactive_connection_ttl
449
- let have = ex_field ! ( pool_clone, exist) ;
450
- assert_eq ! ( have, expected + 1 ) ;
451
-
452
- // then, wait for ttl_check_interval
453
- tokio:: time:: delay_for ( TTL_CHECK_INTERVAL + Duration :: from_millis ( 50 ) ) . await ;
454
- }
455
-
456
478
// check that we have the expected number of connections
457
479
let have = ex_field ! ( pool_clone, exist) ;
458
480
assert_eq ! ( have, expected) ;
@@ -507,61 +529,34 @@ mod test {
507
529
async fn zz_should_check_wait_timeout_on_get_conn ( ) -> super :: Result < ( ) > {
508
530
let pool = Pool :: new ( get_opts ( ) ) ;
509
531
510
- let conn = pool. get_conn ( ) . await ?;
511
- let ( conn, wait_timeout_orig) = conn. first :: < _ , usize > ( "SELECT @@wait_timeout" ) . await ?;
512
- conn. drop_query ( "SET GLOBAL wait_timeout = 3" )
513
- . await ?
514
- . disconnect ( )
515
- . await ?;
532
+ let mut conn = pool. get_conn ( ) . await ?;
533
+ let wait_timeout_orig = conn. first :: < _ , usize > ( "SELECT @@wait_timeout" ) . await ?;
534
+ conn. drop_query ( "SET GLOBAL wait_timeout = 3" ) . await ?;
535
+ conn. disconnect ( ) . await ?;
516
536
517
- let conn = pool. get_conn ( ) . await ?;
518
- let ( conn, wait_timeout) = conn. first :: < _ , usize > ( "SELECT @@wait_timeout" ) . await ?;
519
- let ( _, id1) = conn. first :: < _ , usize > ( "SELECT CONNECTION_ID()" ) . await ?;
537
+ let mut conn = pool. get_conn ( ) . await ?;
538
+ let wait_timeout = conn. first :: < _ , usize > ( "SELECT @@wait_timeout" ) . await ?;
539
+ let id1 = conn. first :: < _ , usize > ( "SELECT CONNECTION_ID()" ) . await ?;
540
+ drop ( conn) ;
520
541
521
542
assert_eq ! ( wait_timeout, Some ( 3 ) ) ;
522
543
assert_eq ! ( ex_field!( pool, exist) , 1 ) ;
523
544
524
545
tokio:: time:: delay_for ( std:: time:: Duration :: from_secs ( 6 ) ) . await ;
525
546
526
- let conn = pool. get_conn ( ) . await ?;
527
- let ( conn , id2) = conn. first :: < _ , usize > ( "SELECT CONNECTION_ID()" ) . await ?;
547
+ let mut conn = pool. get_conn ( ) . await ?;
548
+ let id2 = conn. first :: < _ , usize > ( "SELECT CONNECTION_ID()" ) . await ?;
528
549
assert_eq ! ( ex_field!( pool, exist) , 1 ) ;
529
550
assert_ne ! ( id1, id2) ;
530
551
531
552
conn. drop_exec ( "SET GLOBAL wait_timeout = ?" , ( wait_timeout_orig, ) )
532
553
. await ?;
554
+ drop ( conn) ;
533
555
534
- pool. disconnect ( ) . await
535
- }
536
-
537
- /*
538
- #[test]
539
- fn should_hold_bounds_on_get_conn_drop() {
540
- let pool = Pool::new(format!("{}?pool_min=1&pool_max=2", get_opts()));
541
- let mut runtime = tokio::runtime::Runtime::new().unwrap();
556
+ pool. disconnect ( ) . await ?;
542
557
543
- // This test is a bit more intricate: we need to poll the connection future once to get the
544
- // pool to set it up, then drop it and make sure that the `exist` count is updated.
545
- //
546
- // We wrap all of it in a lazy future to get us into the tokio context that deals with
547
- // setting up tasks. There might be a better way to do this but I don't remember right
548
- // now. Besides, std::future is just around the corner making this obsolete.
549
- //
550
- // It depends on implementation details of GetConn, but that should be fine.
551
- runtime
552
- .block_on(future::lazy(move || {
553
- let mut conn = pool.get_conn();
554
- assert_eq!(pool.inner.exist.load(atomic::Ordering::SeqCst), 0);
555
- let result = conn.poll().expect("successful first poll");
556
- assert!(result.is_not_ready(), "not ready after first poll");
557
- assert_eq!(pool.inner.exist.load(atomic::Ordering::SeqCst), 1);
558
- drop(conn);
559
- assert_eq!(pool.inner.exist.load(atomic::Ordering::SeqCst), 0);
560
- Ok::<(), ()>(())
561
- }))
562
- .unwrap();
558
+ Ok ( ( ) )
563
559
}
564
- */
565
560
566
561
#[ tokio:: test]
567
562
async fn droptest ( ) -> super :: Result < ( ) > {
@@ -607,7 +602,7 @@ mod test {
607
602
let ( tx, rx) = tokio:: sync:: oneshot:: channel ( ) ;
608
603
rt. block_on ( async move {
609
604
let pool = Pool :: new ( get_opts ( ) ) ;
610
- let c = pool. get_conn ( ) . await . unwrap ( ) ;
605
+ let mut c = pool. get_conn ( ) . await . unwrap ( ) ;
611
606
tokio:: spawn ( async move {
612
607
let _ = rx. await ;
613
608
let _ = c. drop_query ( "SELECT 1" ) . await ;
@@ -627,7 +622,7 @@ mod test {
627
622
let ( tx, rx) = tokio:: sync:: oneshot:: channel ( ) ;
628
623
let jh = rt. spawn ( async move {
629
624
let pool = Pool :: new ( get_opts ( ) ) ;
630
- let c = pool. get_conn ( ) . await . unwrap ( ) ;
625
+ let mut c = pool. get_conn ( ) . await . unwrap ( ) ;
631
626
tokio:: spawn ( async move {
632
627
let _ = rx. await ;
633
628
let _ = c. drop_query ( "SELECT 1" ) . await ;
@@ -639,26 +634,6 @@ mod test {
639
634
}
640
635
}
641
636
642
- /*
643
- #[test]
644
- #[ignore]
645
- fn should_not_panic_if_dropped_without_tokio_runtime() {
646
- // NOTE: this test does not work anymore, since the runtime won't be idle until either
647
- //
648
- // - all Pools and Conns are dropped; OR
649
- // - Pool::disconnect is called; OR
650
- // - Runtime::shutdown_now is called
651
- //
652
- // none of these are true in this test, which is why it's been ignored
653
- let pool = Pool::new(get_opts());
654
- run(collect(
655
- (0..10).map(|_| pool.get_conn()).collect::<Vec<_>>(),
656
- ))
657
- .unwrap();
658
- // pool will drop here
659
- }
660
- */
661
-
662
637
#[ cfg( feature = "nightly" ) ]
663
638
mod bench {
664
639
use futures_util:: { future:: FutureExt , try_future:: TryFutureExt } ;
0 commit comments