diff --git a/bb8/src/api.rs b/bb8/src/api.rs index f0d1b82..357d052 100644 --- a/bb8/src/api.rs +++ b/bb8/src/api.rs @@ -95,11 +95,31 @@ pub struct Builder { pub(crate) error_sink: Box>, /// The time interval used to wake up and reap connections. pub(crate) reaper_rate: Duration, + /// Queue strategy (FIFO or LIFO) + pub(crate) queue_strategy: QueueStrategy, /// User-supplied trait object responsible for initializing connections pub(crate) connection_customizer: Option>>, _p: PhantomData, } +#[derive(Debug)] +pub enum QueueStrategy { + /// First in first out + /// This strategy behaves like a queue + /// It will evenly spread load on all existing connections, resetting their idle timeouts, maintaining the pool size + Fifo, + /// Last in first out + /// This behaves like a stack + /// It will use the most recently used connection and help to keep the total pool size small by evicting idle connections + Lifo, +} + +impl Default for QueueStrategy { + fn default() -> Self { + QueueStrategy::Fifo + } +} + impl Default for Builder { fn default() -> Self { Builder { @@ -112,6 +132,7 @@ impl Default for Builder { retry_connection: true, error_sink: Box::new(NopErrorSink), reaper_rate: Duration::from_secs(30), + queue_strategy: QueueStrategy::default(), connection_customizer: None, _p: PhantomData, } @@ -260,6 +281,15 @@ impl Builder { self } + /// Sets the queue strategy to be used by the pool + /// + /// Defaults to `Fifo`. + #[must_use] + pub fn queue_strategy(mut self, queue_strategy: QueueStrategy) -> Self { + self.queue_strategy = queue_strategy; + self + } + /// Set the connection customizer to customize newly checked out connections #[must_use] pub fn connection_customizer( diff --git a/bb8/src/internals.rs b/bb8/src/internals.rs index cffd928..a7a33bb 100644 --- a/bb8/src/internals.rs +++ b/bb8/src/internals.rs @@ -2,7 +2,7 @@ use std::cmp::min; use std::sync::Arc; use std::time::Instant; -use crate::lock::Mutex; +use crate::{api::QueueStrategy, lock::Mutex}; use futures_channel::oneshot; use crate::api::{Builder, ManageConnection}; @@ -42,6 +42,7 @@ where conns: VecDeque>, num_conns: u32, pending_conns: u32, + queue_strategy: QueueStrategy, } impl PoolInternals @@ -80,8 +81,11 @@ where } // Queue it in the idle queue - self.conns - .push_back(IdleConn::from(guard.conn.take().unwrap())); + let conn = IdleConn::from(guard.conn.take().unwrap()); + match self.queue_strategy { + QueueStrategy::Fifo => self.conns.push_back(conn), + QueueStrategy::Lifo => self.conns.push_front(conn), + } } pub(crate) fn connect_failed(&mut self, _: Approval) { @@ -163,6 +167,7 @@ where conns: VecDeque::new(), num_conns: 0, pending_conns: 0, + queue_strategy: QueueStrategy::Lifo, } } }