G27
Self-checkedTier 2 16 min readdbms.recovery-logging

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 TiT_i writes:

recordwritten when
<Ti start>TiT_i begins
<Ti, X, V1, V2>TiT_i changes item XX from the old value V1V_1 to the new value V2V_2 (the update record)
<Ti commit>TiT_i commits
<Ti abort>TiT_i has been completely rolled back
<checkpoint L>a checkpoint, where LL lists the transactions that were active
<Ti, X, V>while undoing: XX restored to VV (a compensation, or redo-only, record)

The old value V1V_1 is what undo uses; the new value V2V_2 is what redo uses.

The write-ahead rules.

  1. 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.
  2. 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 LL. Scan forward from it: redo every update (and compensation) record by writing the new value; when <Ti start> is read, add TiT_i to the undo-list; when <Ti commit> or <Ti abort> is read, remove TiT_i.
  • 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
123456789101112crash
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.

0 / 13
computed by script: histories are run on a small database with a write-ahead log (scripts/rec_lib.py) and recovered by the procedures of the page. python3 scripts/gen-db7-traces.py

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 T1T_1 commits, A=90A = 90 is in memory only (no force); after event 10 the disk holds C=310C = 310 written by T3T_3, which never commits (steal). Third, the last update, T3T_3 writing B=260B = 260, 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
steppassrecord readactionundo-listdiskrecord 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.

0 / 6
computed by script: histories are run on a small database with a write-ahead log (scripts/rec_lib.py) and recovered by the procedures of the page. python3 scripts/gen-db7-traces.py

The last checkpoint lists T2T_2 as active, so the undo-list starts as {T2}. The redo pass repeats everything after the checkpoint, including the update of T3T_3 that is going to be undone (this is what "repeating history" means) and the update A=120A = 120 of T2T_2, which was never on the disk. At the end of the redo pass, T2T_2 is out of the undo-list (its commit record was read) and T3T_3 is in it (no commit record). The undo pass walks back, restores C=300C = 300 and writes the compensation record and <T3 abort>. The result, A=120A = 120, B=250B = 250, C=300C = 300, is exactly the work of the committed transactions T1T_1 and T2T_2.

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 pointrecords on diskredo listundo listdone before the checkpointdisk at the crashafter 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.

0 / 12
computed by script: histories are run on a small database with a write-ahead log (scripts/rec_lib.py) and recovered by the procedures of the page. python3 scripts/gen-db7-traces.py

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
schemelog at the crashdisk at the crashlog record shaperecoverydatabase 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.

0 / 2
computed by script: histories are run on a small database with a write-ahead log (scripts/rec_lib.py) and recovered by the procedures of the page. python3 scripts/gen-db7-traces.py

The two schemes meet the same crash. With immediate modification the page of BB reached the disk before T2T_2 committed, so the disk holds an uncommitted value and the log must supply the old value 200200. With deferred modification T2T_2'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 policycrash stateswith uncommitted data on diskwith committed data missingundo neededredo 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.

0 / 5
computed by script: histories are run on a small database with a write-ahead log (scripts/rec_lib.py) and recovered by the procedures of the page. python3 scripts/gen-db7-traces.py

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

Easy

The 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.

T1T_1 committed before the checkpoint: nothing to do. T2T_2 was active at the checkpoint and committed after it, and T3T_3 started and committed after it: redo T2T_2 and T3T_3. T4T_4 has no commit record: undo T4T_4. The redo pass reads the six records after the checkpoint.

EX 2The database after recovery

Medium

Items start as A=5A = 5, B=7B = 7, C=9C = 9, D=1D = 1, and the disk at the crash holds A=15A = 15, B=17B = 17, C=9C = 9, D=2D = 2 (the checkpoint wrote AA and BB; the page of DD was stolen).

Undo first: T4T_4 wrote DD from 1 to 2, so write D=1D = 1. Then redo: T2T_2's update B=17B = 17 is before the checkpoint and already on the disk (writing it again is harmless); T3T_3's update gives C=19C = 19. The result is A=15A = 15, B=17B = 17, C=19C = 19, D=1D = 1: the committed work of T1T_1, T2T_2, T3T_3 and nothing of T4T_4. 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 TT 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 L logged. 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

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

GATE 2021 · Set 1 · MCQ · 1 markQ9 · page 434 of the book
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.
GATE 2015 · Set 2 · MCQQ23 · page 437 of the book
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
GATE 2006 · MCQ · 2 marksQ34 · page 439 of the book
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 answer

Redo T2T_2 (active at the checkpoint, committed after it). T1T_1 committed before the checkpoint: nothing. Undo T3T_3 (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 answer

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 answer

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