1use futures_util::FutureExt;
10use tokio::sync::mpsc;
11
12use crate::{
13 conn::{pool::futures::*, Conn},
14 error::*,
15 opts::{Opts, PoolOpts},
16 queryable::transaction::{Transaction, TxOpts},
17};
18use std::sync::atomic::Ordering;
19use std::{
20 future::Future,
21 str::FromStr,
22 sync::{atomic, Arc, Mutex},
23 task::{Context, Poll},
24 time::{Duration, Instant},
25};
26
27use in_pool_connections::InPoolConnections;
28pub use metrics::Metrics;
29use waitlist::{QueueId, Waitlist};
30
31mod recycler;
32pub mod futures;
34mod in_pool_connections;
35mod metrics;
36mod ttl_check_inerval;
37mod waitlist;
38
39#[derive(Debug)]
41struct IdlingConn {
42 since: Instant,
44 conn: Conn,
46}
47
48impl IdlingConn {
49 fn expired(&self) -> bool {
51 self.conn
52 .inner
53 .ttl_deadline
54 .map(|t| Instant::now() > t)
55 .unwrap_or_default()
56 }
57
58 fn elapsed(&self) -> Duration {
60 self.since.elapsed()
61 }
62}
63
64impl From<Conn> for IdlingConn {
65 fn from(conn: Conn) -> Self {
66 Self {
67 since: Instant::now(),
68 conn,
69 }
70 }
71}
72
73#[derive(Debug)]
78struct Exchange {
79 waiting: Waitlist,
80 available: in_pool_connections::InPoolConnections,
81 exist: usize,
82 recycler: Option<(mpsc::UnboundedReceiver<Option<Conn>>, PoolOpts)>,
84}
85
86impl Exchange {
87 fn spawn_futures_if_needed(&mut self, inner: &Arc<Inner>) {
90 use recycler::Recycler;
91 use ttl_check_inerval::TtlCheckInterval;
92 if let Some((dropped, pool_opts)) = self.recycler.take() {
93 tokio::spawn(Recycler::new(pool_opts.clone(), inner.clone(), dropped));
95
96 if pool_opts.inactive_connection_ttl() > Duration::ZERO
99 || pool_opts.abs_conn_ttl().is_some()
100 {
101 tokio::spawn(TtlCheckInterval::new(pool_opts, inner.clone()));
102 }
103 }
104 }
105}
106
107#[derive(Debug)]
109pub struct Inner {
110 metrics: Arc<Metrics>,
111 close: atomic::AtomicBool,
112 closed: atomic::AtomicBool,
113 exchange: Mutex<Exchange>,
114}
115
116#[derive(Debug, Clone)]
138pub struct Pool {
139 opts: Opts,
140 inner: Arc<Inner>,
141 drop: mpsc::UnboundedSender<Option<Conn>>,
142}
143
144impl Pool {
145 pub fn new<O>(opts: O) -> Pool
151 where
152 Opts: TryFrom<O>,
153 <Opts as TryFrom<O>>::Error: std::error::Error,
154 {
155 let opts = Opts::try_from(opts).unwrap();
156 let pool_opts = opts.pool_opts().clone();
157 let metrics = Arc::new(Metrics::default());
158 let (tx, rx) = mpsc::unbounded_channel();
159 Pool {
160 opts,
161 inner: Arc::new(Inner {
162 close: false.into(),
163 closed: false.into(),
164 metrics: metrics.clone(),
165 exchange: Mutex::new(Exchange {
166 available: InPoolConnections::new(
167 pool_opts.constraints().max(),
168 metrics.clone(),
169 ),
170 waiting: Waitlist::new(metrics),
171 exist: 0,
172 recycler: Some((rx, pool_opts)),
173 }),
174 }),
175 drop: tx,
176 }
177 }
178
179 pub fn metrics(&self) -> Arc<Metrics> {
181 self.inner.metrics.clone()
182 }
183
184 pub fn from_url<T: AsRef<str>>(url: T) -> Result<Pool> {
186 let opts = Opts::from_str(url.as_ref())?;
187 Ok(Pool::new(opts))
188 }
189
190 pub fn get_conn(&self) -> impl Future<Output = Result<Conn>> {
192 get_conn(self.clone())
193 }
194
195 pub async fn start_transaction(&self, options: TxOpts) -> Result<Transaction<'static>> {
197 let conn = self.get_conn().await?;
198 Transaction::new(conn, options).await
199 }
200
201 pub async fn disconnect(self) -> Result<()> {
206 disconnect_pool(self).await
207 }
208
209 fn return_conn(&mut self, conn: Conn) {
211 self.inner
214 .metrics
215 .connections_in_use
216 .fetch_sub(1, Ordering::Relaxed);
217 self.send_to_recycler(conn);
218 }
219
220 fn send_to_recycler(&self, conn: Conn) {
221 if let Err(conn) = self.drop.send(Some(conn)) {
222 let conn = conn.0.unwrap();
223
224 if !self.inner.closed.load(atomic::Ordering::SeqCst) {
227 assert!(conn.inner.pool.is_none());
230 drop(conn);
231 } else {
232 unreachable!("Recycler exited while connections still exist");
233 }
234 }
235 }
236
237 pub(super) fn cancel_connection(&self) {
242 let mut exchange = self.inner.exchange.lock().unwrap();
243 exchange.exist -= 1;
244 self.inner
245 .metrics
246 .create_failed
247 .fetch_add(1, atomic::Ordering::Relaxed);
248 self.inner
249 .metrics
250 .connection_count
251 .store(exchange.exist, atomic::Ordering::Relaxed);
252 exchange.waiting.wake();
254 }
255
256 fn poll_new_conn(
258 &mut self,
259 cx: &mut Context<'_>,
260 queue_id: QueueId,
261 ) -> Poll<Result<GetConnInner>> {
262 let mut exchange = self.inner.exchange.lock().unwrap();
263
264 if self.inner.close.load(atomic::Ordering::Acquire) {
268 return Err(Error::Driver(DriverError::PoolDisconnected)).into();
269 }
270
271 exchange.spawn_futures_if_needed(&self.inner);
272
273 let highest = if let Some(cur) = exchange.waiting.peek_id() {
275 queue_id > cur
276 } else {
277 true
278 };
279
280 if !highest {
282 exchange.waiting.push(cx.waker().clone(), queue_id);
283 return Poll::Pending;
284 }
285
286 #[allow(unused_variables)] while let Some(IdlingConn { mut conn, since }) = exchange.available.pop_back() {
288 if !conn.expired() {
289 #[cfg(feature = "hdrhistogram")]
290 self.inner
291 .metrics
292 .connection_idle_duration
293 .lock()
294 .unwrap()
295 .record(since.elapsed().as_micros() as u64)
296 .ok();
297 #[cfg(feature = "hdrhistogram")]
298 let metrics = self.metrics();
299 conn.inner.active_since = Instant::now();
300 return Poll::Ready(Ok(GetConnInner::Checking(
301 async move {
302 conn.stream_mut()?.check().await?;
303 #[cfg(feature = "hdrhistogram")]
304 metrics
305 .check_duration
306 .lock()
307 .unwrap()
308 .record(conn.inner.active_since.elapsed().as_micros() as u64)
309 .ok();
310 Ok(conn)
311 }
312 .boxed(),
313 )));
314 } else {
315 self.send_to_recycler(conn);
316 }
317 }
318
319 if exchange.exist < self.opts.pool_opts().constraints().max() {
322 exchange.exist += 1;
324
325 self.inner
326 .metrics
327 .connection_count
328 .store(exchange.exist, atomic::Ordering::Relaxed);
329
330 let opts = self.opts.clone();
331 #[cfg(feature = "hdrhistogram")]
332 let metrics = self.metrics();
333
334 return Poll::Ready(Ok(GetConnInner::Connecting(
335 async move {
336 let conn = Conn::new(opts).await;
337 #[cfg(feature = "hdrhistogram")]
338 if let Ok(conn) = &conn {
339 metrics
340 .connect_duration
341 .lock()
342 .unwrap()
343 .record(conn.inner.active_since.elapsed().as_micros() as u64)
344 .ok();
345 }
346 conn
347 }
348 .boxed(),
349 )));
350 }
351
352 exchange.waiting.push(cx.waker().clone(), queue_id);
354 Poll::Pending
355 }
356
357 fn unqueue(&self, queue_id: QueueId) {
358 let mut exchange = self.inner.exchange.lock().unwrap();
359 exchange.waiting.remove(queue_id);
360 }
361}
362
363impl Drop for Conn {
364 fn drop(&mut self) {
365 self.inner.infile_handler = None;
366
367 if std::thread::panicking() {
368 if let Some(pool) = self.inner.pool.take() {
370 pool.inner
371 .metrics
372 .connections_in_use
373 .fetch_sub(1, Ordering::Relaxed);
374 pool.cancel_connection();
375 }
376
377 return;
378 }
379
380 if let Some(mut pool) = self.inner.pool.take() {
381 pool.return_conn(self.take());
382 } else if self.inner.stream.is_some() && !self.inner.disconnected {
383 crate::conn::disconnect(self.take());
384 }
385 }
386}
387
388#[cfg(test)]
389mod test {
390 use futures_util::{
391 future::{join_all, select, select_all, try_join_all, Either},
392 poll, try_join, FutureExt,
393 };
394 use tokio::time::{sleep, timeout};
395 use waker_fn::waker_fn;
396
397 use std::{
398 future::Future,
399 pin::pin,
400 sync::{Arc, OnceLock},
401 task::{Context, Poll},
402 time::Duration,
403 };
404
405 use crate::{
406 conn::pool::Pool, opts::PoolOpts, prelude::*, test_misc::get_opts, PoolConstraints, Row,
407 TxOpts, Value,
408 };
409
410 macro_rules! conn_ex_field {
411 ($conn:expr, $field:tt) => {
412 ex_field!($conn.inner.pool.as_ref().unwrap(), $field)
413 };
414 }
415
416 macro_rules! ex_field {
417 ($pool:expr, $field:tt) => {
418 $pool.inner.exchange.lock().unwrap().$field
419 };
420 }
421
422 fn pool_with_one_connection() -> Pool {
423 let pool_opts = PoolOpts::new().with_constraints(PoolConstraints::new(1, 1).unwrap());
424 let opts = get_opts().pool_opts(pool_opts.clone());
425 Pool::new(opts)
426 }
427
428 #[tokio::test]
429 async fn should_opt_out_of_connection_reset() -> super::Result<()> {
430 let pool_opts = PoolOpts::new().with_constraints(PoolConstraints::new(1, 1).unwrap());
431 let opts = get_opts().pool_opts(pool_opts.clone());
432
433 let pool = Pool::new(opts.clone());
434
435 let mut conn = pool.get_conn().await.unwrap();
436 assert_eq!(
437 conn.query_first::<Value, _>("SELECT @foo").await?.unwrap(),
438 Value::NULL
439 );
440 conn.query_drop("SET @foo = 'foo'").await?;
441 assert_eq!(
442 conn.query_first::<String, _>("SELECT @foo").await?.unwrap(),
443 "foo",
444 );
445 drop(conn);
446
447 conn = pool.get_conn().await.unwrap();
448 assert_eq!(
449 conn.query_first::<Value, _>("SELECT @foo").await?.unwrap(),
450 Value::NULL
451 );
452 conn.query_drop("SET @foo = 'foo'").await?;
453 conn.reset_connection(false);
454 drop(conn);
455
456 conn = pool.get_conn().await.unwrap();
457 assert_eq!(
458 conn.query_first::<String, _>("SELECT @foo").await?.unwrap(),
459 "foo",
460 );
461 drop(conn);
462 pool.disconnect().await.unwrap();
463
464 let pool = Pool::new(opts.pool_opts(pool_opts.with_reset_connection(false)));
465 conn = pool.get_conn().await.unwrap();
466 conn.query_drop("SET @foo = 'foo'").await?;
467 drop(conn);
468 conn = pool.get_conn().await.unwrap();
469 assert_eq!(
470 conn.query_first::<String, _>("SELECT @foo").await?.unwrap(),
471 "foo",
472 );
473 drop(conn);
474 pool.disconnect().await
475 }
476
477 #[test]
478 fn should_not_hang() -> super::Result<()> {
479 pub struct Database {
480 pool: Pool,
481 }
482
483 impl Database {
484 pub async fn disconnect(self) -> super::Result<()> {
485 self.pool.disconnect().await?;
486 Ok(())
487 }
488 }
489
490 let runtime = tokio::runtime::Runtime::new().unwrap();
491 let database = Database {
492 pool: Pool::new(get_opts()),
493 };
494 runtime.block_on(database.disconnect())
495 }
496
497 #[tokio::test]
498 async fn should_track_conn_if_disconnected_outside_of_a_pool() -> super::Result<()> {
499 let pool = Pool::new(get_opts());
500 let conn = pool.get_conn().await?;
501 conn.disconnect().await?;
502 pool.disconnect().await?;
503 Ok(())
504 }
505
506 #[tokio::test]
507 async fn should_connect() -> super::Result<()> {
508 let pool = Pool::new(crate::Opts::from(get_opts()));
509 pool.get_conn().await?.ping().await?;
510 pool.disconnect().await?;
511 Ok(())
512 }
513
514 #[tokio::test]
515 async fn should_reconnect() -> super::Result<()> {
516 let mut master = crate::Conn::new(get_opts()).await?;
517
518 async fn test(master: &mut crate::Conn, opts: crate::OptsBuilder) -> super::Result<()> {
519 const NUM_CONNS: usize = 5;
520 let pool = Pool::new(opts);
521
522 let connections = (0..NUM_CONNS).map(|_| {
524 async {
525 let mut conn = pool.get_conn().await?;
526 conn.ping().await?;
527 crate::Result::Ok(conn)
528 }
529 .boxed()
530 });
531
532 let ids = try_join_all(connections)
534 .await?
535 .into_iter()
536 .map(|conn| conn.id())
537 .collect::<Vec<_>>();
538
539 sleep(Duration::from_millis(1000)).await;
541
542 pool.get_conn().await?;
544
545 for id in ids {
547 master.query_drop(format!("KILL {}", id)).await?;
548 }
549
550 assert_eq!(ex_field!(pool, available).len(), NUM_CONNS);
552
553 sleep(Duration::from_millis(500)).await;
554
555 let _conn = pool.get_conn().await?;
557
558 assert_eq!(ex_field!(pool, available).len(), 0);
560
561 drop(_conn);
562 pool.disconnect().await
563 }
564
565 println!("Check socket/pipe..");
566 test(&mut master, get_opts()).await?;
567
568 println!("Check tcp..");
569 test(&mut master, get_opts().prefer_socket(false)).await?;
570
571 master.disconnect().await
572 }
573
574 #[tokio::test]
575 async fn should_reuse_connections() -> super::Result<()> {
576 let pool = pool_with_one_connection();
577 let mut conn = pool.get_conn().await?;
578
579 let server_version = conn.server_version();
580 let connection_id = conn.id();
581
582 for _ in 0..16 {
583 drop(conn);
584 conn = pool.get_conn().await?;
585 println!("CONN connection_id={}", conn.id());
586 assert!(conn.id() == connection_id || server_version < (5, 7, 2));
587 }
588
589 Ok(())
590 }
591
592 #[tokio::test]
593 #[ignore]
594 async fn can_handle_the_pressure() {
595 let pool = Pool::new(get_opts());
596 for _ in 0..10i32 {
597 let (tx, mut rx) = tokio::sync::mpsc::unbounded_channel();
598 for i in 0..10_000 {
599 let pool = pool.clone();
600 let tx = tx.clone();
601 tokio::spawn(async move {
602 let _ = pool.get_conn().await.unwrap();
603 tx.send(i).unwrap();
604 });
605 }
606 drop(tx);
607 while (rx.recv().await).is_some() {}
609 }
610 drop(pool);
611 }
612
613 #[tokio::test]
614 async fn should_start_transaction() -> super::Result<()> {
615 let pool = pool_with_one_connection();
616
617 "CREATE TABLE IF NOT EXISTS mysql.tmp(id int)"
618 .ignore(&pool)
619 .await?;
620 "DELETE FROM mysql.tmp".ignore(&pool).await?;
621
622 let mut tx = pool.start_transaction(TxOpts::default()).await?;
623 tx.exec_batch(
624 "INSERT INTO mysql.tmp (id) VALUES (?)",
625 vec![(1_u8,), (2_u8,)],
626 )
627 .await?;
628 tx.exec_drop("SELECT * FROM mysql.tmp", ()).await?;
629 drop(tx);
630 let row_opt = pool
631 .get_conn()
632 .await?
633 .query_first("SELECT COUNT(*) FROM mysql.tmp")
634 .await?;
635 assert_eq!(row_opt, Some((0u8,)));
636 pool.get_conn()
637 .await?
638 .query_drop("DROP TABLE mysql.tmp")
639 .await?;
640 pool.disconnect().await?;
641 Ok(())
642 }
643
644 #[tokio::test]
645 async fn should_check_inactive_connection_ttl() -> super::Result<()> {
646 const POOL_MIN: usize = 5;
647 const POOL_MAX: usize = 10;
648
649 const INACTIVE_CONNECTION_TTL: Duration = Duration::from_millis(500);
650 const TTL_CHECK_INTERVAL: Duration = Duration::from_secs(1);
651
652 let constraints = PoolConstraints::new(POOL_MIN, POOL_MAX).unwrap();
653 let pool_opts = PoolOpts::default()
654 .with_constraints(constraints)
655 .with_inactive_connection_ttl(INACTIVE_CONNECTION_TTL)
656 .with_ttl_check_interval(TTL_CHECK_INTERVAL);
657
658 let pool = Pool::new(get_opts().pool_opts(pool_opts));
659 let pool_clone = pool.clone();
660 let conns = (0..POOL_MAX).map(|_| pool.get_conn()).collect::<Vec<_>>();
661
662 let conns = try_join_all(conns).await?;
663
664 assert_eq!(ex_field!(pool_clone, exist), POOL_MAX);
665 drop(conns);
666
667 sleep(Duration::from_millis(100)).await;
669
670 assert_eq!(ex_field!(pool_clone, available).len(), POOL_MAX);
672
673 sleep(TTL_CHECK_INTERVAL).await;
675
676 sleep(Duration::from_millis(500)).await;
678
679 assert_eq!(ex_field!(pool_clone, available).len(), POOL_MIN);
681
682 Ok(())
683 }
684
685 #[tokio::test]
686 async fn aa_should_hold_bounds2() -> super::Result<()> {
687 use std::cmp::min;
688
689 const POOL_MIN: usize = 5;
690 const POOL_MAX: usize = 10;
691
692 let constraints = PoolConstraints::new(POOL_MIN, POOL_MAX).unwrap();
693 let pool_opts = PoolOpts::default().with_constraints(constraints);
694
695 let pool = Pool::new(get_opts().pool_opts(pool_opts));
696 let pool_clone = pool.clone();
697 let conns = (0..POOL_MAX).map(|_| pool.get_conn()).collect::<Vec<_>>();
698
699 let mut conns = try_join_all(conns).await?;
700
701 assert_eq!(ex_field!(pool_clone, exist), POOL_MAX);
704
705 while !conns.is_empty() {
706 let _ = conns.pop();
708
709 sleep(Duration::from_millis(500)).await;
711
712 let dropped = POOL_MAX - conns.len();
723 let idle = min(dropped, POOL_MIN);
724 let expected = conns.len() + idle;
725
726 let have = ex_field!(pool_clone, exist);
728 assert_eq!(have, expected);
729 }
730
731 pool.disconnect().await?;
732 Ok(())
733 }
734
735 #[tokio::test]
736 async fn should_hold_bounds1() -> super::Result<()> {
737 let constraints = PoolConstraints::new(1, 2).unwrap();
738 let opts = get_opts().pool_opts(PoolOpts::default().with_constraints(constraints));
739 let pool = Pool::new(opts);
740 let pool_clone = pool.clone();
741
742 let (conn1, conn2) = try_join!(pool.get_conn(), pool.get_conn()).unwrap();
743
744 assert_eq!(conn_ex_field!(conn1, exist), 2);
745 assert_eq!(conn_ex_field!(conn1, available).len(), 0);
746
747 drop(conn1);
748 drop(conn2);
749 let conn1 = pool_clone.get_conn().await?;
752 assert_eq!(conn_ex_field!(conn1, available).len(), 0);
753
754 drop(conn1);
755
756 assert!(ex_field!(pool, available).len() <= 1);
759 pool.disconnect().await?;
760 Ok(())
761 }
762
763 #[tokio::test]
765 async fn should_hold_bounds_on_error() -> super::Result<()> {
766 let pool = Pool::new("mysql://255.255.255.255");
768
769 assert!(try_join!(pool.get_conn(), pool.get_conn()).is_err());
770 assert_eq!(ex_field!(pool, exist), 0);
771 Ok(())
772 }
773
774 #[tokio::test]
775 async fn zz_should_check_wait_timeout_on_get_conn() -> super::Result<()> {
776 let pool = Pool::new(get_opts());
777
778 let mut conn = pool.get_conn().await?;
779 let wait_timeout_orig: Option<usize> = conn.query_first("SELECT @@wait_timeout").await?;
780 conn.query_drop("SET GLOBAL wait_timeout = 3").await?;
781 conn.disconnect().await?;
782
783 let mut conn = pool.get_conn().await?;
784 let wait_timeout: Option<usize> = conn.query_first("SELECT @@wait_timeout").await?;
785 let id1: Option<usize> = conn.query_first("SELECT CONNECTION_ID()").await?;
786 drop(conn);
787
788 assert_eq!(wait_timeout, Some(3));
789 assert_eq!(ex_field!(pool, exist), 1);
790
791 sleep(Duration::from_secs(6)).await;
792
793 let mut conn = pool.get_conn().await?;
794 let id2: Option<usize> = conn.query_first("SELECT CONNECTION_ID()").await?;
795 assert_eq!(ex_field!(pool, exist), 1);
796 assert_ne!(id1, id2);
797
798 conn.exec_drop("SET GLOBAL wait_timeout = ?", (wait_timeout_orig,))
799 .await?;
800 drop(conn);
801
802 pool.disconnect().await?;
803
804 Ok(())
805 }
806
807 #[tokio::test]
808 async fn droptest() -> super::Result<()> {
809 let pool = Pool::new(get_opts());
810 let conns = try_join_all((0..10).map(|_| pool.get_conn()))
811 .await
812 .unwrap();
813 drop(conns);
814 drop(pool);
815
816 let pool = Pool::new(get_opts());
817 let conns = try_join_all((0..10).map(|_| pool.get_conn()))
818 .await
819 .unwrap();
820 drop(pool);
821 drop(conns);
822 Ok(())
823 }
824
825 #[test]
826 fn drop_impl_for_conn_should_not_panic_within_unwind() {
827 use tokio::runtime;
828
829 const PANIC_MESSAGE: &str = "ORIGINAL_PANIC";
830
831 let result = std::panic::catch_unwind(|| {
832 runtime::Builder::new_current_thread()
833 .enable_all()
834 .build()
835 .unwrap()
836 .block_on(async {
837 let pool = Pool::new(get_opts());
838 let _conn = pool.get_conn().await.unwrap();
839 std::panic::panic_any(PANIC_MESSAGE);
840 });
841 });
842
843 assert_eq!(
844 *result.unwrap_err().downcast::<&str>().unwrap(),
845 "ORIGINAL_PANIC",
846 );
847 }
848
849 #[test]
850 fn should_not_panic_on_unclean_shutdown() {
851 for _ in 0..10 {
853 let rt = tokio::runtime::Runtime::new().unwrap();
854 let (tx, rx) = tokio::sync::oneshot::channel();
855 rt.block_on(async move {
856 let pool = Pool::new(get_opts());
857 let mut c = pool.get_conn().await.unwrap();
858 tokio::spawn(async move {
859 let _ = rx.await;
860 let _ = c.query_drop("SELECT 1").await;
861 });
862 });
863 drop(rt);
864 let _ = tx.send(());
866 }
867 }
868
869 #[test]
870 fn should_perform_clean_shutdown() {
871 for _ in 0..10 {
873 let rt = tokio::runtime::Runtime::new().unwrap();
874 let (tx, rx) = tokio::sync::oneshot::channel();
875 let jh = rt.spawn(async move {
876 let pool = Pool::new(get_opts());
877 let mut c = pool.get_conn().await.unwrap();
878 tokio::spawn(async move {
879 let _ = rx.await;
880 let _ = c.query_drop("SELECT 1").await;
881 });
882 let _ = pool.disconnect().await;
883 });
884 let _ = tx.send(());
885 rt.block_on(jh).unwrap();
886 }
887 }
888
889 #[tokio::test]
890 async fn issue_126_should_cleanup_errors_in_multiresult_sets() -> super::Result<()> {
891 let pool_constraints = PoolConstraints::new(0, 1).unwrap();
892 let pool_opts = PoolOpts::default().with_constraints(pool_constraints);
893
894 let pool = Pool::new(get_opts().pool_opts(pool_opts));
895
896 for _ in 0u8..100 {
897 pool.get_conn()
898 .await?
899 .query_iter("DO '42'; BLABLA;")
900 .await?;
901 }
902
903 Ok(())
904 }
905
906 #[tokio::test]
907 async fn should_ignore_non_fatal_errors_while_returning_to_a_pool() -> super::Result<()> {
908 let pool = pool_with_one_connection();
909 let id = pool.get_conn().await?.id();
910
911 for _ in 0u8..10 {
913 let mut conn = pool.get_conn().await?;
914 conn.query_iter("DO '42'; BLABLA;").await?;
915 assert_eq!(id, conn.id());
916 }
917
918 Ok(())
919 }
920
921 #[tokio::test]
922 async fn should_remove_waker_of_cancelled_task() {
923 let pool = pool_with_one_connection();
924 let only_conn = pool.get_conn().await.unwrap();
925
926 let join_handle = tokio::spawn(timeout(Duration::from_secs(1), pool.get_conn()));
927
928 sleep(Duration::from_secs(2)).await;
929
930 match join_handle.await.unwrap() {
931 Err(_elapsed) => (),
932 _ => panic!("unexpected Ok()"),
933 }
934 drop(only_conn);
935
936 assert_eq!(0, pool.inner.exchange.lock().unwrap().waiting.len());
937 assert_eq!(
939 0,
940 pool.metrics()
941 .active_wait_requests
942 .load(std::sync::atomic::Ordering::Relaxed)
943 );
944 }
945
946 #[tokio::test]
947 async fn should_work_if_pooled_connection_operation_is_cancelled() -> super::Result<()> {
948 let pool = Pool::new(get_opts());
949
950 join_all((0..10).map(|_| pool.get_conn())).await;
952
953 async fn op(pool: &Pool) {
955 let _: Option<Row> = pool
956 .get_conn()
957 .await
958 .unwrap()
959 .exec_first("SELECT ?, ?", (42, "foo"))
960 .await
961 .unwrap();
962 }
963
964 let mut max_delay = 0_u128;
966 for _ in 0..10_usize {
967 let start = std::time::Instant::now();
968 op(&pool).await;
969 max_delay = std::cmp::max(max_delay, start.elapsed().as_micros());
970 }
971
972 for _ in 0_usize..128 {
973 let fut = select_all((0_usize..5).map(|_| op(&pool).boxed()));
974
975 let delay_micros = rand::random::<u128>() % max_delay;
978 select(
979 sleep(Duration::from_micros(delay_micros as u64)).boxed(),
980 fut,
981 )
982 .await;
983
984 sleep(Duration::from_millis(100)).await;
986 }
987 Ok(())
988 }
989
990 #[tokio::test]
991 async fn check_absolute_connection_ttl() -> super::Result<()> {
992 let constraints = PoolConstraints::new(1, 3).unwrap();
993 let pool_opts = PoolOpts::default()
994 .with_constraints(constraints)
995 .with_inactive_connection_ttl(Duration::from_secs(99))
996 .with_ttl_check_interval(Duration::from_secs(1))
997 .with_abs_conn_ttl(Some(Duration::from_secs(2)));
998
999 let pool = Pool::new(get_opts().pool_opts(pool_opts));
1000
1001 let conn_ttl0 = pool.get_conn().await?;
1002 sleep(Duration::from_millis(1000)).await;
1003 let conn_ttl1 = pool.get_conn().await?;
1004 sleep(Duration::from_millis(1000)).await;
1005 let conn_ttl2 = pool.get_conn().await?;
1006
1007 drop(conn_ttl0);
1008 drop(conn_ttl1);
1009 drop(conn_ttl2);
1010 assert_eq!(ex_field!(pool, exist), 3);
1011
1012 sleep(Duration::from_millis(1500)).await;
1013 assert_eq!(ex_field!(pool, exist), 2);
1014
1015 sleep(Duration::from_millis(1000)).await;
1016 assert_eq!(ex_field!(pool, exist), 1);
1017
1018 sleep(Duration::from_millis(1000)).await;
1020 assert_eq!(ex_field!(pool, exist), 0);
1021
1022 Ok(())
1023 }
1024
1025 #[tokio::test]
1026 async fn save_last_waker() {
1027 let pool = pool_with_one_connection();
1030
1031 let conn = pool.get_conn().await.unwrap();
1034 let mut pending_fut = pin!(pool.get_conn());
1035
1036 let build_waker = || {
1037 let called = Arc::new(OnceLock::new());
1038 let called2 = called.clone();
1039 let waker = waker_fn(move || called2.set(()).unwrap());
1040 (called, waker)
1041 };
1042
1043 let mut assert_pending = |waker| {
1044 let mut context = Context::from_waker(&waker);
1045 let p = pending_fut.as_mut().poll(&mut context);
1046 assert!(matches!(p, Poll::Pending));
1047 };
1048
1049 let (first_called, waker) = build_waker();
1050 assert_pending(waker);
1051
1052 let (second_called, waker) = build_waker();
1053 assert_pending(waker);
1054
1055 drop(conn);
1056
1057 while second_called.get().is_none() {
1058 assert!(first_called.get().is_none());
1059 tokio::time::sleep(Duration::from_millis(100)).await;
1060 }
1061
1062 assert!(first_called.get().is_none());
1063 }
1064
1065 #[tokio::test]
1066 async fn check_priorities() -> super::Result<()> {
1067 let pool = pool_with_one_connection();
1068
1069 let queue_len = || {
1070 let exchange = pool.inner.exchange.lock().unwrap();
1071 exchange.waiting.len()
1072 };
1073
1074 let conn = pool.get_conn().await.unwrap();
1077
1078 #[allow(clippy::async_yields_async)]
1079 let get_pending = || async {
1080 let fut = async {
1081 pool.get_conn().await.unwrap();
1082 }
1083 .shared();
1084 let p = poll!(fut.clone());
1085 assert!(matches!(p, Poll::Pending));
1086 fut
1087 };
1088
1089 let fut1 = get_pending().await;
1090 let fut2 = get_pending().await;
1091
1092 assert_eq!(queue_len(), 2);
1094
1095 drop(conn); while queue_len() != 1 {
1097 tokio::time::sleep(Duration::from_millis(100)).await;
1098 }
1099
1100 let Either::Right((_, fut2)) = select(fut2, fut1).await else {
1103 panic!("wrong future");
1104 };
1105
1106 assert_eq!(queue_len(), 1);
1109
1110 let p = poll!(fut2.clone());
1111 assert!(matches!(p, Poll::Pending));
1112 assert_eq!(queue_len(), 1); fut2.await;
1117 assert_eq!(queue_len(), 0);
1118
1119 let fut3 = get_pending().await;
1122 assert_eq!(queue_len(), 1);
1123
1124 fut3.await;
1126
1127 Ok(())
1128 }
1129
1130 #[cfg(feature = "hdrhistogram")]
1131 #[tokio::test]
1132 async fn metrics() -> super::Result<()> {
1133 let pool = pool_with_one_connection();
1134
1135 let metrics = pool.metrics();
1136 let conn = pool.get_conn().await.unwrap();
1137 tokio::time::sleep(Duration::from_millis(100)).await;
1138 drop(conn);
1139 pool.get_conn().await.unwrap();
1140
1141 let max = metrics.connection_active_duration.lock().unwrap().max();
1142 assert!(max > 100_000);
1144
1145 Ok(())
1146 }
1147
1148 #[tokio::test]
1149 async fn connection_in_use_metric() {
1150 let pool = pool_with_one_connection();
1151 let metrics = pool.metrics();
1152
1153 let conn = pool.get_conn().await.unwrap();
1154 assert_eq!(
1155 metrics
1156 .connections_in_use
1157 .load(std::sync::atomic::Ordering::Relaxed),
1158 1
1159 );
1160
1161 drop(conn);
1162 assert_eq!(
1163 metrics
1164 .connections_in_use
1165 .load(std::sync::atomic::Ordering::Relaxed),
1166 0
1167 );
1168 loop {
1169 if metrics
1170 .connections_in_pool
1171 .load(std::sync::atomic::Ordering::Relaxed)
1172 == 1
1173 {
1174 break;
1175 }
1176 tokio::time::sleep(Duration::from_millis(100)).await;
1177 }
1178
1179 let conn = pool.get_conn().await.unwrap();
1181 assert_eq!(
1182 metrics
1183 .connections_in_use
1184 .load(std::sync::atomic::Ordering::Relaxed),
1185 1
1186 );
1187 assert_eq!(
1188 metrics
1189 .connections_in_pool
1190 .load(std::sync::atomic::Ordering::Relaxed),
1191 0
1192 );
1193
1194 drop(conn);
1195 assert_eq!(
1196 metrics
1197 .connections_in_use
1198 .load(std::sync::atomic::Ordering::Relaxed),
1199 0
1200 );
1201 loop {
1202 if metrics
1203 .connections_in_pool
1204 .load(std::sync::atomic::Ordering::Relaxed)
1205 == 1
1206 {
1207 break;
1208 }
1209 tokio::time::sleep(Duration::from_millis(100)).await;
1210 }
1211 }
1212
1213 #[cfg(feature = "nightly")]
1214 mod bench {
1215 use futures_util::future::{FutureExt, TryFutureExt};
1216 use tokio::runtime::Runtime;
1217
1218 use crate::{prelude::Queryable, test_misc::get_opts, Pool, PoolConstraints, PoolOpts};
1219 use std::time::Duration;
1220
1221 #[bench]
1222 fn get_conn(bencher: &mut test::Bencher) {
1223 let mut runtime = Runtime::new().unwrap();
1224 let pool = Pool::new(get_opts());
1225
1226 bencher.iter(|| {
1227 let fut = pool
1228 .get_conn()
1229 .and_then(|mut conn| async { conn.ping().await.map(|_| conn) });
1230 runtime.block_on(fut).unwrap();
1231 });
1232
1233 runtime.block_on(pool.disconnect()).unwrap();
1234 }
1235
1236 #[bench]
1237 fn new_conn_on_pool_soft_boundary(bencher: &mut test::Bencher) {
1238 let mut runtime = Runtime::new().unwrap();
1239
1240 let pool_constraints = PoolConstraints::new(0, 1).unwrap();
1241 let pool_opts = PoolOpts::default()
1242 .with_constraints(pool_constraints)
1243 .with_inactive_connection_ttl(Duration::from_secs(1));
1244
1245 let pool = Pool::new(get_opts().pool_opts(pool_opts));
1246
1247 bencher.iter(|| {
1248 let fut = pool.get_conn().map(drop);
1249 runtime.block_on(fut);
1250 });
1251
1252 runtime.block_on(pool.disconnect()).unwrap();
1253 }
1254 }
1255}