From 9645a8e1b1c6b06b5658e220b826958f98dfa098 Mon Sep 17 00:00:00 2001
From: Huo Linhe <huolinhe@berrygenomics.com>
Date: Mon, 7 Mar 2016 10:35:50 +0800
Subject: [PATCH] feat(transaction): complete the manual transations

Related functions:
* unqlite_begin
* unqlite_commit
* unqlite_rollback

Cc #1
---
 src/engine/mod.rs         |  2 ++
 src/engine/transaction.rs | 51 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 53 insertions(+)
 create mode 100644 src/engine/transaction.rs

diff --git a/src/engine/mod.rs b/src/engine/mod.rs
index 4667f240..a5df7c6f 100644
--- a/src/engine/mod.rs
+++ b/src/engine/mod.rs
@@ -144,10 +144,12 @@ impl Drop for UnQlite {
 
 pub use self::config::*;
 pub use self::util::*;
+pub use self::transaction::*;
 
 mod openmode;
 mod config;
 mod util;
+mod transaction;
 
 #[cfg(test)]
 #[cfg(feature = "enable-threads")]
diff --git a/src/engine/transaction.rs b/src/engine/transaction.rs
new file mode 100644
index 00000000..b634312f
--- /dev/null
+++ b/src/engine/transaction.rs
@@ -0,0 +1,51 @@
+use super::UnQlite;
+use ffi::{unqlite_begin, unqlite_commit, unqlite_rollback};
+
+/// Manual Transaction Manager
+impl<'transaction> UnQlite {
+    /// 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.
+    ///
+    pub fn begin(&mut self) -> ::Result<()> {
+        error_or!(unsafe { unqlite_begin(self.db) })
+    }
+
+    /// 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).
+    pub fn commit(&mut self) -> ::Result<()> {
+        match error_or!(unsafe { unqlite_commit(self.db) }) {
+            Ok(_) => Ok(()),
+            Err(err) => {
+                let _ = self.rollback();
+                Err(err)
+            }
+        }
+    }
+
+    /// 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(&mut self) -> ::Result<()> {
+        error_or!(unsafe { unqlite_rollback(self.db) })
+    }
+}