Package dev.frostlake.transaction
Class TransactionWriteSet
java.lang.Object
dev.frostlake.transaction.TransactionWriteSet
Per-transaction buffer of pending changes — the foundation of the deferred-apply / READ COMMITTED model
(see
docs/acid-snowflake-plan.md). Instead of mutating live storage, DML records changes here:
overlayRows(java.lang.String, dev.frostlake.storage.TableStorage)gives the transaction its OWN view — committed base rows with this write set's updates applied, deletes removed, and inserts appended. So own writes are visible to self, while other transactions' uncommitted writes are not (they live in their own write set, never in the shared base store until commit) — exactly READ COMMITTED.applyTo(dev.frostlake.storage.StorageEngine)flushes the buffer to the base store on COMMIT; simply discarding the write set (never callingapplyTo) IS the ROLLBACK.
TableStorage.getRowId(int)), never by position,
so an interleaving mutation can't make the buffer target the wrong row.
Not yet wired into the executor — this is the tested foundation the Phase-1 DML wiring will build on. Known follow-up: modifying a row this same transaction just inserted (its id is not a base id) is handled by the executor mutating the pending insert directly, not here.
-
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionvoidapplyTo(StorageEngine storage) Flush this write set to the base store (the COMMIT step).voidapplyTo(StorageEngine storage, StreamManager streamManager) Flush this write set to the base store (the COMMIT step): updates, then deletes, then inserts.Begin a statement savepoint (deferred-apply explicit transactions).bufferedChangeRecords(String table, TableStorage base, String captureName) Synthesize the stream change records fortable's buffered (not-yet-committed) changes, exactly asapplyTo(dev.frostlake.storage.StorageEngine)would track them at commit — an update as a DELETE(old)+INSERT(new) pair, a delete as a DELETE(old), an insert as an INSERT(new) — but WITHOUT mutating storage or any stream.The fully-qualified names of every table this write set holds a buffered insert, update, or delete for.voidclear()copy()A statement savepoint: a copy of this write set's structure (Rows are shared — they're built fresh per change and never mutated in place).voidEnd the statement savepoint without restoring (the statement succeeded).voidforgetTable(String table) Discard every pending change (inserts, updates, deletes) fortable— used when the table is dropped or replaced within this transaction.The tables this write set touched, each with the lock its first touch acquired.booleanTrue if this transaction has deleted the base row with the given stable id.booleanisEmpty()overlayRows(String table, TableStorage base) This transaction's view oftable: committed base rows with this write set's updates applied and deletes removed, then this write set's inserts appended.pendingInserts(String table) A snapshot of the rows this transaction has inserted intotable(empty if none); the indices line up withsetPendingInsert(java.lang.String, int, dev.frostlake.storage.Row)/removePendingInsert(java.lang.String, int).pendingUpdate(String table, long rowId) The pending new value for the base row with this stable id, or null if it isn't updated here.voidrecordDelete(String table, long rowId) Record deletion of an existing base row (by stable id); supersedes any pending update of that row.voidrecordInsert(String table, Row row) voidrecordTruncate(String table, List<Long> committedRowIds) Record a TRUNCATE oftablewithin this transaction: every committed base row (given bycommittedRowIds) becomes a pending delete and any not-yet-committed inserts/updates for the table are dropped.voidrecordUpdate(String table, long rowId, Row newValue) Record a new value for an existing base row (by stable id).voidremovePendingInsert(String table, int index) Drop a not-yet-committed inserted row (in-transaction DELETE of a row this txn just inserted).voidrestoreFrom(TransactionWriteSet savepoint) Restore this write set's contents from acopy()savepoint (statement-level rollback).voidrollbackToSavepoint(WriteSetSavepoint savepoint) Restore exactly the entries the failed statement touched, and the lock map.voidsetPendingInsert(String table, int index, Row newRow) Replace a not-yet-committed inserted row (in-transaction UPDATE of a row this txn just inserted).
-
Constructor Details
-
TransactionWriteSet
public TransactionWriteSet()
-
-
Method Details
-
beginStatementSavepoint
Begin a statement savepoint (deferred-apply explicit transactions). -
endStatementSavepoint
public void endStatementSavepoint()End the statement savepoint without restoring (the statement succeeded). -
rollbackToSavepoint
Restore exactly the entries the failed statement touched, and the lock map. -
recordInsert
-
recordUpdate
Record a new value for an existing base row (by stable id). No-op if this txn already deleted it. -
recordDelete
Record deletion of an existing base row (by stable id); supersedes any pending update of that row. -
getTableLocks
The tables this write set touched, each with the lock its first touch acquired. -
recordTruncate
Record a TRUNCATE oftablewithin this transaction: every committed base row (given bycommittedRowIds) becomes a pending delete and any not-yet-committed inserts/updates for the table are dropped. The transaction then sees the table as empty, while a rollback still restores the committed rows — the base store is cleared only when these deletes are applied at commit. Clearing the base store directly instead would let this transaction's buffered inserts reappear on next read. -
forgetTable
Discard every pending change (inserts, updates, deletes) fortable— used when the table is dropped or replaced within this transaction. The table (and its rows) will not exist after commit, so flushing these buffered writes would fail against missing storage; dropping them here also stops a drop-then-recreate of the same name in one transaction from resurrecting the pre-drop rows. -
isDeleted
True if this transaction has deleted the base row with the given stable id. -
pendingUpdate
The pending new value for the base row with this stable id, or null if it isn't updated here. -
pendingInserts
A snapshot of the rows this transaction has inserted intotable(empty if none); the indices line up withsetPendingInsert(java.lang.String, int, dev.frostlake.storage.Row)/removePendingInsert(java.lang.String, int). -
setPendingInsert
Replace a not-yet-committed inserted row (in-transaction UPDATE of a row this txn just inserted). -
removePendingInsert
Drop a not-yet-committed inserted row (in-transaction DELETE of a row this txn just inserted). -
overlayRows
This transaction's view oftable: committed base rows with this write set's updates applied and deletes removed, then this write set's inserts appended.baseis read once; callers hold the engine lock soscan()andgetRowIds()stay index-aligned. -
bufferedChangeRecords
public List<StreamRecord> bufferedChangeRecords(String table, TableStorage base, String captureName) Synthesize the stream change records fortable's buffered (not-yet-committed) changes, exactly asapplyTo(dev.frostlake.storage.StorageEngine)would track them at commit — an update as a DELETE(old)+INSERT(new) pair, a delete as a DELETE(old), an insert as an INSERT(new) — but WITHOUT mutating storage or any stream. Old images are read frombaseby stable id; every record is tagged withcaptureName(the bare source-table name, to match committed records) and carries a negative, per-record id that cannot collide with a real (positive) committed record id. Lets a stream read inside a transaction fold this transaction's own uncommitted DML into its net delta; empty when nothing is buffered fortable. -
applyTo
Flush this write set to the base store (the COMMIT step). -
applyTo
Flush this write set to the base store (the COMMIT step): updates, then deletes, then inserts. WhenstreamManageris non-null, change-tracking (CDC) events are emitted HERE — at apply/commit time, not at DML time — so streams observe only committed changes and a rolled-back write set emits nothing. Pre-change values for updates/deletes are read before the row is mutated. -
changedTables
The fully-qualified names of every table this write set holds a buffered insert, update, or delete for. -
isEmpty
public boolean isEmpty() -
clear
public void clear() -
copy
A statement savepoint: a copy of this write set's structure (Rows are shared — they're built fresh per change and never mutated in place). Pairs withrestoreFrom(dev.frostlake.transaction.TransactionWriteSet)for statement-level rollback (a failed statement inside an explicit transaction undoes only itself and keeps the txn open). -
restoreFrom
Restore this write set's contents from acopy()savepoint (statement-level rollback).
-