1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
use std::{marker::PhantomData, time::Duration};

use super::Pool;
use crate::connection::{Connect, Connection};

/// Builder for [Pool].
pub struct Builder<C> {
    phantom: PhantomData<C>,
    options: Options,
}

impl<C> Builder<C> {
    /// Get a new builder with default options.
    ///
    /// See the source of this method for current defaults.
    pub(crate) fn new() -> Self {
        Self {
            phantom: PhantomData,
            options: Options {
                // pool a maximum of 10 connections to the same database
                max_size: 10,
                // don't open connections until necessary
                min_size: 0,
                // try to connect for 10 seconds before erroring
                connect_timeout: Duration::from_secs(60),
                // reap connections that have been alive > 30 minutes
                // prevents unbounded live-leaking of memory due to naive prepared statement caching
                // see src/cache.rs for context
                max_lifetime: Some(Duration::from_secs(1800)),
                // don't reap connections based on idle time
                idle_timeout: None,
                // If true, test the health of a connection on acquire
                test_on_acquire: true,
            },
        }
    }

    /// Set the maximum number of connections that this pool should maintain.
    pub fn max_size(mut self, max_size: u32) -> Self {
        self.options.max_size = max_size;
        self
    }

    /// Set the amount of time to attempt connecting to the database.
    ///
    /// If this timeout elapses, [Pool::acquire] will return an error.
    pub fn connect_timeout(mut self, connect_timeout: Duration) -> Self {
        self.options.connect_timeout = connect_timeout;
        self
    }

    /// Set the minimum number of connections to maintain at all times.
    ///
    /// When the pool is built, this many connections will be automatically spun up.
    ///
    /// If any connection is reaped by [max_lifetime] or [idle_timeout] and it brings
    /// the connection count below this amount, a new connection will be opened to replace it.
    pub fn min_size(mut self, min_size: u32) -> Self {
        self.options.min_size = min_size;
        self
    }

    /// Set the maximum lifetime of individual connections.
    ///
    /// Any connection with a lifetime greater than this will be closed.
    ///
    /// When set to `None`, all connections live until either reaped by [idle_timeout]
    /// or explicitly disconnected.
    ///
    /// Infinite connections are not recommended due to the unfortunate reality of memory/resource
    /// leaks on the database-side. It is better to retire connections periodically
    /// (even if only once daily) to allow the database the opportunity to clean up data structures
    /// (parse trees, query metadata caches, thread-local storage, etc.) that are associated with a
    /// session.
    pub fn max_lifetime(mut self, max_lifetime: impl Into<Option<Duration>>) -> Self {
        self.options.max_lifetime = max_lifetime.into();
        self
    }

    /// Set a maximum idle duration for individual connections.
    ///
    /// Any connection with an idle duration longer than this will be closed.
    ///
    /// For usage-based database server billing, this can be a cost saver.
    pub fn idle_timeout(mut self, idle_timeout: impl Into<Option<Duration>>) -> Self {
        self.options.idle_timeout = idle_timeout.into();
        self
    }

    /// If true, the health of a connection will be verified by a call to `Connection::ping`
    /// before returning the connection.
    ///
    /// Defaults to `true`.
    pub fn test_on_acquire(mut self, test: bool) -> Self {
        self.options.test_on_acquire = test;
        self
    }

    /// Spin up the connection pool.
    ///
    /// If [min_size] was set to a non-zero value, that many connections will be immediately
    /// opened and placed into the pool.
    pub async fn build(self, url: &str) -> crate::Result<Pool<C>>
    where
        C: Connection + Connect<Connection = C>,
    {
        Pool::with_options(url, self.options).await
    }
}

impl<C> Default for Builder<C> {
    fn default() -> Self {
        Self::new()
    }
}

#[derive(Debug)]
pub(crate) struct Options {
    pub max_size: u32,
    pub connect_timeout: Duration,
    pub min_size: u32,
    pub max_lifetime: Option<Duration>,
    pub idle_timeout: Option<Duration>,
    pub test_on_acquire: bool,
}