workshop private

← all creations

Skew

viz · created 2026-09-11

Two transactions on one schedule, rows drawn as version chains, and an isolation dial. Both transactions read the same world, both check the same rule, both are correct — and the rule is false the moment they both commit. Snapshot isolation stops two of the three anomalies here and cannot stop the third, because the third is the one where they write different rows.

architectureinterview-prepcanvas

Two transactions, side by side, time running down the page. Every row in the little database is a version chain — a write never overwrites anything, it appends — and every read walks that chain looking for the newest version its snapshot is allowed to see. Change the isolation level and the only things that change are when the snapshot is taken and what a conflict does. Every anomaly on screen falls out of those two knobs.

Three schedules, chosen because the same picture gives three different answers:

The overlap slider slides the second transaction later in time. Drag it down and the anomalies close one by one — not because the level changed, but because the transactions stopped being concurrent, and at full separation the application’s own guard finally sees the world the first transaction left behind and refuses to write. Every anomaly here is a timing bug wearing a correctness costume.

The 3 × 3 table in the corner recomputes at whatever overlap you have dialled in; its cells are clickable, so it doubles as the navigation. At full overlap it settles into the table worth remembering:

read committedsnapshotserializable
write skew✓ (abort)
lost update✓ (abort)✓ (abort)
read skew

Snapshot isolation catches exactly the anomalies where both transactions write the same row — there it can hold a lock and shoot the second writer. Write skew is the shape where they write different rows, so there is no collision to detect, and the only defense left is watching the read-write dependencies between them and refusing the commit that closes a cycle. That last row is why “repeatable read” in PostgreSQL is not serializable, and why Oracle’s SERIALIZABLE is snapshot isolation wearing the wrong name.

The two rw: arrows under the rows are that dependency graph being built live. When both arrows exist — T1 read something T2 wrote, T2 read something T1 wrote — the cycle marker lights up. Under SI it is decoration; under SSI it is the thing that kills the second committer.

Reuse

src/skew.js is a framework-free ES module with no timers and no rendering:

The MVCC core is small enough to read in one sitting: visibleIndex is the whole visibility rule, the write path holds the row lock and the first-updater-wins abort, and findCycle is the SSI check.

Gotchas