sqlsrv/wrconn.rs
1use std::{
2 mem::ManuallyDrop,
3 ops::{Deref, DerefMut},
4 sync::Arc
5};
6
7use rusqlite::{params, Connection};
8
9use super::{InnerWrConn, Shared};
10
11
12/// SQLite connection object that can be used for operations that modify the
13/// database.
14///
15/// The `WrConn` connection will be returned to the
16/// [`ConnPool`](super::ConnPool) connection pool once it is dropped.
17pub struct WrConn {
18 /// The context buffer shared between the connection pool and `WrConn`.
19 pub(super) sh: Arc<Shared>,
20
21 /// The actual connection object.
22 ///
23 /// The connection object is placed in a `ManuallyDrop` so that it doesn't
24 /// get closed (read: dropped) on `Drop`. The connection will be closed
25 /// when it is dropped by [`Shared`] (which is why it must also hold a
26 /// strong reference to `Shared`).
27 pub(super) inner: ManuallyDrop<InnerWrConn>
28}
29
30impl WrConn {
31 /// Add dirt to the writer connection.
32 // ToDo: broken-lint
33 #[allow(clippy::missing_const_for_fn)]
34 pub fn add_dirt(&mut self, weight: usize) {
35 self.inner.dirt = self.inner.dirt.saturating_add(weight);
36 }
37}
38
39impl WrConn {
40 /// Run incremental vacuum.
41 ///
42 /// # Errors
43 /// On error `rusqlite::Error` is returned.
44 pub fn incremental_vacuum(
45 &self,
46 n: Option<usize>
47 ) -> Result<(), rusqlite::Error> {
48 n.map_or_else(
49 || {
50 self
51 .inner
52 .conn
53 .execute("PRAGMA incremental_vacuum;", params![])
54 },
55 |n| {
56 self
57 .inner
58 .conn
59 .execute("PRAGMA incremental_vacuum(?);", params![n])
60 }
61 )
62 .map(|_| ())
63 }
64}
65
66impl Deref for WrConn {
67 type Target = Connection;
68
69 fn deref(&self) -> &Connection {
70 &self.inner.conn
71 }
72}
73
74impl DerefMut for WrConn {
75 fn deref_mut(&mut self) -> &mut Connection {
76 &mut self.inner.conn
77 }
78}
79
80impl Drop for WrConn {
81 /// Return the write connection to the connection pool.
82 fn drop(&mut self) {
83 //
84 // If autovacuum is configured, then check if the dirt level has passed the
85 // watermark before returning write connection.
86 //
87 if let Some(ref autoclean) = self.sh.autoclean {
88 if self.inner.dirt >= autoclean.dirt_threshold {
89 // Did reach/pass the watermark -- perform incremental vacuum.
90 // ToDo: There should be some mechanism to report errors back to the
91 // application.
92 if let Some(num) = autoclean.npages {
93 let num = num.get();
94 let _ = self
95 .inner
96 .conn
97 .execute("PRAGMA incremental_vacuum(?);", params![num]);
98 } else {
99 let _ = self
100 .inner
101 .conn
102 .execute("PRAGMA incremental_vacuum;", params![]);
103 }
104
105 // Reset dirt level after running incremental autovacuum
106 self.inner.dirt = 0;
107 }
108 }
109
110 let mut g = self.sh.inner.lock();
111
112 // Take writer connection out of Self and put it back in ConnPool's Inner
113 // structure.
114 g.conn = Some(unsafe { ManuallyDrop::take(&mut self.inner) });
115 self.sh.signal.notify_one();
116 }
117}
118
119// vim: set ft=rust et sw=2 ts=2 sts=2 cinoptions=2 tw=79 :