Expand description
ConcurrentTx — per-Connection BEGIN CONCURRENT
transaction state (Phase 11.4).
Per docs/concurrent-writes-plan.md:
BEGIN CONCURRENTdoesn’t acquire any locks; writes go to the version chain tagged with the transaction id; reads use snapshot-isolation visibility.
§How this slice does it
Each Connection owns at most one ConcurrentTx at a time.
When the user issues BEGIN CONCURRENT, the connection deep-
clones the database’s tables map into ConcurrentTx::tables
and stores a TxHandle (which advances the
MvccClock to allocate a begin_ts). Subsequent INSERT /
UPDATE / DELETE statements run against the cloned tables
(the executor thinks it’s writing to the live database —
Connection swaps the cloned tables in just for the duration
of each statement). The live Database::tables stays
unchanged until commit.
At COMMIT:
- Diff
tx.tables_at_begin(the immutable BEGIN-time clone) vstx.tables(post-write) to derive a write-set: every(RowID, payload)the transaction changed. - For each row in the write-set, walk the
super::MvStorechain. If any committed version’sbegin > tx.begin_ts, ABORT withcrate::error::SQLRiteError::Busy— some other transaction touched the row after our snapshot. - On success, allocate a
commit_ts, push each write into theMvStoreas a committed version (caps the previous latest version’sendatcommit_ts), apply the writes todb.tables, and run the legacysave_databaseso changes persist via the existing WAL.
ROLLBACK just drops the ConcurrentTx — the cloned tables
are released, the TxHandle drops (unregistering the
transaction from ActiveTxRegistry), and db.tables is
unchanged because we never touched it.
§What this slice doesn’t do (yet)
- Snapshot-isolated reads inside the transaction. Reads
inside
BEGIN CONCURRENTsee the cloned-at-BEGIN state of the tables (because the executor is dispatched againsttx.tables), but they don’t consultMvStoreto filter bybegin_ts. Concurrent writes from outside the tx land ondb.tables, not on our snapshot — so we don’t see them inside the tx. That’s partial snapshot isolation: it isolates correctly under the current “lock the database per statement” mutex, but doesn’t survive once the engine genuinely supports overlapping in-flight transactions reading concurrently. - DDL inside
BEGIN CONCURRENT. v0 rejects with a typed error before the swap, mirroring the plan’s stated non-goal. AUTOINCREMENT. Same — rejected with a typed error.- Persistence of the in-flight write-set across crashes.
The write-set lives entirely in memory until commit. A
crash mid-transaction loses everything — that’s correct
(the transaction never committed), and the legacy WAL
still owns durability of
Database::tablesfor committed data. Phase 11.5 adds the MVCC log-record frame format that lets writes start landing in the WAL pre-commit.
Structs§
- Concurrent
Tx - Per-
Connectionsnapshot ofBEGIN CONCURRENTstate.