From ecbf8066c09b869190677a52df386ad45ab9489b Mon Sep 17 00:00:00 2001 From: Lev Kokotov Date: Wed, 3 May 2023 09:04:38 -0700 Subject: [PATCH 1/3] Set reaper rate to minimum value --- bb8/src/api.rs | 19 ++++++++++++++++++- bb8/tests/test.rs | 1 - 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/bb8/src/api.rs b/bb8/src/api.rs index f0d1b82..6d2c72a 100644 --- a/bb8/src/api.rs +++ b/bb8/src/api.rs @@ -11,6 +11,9 @@ use crate::inner::PoolInner; use crate::internals::Conn; pub use crate::internals::State; +// Default connection reaper rate +static DEFAULT_REAPER_RATE: Duration = Duration::from_secs(30); + /// A generic connection pool. pub struct Pool where @@ -111,7 +114,7 @@ impl Default for Builder { connection_timeout: Duration::from_secs(30), retry_connection: true, error_sink: Box::new(NopErrorSink), - reaper_rate: Duration::from_secs(30), + reaper_rate: DEFAULT_REAPER_RATE, connection_customizer: None, _p: PhantomData, } @@ -183,6 +186,13 @@ impl Builder { Some(Duration::from_secs(0)), "max_lifetime must be greater than zero!" ); + + if let Some(max_lifetime) = max_lifetime { + self.reaper_rate = std::cmp::min(DEFAULT_REAPER_RATE, max_lifetime); + } else { + self.reaper_rate = std::cmp::min(DEFAULT_REAPER_RATE, self.reaper_rate) + } + self.max_lifetime = max_lifetime; self } @@ -204,6 +214,13 @@ impl Builder { Some(Duration::from_secs(0)), "idle_timeout must be greater than zero!" ); + + if let Some(idle_timeout) = idle_timeout { + self.reaper_rate = std::cmp::min(DEFAULT_REAPER_RATE, idle_timeout); + } else { + self.reaper_rate = std::cmp::min(DEFAULT_REAPER_RATE, self.reaper_rate) + } + self.idle_timeout = idle_timeout; self } diff --git a/bb8/tests/test.rs b/bb8/tests/test.rs index a8e1d02..dd76f82 100644 --- a/bb8/tests/test.rs +++ b/bb8/tests/test.rs @@ -413,7 +413,6 @@ async fn test_max_lifetime() { let pool = Pool::builder() .max_lifetime(Some(Duration::from_secs(1))) .connection_timeout(Duration::from_secs(1)) - .reaper_rate(Duration::from_secs(1)) .max_size(5) .min_idle(Some(5)) .build(manager) From 70f431732202ec59223bcc55c2c36b1ecb5776ca Mon Sep 17 00:00:00 2001 From: Lev Kokotov Date: Wed, 3 May 2023 09:07:32 -0700 Subject: [PATCH 2/3] the else branchn is wrong --- bb8/src/api.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/bb8/src/api.rs b/bb8/src/api.rs index 6d2c72a..0d14131 100644 --- a/bb8/src/api.rs +++ b/bb8/src/api.rs @@ -189,8 +189,6 @@ impl Builder { if let Some(max_lifetime) = max_lifetime { self.reaper_rate = std::cmp::min(DEFAULT_REAPER_RATE, max_lifetime); - } else { - self.reaper_rate = std::cmp::min(DEFAULT_REAPER_RATE, self.reaper_rate) } self.max_lifetime = max_lifetime; @@ -217,8 +215,6 @@ impl Builder { if let Some(idle_timeout) = idle_timeout { self.reaper_rate = std::cmp::min(DEFAULT_REAPER_RATE, idle_timeout); - } else { - self.reaper_rate = std::cmp::min(DEFAULT_REAPER_RATE, self.reaper_rate) } self.idle_timeout = idle_timeout; From d6e498c7ff432cdbaae729b96daedf82c2f365fe Mon Sep 17 00:00:00 2001 From: Lev Kokotov Date: Wed, 3 May 2023 09:41:51 -0700 Subject: [PATCH 3/3] add idle_timeout test --- bb8/tests/test.rs | 55 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/bb8/tests/test.rs b/bb8/tests/test.rs index dd76f82..a21be3e 100644 --- a/bb8/tests/test.rs +++ b/bb8/tests/test.rs @@ -451,6 +451,61 @@ async fn test_max_lifetime() { assert_eq!(DROPPED.load(Ordering::SeqCst), 5); } +#[tokio::test] +async fn test_idle_timeout() { + static DROPPED: AtomicUsize = AtomicUsize::new(0); + + #[derive(Default)] + struct Connection; + + impl Drop for Connection { + fn drop(&mut self) { + DROPPED.fetch_add(1, Ordering::SeqCst); + } + } + + let manager = NthConnectionFailManager::::new(5); + let pool = Pool::builder() + .idle_timeout(Some(Duration::from_secs(1))) + .connection_timeout(Duration::from_secs(1)) + .max_size(5) + .min_idle(Some(5)) + .build(manager) + .await + .unwrap(); + + let (tx1, rx1) = oneshot::channel(); + let (tx2, rx2) = oneshot::channel(); + let clone = pool.clone(); + tokio::spawn(async move { + let conn = clone.get().await.unwrap(); + tx1.send(()).unwrap(); + // NB: If we sleep here we'll block this thread's event loop, and the + // reaper can't run. + let _ = rx2 + .map(|r| match r { + Ok(v) => Ok((v, conn)), + Err(_) => Err((Error, conn)), + }) + .await; + }); + + rx1.await.unwrap(); + + // And wait. + assert!(timeout(Duration::from_secs(2), pending::<()>()) + .await + .is_err()); + assert_eq!(DROPPED.load(Ordering::SeqCst), 4); + tx2.send(()).unwrap(); + + // And wait some more. + assert!(timeout(Duration::from_secs(2), pending::<()>()) + .await + .is_err()); + assert_eq!(DROPPED.load(Ordering::SeqCst), 5); +} + #[tokio::test] async fn test_min_idle() { let pool = Pool::builder()