Upsert, delete with tombstones, compaction
A real store does the same in files and index structures instead of a list, and compacts in the background.
Documents change while people search. Stores handle this by appending a new row and marking the old one dead (a tombstone), clearing the dead rows later (compaction), and, when copies exist, by making a reader wait until its copy has seen the write.
Change the code and press Run (Ctrl+Enter). Predict what will happen first, then break it on purpose and read what changes. Your edits are saved and match the lesson page.
Ready for more? This phase has 5 hands-on exercises with automatic checks.
Practice questions
Write the code in the editor, run it, then open the model answer to compare.
Write dead_ratio(rows) where rows is a list of (id, alive) pairs. Return the share of dead rows as a number between 0 and 1, and 0 for an empty list. Print it with 2 decimals for 5 rows with 2 dead.
Write compact(rows) that returns the rows with the dead ones removed, order kept. Print the ids that remain.
Explain it without notes
What is a tombstone and why do stores use them?
What does compaction do, and what does it cost?
Why is upsert safer than delete followed by insert?
What is "reading your own writes" and how can a replica break it?
Expected output
loaded: rows=4 live=4 dead=0 top2=A,B
deleted A: rows=4 live=3 dead=1 top2=B,D
B moved: rows=5 live=3 dead=2 top2=D,C
after compaction: rows=3 live=3 dead=0 top2=D,C