compio_pool/builder.rs
1//! Build a [`Pool`] from a manager and a handful of knobs — the bb8 `Builder`,
2//! minus the settings that only make sense for a single shared pool.
3
4use std::{marker::PhantomData, time::Duration};
5
6use crate::{manage::ManageConnection, pool::Pool};
7
8/// The resolved configuration every thread's pool reads. Cheap to copy; it lives
9/// behind the pool's `Arc` and is shared read-only across threads.
10#[derive(Clone, Copy, Debug)]
11pub(crate) struct PoolConfig {
12 pub max_size: u32,
13 pub min_idle: u32,
14 pub connection_timeout: Duration,
15 pub idle_timeout: Option<Duration>,
16 pub max_lifetime: Option<Duration>,
17 pub test_on_check_out: bool,
18}
19
20impl Default for PoolConfig {
21 fn default() -> Self {
22 Self {
23 max_size: 10,
24 min_idle: 0,
25 connection_timeout: Duration::from_secs(30),
26 idle_timeout: Some(Duration::from_secs(10 * 60)),
27 max_lifetime: Some(Duration::from_secs(30 * 60)),
28 test_on_check_out: true,
29 }
30 }
31}
32
33/// Configures and builds a [`Pool`].
34///
35/// Every size here is **per thread**: [`max_size`](Self::max_size) caps one
36/// thread's [`LocalPool`](crate::LocalPool), not the process. A 48-core server
37/// with `max_size(16)` can therefore hold up to `48 × 16` connections, 16 of
38/// them to any one thread's ring.
39///
40/// Defaults match bb8: `max_size` 10, `min_idle` 0, `connection_timeout` 30s,
41/// `idle_timeout` 10 min, `max_lifetime` 30 min, `test_on_check_out` on.
42pub struct Builder<M: ManageConnection> {
43 config: PoolConfig,
44 _marker: PhantomData<fn() -> M>,
45}
46
47impl<M: ManageConnection> Default for Builder<M> {
48 fn default() -> Self {
49 Self {
50 config: PoolConfig::default(),
51 _marker: PhantomData,
52 }
53 }
54}
55
56impl<M: ManageConnection> Builder<M> {
57 /// A builder with the default settings.
58 pub fn new() -> Self {
59 Self::default()
60 }
61
62 /// The most connections one thread's pool keeps open at once (idle plus
63 /// checked out). Default 10.
64 pub fn max_size(mut self, n: u32) -> Self {
65 self.config.max_size = n;
66 self
67 }
68
69 /// How many connections each thread opens up front and keeps idle, created
70 /// by [`LocalPool::warm`](crate::LocalPool::warm). Capped at
71 /// [`max_size`](Self::max_size). Default 0.
72 pub fn min_idle(mut self, n: u32) -> Self {
73 self.config.min_idle = n;
74 self
75 }
76
77 /// How long [`get`](crate::LocalPool::get) waits — for a free slot and a live
78 /// connection — before returning [`RunError::TimedOut`](crate::RunError::TimedOut).
79 /// Default 30s.
80 pub fn connection_timeout(mut self, d: Duration) -> Self {
81 self.config.connection_timeout = d;
82 self
83 }
84
85 /// Drop an idle connection that has gone unused for this long. `None` keeps
86 /// idle connections forever. Default 10 minutes.
87 pub fn idle_timeout(mut self, d: Option<Duration>) -> Self {
88 self.config.idle_timeout = d;
89 self
90 }
91
92 /// Drop a connection older than this, idle or not, the next time it is
93 /// checked out or returned. `None` never retires on age. Default 30 minutes.
94 pub fn max_lifetime(mut self, d: Option<Duration>) -> Self {
95 self.config.max_lifetime = d;
96 self
97 }
98
99 /// Call [`ManageConnection::is_valid`] on a reused connection as it is
100 /// checked out. Default `true`.
101 pub fn test_on_check_out(mut self, yes: bool) -> Self {
102 self.config.test_on_check_out = yes;
103 self
104 }
105
106 /// Finish, producing the `Send + Clone` [`Pool`] blueprint.
107 ///
108 /// # Panics
109 ///
110 /// If `max_size` is 0.
111 pub fn build(self, manager: M) -> Pool<M> {
112 assert!(self.config.max_size > 0, "max_size must be at least 1");
113 let mut config = self.config;
114 config.min_idle = config.min_idle.min(config.max_size);
115 Pool::new(manager, config)
116 }
117}