1#![doc = include_str!("../README.md")]
2#![cfg_attr(docsrs, feature(doc_cfg))]
3#![deny(
4 nonstandard_style,
5 rust_2018_idioms,
6 rustdoc::broken_intra_doc_links,
7 rustdoc::private_intra_doc_links
8)]
9#![forbid(non_ascii_idents, unsafe_code)]
10#![warn(
11 deprecated_in_future,
12 missing_copy_implementations,
13 missing_debug_implementations,
14 missing_docs,
15 unreachable_pub,
16 unused_import_braces,
17 unused_labels,
18 unused_lifetimes,
19 unused_qualifications,
20 unused_results
21)]
22#![allow(clippy::uninlined_format_args)]
23
24mod config;
25
26use std::sync::atomic::{AtomicUsize, Ordering};
27
28use deadpool::managed::{self, RecycleError};
29use deadpool_sync::SyncWrapper;
30
31pub use deadpool::managed::reexports::*;
32pub use deadpool_sync::reexports::*;
33pub use rusqlite;
34
35deadpool::managed_reexports!(
36 "rusqlite",
37 Manager,
38 managed::Object<Manager>,
39 rusqlite::Error,
40 ConfigError
41);
42
43pub use self::config::{Config, ConfigError};
44
45pub type Connection = Object;
47
48#[derive(Debug)]
52pub struct Manager {
53 config: Config,
54 recycle_count: AtomicUsize,
55 runtime: Runtime,
56}
57
58impl Manager {
59 #[must_use]
62 pub fn from_config(config: &Config, runtime: Runtime) -> Self {
63 Self {
64 config: config.clone(),
65 recycle_count: AtomicUsize::new(0),
66 runtime,
67 }
68 }
69}
70
71impl managed::Manager for Manager {
72 type Type = SyncWrapper<rusqlite::Connection>;
73 type Error = rusqlite::Error;
74
75 async fn create(&self) -> Result<Self::Type, Self::Error> {
76 let path = self.config.path.clone();
77 SyncWrapper::new(self.runtime, move || rusqlite::Connection::open(path)).await
78 }
79
80 async fn recycle(
81 &self,
82 conn: &mut Self::Type,
83 _: &Metrics,
84 ) -> managed::RecycleResult<Self::Error> {
85 if conn.is_mutex_poisoned() {
86 return Err(RecycleError::Message(
87 "Mutex is poisoned. Connection is considered unusable.".into(),
88 ));
89 }
90 let recycle_count = self.recycle_count.fetch_add(1, Ordering::Relaxed);
91 let n: usize = conn
92 .interact(move |conn| conn.query_row("SELECT $1", [recycle_count], |row| row.get(0)))
93 .await
94 .map_err(|e| RecycleError::message(format!("{}", e)))??;
95 if n == recycle_count {
96 Ok(())
97 } else {
98 Err(RecycleError::message("Recycle count mismatch"))
99 }
100 }
101}