quill_sql/transaction/
runtime.rs

1use crate::error::{QuillSQLError, QuillSQLResult};
2use crate::storage::page::TupleMeta;
3use crate::transaction::{
4    IsolationLevel, LockMode, Transaction, TransactionManager, TransactionSnapshot,
5};
6use crate::utils::table_ref::TableReference;
7
8use crate::storage::page::RecordId;
9
10/// Runtime wrapper that bundles a transaction handle with its manager, snapshot, and command id.
11/// Execution operators interact with this struct instead of juggling raw references, which keeps
12/// MVCC/2PL details inside the transaction layer.
13pub struct TxnRuntime<'a> {
14    txn: &'a mut Transaction,
15    manager: &'a TransactionManager,
16    snapshot: TransactionSnapshot,
17    command_id: crate::transaction::CommandId,
18}
19
20impl<'a> TxnRuntime<'a> {
21    pub fn new(manager: &'a TransactionManager, txn: &'a mut Transaction) -> Self {
22        let command_id = txn.begin_command();
23        let snapshot = match txn.isolation_level() {
24            IsolationLevel::RepeatableRead | IsolationLevel::Serializable => {
25                if let Some(existing) = txn.snapshot().cloned() {
26                    existing
27                } else {
28                    let snap = manager.snapshot(txn.id());
29                    txn.set_snapshot(snap.clone());
30                    snap
31                }
32            }
33            IsolationLevel::ReadCommitted | IsolationLevel::ReadUncommitted => {
34                let snap = manager.snapshot(txn.id());
35                txn.clear_snapshot();
36                snap
37            }
38        };
39        Self {
40            txn,
41            manager,
42            snapshot,
43            command_id,
44        }
45    }
46
47    pub fn id(&self) -> crate::transaction::TransactionId {
48        self.txn.id()
49    }
50
51    pub fn command_id(&self) -> crate::transaction::CommandId {
52        self.command_id
53    }
54
55    pub fn snapshot(&self) -> &TransactionSnapshot {
56        &self.snapshot
57    }
58
59    pub fn transaction(&self) -> &Transaction {
60        self.txn
61    }
62
63    pub fn transaction_mut(&mut self) -> &mut Transaction {
64        self.txn
65    }
66
67    pub fn manager(&self) -> &TransactionManager {
68        self.manager
69    }
70
71    pub fn is_visible(&self, meta: &TupleMeta) -> bool {
72        self.snapshot.is_visible(meta, self.command_id, |txn_id| {
73            self.manager.transaction_status(txn_id)
74        })
75    }
76
77    pub fn lock_table(&self, table: TableReference, mode: LockMode) -> QuillSQLResult<()> {
78        self.manager
79            .acquire_table_lock(self.txn, table.clone(), mode)
80            .map_err(|e| QuillSQLError::Execution(format!("lock error: {}", e)))
81    }
82
83    pub fn try_lock_row(
84        &self,
85        table: TableReference,
86        rid: RecordId,
87        mode: LockMode,
88    ) -> QuillSQLResult<bool> {
89        self.manager
90            .try_acquire_row_lock(self.txn, table, rid, mode)
91    }
92
93    pub fn record_shared_row_lock(&self, table: TableReference, rid: RecordId) {
94        self.manager
95            .record_shared_row_lock(self.txn.id(), table, rid);
96    }
97
98    pub fn remove_row_key_marker(&self, table: &TableReference, rid: RecordId) {
99        self.manager
100            .remove_row_key_marker(self.txn.id(), table, rid);
101    }
102
103    pub fn try_unlock_shared_row(
104        &self,
105        table: &TableReference,
106        rid: RecordId,
107    ) -> QuillSQLResult<()> {
108        self.manager
109            .try_unlock_shared_row(self.txn.id(), table, rid)
110    }
111
112    pub fn unlock_row(&self, table: &TableReference, rid: RecordId) {
113        self.manager.unlock_row(self.txn.id(), table, rid);
114    }
115}