149 lines
4.6 KiB
Rust
149 lines
4.6 KiB
Rust
|
|
#![cfg(feature = "managed")]
|
||
|
|
|
||
|
|
use std::convert::Infallible;
|
||
|
|
|
||
|
|
use deadpool::managed::{self, Metrics, Object, RecycleResult};
|
||
|
|
|
||
|
|
type Pool = managed::Pool<Manager, Object<Manager>>;
|
||
|
|
|
||
|
|
struct Manager {}
|
||
|
|
|
||
|
|
impl managed::Manager for Manager {
|
||
|
|
type Type = ();
|
||
|
|
type Error = Infallible;
|
||
|
|
|
||
|
|
async fn create(&self) -> Result<(), Infallible> {
|
||
|
|
Ok(())
|
||
|
|
}
|
||
|
|
|
||
|
|
async fn recycle(&self, _conn: &mut (), _: &Metrics) -> RecycleResult<Infallible> {
|
||
|
|
Ok(())
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Regression test for https://github.com/bikeshedder/deadpool/issues/380
|
||
|
|
#[tokio::test]
|
||
|
|
async fn test_grow_reuse_existing() {
|
||
|
|
// Shrink doesn't discard objects currently borrowed from the pool but
|
||
|
|
// keeps track of them so that repeatedly growing and shrinking will
|
||
|
|
// not cause excessive object creation. This logic used to contain a bug
|
||
|
|
// causing an overflow.
|
||
|
|
let mgr = Manager {};
|
||
|
|
let pool = Pool::builder(mgr).max_size(2).build().unwrap();
|
||
|
|
let obj1 = pool.get().await.unwrap();
|
||
|
|
let obj2 = pool.get().await.unwrap();
|
||
|
|
assert!(pool.status().size == 2);
|
||
|
|
assert!(pool.status().max_size == 2);
|
||
|
|
pool.resize(0);
|
||
|
|
// At this point the two objects are still tracked
|
||
|
|
assert!(pool.status().size == 2);
|
||
|
|
assert!(pool.status().max_size == 0);
|
||
|
|
pool.resize(1);
|
||
|
|
// Only one of the objects should be returned to the pool
|
||
|
|
assert!(pool.status().size == 2);
|
||
|
|
assert!(pool.status().max_size == 1);
|
||
|
|
drop(obj1);
|
||
|
|
// The first drop brings the size to 1.
|
||
|
|
assert!(pool.status().size == 1);
|
||
|
|
assert!(pool.status().max_size == 1);
|
||
|
|
drop(obj2);
|
||
|
|
assert!(pool.status().size == 1);
|
||
|
|
assert!(pool.status().max_size == 1);
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn resize_pool_shrink() {
|
||
|
|
let mgr = Manager {};
|
||
|
|
let pool = Pool::builder(mgr).max_size(2).build().unwrap();
|
||
|
|
let obj0 = pool.get().await.unwrap();
|
||
|
|
let obj1 = pool.get().await.unwrap();
|
||
|
|
pool.resize(1);
|
||
|
|
assert_eq!(pool.status().max_size, 1);
|
||
|
|
assert_eq!(pool.status().size, 2);
|
||
|
|
drop(obj1);
|
||
|
|
assert_eq!(pool.status().max_size, 1);
|
||
|
|
assert_eq!(pool.status().size, 1);
|
||
|
|
drop(obj0);
|
||
|
|
assert_eq!(pool.status().max_size, 1);
|
||
|
|
assert_eq!(pool.status().size, 1);
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn resize_pool_grow() {
|
||
|
|
let mgr = Manager {};
|
||
|
|
let pool = Pool::builder(mgr).max_size(1).build().unwrap();
|
||
|
|
let obj0 = pool.get().await.unwrap();
|
||
|
|
pool.resize(2);
|
||
|
|
assert_eq!(pool.status().max_size, 2);
|
||
|
|
assert_eq!(pool.status().size, 1);
|
||
|
|
let obj1 = pool.get().await.unwrap();
|
||
|
|
assert_eq!(pool.status().max_size, 2);
|
||
|
|
assert_eq!(pool.status().size, 2);
|
||
|
|
drop(obj1);
|
||
|
|
assert_eq!(pool.status().max_size, 2);
|
||
|
|
assert_eq!(pool.status().size, 2);
|
||
|
|
drop(obj0);
|
||
|
|
assert_eq!(pool.status().max_size, 2);
|
||
|
|
assert_eq!(pool.status().size, 2);
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn resize_pool_shrink_grow() {
|
||
|
|
let mgr = Manager {};
|
||
|
|
let pool = Pool::builder(mgr).max_size(1).build().unwrap();
|
||
|
|
let obj0 = pool.get().await.unwrap();
|
||
|
|
pool.resize(2);
|
||
|
|
pool.resize(0);
|
||
|
|
pool.resize(5);
|
||
|
|
assert_eq!(pool.status().max_size, 5);
|
||
|
|
assert_eq!(pool.status().size, 1);
|
||
|
|
drop(obj0);
|
||
|
|
assert_eq!(pool.status().max_size, 5);
|
||
|
|
assert_eq!(pool.status().size, 1);
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn resize_pool_grow_concurrent() {
|
||
|
|
let mgr = Manager {};
|
||
|
|
let pool = Pool::builder(mgr).max_size(0).build().unwrap();
|
||
|
|
let join_handle = {
|
||
|
|
let pool = pool.clone();
|
||
|
|
tokio::spawn(async move { pool.get().await })
|
||
|
|
};
|
||
|
|
tokio::task::yield_now().await;
|
||
|
|
assert_eq!(pool.status().max_size, 0);
|
||
|
|
assert_eq!(pool.status().size, 0);
|
||
|
|
assert_eq!(pool.status().available, 0);
|
||
|
|
assert_eq!(pool.status().waiting, 1);
|
||
|
|
pool.resize(1);
|
||
|
|
assert_eq!(pool.status().max_size, 1);
|
||
|
|
assert_eq!(pool.status().size, 0);
|
||
|
|
assert_eq!(pool.status().available, 0);
|
||
|
|
assert_eq!(pool.status().waiting, 1);
|
||
|
|
tokio::task::yield_now().await;
|
||
|
|
assert_eq!(pool.status().max_size, 1);
|
||
|
|
assert_eq!(pool.status().size, 1);
|
||
|
|
assert_eq!(pool.status().available, 0);
|
||
|
|
assert_eq!(pool.status().waiting, 0);
|
||
|
|
let obj0 = join_handle.await.unwrap().unwrap();
|
||
|
|
assert_eq!(pool.status().max_size, 1);
|
||
|
|
assert_eq!(pool.status().size, 1);
|
||
|
|
assert_eq!(pool.status().available, 0);
|
||
|
|
assert_eq!(pool.status().waiting, 0);
|
||
|
|
drop(obj0);
|
||
|
|
assert_eq!(pool.status().max_size, 1);
|
||
|
|
assert_eq!(pool.status().size, 1);
|
||
|
|
assert_eq!(pool.status().available, 1);
|
||
|
|
assert_eq!(pool.status().waiting, 0);
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn close_resize() {
|
||
|
|
let mgr = Manager {};
|
||
|
|
let pool = Pool::builder(mgr).max_size(1).build().unwrap();
|
||
|
|
pool.close();
|
||
|
|
pool.resize(16);
|
||
|
|
assert_eq!(pool.status().size, 0);
|
||
|
|
assert_eq!(pool.status().max_size, 0);
|
||
|
|
}
|