Recovery Post-Crash
Concept. Recovery preserves committed changes and removes unfinished work after a crash. Committed work that never flushed is missing, so durability is at risk. Uncommitted work that did flush is present, so atomicity is at risk. Recovery fixes both in two passes over one log. The forward pass, REPLAY, re-applies every logged change top to bottom, redoing every row, committed or not, to rebuild the exact state at the crash. The backward pass, UNDO, then reverses every transaction still unfinished at the crash, with no COMMIT or ABORT in the log. A transaction that already aborted needs no undo, because the replay re-applied its rollback. Committed work survives the replay, which is durability; unfinished work is undone, which is atomicity. This repeat-history algorithm is ARIES, from IBM, and it leaves the database fully consistent, ready for new traffic.
Intuition. When the server crashes mid-rush, the log shows Mickey, Minnie, and Daffy were all mid-Premium-purchase. The forward pass replays all three in case their account-table pages never flushed, and notes that Mickey and Minnie COMMITted but Daffy did not. The backward pass then reverses Daffy's charge, because his transaction never finished. Mickey and Minnie stay Premium, Daffy is refunded, and the database is back online.
Figure: After a crash, recovery answers one question from the WAL: which work survives and which is thrown awayA crash interrupts running transactions. When the server reboots it must answer one question, which work survives and which gets thrown away. The whole answer lives in the WAL, the durable record of every change. Committed transactions are kept, green; transactions that never committed are thrown away, orange; and the log, the source of truth, decides which is which. Color key: green = committed work that survives, orange = uncommitted work that is thrown away, grey = the durable log that decides.
Figure 1. A crash leaves recovery one question: which work survives, which gets thrown away. The whole answer is in the **WAL**. Committed transactions are kept, green; transactions that never committed are reversed, orange. Recovery is the procedure that reads the log and enforces both.
Recovery on One Log: Down, Then Up
The whole algorithm fits on one WAL. The example: start state A=10, B=20, C=30, D=40, E=50, update f(x) = x * 1.2, five transactions, then the server crashes. Recovery reads the log down to replay, then up to undo.
Figure: Crash recovery on one WAL: a forward replay rebuilds the crash state, then a backward undo reverses the unfinished transactionsA WAL drawn top to bottom in time order, with the page log columns: Time, Txn, Action, Var, old value, new value. Start state A=10, B=20, C=30, D=40, E=50, update f(x)=x times 1.2. The figure runs in five stages. First the log and the start state. Then a red CRASH line marks where the server stopped. Then the REPLAY pass runs down the left re-applying every logged row, original writes and the in-log abort rows alike, rebuilding the exact crash state A=12, B=20, C=43.2, D=48, E=60. Then the UNDO pass runs up the right and reverses only the uncommitted transactions newest-first: E 60 to 50, C 43.2 to 36, C 36 to 30. Finally the consistent state A=12, B=20, C=30, D=48, E=50. T1 and T4 committed and are kept; T2 aborted explicitly and was already rolled back in the log; T3 and T5 never committed and are undone. Color key: violet = the replay and undo passes and the rows undo removes, blue = durability, the committed work the replay keeps, orange = atomicity, the uncommitted work the undo removes, grey = rows left untouched, red = the crash.
| Time | Txn | Action | Var | old value | new value |
|---|---|---|---|---|---|
| 1 | T1 | W | A | 10 | 12 |
| 2 | T3 | W | C | 30 | 36 |
| 3 | T1 | COMMIT | |||
| 4 | T2 | W | B | 20 | 24 |
| 5 | T4 | W | D | 40 | 48 |
| 6 | T2 | W-abort | B | 24 | 20 |
| 7 | T2 | ABORT | |||
| 8 | T3 | W | C | 36 | 43.2 |
| 9 | T4 | COMMIT | |||
| 10 | T5 | W | E | 50 | 60 |
Figure 2. Recovery as two passes over one log:
- REPLAY (down): re-apply every row exactly as it happened, redos and undos alike, to rebuild the state at the crash.
- UNDO (up): then undo every transaction still unfinished at the crash, with no COMMIT or ABORT row, reversing its writes newest-first. T2 aborted before the crash, so the replay already rolled it back.
The undone rows are scattered, not a trailing block: T4 even commits late, after T3's writes, yet survives. What gets undone depends on commit status, not position in the log.
Why down before up. After a crash you cannot tell which data pages reached disk, so there is no consistent state to roll back from yet. The forward pass replays the whole log first and rebuilds the exact state at the crash, a known starting point. Only then does the backward pass peel off the transactions that never finished. Run the other way, undoing against half-written pages, and the result is undefined.
No separate analysis pass. You might expect a first pass just to work out who committed. You do not need one: as the forward pass reads the log, it marks each transaction finished when it meets that transaction's COMMIT or ABORT. By the crash it already knows which never finished, exactly the ones the backward pass undoes. The tracking is free. (Checkpoints are the one exception, see Optimizations below.)
After the Crash: Fix the Disk from the WAL
On reboot, RAM is gone with every in-progress change. The disk survived, but the pages that flushed before the crash are a half-written mix: some committed writes never reached disk, so committed work is missing; some uncommitted writes did reach disk, so wrong values are sitting there.
Figure: Just after the crash: RAM is gone and the disk is an inconsistent mix of flushed and unflushed workThe instant after the crash. RAM is gone, every in-flight change with it. The disk survived but it is not consistent: it holds whatever was written before the power died. Some committed writes never flushed, so a committed value is missing. Some uncommitted writes did flush, so an uncommitted value is sitting on disk. The durable WAL is untouched and still holds the full history, which is how recovery sorts the mess out. Color key: red = RAM, now empty, green = the durable disk that is not yet consistent, violet = the durable, sequential WAL that survived and drives recovery.
| Disk · not consistent |
|---|
| A=12 flushed |
| D=40 stale |
| E=60 wrong |
| WAL · durable, sequential |
|---|
| A: 10→12 |
| C: 30→36 |
| D: 40→48 |
| C: 36→43.2 |
| E: 50→60 |
Figure 3. Just after the crash. RAM, red, is gone with every in-flight change. The disk, green, survived but is not consistent: a committed write is missing, and an uncommitted write is wrongly present. The WAL, violet, is untouched, and it is the only thing recovery can use, because RAM holds nothing.
Why can the WAL fix all of this? Because it survived the crash, and it holds every change as an old and a new value. The new values redo the committed writes that never flushed; the old values undo the uncommitted writes that did. RAM held the only other copy and it is gone, so the WAL is the sole source of truth. Not one byte of the repair comes from RAM.
Recovery Guarantees
Recovery restores the ACID guarantees across a crash: committed work survives (durability), unfinished work vanishes (atomicity), the rules hold (consistency), and rerunning it lands on the same state (repeatability). This safety has a cost.
Figure: Recovery restores two ACID guarantees across a crash: durability from the replay, atomicity from the undo pass, both resting on the write-ahead ruleTwo of the ACID guarantees fall out of the two passes. Durability, the D icon in violet, comes from the replay: committed work is replayed and never undone, so it survives any failure. Atomicity, the A icon in blue, comes from the undo pass: a transaction is all or nothing, so unfinished work is reversed across a crash. Both rest on the write-ahead rule at the base: the log reaches the disk before the data page, so the log is always enough to finish the story. Color key: violet = durability from replay, blue = atomicity from undo, grey = the write-ahead rule both rest on.
Figure 4. Two ACID guarantees fall out of the two passes, in the order the passes run. Durability, the violet D, comes from the replay: once you see COMMIT, that work is replayed and never undone, so it survives any failure. Atomicity, the blue A, comes from the undo pass: a transaction is all or nothing, so unfinished work is reversed. Both rest on the write-ahead rule at the base, the log reaching disk before the data.
What Recovery Costs
-
Time: Can take minutes to hours for large databases.
-
I/O: Must read the WAL since the last checkpoint.
-
Availability: Database offline during recovery.
-
Complexity: Requires careful implementation.
Optimizations
Checkpointing. Periodically flush all dirty pages to disk. That limits how far back recovery must go: replay can start from the last checkpoint instead of the start of the log. The trade-off is checkpoint overhead against recovery speed.
Checkpoints are the one case where the live-transaction tracking needs its own quick scan. Instead of replaying from the start of the log, recovery scans from the last checkpoint to rebuild the table of live transactions and find where to start replaying. Without checkpoints, the forward pass starts at the beginning and the tracking is free, built as it reads.
Practice Questions
Test your understanding.
-
Why does the forward pass run before the backward pass?
-
What if the system crashes during recovery?
-
How does recovery know which transactions were unfinished at crash time?