tarantool_module/
transaction.rs

1//! Transaction management
2//!
3//! For general information and examples, see
4//! [Transaction control](https://www.tarantool.io/en/doc/latest/book/box/atomic_index/#atomic-atomic-execution).
5//!
6//! Observe the following rules when working with transactions:
7//!
8//! 👉 **Rule #1**
9//! The requests in a transaction must be sent to a server as a single block.
10//! It is not enough to enclose them between begin and commit or rollback.
11//! To ensure they are sent as a single block: put them in a function, or put them all on one line, or use a delimiter
12//! so that multi-line requests are handled together.
13//!
14//! 👉 **Rule #2**
15//! All database operations in a transaction should use the same storage engine.
16//! It is not safe to access tuple sets that are defined with `{engine='vinyl'}` and also access tuple sets that are
17//! defined with `{engine='memtx'}`, in the same transaction.
18//!
19//! 👉 **Rule #3**
20//! Requests which cause changes to the data definition – create, alter, drop, truncate – are only allowed with
21//! Tarantool version 2.1 or later. Data-definition requests which change an index or change a format, such as
22//! `space_object:create_index()` and `space_object:format()`, are not allowed inside transactions except as the first
23//! request.
24//!
25//! See also:
26//! - [Transaction control](https://www.tarantool.io/en/doc/latest/book/box/atomic/)
27//! - [Lua reference: Functions for transaction management](https://www.tarantool.io/en/doc/latest/reference/reference_lua/box_txn_management/)
28//! - [C API reference: Module txn](https://www.tarantool.io/en/doc/latest/dev_guide/reference_capi/txn/)
29
30use crate::error::TransactionError;
31
32/// Begin a transaction in the current fiber.
33///
34/// A transaction is attached to caller fiber, therefore one fiber can have
35/// only one active transaction.
36///
37/// - `f` - function will be invoked within transaction
38///
39/// Returns result of function `f` execution. Depending on the function result:
40/// - will **commit** - if function completes successfully
41/// - will **rollback** - if function completes with any error
42pub fn start_transaction<T, E, F>(f: F) -> Result<T, E>
43where
44    F: FnOnce() -> Result<T, E>,
45    E: From<TransactionError>,
46{
47    if unsafe { ffi::box_txn_begin() } < 0 {
48        return Err(TransactionError::AlreadyStarted.into());
49    }
50
51    let result = f();
52    match &result {
53        Ok(_) => {
54            if unsafe { ffi::box_txn_commit() } < 0 {
55                return Err(TransactionError::FailedToCommit.into());
56            }
57        }
58        Err(_) => {
59            if unsafe { ffi::box_txn_rollback() } < 0 {
60                return Err(TransactionError::FailedToRollback.into());
61            }
62        }
63    }
64    result
65}
66
67pub(crate) mod ffi {
68    use std::ffi::c_void;
69    use std::os::raw::c_int;
70
71    extern "C" {
72        pub fn box_txn() -> bool;
73        pub fn box_txn_begin() -> c_int;
74        pub fn box_txn_commit() -> c_int;
75        pub fn box_txn_rollback() -> c_int;
76        pub fn box_txn_alloc(size: usize) -> *mut c_void;
77    }
78}