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(())
}
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 inPooledConnection
toWeak<SharedPool<M>>
can fix this problem.For example: