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 :