Skip to content

Commit

Permalink
Better idle conn handling when max open is unlimited
Browse files Browse the repository at this point in the history
* Treat `max_idle == 0` as unlimited idle connections. In this case, open connections will be limited by `max_open`.
* Allow Builder to be configured with `max_idle > max_open` when `max_open == 0`, matching the behavior of `Pool::set_max_idle_conns()`

Fixes #81
  • Loading branch information
dcormier committed Sep 27, 2023
1 parent f8c9779 commit 931d3e1
Show file tree
Hide file tree
Showing 4 changed files with 271 additions and 92 deletions.
21 changes: 7 additions & 14 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ impl<M: Manager> Builder<M> {
/// The pool will maintain at most this many idle connections
/// at all times, while respecting the value of `max_open`.
///
/// - 0 means unlimited (limited only by `max_open`).
/// - Defaults to 2.
pub fn max_idle(mut self, max_idle: u64) -> Self {
self.max_idle = Some(max_idle);
Expand Down Expand Up @@ -228,22 +229,14 @@ impl<M: Manager> Builder<M> {
}

/// Consumes the builder, returning a new, initialized pool.
///
/// # Panics
///
/// Panics if `max_idle` is greater than `max_size`.
pub fn build(self, manager: M) -> Pool<M> {
use std::cmp;

describe_metrics();
let max_idle = self
.max_idle
.unwrap_or_else(|| cmp::min(self.max_open, DEFAULT_MAX_IDLE_CONNS));

assert!(
self.max_open >= max_idle,
"max_idle must be no larger than max_open"
);
let max_idle = self.max_idle.unwrap_or(DEFAULT_MAX_IDLE_CONNS);
let max_idle = if self.max_open > 0 && max_idle > self.max_open {
self.max_open
} else {
max_idle
};

let config = Config {
max_open: self.max_open,
Expand Down
27 changes: 8 additions & 19 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,6 @@ use futures_util::SinkExt;
use futures_util::StreamExt;
use metrics::{decrement_gauge, gauge, histogram, increment_counter, increment_gauge};
pub use spawn::spawn;
use std::fmt;
use std::future::Future;
use std::ops::{Deref, DerefMut};
use std::sync::{
Expand Down Expand Up @@ -241,6 +240,7 @@ impl<M: Manager> Clone for Pool<M> {
}

/// Information about the state of a `Pool`.
#[derive(Debug, Clone, Copy)]
pub struct State {
/// Maximum number of open connections to the database
pub max_open: u64,
Expand All @@ -264,21 +264,6 @@ pub struct State {
pub max_lifetime_closed: u64,
}

impl fmt::Debug for State {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("Stats")
.field("max_open", &self.max_open)
.field("connections", &self.connections)
.field("in_use", &self.in_use)
.field("idle", &self.idle)
.field("wait_count", &self.wait_count)
.field("wait_duration", &self.wait_duration)
.field("max_idle_closed", &self.max_idle_closed)
.field("max_lifetime_closed", &self.max_lifetime_closed)
.finish()
}
}

impl<M: Manager> Drop for Pool<M> {
fn drop(&mut self) {}
}
Expand Down Expand Up @@ -311,7 +296,7 @@ impl<M: Manager> Pool<M> {
/// The pool will maintain at most this many idle connections
/// at all times, while respecting the value of `max_open`.
///
/// Defaults to 2.
/// 0 means unlimited (limited only by `max_open`), defaults to 2.
pub async fn set_max_idle_conns(&self, n: u64) {
let mut internals = self.0.internals.lock().await;
internals.config.max_idle =
Expand All @@ -322,7 +307,8 @@ impl<M: Manager> Pool<M> {
};

let max_idle = internals.config.max_idle as usize;
if internals.free_conns.len() > max_idle {
// Treat max_idle == 0 as unlimited
if max_idle > 0 && internals.free_conns.len() > max_idle {
let closing = internals.free_conns.split_off(max_idle);
for conn in closing {
conn.close(&self.0.state);
Expand Down Expand Up @@ -619,7 +605,10 @@ fn put_idle_conn<M: Manager>(
mut internals: MutexGuard<'_, PoolInternals<M::Connection, M::Error>>,
conn: Conn<M::Connection, M::Error>,
) {
if internals.config.max_idle > internals.free_conns.len() as u64 {
// Treat max_idle == 0 as unlimited idle connections.
if internals.config.max_idle == 0
|| internals.config.max_idle > internals.free_conns.len() as u64
{
internals.free_conns.push(conn);
drop(internals);
} else {
Expand Down
1 change: 1 addition & 0 deletions src/time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ mod time {
}

/// Wait until duration has elapsed.
#[must_use = "This does nothing if you do not await"]
pub fn delay_for(duration: Duration) -> Delay {
Delay::new(duration)
}
Expand Down
Loading

0 comments on commit 931d3e1

Please sign in to comment.