Log-based recovery and checkpoints
How a database survives a crash with atomicity and durability: the write-ahead log (start, update with old and new value, commit, abort, checkpoint, compensation records), the two write-ahead rules, the buffer policies steal and force and what each makes necessary (undo, redo), immediate against deferred modification, simple checkpoints, recovery by repeating history (redo pass, undo pass), the quick redo-list and undo-list rule used in exam questions and the case where it fails, idempotence when the system crashes during recovery, and shadow paging and ARIES in outline; every table is produced by running a small database through crashes and recovering it.
Why it exists
A transaction promises two things that a crash can break. Atomicity: all of its changes or none. Durability: once it has committed, its changes survive. But the database lives in two places. The disk keeps data safely but is slow, so changes are made in memory buffers and written out later. When the machine crashes, the memory is lost: the disk may then hold half of an uncommitted transaction's work (a page was written out early) and may lack the work of a transaction that already committed (its pages were not yet written). The system needs a record, kept safely, of what every transaction did, so that after a crash it can undo the unfinished work and redo the finished work. That record is the log.
Prerequisites
You need the four properties of a transaction (transactions and ACID), and the idea that a rolled-back transaction is undone by restoring the values it overwrote, which is only safe when nobody else has touched them (strict schedules, obtained by strict two-phase locking). Everything on this page assumes strict schedules: a value written by an unfinished transaction is not read or overwritten by another.
Precise definitions
Failures. A transaction failure (a logical error, a deadlock victim) affects one transaction. A system crash (power, operating system) loses the memory but not the disk. A media failure destroys the disk; the remedy is a backup plus the archived log, and it is not treated here. The model of this page is the system crash, with stable storage (the disk and the log on it) assumed to survive.
The log is a sequence of records appended in order and written to stable storage. In the notation of the textbook of Silberschatz, Korth and Sudarshan, a transaction writes:
| record | written when |
|---|---|
<Ti start> | begins |
<Ti, X, V1, V2> | changes item from the old value to the new value (the update record) |
<Ti commit> | commits |
<Ti abort> | has been completely rolled back |
<checkpoint L> | a checkpoint, where lists the transactions that were active |
<Ti, X, V> | while undoing: restored to (a compensation, or redo-only, record) |
The old value is what undo uses; the new value is what redo uses.
The write-ahead rules.
- Write-ahead logging (WAL): before a modified page is written to the database on disk, the log records that describe its changes must already be on stable storage. Otherwise a crash could leave an uncommitted change on the disk with no record of the old value.
- Commit rule: a transaction counts as committed only after its commit record, and with it every earlier record of the log, is on stable storage. Otherwise a crash could lose a transaction that was reported as committed.
Buffer policies. Steal: the buffer manager may write a page that contains uncommitted changes to disk (to free a frame). No steal: it may not. Force: at commit, every page the transaction changed is written to disk before the commit completes. No force: commit writes only the log; the pages follow later. Real systems use steal and no force, because they are the fastest.
What each policy makes necessary. Steal means an uncommitted value can be on the disk after a crash, so undo information is needed. No force means a committed value can be missing from the disk after a crash, so redo information is needed.
Immediate and deferred modification. In immediate modification the changes reach the buffer (and possibly the disk) as the transaction runs; the log needs old and new values (UNDO/REDO). In deferred modification nothing is changed in the database until the transaction commits: its writes are only logged (new value only, <Ti, X, V>) and held in a private workspace, and are applied after the commit record is on the log. An uncommitted value never reaches the disk, so only redo is ever needed (NO-UNDO/REDO).
Checkpoint (simple form). The system writes the log to stable storage, writes every modified page to disk, and then appends <checkpoint L>. After a checkpoint, everything done by transactions that had already committed is on the disk, so recovery need not look at the log before the checkpoint for them.
Recovery by repeating history (the algorithm of the textbook), run after a crash on the stable log:
- Redo pass. Find the last checkpoint record. Set the undo-list to its list . Scan forward from it: redo every update (and compensation) record by writing the new value; when
<Ti start>is read, add to the undo-list; when<Ti commit>or<Ti abort>is read, remove . - Undo pass. Scan backward from the end of the log. For every update record of a transaction in the undo-list, write the old value and append a compensation record
<Ti, X, V1>; when<Ti start>of a transaction in the undo-list is reached, append<Ti abort>and remove it. Stop when the undo-list is empty.
Idempotence. Writing a value is idempotent: doing it twice equals doing it once. So recovery can be started again, from the beginning, if the system crashes while recovering.
How it works
One history, event by event
One history: log records, the log forced to disk, memory and disk: start
Computed by a script, not typed| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | crash | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| event | |||||||||||||
| log record written | |||||||||||||
| log on disk (records) | |||||||||||||
| memory (current values) | |||||||||||||
| disk |
Step 0
Items A = 100, B = 200, C = 300 on the disk. Three transactions run; the log is kept on stable storage only up to the 'log on disk' mark. A step adds one event.
Look at three things in the table. First, the log on disk mark lags behind the log: a record is forced only at a commit, a checkpoint, or when a page it describes is written out. Second, the memory and disk lines differ: after commits, is in memory only (no force); after event 10 the disk holds written by , which never commits (steal). Third, the last update, writing , is in the volatile tail and is lost with the memory: recovery will never hear of it, and it need not, because it never reached the disk (the page could only be written after its log record was forced).
Recovery of that crash
Recovery by repeating history: redo pass, then undo pass: start
Computed by a script, not typed| step | pass | record read | action | undo-list | disk | record appended |
|---|---|---|---|---|---|---|
| 1 | ||||||
| 2 | ||||||
| 3 | ||||||
| 4 | ||||||
| 5 | ||||||
| 6 |
Step 0
Stable log (10 records): <T1 start> <T1, A, 100, 90> <T2 start> <T2, B, 200, 250> <T1 commit> <checkpoint {T2}> <T3 start> <T3, C, 300, 310> <T2, A, 90, 120> <T2 commit>. Disk after the crash: A = 90, B = 250, C = 310. The last checkpoint is record 6: its list says T2 was active, so the undo-list starts as {T2}. The redo pass reads the records after it.
The last checkpoint lists as active, so the undo-list starts as {T2}. The redo pass repeats everything after the checkpoint, including the update of that is going to be undone (this is what "repeating history" means) and the update of , which was never on the disk. At the end of the redo pass, is out of the undo-list (its commit record was read) and is in it (no commit record). The undo pass walks back, restores and writes the compensation record and <T3 abort>. The result, , , , is exactly the work of the committed transactions and .
The quick rule for exam questions
For a log without rollbacks, the same final database follows from two lists:
- undo-list: the transactions that have a start record but no commit record. Restore their old values, scanning the log backward.
- redo-list: the transactions that committed after the last checkpoint. Write their new values, scanning forward.
- Transactions that committed before the last checkpoint need nothing: the checkpoint wrote their pages.
A transaction that was active at the checkpoint and committed after it is in the redo-list (its updates after the checkpoint may be missing from the disk; the ones before it were written by the checkpoint, and redoing them again does no harm). Undo comes first and redo second: an item may have been written by a committed transaction and then by an unfinished one.
Crashing after every event: what recovery has to do: start
Computed by a script, not typed| crash point | records on disk | redo list | undo list | done before the checkpoint | disk at the crash | after recovery | = committed work? |
|---|---|---|---|---|---|---|---|
| after event 1: T1 starts | |||||||
| after event 2: T1 writes A = 90 | |||||||
| after event 3: T2 starts | |||||||
| after event 4: T2 writes B = 250 | |||||||
| after event 5: T1 commits | |||||||
| after event 6: checkpoint | |||||||
| after event 7: T3 starts | |||||||
| after event 8: T3 writes C = 310 | |||||||
| after event 9: T2 writes A = 120 | |||||||
| after event 10: page C written to disk | |||||||
| after event 11: T2 commits | |||||||
| after event 12: T3 writes B = 260 |
Step 0
The history of the previous tables, crashed after each event in turn (the stable log is what had been forced by then). For each crash the table shows the redo and undo lists, the disk before recovery and the database after it.
The table crashes the history of the first table after every event. The redo and undo lists change as commits and the checkpoint reach the stable log; in this history nothing at all is on stable storage before the first commit, so a crash in the first four events leaves a disk that was never touched, and recovery has nothing to do. In all twelve cases both procedures give the committed work.
Deferred against immediate modification
Immediate against deferred modification on one crash: start
Computed by a script, not typed| scheme | log at the crash | disk at the crash | log record shape | recovery | database afterwards |
|---|---|---|---|---|---|
| immediate modification | |||||
| deferred modification |
Step 0
The same two transactions: T1 writes A = 90 and commits; T2 writes B = 250, has not committed, and the crash comes when the page of B is written out (immediate scheme) or could have been (deferred scheme). Items start as A = 100, B = 200.
The two schemes meet the same crash. With immediate modification the page of reached the disk before committed, so the disk holds an uncommitted value and the log must supply the old value . With deferred modification 's write never left the log, so there is nothing to undo, the log records need only the new value, and recovery only redoes. The price of deferral: every write must be kept in a private workspace, and a transaction must be able to read its own writes from there.
Why steal and no force force the design
Steal and force: which crash states need undo and which need redo: start
Computed by a script, not typed| buffer policy | crash states | with uncommitted data on disk | with committed data missing | undo needed | redo needed |
|---|---|---|---|---|---|
| steal, no force | |||||
| steal, force | |||||
| no steal, no force | |||||
| no steal, force (the commit step writes all pages as one step) | |||||
| no steal, force (pages forced one at a time, then the commit record) |
Step 0
Two transactions, T1 (writes A and B, then commits) and T2 (writes C, then commits), and every crash point of every legal sequence of events, including the buffer manager writing a modified page to disk at any moment its policy allows. Each row is one buffer policy.
The table enumerates every crash state of two small transactions under each buffer policy. Steal produces states with uncommitted data on the disk (undo needed) and no force produces states with committed data missing (redo needed); a policy that forbids both needs neither. The last row is a warning: forcing pages one at a time before the commit record is not atomic, and a crash in the middle leaves part of the transaction on the disk, so undo is needed again. The "neither undo nor redo" row is therefore only true if the commit can switch all of a transaction's pages at once; that is what shadow paging provides, at a high price (see below).
Each ingredient is necessary
A check with deliberately broken variants confirms that nothing in the design is decoration: if the write-ahead rule is dropped (pages written before their log records), some crashes leave a stolen value on the disk with no old value to restore; recovery with only a redo pass, or only an undo pass, is wrong on roughly one random history in six. The log must reach the disk before the page; the commit record must reach the disk before the commit is reported.
Crash during recovery
Every action of the recovery passes is a write of a value to the disk or an append to the log. The compensation records written during the undo pass make a partly finished undo look like a transaction that was rolled back partway, and the next recovery handles it by undoing the same updates again. The check stopped recovery after every single action and ran it again: the result was the same database every time. In an exam this is the statement "recovery is idempotent: a crash during recovery is handled by running recovery again".
Shadow paging and ARIES (quoted)
Shadow paging keeps two page tables: the current one, used by the running transaction, and the shadow one, which points to the pages as they were before the transaction. A write goes to a new copy of the page. Commit makes the current table the shadow table with one atomic write. No log is needed and a crash needs no undo or redo (the shadow table is simply used), but the pages scatter over the disk, old pages must be reclaimed, and concurrent transactions are hard to support, so it is rarely used. ARIES is the recovery method of most real systems: it uses steal and no force, write-ahead logging, a sequence number on every log record and on every page, an analysis pass (to rebuild the list of active transactions and modified pages), a redo pass that repeats history and an undo pass that writes compensation records, exactly the structure above plus the bookkeeping that makes it fast. These two paragraphs are textbook content; they are not computed by the tools of this page.
Worked examples
EX 1Redo list and undo list
EasyThe stable log is: <T1 start>, <T1, A, 5, 15>, <T1 commit>, <T2 start>, <T2, B, 7, 17>, <checkpoint {T2}>, <T3 start>, <T3, C, 9, 19>, <T2 commit>, <T4 start>, <T4, D, 1, 2>, <T3 commit>, and then the system crashes.
committed before the checkpoint: nothing to do. was active at the checkpoint and committed after it, and started and committed after it: redo and . has no commit record: undo . The redo pass reads the six records after the checkpoint.
EX 2The database after recovery
MediumItems start as , , , , and the disk at the crash holds , , , (the checkpoint wrote and ; the page of was stolen).
Undo first: wrote from 1 to 2, so write . Then redo: 's update is before the checkpoint and already on the disk (writing it again is harmless); 's update gives . The result is , , , : the committed work of , , and nothing of . The repeating-history algorithm gives the same, and appends <T4, D, 1> and <T4 abort> to the log.
EX 3Which rule was broken?
Medium(a) A page holding an uncommitted change of is written to disk, and the machine crashes before the log record of that change was forced. The disk holds a new value and the log has no record of the old one: nothing can undo it. The write-ahead logging rule was broken. (b) A transaction is told "committed" and the machine crashes before its commit record reached the disk. After the restart there is no commit record, so recovery undoes the transaction: a committed transaction has been lost. The commit rule was broken.
EX 4Typical questions
GATE level(a) "A transaction committed before the last checkpoint. After a crash, is it redone?" No: the checkpoint wrote its pages. (b) "A transaction active at the checkpoint commits after it. In which list is it?" The redo-list. (c) "Which of steal and no force makes undo necessary?" Steal; no force makes redo necessary. (d) "Does the deferred scheme need undo?" No: an uncommitted value never reaches the database. (e) "What if the system crashes while recovering?" Recovery is run again; redo and undo are idempotent. (f) "Which values does an update record hold?" Both the old (for undo) and the new (for redo).
Cheat box
Cheat box
- Update record: old value (undo) and new value (redo). Redo goes forward, undo goes backward.
- WAL: log before page. Commit: log (with the commit record) before reporting commit.
- Steal implies undo. No force implies redo. Deferred modification: redo only.
- Simple checkpoint: log forced, all modified pages written,
checkpoint Llogged. Committed before it: nothing to do. - Redo-list: committed after the last checkpoint. Undo-list: no commit record. Undo first, redo second.
- Full algorithm: redo pass repeats history from the checkpoint, undo pass writes compensation records and abort records.
- A crash during recovery is harmless: run recovery again.
Traps and GATE patterns
Connections
Builds on
Across subjects
No cross-subject links yet.
The log is what makes atomicity and durability true. Undo by before-images is correct only for strict schedules, which strict two-phase locking produces. Steal and no force are buffer-management decisions of the same kind as the write policies of a cache (cache replacement and write policies): write-back against write-through, with a log added because a database cannot lose a committed update.
PYQs
3 previous year questions from your book. I re-solved each one myself (1 by running or simulating, 2 by reasoning only); the book's key is shown next to my answer. All PYQs
Suppose a database system crashes again while recovering from a previous crash. Assume checkpointing is not done by the database either during the transactions or during recovery. Which of the following statements is/are correct?
- (a)The system cannot recover any further.
- (b)The same undo and redo list will be used while recovering again.
- (c)The database will become inconsistent.
- (d)All the transactions that are already undone and redone will not be recovered again.
Consider a simple checkpointing protocol and the following set of operations in the log. (Start, T4); (write, T4, y, 2, 3); (Start, T1); (commit, T4); (write, T1, z, 5, 7); (check point); (Start, T2); (write, T2, x, 1, 9); (commit, T2); (start, T3); (write, T3, z, 7, 2); If a crash happens now and the system tries to recover using both undo and redo operations, what are the contents of the undo list and the redo list?
- (a)Undo T3, T1; Redo T2
- (b)Undo T3, T1; Redo T2, T4
- (c)Undo: none; redo: T2, T4, T3, T1
- (d)Undo T3, T1; T4; Redo: T2
Consider the following log sequence of two transactions on a bank account, with initial balance 12000, that transfer 2000 to a mortgage payment and then apply a 5% interest. 1. T1 start 2. T1 B old=12000 new=10000 3. T1 M old=0 new=2000 4. T1 commit 5. T2 start 6. T2 B old=10000 new=10500 7. T2 commit Suppose the database system crashes just before log record 7 is written. When the system is restarted, which one statement is true of the recovery procedure?
- (a)We must redo log record 6 to set B to 10500
- (b)We must undo log record 6 to set B to 10000 and then redo log records 2 and 3.
- (c)We need not redo log records 2 and 3 because transaction T1 has committed.
- (d)We can apply redo and undo operations in arbitrary order because they are idempotent DATABASE MANAGEMENT SYSTEM
Self-check
Question 1
Log: <T1 start>, <T1, A, 10, 20>, <T2 start>, <T2, B, 30, 40>, <T1 commit>, <checkpoint {T2}>, <T3 start>, <T3, C, 50, 60>, <T2 commit>, then a crash. Which transactions are redone and which are undone?
Show answerHide
Redo (active at the checkpoint, committed after it). committed before the checkpoint: nothing. Undo (no commit record). The redo pass reads the three records after the checkpoint.
Question 2
Why must the log record of an update reach the disk before the page does?
Show answerHide
If the page is written first and the machine crashes, the disk holds a new value of a possibly uncommitted transaction and no record of the old value exists to undo it.
Question 3
In which recovery scheme is undo never needed, and what does it cost?
Show answerHide
Deferred modification: nothing reaches the database before the commit record is on the log. It costs a private workspace for each transaction's writes (and reads must look there first).
Revision card
One-screen revision
- Log record: start, update (item, old, new), commit, abort, checkpoint with the active list, compensation (item, restored value).
- WAL and commit rules. Steal needs undo, no force needs redo; deferred modification needs only redo.
- Recovery: redo forward from the last checkpoint (repeat history, build the undo-list), undo backward with compensation and abort records.
- Quick rule: redo = committed after the checkpoint, undo = no commit record, committed before the checkpoint = nothing. Not for logs with finished rollbacks.
- Recovery is idempotent.
References
- ·Silberschatz, Korth, Sudarshan, Database System Concepts (7th edition), Chapter 19 (Recovery System)
- ·Elmasri, Navathe, Fundamentals of Database Systems (7th edition), Chapter 22 (Database Recovery Techniques)
Verification
scripts/enum-checks/db_recovery_check.py: 1500 random histories of a small database (2 to 4 transactions, 4 items, strict write locks, steal with the write-ahead rule, no force, rollbacks that run to the end, simple checkpoints, a lost log tail) were crashed and recovered; the reference looks only at the commit records of the stable log (initial values plus the writes of committed transactions in log order). Recovery by repeating history was correct in every case, also with all checkpoint records removed (the checkpoint only shortens the scan), also when run twice, and also when the system crashed in the middle of recovery at EVERY action (6792 crash points) and recovery was run again. The exam-style rule (undo the transactions without commit record backward, then redo those committed after the last checkpoint) was correct on the 692 histories without rollbacks and is WRONG on a log in which a transaction that rolled back completely is followed by a committed writer of the same item (the example of the page). Negative controls: without the write-ahead rule 46 histories recovered wrongly, with redo only 234, with undo only 258; the deferred scheme never had a value of an uncommitted transaction on the disk, the immediate scheme did in 279 of 1500 histories. The steal/force table was recomputed by a second enumeration (depth first against breadth first) and in TypeScript (tests/db-recovery-traces.test.ts). CONVENTIONS: log record shapes follow Silberschatz et al.; a rollback, once begun, is carried to the end (no partial rollback to a savepoint); the checkpoint is the simple (quiescent) one that writes every modified page; compensation records are redo-only records without the old value. NOT COMPUTED, quoted from the textbooks: shadow paging, ARIES, fuzzy checkpoints, media failure. The names NO-UNDO/REDO, UNDO/REDO and UNDO/NO-REDO and the chapter numbers are from memory and need verification. SECOND PASS (2026-11-02, done by the assistant, not a human check): every Self-check question was solved before the printed answer was read and all agreed; the definitions, worked examples, cheat box and traps were read claim by claim and re-derived against the textbook definitions and the sample database. No defect found. Status raised to self-checked; verified needs a textbook or human check.
last verified: never
My notes (saved in this browser)