r2d2/
config.rs

1use scheduled_thread_pool::ScheduledThreadPool;
2use std::fmt;
3use std::marker::PhantomData;
4use std::sync::Arc;
5use std::time::Duration;
6
7use crate::{
8    CustomizeConnection, Error, HandleError, HandleEvent, LoggingErrorHandler, ManageConnection,
9    NopConnectionCustomizer, NopEventHandler, Pool,
10};
11
12/// A builder for a connection pool.
13pub struct Builder<M>
14where
15    M: ManageConnection,
16{
17    max_size: u32,
18    min_idle: Option<u32>,
19    test_on_check_out: bool,
20    max_lifetime: Option<Duration>,
21    idle_timeout: Option<Duration>,
22    connection_timeout: Duration,
23    error_handler: Box<dyn HandleError<M::Error>>,
24    connection_customizer: Box<dyn CustomizeConnection<M::Connection, M::Error>>,
25    event_handler: Box<dyn HandleEvent>,
26    thread_pool: Option<Arc<ScheduledThreadPool>>,
27    reaper_rate: Duration,
28    _p: PhantomData<M>,
29}
30
31impl<M> fmt::Debug for Builder<M>
32where
33    M: ManageConnection,
34{
35    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
36        fmt.debug_struct("Builder")
37            .field("max_size", &self.max_size)
38            .field("min_idle", &self.min_idle)
39            .field("test_on_check_out", &self.test_on_check_out)
40            .field("max_lifetime", &self.max_lifetime)
41            .field("idle_timeout", &self.idle_timeout)
42            .field("connection_timeout", &self.connection_timeout)
43            .field("error_handler", &self.error_handler)
44            .field("event_handler", &self.event_handler)
45            .field("connection_customizer", &self.connection_customizer)
46            .finish()
47    }
48}
49
50impl<M> Default for Builder<M>
51where
52    M: ManageConnection,
53{
54    fn default() -> Builder<M> {
55        Builder {
56            max_size: 10,
57            min_idle: None,
58            test_on_check_out: true,
59            idle_timeout: Some(Duration::from_secs(10 * 60)),
60            max_lifetime: Some(Duration::from_secs(30 * 60)),
61            connection_timeout: Duration::from_secs(30),
62            error_handler: Box::new(LoggingErrorHandler),
63            event_handler: Box::new(NopEventHandler),
64            connection_customizer: Box::new(NopConnectionCustomizer),
65            thread_pool: None,
66            reaper_rate: Duration::from_secs(30),
67            _p: PhantomData,
68        }
69    }
70}
71
72impl<M> Builder<M>
73where
74    M: ManageConnection,
75{
76    /// Constructs a new `Builder`.
77    ///
78    /// Parameters are initialized with their default values.
79    pub fn new() -> Builder<M> {
80        Builder::default()
81    }
82
83    /// Sets the maximum number of connections managed by the pool.
84    ///
85    /// Defaults to 10.
86    ///
87    /// # Panics
88    ///
89    /// Panics if `max_size` is 0.
90    pub fn max_size(mut self, max_size: u32) -> Builder<M> {
91        assert!(max_size > 0, "max_size must be positive");
92        self.max_size = max_size;
93        self
94    }
95
96    /// Sets the minimum idle connection count maintained by the pool.
97    ///
98    /// If set, the pool will try to maintain at least this many idle
99    /// connections at all times, while respecting the value of `max_size`.
100    ///
101    /// Defaults to `None` (equivalent to the value of `max_size`).
102    pub fn min_idle(mut self, min_idle: Option<u32>) -> Builder<M> {
103        self.min_idle = min_idle;
104        self
105    }
106
107    /// Sets the thread pool used for asynchronous operations such as connection
108    /// creation.
109    ///
110    /// Defaults to a new pool with 3 threads.
111    pub fn thread_pool(mut self, thread_pool: Arc<ScheduledThreadPool>) -> Builder<M> {
112        self.thread_pool = Some(thread_pool);
113        self
114    }
115
116    /// If true, the health of a connection will be verified via a call to
117    /// `ConnectionManager::is_valid` before it is checked out of the pool.
118    ///
119    /// Defaults to true.
120    pub fn test_on_check_out(mut self, test_on_check_out: bool) -> Builder<M> {
121        self.test_on_check_out = test_on_check_out;
122        self
123    }
124
125    /// Sets the maximum lifetime of connections in the pool.
126    ///
127    /// If set, connections will be closed after existing for at most 30 seconds
128    /// beyond this duration.
129    ///
130    /// If a connection reaches its maximum lifetime while checked out it will
131    /// be closed when it is returned to the pool.
132    ///
133    /// Defaults to 30 minutes.
134    ///
135    /// # Panics
136    ///
137    /// Panics if `max_lifetime` is the zero `Duration`.
138    pub fn max_lifetime(mut self, max_lifetime: Option<Duration>) -> Builder<M> {
139        assert_ne!(max_lifetime, Some(Duration::from_secs(0)), "max_lifetime must be positive");
140        self.max_lifetime = max_lifetime;
141        self
142    }
143
144    /// Sets the idle timeout used by the pool.
145    ///
146    /// If set, connections will be closed after sitting idle for at most 30
147    /// seconds beyond this duration.
148    ///
149    /// Defaults to 10 minutes.
150    ///
151    /// # Panics
152    ///
153    /// Panics if `idle_timeout` is the zero `Duration`.
154    pub fn idle_timeout(mut self, idle_timeout: Option<Duration>) -> Builder<M> {
155        assert_ne!(idle_timeout, Some(Duration::from_secs(0)), "idle_timeout must be positive");
156        self.idle_timeout = idle_timeout;
157        self
158    }
159
160    /// Sets the connection timeout used by the pool.
161    ///
162    /// Calls to `Pool::get` will wait this long for a connection to become
163    /// available before returning an error.
164    ///
165    /// Defaults to 30 seconds.
166    ///
167    /// # Panics
168    ///
169    /// Panics if `connection_timeout` is the zero duration
170    pub fn connection_timeout(mut self, connection_timeout: Duration) -> Builder<M> {
171        assert!(
172            connection_timeout > Duration::from_secs(0),
173            "connection_timeout must be positive"
174        );
175        self.connection_timeout = connection_timeout;
176        self
177    }
178
179    /// Sets the handler for errors reported in the pool.
180    ///
181    /// Defaults to the `LoggingErrorHandler`.
182    pub fn error_handler(mut self, error_handler: Box<dyn HandleError<M::Error>>) -> Builder<M> {
183        self.error_handler = error_handler;
184        self
185    }
186
187    /// Sets the handler for events reported by the pool.
188    ///
189    /// Defaults to the `NopEventHandler`.
190    pub fn event_handler(mut self, event_handler: Box<dyn HandleEvent>) -> Builder<M> {
191        self.event_handler = event_handler;
192        self
193    }
194
195    /// Sets the connection customizer used by the pool.
196    ///
197    /// Defaults to the `NopConnectionCustomizer`.
198    pub fn connection_customizer(
199        mut self,
200        connection_customizer: Box<dyn CustomizeConnection<M::Connection, M::Error>>,
201    ) -> Builder<M> {
202        self.connection_customizer = connection_customizer;
203        self
204    }
205
206    // used by tests
207    #[allow(dead_code)]
208    pub(crate) fn reaper_rate(mut self, reaper_rate: Duration) -> Builder<M> {
209        self.reaper_rate = reaper_rate;
210        self
211    }
212
213    /// Consumes the builder, returning a new, initialized pool.
214    ///
215    /// It will block until the pool has established its configured minimum
216    /// number of connections, or it times out.
217    ///
218    /// # Errors
219    ///
220    /// Returns an error if the pool is unable to open its minimum number of
221    /// connections.
222    ///
223    /// # Panics
224    ///
225    /// Panics if `min_idle` is greater than `max_size`.
226    pub fn build(self, manager: M) -> Result<Pool<M>, Error> {
227        let pool = self.build_unchecked(manager);
228        pool.wait_for_initialization()?;
229        Ok(pool)
230    }
231
232    /// Consumes the builder, returning a new pool.
233    ///
234    /// Unlike `build`, this method does not wait for any connections to be
235    /// established before returning.
236    ///
237    /// # Panics
238    ///
239    /// Panics if `min_idle` is greater than `max_size`.
240    pub fn build_unchecked(self, manager: M) -> Pool<M> {
241        if let Some(min_idle) = self.min_idle {
242            assert!(
243                self.max_size >= min_idle,
244                "min_idle must be no larger than max_size"
245            );
246        }
247
248        let thread_pool = match self.thread_pool {
249            Some(thread_pool) => thread_pool,
250            None => Arc::new(ScheduledThreadPool::with_name("r2d2-worker-{}", 3)),
251        };
252
253        let config = Config {
254            max_size: self.max_size,
255            min_idle: self.min_idle,
256            test_on_check_out: self.test_on_check_out,
257            max_lifetime: self.max_lifetime,
258            idle_timeout: self.idle_timeout,
259            connection_timeout: self.connection_timeout,
260            error_handler: self.error_handler,
261            event_handler: self.event_handler,
262            connection_customizer: self.connection_customizer,
263            thread_pool,
264        };
265
266        Pool::new_inner(config, manager, self.reaper_rate)
267    }
268}
269
270pub struct Config<C, E> {
271    pub max_size: u32,
272    pub min_idle: Option<u32>,
273    pub test_on_check_out: bool,
274    pub max_lifetime: Option<Duration>,
275    pub idle_timeout: Option<Duration>,
276    pub connection_timeout: Duration,
277    pub error_handler: Box<dyn HandleError<E>>,
278    pub event_handler: Box<dyn HandleEvent>,
279    pub connection_customizer: Box<dyn CustomizeConnection<C, E>>,
280    pub thread_pool: Arc<ScheduledThreadPool>,
281}
282
283// manual to avoid bounds on C and E
284impl<C, E> fmt::Debug for Config<C, E> {
285    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
286        fmt.debug_struct("Config")
287            .field("max_size", &self.max_size)
288            .field("min_idle", &self.min_idle)
289            .field("test_on_check_out", &self.test_on_check_out)
290            .field("max_lifetime", &self.max_lifetime)
291            .field("idle_timeout", &self.idle_timeout)
292            .field("connection_timeout", &self.connection_timeout)
293            .field("error_handler", &self.error_handler)
294            .field("event_handler", &self.event_handler)
295            .field("connection_customizer", &self.connection_customizer)
296            .finish()
297    }
298}