Date: 2026-05-29
Time: 10:00
SSIDatabase._snapshotsnapshot materializes the entire database state as it would appear to a reader at a specific point in time. It produces a point-in-time dictionary by scanning every key in the MVCC store and selecting the version visible at snapshotts. This is the mechanism that gives SSI transactions a consistent, frozen view of the database — the "snapshot" in Snapshot Isolation.
It exists to support two distinct needs:
1. Predicate reads (read_predicate) — the transaction needs the full key-value space to evaluate arbitrary predicate functions.
2. Commit-time validation — during commit, the database re-evaluates predicates against the *current* state and builds hypothetical snapshots for constraint checking.
snapshot_ts must be a valid timestamp from the database's monotonic counter. No enforcement exists — passing an arbitrary integer won't raise, but will produce a semantically meaningless result.committs <= snapshotts. Each key maps to the value from the *latest* such version.| Parameter | Type | Description |
|-----------|------|-------------|
| snapshot_ts | int | The logical timestamp defining the visibility horizon. Only versions committed at or before this timestamp are included. |
Edge case: if snapshot_ts is 0 or lower than any committed version, the result is an empty dict — the database "didn't exist yet."
A dict[str, Any] mapping keys to their visible values. Deleted keys and keys with no version at or before snapshot_ts are excluded (not present in the dict, not mapped to None). The caller gets a detached copy — the only obligation is understanding that this is a frozen view, not a live reference.
1. Initialize an empty result dict.
2. Iterate over every key that has *ever* been written to the MVCC store (self._store).
3. For each key, delegate to visiblevalue(key, snapshotts), which scans all versions of that key and returns the value from the latest version with committs <= snapshotts. If that version is a DELETED sentinel, it returns (None, writertxid).
4. If the returned value is not None (meaning the key exists and isn't deleted at this timestamp), add it to the result dict.
5. Return the result.
The in val, = self.visiblevalue(...) discards the writer transaction ID — _snapshot doesn't need causal tracking, only the values.
None. This is a pure read operation — no mutations to self._store, no timestamp increments, no dependency graph updates.
None. The method cannot raise under normal use. visiblevalue handles missing keys gracefully by returning (None, None). If self.store contains malformed version tuples, the unpacking in visible_value would raise a ValueError, but that indicates a corrupted store, not a recoverable error.
Three call sites in commit and read_predicate:
1. readpredicate — called with tx.starttimestamp to build the transaction's consistent view before evaluating the predicate function. The result is merged with buffered writes/deletes to reflect uncommitted local changes.
2. Phantom detection in commit — called with self.nexttimestamp (the *current* logical time, strictly greater than all committed timestamps) to get the latest committed state. This is compared against the predicate's original result to detect phantoms.
3. Constraint validation in commit — called with self.nexttimestamp again, then mutated in-place with the transaction's buffered writes and deletes to build a hypothetical post-commit state for constraint checking.
Caller obligation: understand that this snapshot does not include uncommitted writes from any active transaction. If you need the transaction-local view, you must overlay tx.writes and tx.deletes yourself (as read_predicate and constraint validation both do).
self.store — the MVCC version store, structured as dict[key, list[tuple[committs, value, tx_id]]].self.visiblevalue — performs the per-key version resolution with linear scan over the version chain.DELETED sentinel — visiblevalue converts deleted keys to None values, so snapshot never needs to handle the sentinel directly.This is an O(K × V) operation where K is the number of distinct keys and V is the average number of versions per key, since visiblevalue does a linear scan over all versions. For a production system this would be a concern, but for a reference implementation demonstrating SSI concepts, correctness over performance is the right trade-off.
write-skew-detection/ssidatabase.py:visiblevalue — The per-key MVCC version resolution that snapshot delegates to; understanding its linear scan and deletion handling is essentialwrite-skew-detection/ssidatabase.py:readpredicate — The primary consumer of _snapshot, showing how predicate locks and phantom detection work togetherwrite-skew-detection/ssidatabase.py:commit — Where snapshot is used at commit time for both phantom re-evaluation and constraint validation against hypothetical statesnapshot-isolation-vs-ssi — How plain Snapshot Isolation allows write skew, and why SSI adds read-write conflict detection and predicate locks on topmvcc-version-chain-design — Alternative version chain structures (linked lists, index-organized) and how they affect snapshot materialization costsnapshot-returns-detached-copy — snapshot returns a new dict each call; callers in readpredicate and commit mutate it freely without corrupting the MVCC storesnapshot-excludes-uncommitted-writes — snapshot only reflects committed versions; all three call sites manually overlay tx.writes and tx._deletes when they need the transaction-local viewsnapshot-uses-next-timestamp-for-current-state — During commit validation, snapshot(self.nexttimestamp) is used to capture all committed versions because nexttimestamp is strictly greater than any existing committssnapshot-discards-writer-identity — snapshot drops the writer txid returned by visiblevalue; causal dependency tracking is handled elsewhere (in read and read_predicate)