use std::sync::Arc;
use std::time::Duration;
use crate::config::DaemonServer;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum RecyclingMethod {
#[default]
Verified,
Fast,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum ParameterLogging {
#[default]
None,
TypesAndCount,
Full,
}
#[must_use]
pub struct PoolBuilder {
pub(crate) server: Arc<DaemonServer>,
pub(crate) max_size: usize,
pub(crate) starting_size: usize,
pub(crate) acquire_timeout: Option<Duration>,
pub(crate) idle_timeout: Option<Duration>,
pub(crate) recycle: RecyclingMethod,
pub(crate) default_page_size: u32,
pub(crate) parameter_logging: ParameterLogging,
}
impl PoolBuilder {
pub(crate) fn new(server: Arc<DaemonServer>) -> Self {
Self {
server,
max_size: 16,
starting_size: 0,
acquire_timeout: Some(Duration::from_secs(5)),
idle_timeout: Some(Duration::from_secs(300)),
recycle: RecyclingMethod::Verified,
default_page_size: 100,
parameter_logging: ParameterLogging::None,
}
}
pub fn max_size(mut self, n: usize) -> Self {
self.max_size = n;
self
}
pub fn starting_size(mut self, n: usize) -> Self {
self.starting_size = n;
self
}
pub fn acquire_timeout(mut self, d: Option<Duration>) -> Self {
self.acquire_timeout = d;
self
}
pub fn idle_timeout(mut self, d: Option<Duration>) -> Self {
self.idle_timeout = d;
self
}
pub fn recycle(mut self, m: RecyclingMethod) -> Self {
self.recycle = m;
self
}
pub fn default_page_size(mut self, n: u32) -> Self {
self.default_page_size = n;
self
}
pub fn parameter_logging(mut self, p: ParameterLogging) -> Self {
self.parameter_logging = p;
self
}
}
impl PoolBuilder {
pub async fn build(self) -> crate::Result<crate::Pool> {
use deadpool::Runtime;
use deadpool::managed::{Pool as DeadPool, Timeouts};
let acquire_timeout = self.acquire_timeout;
let starting_size = self.starting_size;
let idle_timeout = self.idle_timeout;
let registry = Arc::new(crate::pool::routing::Registry::default());
let mgr = crate::pool::manager::JobManager::new(self.server, Arc::clone(®istry));
let inner = DeadPool::builder(mgr)
.max_size(self.max_size)
.runtime(Runtime::Tokio1)
.timeouts(Timeouts {
wait: acquire_timeout,
create: None,
recycle: None,
})
.build()
.map_err(|e| crate::Error::Internal(format!("pool builder: {e}")))?;
for _ in 0..starting_size {
let _ = Box::pin(inner.get())
.await
.map_err(|e| crate::Error::Internal(format!("starting_size eager open: {e}")))?;
}
let reaper = idle_timeout
.and_then(|d| crate::pool::runtime::reaper_period(d).map(|p| (d, p)))
.map(|(timeout, period)| {
let handle = crate::pool::runtime::spawn_idle_reaper(&inner, timeout, period);
Arc::new(crate::pool::runtime::ReaperGuard { handle })
});
Ok(crate::Pool {
inner,
registry,
acquire_timeout,
parameter_logging: self.parameter_logging,
_reaper: reaper,
})
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::config::{DaemonServer, TlsConfig};
fn server() -> Arc<DaemonServer> {
Arc::new(
DaemonServer::builder()
.host("h")
.user("u")
.password("p".into())
.tls(TlsConfig::Verified)
.build()
.expect("DaemonServer builds with all required fields set"),
)
}
#[test]
fn defaults_match_spec() {
let b = PoolBuilder::new(server());
assert_eq!(b.max_size, 16);
assert_eq!(b.starting_size, 0);
assert_eq!(b.acquire_timeout, Some(Duration::from_secs(5)));
assert_eq!(b.idle_timeout, Some(Duration::from_secs(300)));
assert_eq!(b.recycle, RecyclingMethod::Verified);
assert_eq!(b.default_page_size, 100);
assert_eq!(b.parameter_logging, ParameterLogging::None);
}
#[test]
fn setters_chain() {
let b = PoolBuilder::new(server())
.max_size(32)
.starting_size(2)
.acquire_timeout(None)
.idle_timeout(Some(Duration::from_secs(60)))
.recycle(RecyclingMethod::Fast)
.default_page_size(50)
.parameter_logging(ParameterLogging::TypesAndCount);
assert_eq!(b.max_size, 32);
assert_eq!(b.starting_size, 2);
assert_eq!(b.acquire_timeout, None);
assert_eq!(b.idle_timeout, Some(Duration::from_secs(60)));
assert_eq!(b.recycle, RecyclingMethod::Fast);
assert_eq!(b.default_page_size, 50);
assert_eq!(b.parameter_logging, ParameterLogging::TypesAndCount);
}
}