sfackler / r2d2

A generic connection pool for Rust
Apache License 2.0
1.51k stars 82 forks source link

drop idle connections immediately after the pool is dropped #136

Closed name1e5s closed 1 year ago

name1e5s commented 2 years ago

I found that when the pool is dropped with some connections remain in lifetime, ALL idle connections will not drop until the connection checked out is dropped. Changing pool field in PooledConnection to Weak<SharedPool<M>> can fix this problem.

For example:

use std::{
    sync::RwLock,
    thread::sleep,
    time::{Duration, Instant},
};

use r2d2::{ManageConnection, Pool};

struct FooConnection;

impl FooConnection {
    fn new() -> FooConnection {
        println!("connection");
        FooConnection
    }
}

impl Drop for FooConnection {
    fn drop(&mut self) {
        println!("drop connection, t: {:?}", Instant::now());
    }
}

struct FooManager;

impl ManageConnection for FooManager {
    type Connection = FooConnection;
    type Error = std::io::Error;

    fn connect(&self) -> Result<FooConnection, Self::Error> {
        Ok(FooConnection::new())
    }

    fn is_valid(&self, _: &mut FooConnection) -> Result<(), Self::Error> {
        Ok(())
    }

    fn has_broken(&self, _: &mut FooConnection) -> bool {
        false
    }
}

static POOL: RwLock<Option<Pool<FooManager>>> = RwLock::new(None);

fn main() -> anyhow::Result<()> {
    let pool = r2d2::Pool::builder()
        .min_idle(Some(2))
        .max_size(4)
        .build(FooManager)?;

    *POOL.write().unwrap() = Some(pool);

    std::thread::spawn(|| {
        let _conn = POOL.read().unwrap().as_ref().unwrap().get().unwrap();
        sleep(Duration::from_secs(5));
        // <- all connections dropped here before our change

        // <- only `_conn` dropped here after our change
        // <- other idle connections will dropped eralier.
    });
    sleep(Duration::from_micros(5000));

    {
        let _ = POOL.write().unwrap().take();
        // <- all IDLE connections will dropped here after our change
    }

    sleep(Duration::from_secs(10));
    Ok(())
}