Skip to main content

noxu_db/
lock_mode.rs

1//! Lock modes for read operations.
2//!
3
4/// Lock mode for read operations.
5///
6/// Specifies the locking behavior for a read operation. Controls isolation
7/// level and whether locks are acquired.
8///
9///
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
11pub enum LockMode {
12    /// Use the default isolation level for the cursor or transaction.
13    ///
14    /// For transactional operations, this is typically read-committed.
15    /// For non-transactional operations, this is read-uncommitted.
16    #[default]
17    Default,
18
19    /// Read without acquiring locks (dirty reads).
20    ///
21    /// Reads may return data that is currently being modified by another
22    /// transaction and may be rolled back. Provides maximum concurrency
23    /// but minimal isolation.
24    ReadUncommitted,
25
26    /// Read with read-committed isolation.
27    ///
28    /// A read lock is acquired but released when the cursor moves or
29    /// the read operation completes. Prevents dirty reads but allows
30    /// non-repeatable reads.
31    ReadCommitted,
32
33    /// Read-modify-write: acquire write lock on read.
34    ///
35    /// Acquires a write lock immediately, even though the operation is a read.
36    /// Use this when you intend to modify the record after reading it, to
37    /// avoid deadlocks caused by lock upgrades.
38    Rmw,
39}
40
41impl LockMode {
42    /// Returns whether this mode allows dirty reads.
43    pub fn allows_dirty_reads(&self) -> bool {
44        matches!(self, LockMode::ReadUncommitted)
45    }
46
47    /// Returns whether this mode acquires a write lock.
48    pub fn acquires_write_lock(&self) -> bool {
49        matches!(self, LockMode::Rmw)
50    }
51
52    /// Returns whether this mode provides read-committed isolation.
53    pub fn is_read_committed(&self) -> bool {
54        matches!(self, LockMode::ReadCommitted | LockMode::Default)
55    }
56}
57
58#[cfg(test)]
59mod tests {
60    use super::*;
61
62    #[test]
63    fn test_default() {
64        assert_eq!(LockMode::default(), LockMode::Default);
65    }
66
67    #[test]
68    fn test_allows_dirty_reads() {
69        assert!(LockMode::ReadUncommitted.allows_dirty_reads());
70        assert!(!LockMode::Default.allows_dirty_reads());
71        assert!(!LockMode::ReadCommitted.allows_dirty_reads());
72        assert!(!LockMode::Rmw.allows_dirty_reads());
73    }
74
75    #[test]
76    fn test_acquires_write_lock() {
77        assert!(LockMode::Rmw.acquires_write_lock());
78        assert!(!LockMode::Default.acquires_write_lock());
79        assert!(!LockMode::ReadUncommitted.acquires_write_lock());
80        assert!(!LockMode::ReadCommitted.acquires_write_lock());
81    }
82
83    #[test]
84    fn test_is_read_committed() {
85        assert!(LockMode::Default.is_read_committed());
86        assert!(LockMode::ReadCommitted.is_read_committed());
87        assert!(!LockMode::ReadUncommitted.is_read_committed());
88        assert!(!LockMode::Rmw.is_read_committed());
89    }
90
91    #[test]
92    fn test_equality() {
93        assert_eq!(LockMode::Default, LockMode::Default);
94        assert_ne!(LockMode::Default, LockMode::Rmw);
95    }
96
97    #[test]
98    fn test_clone() {
99        let mode1 = LockMode::Rmw;
100        let mode2 = mode1;
101        assert_eq!(mode1, mode2);
102    }
103
104    #[test]
105    fn test_copy() {
106        let mode1 = LockMode::ReadCommitted;
107        let mode2 = mode1;
108        assert_eq!(mode1, mode2);
109    }
110
111    #[test]
112    fn test_debug() {
113        let mode = LockMode::Rmw;
114        let debug = format!("{:?}", mode);
115        assert_eq!(debug, "Rmw");
116    }
117}