mysql/conn/opts/
pool_opts.rs

1// Copyright (c) 2023 rust-mysql-simple contributors
2//
3// Licensed under the Apache License, Version 2.0
4// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
5// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. All files in the project carrying such notice may not be copied,
7// modified, or distributed except according to those terms.
8
9macro_rules! const_assert {
10    ($name:ident, $($xs:expr),+ $(,)*) => {
11        #[allow(unknown_lints, clippy::eq_op)]
12        const $name: [(); 0 - !($($xs)&&+) as usize] = [];
13    };
14}
15
16/// Connection pool options.
17///
18/// ```
19/// # use mysql::{PoolOpts, PoolConstraints};
20/// # use std::time::Duration;
21/// let pool_opts = PoolOpts::default()
22///     .with_constraints(PoolConstraints::new(15, 30).unwrap())
23///     .with_reset_connection(false);
24/// ```
25#[derive(Debug, Clone, Eq, PartialEq, Hash)]
26pub struct PoolOpts {
27    constraints: PoolConstraints,
28    reset_connection: bool,
29    check_health: bool,
30}
31
32impl PoolOpts {
33    /// Calls `Self::default`.
34    pub fn new() -> Self {
35        Self::default()
36    }
37
38    /// Creates the default [`PoolOpts`] with the given constraints.
39    pub fn with_constraints(mut self, constraints: PoolConstraints) -> Self {
40        self.constraints = constraints;
41        self
42    }
43
44    /// Returns pool constraints.
45    pub fn constraints(&self) -> PoolConstraints {
46        self.constraints
47    }
48
49    /// Sets whether to reset the connection upon returning it to a pool (defaults to `true`).
50    ///
51    /// Default behavior increases reliability but comes with cons:
52    ///
53    /// * reset procedure removes all prepared statements, i.e. kills prepared statements cache
54    /// * connection reset is quite fast but requires additional client-server roundtrip
55    ///   (might require re-authentication for older servers)
56    ///
57    /// The purpose of the reset procedure is to:
58    ///
59    /// * rollback any opened transactions
60    /// * reset transaction isolation level
61    /// * reset session variables
62    /// * delete user variables
63    /// * remove temporary tables
64    /// * remove all PREPARE statement (this action kills prepared statements cache)
65    ///
66    /// So to increase overall performance you can safely opt-out of the default behavior
67    /// if you are not willing to change the session state in an unpleasant way.
68    ///
69    /// It is also possible to selectively opt-in/out using [`crate::PooledConn::reset_connection`].
70    ///
71    /// # Connection URL
72    ///
73    /// You can use `reset_connection` URL parameter to set this value. E.g.
74    ///
75    /// ```
76    /// # use mysql::*;
77    /// # use std::time::Duration;
78    /// # fn main() -> Result<()> {
79    /// let opts = Opts::from_url("mysql://localhost/db?reset_connection=false")?;
80    /// assert_eq!(opts.get_pool_opts().reset_connection(), false);
81    /// # Ok(()) }
82    /// ```
83    pub fn with_reset_connection(mut self, reset_connection: bool) -> Self {
84        self.reset_connection = reset_connection;
85        self
86    }
87
88    /// Returns the `reset_connection` value (see [`PoolOpts::with_reset_connection`]).
89    pub fn reset_connection(&self) -> bool {
90        self.reset_connection
91    }
92
93    /// Sets whether to check connection health upon retrieving it from a pool (defaults to `true`).
94    ///
95    /// If `true`, then `Conn::ping` will be invoked on a non-fresh pooled connection.
96    ///
97    /// # Connection URL
98    ///
99    /// Use `check_health` URL parameter to set this value. E.g.
100    ///
101    /// ```
102    /// # use mysql::*;
103    /// # use std::time::Duration;
104    /// # fn main() -> Result<()> {
105    /// let opts = Opts::from_url("mysql://localhost/db?check_health=false")?;
106    /// assert_eq!(opts.get_pool_opts().check_health(), false);
107    /// # Ok(()) }
108    /// ```
109    pub fn with_check_health(mut self, check_health: bool) -> Self {
110        self.check_health = check_health;
111        self
112    }
113
114    pub fn check_health(&self) -> bool {
115        self.check_health
116    }
117}
118
119impl Default for PoolOpts {
120    fn default() -> Self {
121        Self {
122            constraints: PoolConstraints::DEFAULT,
123            reset_connection: true,
124            check_health: true,
125        }
126    }
127}
128
129/// Connection pool constraints.
130///
131/// This type stores `min` and `max` constraints for [`crate::Pool`] and ensures that `min <= max`.
132#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
133pub struct PoolConstraints {
134    min: usize,
135    max: usize,
136}
137
138const_assert!(
139    _DEFAULT_POOL_CONSTRAINTS_ARE_CORRECT,
140    PoolConstraints::DEFAULT.min <= PoolConstraints::DEFAULT.max,
141);
142
143pub struct Assert<const L: usize, const R: usize>;
144impl<const L: usize, const R: usize> Assert<L, R> {
145    pub const LEQ: usize = R - L;
146}
147
148#[allow(path_statements)]
149pub const fn gte<const M: usize, const N: usize>() {
150    #[allow(clippy::no_effect)]
151    Assert::<M, N>::LEQ;
152}
153
154impl PoolConstraints {
155    /// Default pool constraints.
156    pub const DEFAULT: PoolConstraints = PoolConstraints { min: 10, max: 100 };
157
158    /// Creates new [`PoolConstraints`] if constraints are valid (`min <= max`).
159    ///
160    /// # Connection URL
161    ///
162    /// You can use `pool_min` and `pool_max` URL parameters to define pool constraints.
163    ///
164    /// ```
165    /// # use mysql::*;
166    /// # fn main() -> Result<()> {
167    /// let opts = Opts::from_url("mysql://localhost/db?pool_min=0&pool_max=151")?;
168    /// assert_eq!(opts.get_pool_opts().constraints(), PoolConstraints::new(0, 151).unwrap());
169    /// # Ok(()) }
170    /// ```
171    pub fn new(min: usize, max: usize) -> Option<PoolConstraints> {
172        if min <= max {
173            Some(PoolConstraints { min, max })
174        } else {
175            None
176        }
177    }
178
179    pub const fn new_const<const MIN: usize, const MAX: usize>() -> PoolConstraints {
180        gte::<MIN, MAX>();
181        PoolConstraints { min: MIN, max: MAX }
182    }
183
184    /// Lower bound of this pool constraints.
185    pub const fn min(&self) -> usize {
186        self.min
187    }
188
189    /// Upper bound of this pool constraints.
190    pub const fn max(&self) -> usize {
191        self.max
192    }
193}
194
195impl Default for PoolConstraints {
196    fn default() -> Self {
197        PoolConstraints::DEFAULT
198    }
199}
200
201impl From<PoolConstraints> for (usize, usize) {
202    /// Transforms constraints to a pair of `(min, max)`.
203    fn from(PoolConstraints { min, max }: PoolConstraints) -> Self {
204        (min, max)
205    }
206}