Reliability: Buffer, Log & Recovery
How atomicity and durability survive a crash. Stable memory, the buffer policies that decide what recovery must do, the log and its two write rules, checkpoints and dumps, and the warm-restart procedure that rebuilds a consistent database from the log.
01 · Exam
What the papers say about this chapter
An honest word before you invest time here, because this chapter’s status is unusual.
Reliability and recovery is squarely in the syllabus: it gets two lecture decks and 45 slides, and it falls under exam topic 4, “DB architecture and technologies”. But across the fourteen sessions in the question bank — January 2024 to July 2026 — it has never once been the subject of an exercise. The architecture slot was contested fourteen times, and concurrency control took it every time. Its only appearance anywhere in the bank is a three-point theory sub-question in February 2025, asking why long-duration write locks are required.
Zero dedicated exercises in 14 sessions
That is the evidence, and it is why this chapter carries a low derived exam weight. Two conclusions follow, and they point in opposite directions — take both.
Do not spend concurrency-control time here. If revision hours are scarce, chapters 5 to 7 are where the marks are.
Do not skip it either. Everything published on WeBeep is examinable by the stated rules, the professors could set it in any sitting, and — more immediately — the log is the machinery that makes the abort semantics you are examined on in chapter 6 actually work. The last section closes that loop.
The chapter is therefore complete but compact: full coverage, no padding.
02 · Foundation
Stable memory and the reliability manager
Durability promises that committed effects survive “forever”. Since every real storage medium can fail, that promise is an abstraction built on top of ones that can.
Three levels, of increasing (claimed) permanence:
- Main memory — not persistent.
- Mass memory — persistent, but can be damaged.
- Stable memory — cannot be damaged. Plainly an idealisation: in practice stability means a failure probability close to zero, achieved by replication and write protocols.
Replication comes in two forms. On-line: mirroring two disks, or the RAID architectures covered in Computing Infrastructures. Off-line: periodic backup to tape or equivalent — the dump.
The Reliability Manager sits alongside the data path (chapter 1’s diagram) and does three
things: it realizes the transactional commands commit and abort, it orchestrates read/write access
to both data and log pages, and it handles recovery after failures.
03 · Mechanism
Buffer management: STEAL and FORCE
The buffer exists for speed. Its two policy choices are what create the entire recovery problem — this is the most examinable idea in the chapter.
The buffer caches disk blocks as pages in main memory and defers writing them back. Each page carries a transaction counter (how many transactions are using it) and a dirty flag (whether it has been modified and must eventually be aligned to disk). On a dedicated database server, up to 80 % of physical memory may be given to the buffer.
Its primitives:
| Primitive | Effect |
|---|---|
fix | load a page into the buffer, return a reference, increment the use count |
unfix | release the page, decrement the use count |
force | transfer a page to disk synchronously |
setDirty | mark the page modified |
flush | transfer pages to disk asynchronously, when no longer in use |
When fix finds no free page, it must evict one — and which page it is allowed to evict is the
first policy question:
STEAL
The buffer may evict a dirty page even if the transaction that modified it has not committed. Reduces memory pressure — but uncommitted changes can now reach disk, so recovery must be able to UNDO them.
NO-STEAL
Dirty pages of uncommitted transactions stay in memory until commit or rollback. No UNDO needed — but new transactions may block when memory is full.
FORCE
At commit, all the transaction’s modified pages are forced to disk. Simpler recovery — no REDO needed — at the price of slow commits waiting on disk I/O.
NO-FORCE
Committed changes may stay in memory; writing is deferred to a checkpoint or an eviction. Fast, asynchronous commits — but committed data may exist only in RAM when the crash comes, so recovery must be able to REDO.
The pairing to memorise
And the normal default configuration is NO-STEAL, NO-FORCE — so in the common
case the system still needs REDO. Two optimisations round it out: pre-fetching
anticipates loading pages likely to be read (very effective for sequential reads), and
pre-flushing anticipates writing de-allocated pages so that later fix calls are fast.
04 · Mechanism
The log and its records
A sequential file on stable memory recording, as state transitions, what every transaction did.
The log is written sequentially up to its top block — the current instant. If an update transforms object from to , the log records the before-state and the after-state . Inserts and deletes are logged identically, except that an insert record has no before-state and a delete record has no after-state.
| Record | Meaning |
|---|---|
B(T), C(T), A(T) | begin, commit, abort of transaction T |
U(T, O, BS, AS) | update: object O from before-state BS to after-state AS |
I(T, O, AS) | insert: no before-state |
D(T, O, BS) | delete: no after-state |
DUMP, CKPT(T1, …, Tn) | recovery markers — backup taken, checkpoint with the active transactions |
Two operations use it, and they are exact inverses:
- UNDO a transaction: set .
- REDO a transaction: set .
Both are idempotent
and likewise for REDO. This is not a curiosity — it is a requirement. The reliability manager may be in doubt about whether a particular write reached the disk, and idempotence means it can simply apply the action again without checking. Recovery may therefore fail halfway and be re-run from the start.
A concrete log sequence, from a debit transaction:
<BEGIN T1>
<T1, Accounts.balance(account_id=1), old=500, new=400>
<T1, Transactions, inserted(account_id=1, amount=100, type='debit', date=2025-11-13)>
<COMMIT T1> 05 · Rules
Write-ahead log and the commit rule
Two rules govern the ordering of log writes against database writes. Between them they guarantee that whatever the crash timing, recovery has what it needs.
Write-Ahead Log (WAL)
The before-state part of a record must be written to the log before the corresponding
change is made to the database.
⇒ actions can always be undone.
Commit rule
The after-state part must be written to the log before the commit is carried out.
⇒ actions can always be redone.
The commit log record itself is written synchronously, with a force — it is the one write the
system cannot afford to defer, because it is what defines whether the transaction happened.
Since database writes are asynchronous, three timing regimes are possible, and each changes what recovery must do:
| When the database is written | Consequence |
|---|---|
| Entirely before commit | REDO unnecessary — the database already reflects the log |
| Entirely after commit | UNDO unnecessary — nothing uncommitted ever reached disk |
| At arbitrary points | both UNDO and REDO needed — but the buffer manager is free to optimise |
The third is what real systems do, which is why the general recovery algorithm needs both directions. Reading it against the previous section: writing before commit is the STEAL case, writing after commit is the FORCE case, and arbitrary timing is STEAL + NO-FORCE.
06 · Recovery
Checkpoint and dump
Recovery cannot scan the log back to the beginning of time. Two markers bound the work.
A checkpoint is performed periodically to identify a consistent time point. In the simple variant the lectures give:
- Acceptance of all commit and abort requests is suspended.
- All dirty buffer pages belonging to committed transactions are forced to disk — log entries first (if not already forced), then the page.
- The identifiers of transactions still in progress are recorded in a
CKPTrecord, forced to the log. No new transaction may start during this recording. - Normal operation resumes.
The guarantee is therefore: at the checkpoint, everything committed is on disk, and everything half-way is named in a record in stable memory. Real systems soften this — MySQL uses fuzzy checkpointing, gradually writing dirty pages while transactions continue running.
A dump is a complete backup copy of the database, taken typically at night or at weekends, stored in stable memory, with its availability recorded in the log. MySQL’s own backup taxonomy shows the dimensions that matter in practice: physical versus logical (file copy versus SQL export), hot versus cold (server live or stopped), local versus remote, snapshot versus full versus incremental, and full versus point-in-time recovery.
07 · Recovery
Warm restart
Recovery from a soft failure — main memory lost, disk intact. The log is replayed to resolve every in-doubt transaction.
1 · Find the last checkpoint
Trace back through the log to the most recent CKPT record — the last point at which all
committed changes were known to be on disk.
2 · Build the UNDO and REDO sets
Initialise UNDO = the transactions listed as active in the CKPT record, and REDO = ∅.
Then scan forward from the checkpoint to the top of the log:
· on B(Ti) → add Ti to UNDO (it started, so it may need undoing)
· on C(Tj) → remove Tj from UNDO and add it to REDO (it finished, so it needs redoing)
3 · Undo, backwards
Scan backwards from the top of the log to the first action of the oldest transaction in
UNDO, applying undo for every record belonging to a transaction in UNDO. Reverse order
matters: later changes must be rolled back before earlier ones.
4 · Redo, forwards
Scan forwards from the first action of the oldest transaction in REDO to the top of the log,
applying redo for every record belonging to a transaction in REDO. Log order matters here, for
the mirror-image reason.
The lectures’ worked example, which is the shape to reproduce:
B(T1) B(T2) U(T1,O1,B1,A1) I(T1,O2,A2) U(T2,O3,B3,A3) B(T3)
U(T3,O4,B4,A4) D(T3,O5,B5) CKPT(T1,T2,T3) C(T2) B(T4)
U(T4,O6,B6,A6) A(T4) ——— failure
after CKPT: UNDO = {T1,T2,T3} REDO = {}
after C(T2): UNDO = {T1,T3} REDO = {T2}
after B(T4): UNDO = {T1,T3,T4} REDO = {T2}
undo, backwards: (1) O6 = B6 (2) re-insert O5 = B5 (3) O4 = B4
(4) delete O2 (5) O1 = B1
redo, forwards: (6) O3 = A3Note that A(T4) does not remove T4 from UNDO — an aborted transaction still needs its effects
rolled back, exactly like an unfinished one. And notice the delete/insert inversion in steps 2 and 4:
undoing a delete re-inserts, undoing an insert deletes.
A log shows CKPT(T1,T4), then C(T4), then B(T5), then C(T5), then B(T6), then the crash. What are the UNDO and REDO sets?
08 · Recovery
Cold restart, and why strict 2PL needs the log
The harder failure, and then the loop back to chapter 6.
Failures come in three severities:
- Soft failure — part of main memory lost. Requires a warm restart, using the log.
- Hard failure — part of the secondary memory devices lost or failed. Requires a cold restart.
- Disaster — stable memory itself lost, log and dump included. Out of scope here; the province of disaster recovery.
A cold restart proceeds in three moves: restore the data from the most recent dump; re-apply the operations recorded in the log, in log order, up to the failure time; then execute a warm restart from there, undoing whatever remains uncertain.
Which brings us back to where chapter 6 left an argument dangling. Strict two-phase locking holds write locks until commit or rollback, and the justification given there was that otherwise abort processing becomes impossible — the dirty write problem, where T1 aborts after T2 has overwritten the same object and neither transaction’s before-state can be correctly reinstalled.
That argument is really a statement about this chapter’s machinery. What “restoring the state prior to the aborted updates” means is applying the log’s before-states in reverse order. If two transactions’ updates to one object interleave, the log’s before-state for the second is the first’s uncommitted value, and UNDO produces nonsense. Long-duration write locks exist precisely so that the log’s chain of before-states per object never interleaves across transactions.
Load-bearing ideas
- Durability rests on stable memory — an abstraction delivered by replication (mirroring, RAID) and by off-line dumps.
- The buffer’s two policies decide recovery.
STEAL⇒ UNDO necessary;NO-FORCE⇒ REDO necessary. Default is NO-STEAL, NO-FORCE. - The log records state transitions —
B/C/A,U(T,O,BS,AS),I,D, plusDUMPandCKPT. UNDO sets , REDO sets , and both are idempotent so recovery can be re-run. - Two write rules. WAL: before-state to the log before the database changes (so UNDO is possible). Commit rule: after-state to the log before commit (so REDO is possible). The commit record is forced.
- Checkpoint = committed pages flushed + active transactions named. Dump = full backup.
- Warm restart: find the last checkpoint; forward scan building UNDO (seeded from the checkpoint,
grown by
B, drained byC) and REDO; undo backwards; redo forwards. AnA(T)record leaves the transaction in UNDO. - Cold restart = dump + forward log replay + warm restart.
- Exam radar. Nothing in this chapter has been an exercise in 14 sessions. If you carry three things forward, make them the STEAL⇒UNDO / NO-FORCE⇒REDO pairing, the warm-restart set construction, and the log-level reason strict 2PL holds write locks to commit — the one point of contact with a question that has actually been asked.