Keep the old versions, and readers and writers stop fighting. Every write forges a new version stamped with the time it committed; a reader carries a start time Ts and sees, for each item, the last version committed before Ts — a stable past that never blocks and never shifts underneath it. Down the center, data flows: the commit log goes in, the snapshot resolves, the consistent read comes out. The blue team builds the version chains and proves them against a replay of the log; the red team makes a reader ignore its own clock.
source D. P. Reed, Naming and Synchronization in a Decentralized Computer System, MIT Ph.D. thesis (1978) — dspace.mit.edu/handle/1721.1/16279; formalized by Bernstein & Goodman, "Multiversion Concurrency Control" (ACM TODS, 1983). Rendered, not quoted.
Nothing is overwritten. Each item is a chain of versions, each stamped val@commitTs. A read is not a lock — it is a lookup: the reader's rule is as-of Ts = the newest version whose commit time is strictly below its start time.
For the current reader, which version each chain resolves to (green):
| item | chain (val@commitTs) | reader sees |
|---|
Reed's 1978 insight: give every object a versioned, immutable past, and synchronization stops being a fight over the present. Each reader owns a moment and the moment holds still.
That mechanism is the engine under the-snapshot-isolation, and the default concurrency model of PostgreSQL, Oracle, and MySQL InnoDB. Each sphere is the next one's premise.
The blue team's live check: recompute every reader's snapshot and confirm it equals a replay of the commit log up to that reader's Ts, and that garbage-collecting shadowed versions changes none of them. If red tampers, this badge is where it shows.
The input is an append-only commit log: each committed write records an item, a value, and the commit timestamp at which it became visible. Four transactions, seven writes:
| commitTs | txn | writes |
|---|---|---|
| 0 | init | x=10, y=20, z=30 |
| 10 | T1 | x=11 |
| 20 | T2 | y=21 |
| 30 | T3 | x=12, z=31 |
A write never touches an existing version — it appends a new one. Old versions stay put so old readers keep their view. That is the whole trick, and it is what feeds the panel below.
Snapshot read: for each item, the newest version committed before Ts. No locks — the reader never waits, and a write committing after Ts is invisible to it.
Change the reader — each snapshot is resolved live from the chains and checked against a replay of the log, never looked up.
What the machine produces, proven: all 4 readers get a consistent snapshot that equals an independent replay of the commit log up to their Ts — R_a→{x10,y20,z30}, R_b→{x11,y20,z30}, R_c→{x11,y21,z30}, R_d→{x12,y21,z31}. Versions older than the oldest active reader (Ts=15) are garbage-collected — exactly one, x@0 — and every snapshot is byte-identical after. Reads never block; a read-only txn never conflicts.
The blue team's witness (left) confirms these live; the red team (right) tries to make a reader see the future.
And the past is not free: long-running readers pin old versions, blocking garbage collection — the bloat/vacuum problem. First-committer-wins still aborts concurrent writers. MVCC ends the read-write fight; it does not end the write-write one, and it does not give you serializability.
"MVCC means nothing ever waits." Cut. Readers never block and never abort — but two writers to the same row still conflict, and first-committer-wins aborts the loser.
"Snapshot isolation is serializable." Cut. It forbids dirty/non-repeatable reads but allows write skew and read-only anomalies — strictly weaker than serializable.
"Old versions are free." Kept, corrected. They cost storage and a garbage collector (Postgres VACUUM); a single old reader can stall the whole cleanup.
The red team's move: delete the as-of Ts rule so every reader reads the latest version, ignoring its own start time. A write committed after the reader began leaks in — a non-repeatable read. The blue team's witness (window 7) is watching.
Drop the as-of rule and R_b (Ts=15) reads x=12 — a value T3 committed at Ts=30, long after R_b began. The witness recomputes, the snapshots no longer match the log replay, and it turns red. Nothing is faked; the attack is real and it is caught.