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
use crate::error::{Result, Wrap};
use crate::ffi::{unqlite_begin, unqlite_commit, unqlite_rollback};
use crate::UnQLite;

/// Manual Transaction Manager
///
///
pub trait Transaction {
    /// Manually begin a write-transaction on the specified database handle.
    ///
    /// Begin a write-transaction on the specified database handle. If a write-transaction has
    /// already been opened, this function is a no-op.
    /// Tip: For maximum concurrency, it is preferable to let UnQLite start the transaction for you
    /// automatically. An automatic transaction is started each time upper-layers or client code
    /// request a store, delete or an append operation.
    ///
    fn begin(&self) -> Result<()>;

    /// Commit all changes to the database.
    ///
    /// Commit all changes to the database and release the exclusive lock. In other words, make
    /// sure that all changes reaches the disk surface.
    ///
    /// **Note**: Normally, a call to this routine is not necessary since transactions are committed
    /// automatically by the engine when the database is closed after lifetime end unless the
    /// `disable_auto_commit()` option is set. In which case, you should manually call
    /// `commit()`. Otherwise, the database is rolled back.
    ///
    /// *Tip*: For maximum concurrency, it is recommended that you commit your transaction manually
    /// as soon as you have no more insertions. Also, for very large insertions (More than 20000),
    /// you should call `commit()` periodically to free some memory (A new transaction is
    /// started automatically in the next insertion).
    fn commit(&self) -> Result<()>;

    /// Rollback a write-transaction on the specified database handle.
    ///
    /// If a write transaction is open, then all changes made within the transaction are reverted
    /// and the current write-transaction is closed (Dropping all exclusive locks on the target
    /// database, deletion of the journal file, etc.). Otherwise this routine is a no-op.
    ///
    fn rollback(&self) -> Result<()>;
}

impl Transaction for UnQLite {
    fn begin(&self) -> Result<()> {
        wrap_raw!(self, begin)
    }

    fn commit(&self) -> Result<()> {
        wrap_raw!(self, commit).map_err(|err| {
            let _ = self.rollback();
            err
        })
    }

    fn rollback(&self) -> Result<()> {
        wrap_raw!(self, rollback)
    }
}

#[cfg(test)]
#[cfg(feature = "enable-threads")]
mod tests {
    use super::Transaction;
    use crate::Config;
    use crate::UnQLite;
    #[test]
    fn transaction() {
        let uq = UnQLite::create_temp().disable_auto_commit();
        uq.begin().expect("begin");
        uq.commit().expect("commit");
        uq.rollback().expect("rollback");
    }
}