Skip to main content

sochdb_storage/
transaction.rs

1// SPDX-License-Identifier: AGPL-3.0-or-later
2// SochDB - LLM-Optimized Embedded Database
3// Copyright (C) 2026 Sushanth Reddy Vanagala (https://github.com/sushanthpy)
4//
5// This program is free software: you can redistribute it and/or modify
6// it under the terms of the GNU Affero General Public License as published by
7// the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// This program is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU Affero General Public License for more details.
14//
15// You should have received a copy of the GNU Affero General Public License
16// along with this program. If not, see <https://www.gnu.org/licenses/>.
17
18//! Unified Transaction Coordinator
19//!
20//! This module defines the canonical transaction management interface for SochDB.
21//! It consolidates the functionality of multiple transaction managers:
22//!
23//! ## Implementation Guide
24//!
25//! **The live concurrency contract is multi-reader, single-writer.** Production
26//! isolation and durability run through `DurableStorage` (`database.rs` /
27//! `durable_storage.rs`): lock-free MVCC snapshot reads via `ConcurrentMvcc`,
28//! writes serialized by a single-writer lock (`acquire_writer`, "serialize WAL
29//! commits across processes"), and SSI conflict validation via `MvccManager`.
30//! WAL crash recovery is wired here (`txn_wal` / `RecoveryStats` /
31//! `durability_contract`). There is **no concurrent-writer (wired SSI) path on
32//! the live engine** — do not assume one exists.
33//!
34//! SochDB contains three transaction-manager types; only the first is on the
35//! live path:
36//!
37//! ### 1. `DurableStorage` + `MvccManager` (durable_storage.rs) — LIVE / PRODUCTION
38//!
39//! The actual production path. Single-writer write coordination + MVCC snapshot
40//! reads, with `MvccManager` providing SSI rw-antidependency validation and the
41//! storage layer providing WAL durability and crash recovery.
42//!
43//! ### 2. `MvccTransactionManager` (wal_integration.rs) — STANDALONE, NOT WIRED
44//!
45//! A complete, self-contained manager (WAL durability, MVCC snapshot isolation,
46//! optional SSI, group commit, version-chain GC). Despite being feature-rich it
47//! has **no functional caller in the engine** — `DurableStorage` does not use
48//! it — so it is **not** the production path. Use it only if you explicitly
49//! construct and own one; it does not participate in the live database's
50//! single-writer concurrency contract. (Its SSI read/write tracking is correct
51//! as of the Task 1B id-divergence fix, but it remains unwired.)
52//!
53//! ```ignore
54//! use sochdb_storage::wal_integration::MvccTransactionManager;
55//! let txm = MvccTransactionManager::new("wal.log", |_key, _value| Ok(()))?;
56//! let txn_id = txm.begin(IsolationLevel::Serializable)?;
57//! txm.write(txn_id, b"key", b"value")?;
58//! txm.commit(txn_id)?;
59//! ```
60//!
61//! ### 3. `TransactionManager` (mvcc_snapshot.rs) — `#[deprecated]`
62//!
63//! Minimal snapshot isolation without durability. Unit tests / ephemeral
64//! in-memory only. **Not for production workloads requiring crash recovery.**
65//!
66//! ## Transaction Coordinator Trait
67//!
68//! The `TransactionCoordinator` trait unifies the common interface:
69
70use sochdb_core::Result;
71
72// Re-export TransactionMode from durable_storage (canonical definition)
73pub use crate::durable_storage::TransactionMode;
74
75/// Isolation level for transactions
76#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
77pub enum IsolationLevel {
78    /// Read committed - see all committed data
79    ReadCommitted,
80    /// Snapshot isolation (default) - consistent point-in-time view
81    #[default]
82    SnapshotIsolation,
83    /// Serializable via SSI - full serializability guarantee
84    Serializable,
85}
86
87/// Transaction handle returned by begin operations
88#[derive(Debug, Clone)]
89pub struct TransactionHandle {
90    /// Unique transaction ID
91    pub txn_id: u64,
92    /// Snapshot timestamp for MVCC visibility
93    pub snapshot_ts: u64,
94    /// Transaction mode
95    pub mode: TransactionMode,
96    /// Isolation level
97    pub isolation_level: IsolationLevel,
98}
99
100/// Unified transaction coordinator interface
101///
102/// This trait defines the canonical API for transaction management.
103/// All new transaction manager implementations should implement this trait.
104///
105/// ## Durability Contract
106///
107/// Implementations MUST document their durability guarantees:
108/// - `Durable`: Committed transactions survive crash (WAL + fsync)
109/// - `Ephemeral`: No durability guarantee (in-memory only)
110pub trait TransactionCoordinator: Send + Sync {
111    /// Begin a new transaction with default isolation level
112    fn begin(&self) -> Result<TransactionHandle>;
113
114    /// Begin a transaction with specified isolation level
115    fn begin_with_isolation(&self, isolation: IsolationLevel) -> Result<TransactionHandle>;
116
117    /// Begin a transaction with specified mode (for optimization)
118    fn begin_with_mode(&self, mode: TransactionMode) -> Result<TransactionHandle>;
119
120    /// Commit a transaction
121    ///
122    /// For durable implementations, this includes fsync.
123    /// Returns the commit timestamp on success.
124    fn commit(&self, txn_id: u64) -> Result<u64>;
125
126    /// Abort a transaction
127    ///
128    /// Discards all changes made by the transaction.
129    fn abort(&self, txn_id: u64) -> Result<()>;
130
131    /// Get the current snapshot timestamp for a transaction
132    fn get_snapshot_ts(&self, txn_id: u64) -> Option<u64>;
133
134    /// Check if a transaction is still active
135    fn is_active(&self, txn_id: u64) -> bool;
136
137    /// Record a read for SSI tracking
138    fn record_read(&self, txn_id: u64, key: &[u8]);
139
140    /// Record a write for SSI tracking
141    fn record_write(&self, txn_id: u64, key: &[u8]);
142
143    /// Get durability guarantee of this implementation
144    fn durability(&self) -> DurabilityLevel;
145}
146
147/// Durability guarantee level
148#[derive(Debug, Clone, Copy, PartialEq, Eq)]
149pub enum DurabilityLevel {
150    /// Fully durable with WAL + fsync
151    Durable,
152    /// Group commit (durable after batch fsync)
153    GroupCommit,
154    /// No durability (in-memory only)
155    Ephemeral,
156}
157
158/// Recovery statistics returned after crash recovery
159#[derive(Debug, Clone, Default)]
160pub struct RecoveryStats {
161    /// Number of transactions recovered
162    pub transactions_recovered: usize,
163    /// Number of individual writes recovered
164    pub writes_recovered: usize,
165    /// The commit timestamp after recovery
166    pub commit_ts: u64,
167}
168
169// =============================================================================
170// Re-exports for convenience
171// =============================================================================
172
173// Note: The canonical implementation is MvccTransactionManager from wal_integration
174// pub use crate::wal_integration::MvccTransactionManager;
175
176#[cfg(test)]
177mod tests {
178    use super::*;
179
180    #[test]
181    fn test_transaction_mode_tracking() {
182        assert!(TransactionMode::ReadWrite.tracks_reads());
183        assert!(TransactionMode::ReadWrite.tracks_writes());
184
185        assert!(!TransactionMode::ReadOnly.tracks_reads());
186        assert!(!TransactionMode::ReadOnly.tracks_writes());
187
188        assert!(!TransactionMode::WriteOnly.tracks_reads());
189        assert!(TransactionMode::WriteOnly.tracks_writes());
190    }
191
192    #[test]
193    fn test_isolation_level_default() {
194        assert_eq!(IsolationLevel::default(), IsolationLevel::SnapshotIsolation);
195    }
196}