Transaction Module
src/transaction/ enforces the Atomicity and Isolation parts of ACID. It combines MVCC
with strict two-phase locking so reads and writes can proceed concurrently without
violating correctness.
Main Components
| Type | Role |
|---|---|
TransactionManager | Creates/commits/aborts transactions, assigns txn & command ids, coordinates WAL. |
Transaction | Stores state, held locks, undo chain, and cached snapshot. |
TxnContext / TxnRuntime | Execution-time wrapper exposing MVCC + locking helpers. |
LockManager | Multi-granularity locking (IS/IX/S/SIX/X) with deadlock detection. |
TransactionSnapshot | Tracks xmin/xmax/active_txns for visibility checks. |
Workflow
SessionContextcallsTransactionManager::beginto create a transaction.- Each SQL statement builds a
TxnRuntime, yielding a fresh command id and snapshot. - Operators call
TxnContext::lock_table/lock_rowto obey strict 2PL. TableHandle::insert/delete/updaterecords undo, acquires locks, and emits WAL viaTxnContext.- Commit: write a
Commitrecord → flush depending onsynchronous_commit→ release locks. - Abort: walk the undo list, write CLRs, restore heap/index state, release locks.
MVCC Details
TupleMetastores inserting/deleting txn ids and command ids.read_visible_tuplechecks snapshots and, if needed, rewinds to the latest visible version.- Isolation levels:
- Read Uncommitted – minimal snapshot caching.
- Read Committed – refresh snapshot each command to avoid dirty reads.
- Repeatable Read / Serializable – capture the snapshot once; RR releases shared locks at statement end, Serializable holds them to commit to avoid phantoms.
- UPDATE skips versions created by the same
(txn_id, command_id)to avoid looping back over freshly inserted tuples.
Locking
- Multi-granularity hierarchy: table-level IS/IX/S/SIX/X plus row-level S/X.
- Deadlock detection:
LockManagermaintains a wait-for graph and periodically chooses a victim (usually the longest waiter). - Release policy: exclusive/intent locks stay until commit; RR drops shared row locks at statement end, Serializable waits until commit.
Interactions
- ExecutionContext – all helpers (lock acquisition, visibility checks, undo logging)
are exposed here, so physical operators never touch
LockManagerdirectly. - StorageEngine – handles call
TxnContextbefore mutating heaps/indexes; MVCC metadata lives inTupleMeta. Deletes and updates now push the affected index keys into the undo chain so heap/index WAL stay in lockstep. - Recovery – Begin/Commit/Abort records emitted here drive ARIES undo/redo.
- Background – MVCC vacuum reads
TransactionManager::oldest_active_txn()to computesafe_xmin.
Teaching Ideas
- Change
DatabaseOptions::default_isolation_leveland compare SELECT behaviour under RC vs RR. - Write a unit test that deadlocks two transactions and watch
LockManagerpick a victim. - Implement statement-level snapshot refresh or Serializable Snapshot Isolation (SSI) as an advanced exercise.
Lab Walkthrough (à la CMU 15-445)
- Warm-up – Start two sessions, run
BEGIN; SELECT ...;under RC vs RR, and trace which snapshotTxnRuntimeinstalls by loggingtxn.current_command_id(). - MVCC visibility – Extend the
transaction_tests.rssuite with a scenario wheretxn1updates a row whiletxn2reads it. InstrumentTupleMetaprinting so students see how(insert_txn_id, delete_txn_id)change as versions are linked. - Undo tracing – Force an abort after a multi-index UPDATE. Watch the undo stack
entries unfold:
Insertremoves the new version + index entries,Deleterestores the old version + keys. Map each step to the WAL records that are written. - Crash drill – Add
panic!()right afterTransactionManager::commitis called but before locks are released. Reboot, run recovery, and inspect the loser list; students can connect the dots between undo actions, CLRs, and ARIES theory.
Further reading: MVCC and 2PL