skip to content

In ARIES-style recovery, the redo pass reapplies changes made by transactions that were still uncommitted at crash time, only for the undo pass to roll them back immediately afterwards. Why is that apparently wasteful design chosen over skipping the uncommitted transactions during redo?

level: seniorimportance: should knowfreq 35%

answer

  1. reconstruct exact crash-time state
  2. before-images assume real history
  3. interleaved slots and index splits cannot be separated
  4. reuse the runtime rollback path
  5. cost bounded by checkpoint distance

basics

~20 s

Redo repeats history so that after it, the pages match the exact state at the moment of the crash. Undo then operates on a state it understands, using the same rollback path used at runtime. Selective redo would create a state that never existed, where logged before-images and page-internal structures no longer line up.

solid answer

~60 s

Redo restores the page state as of the crash instant, uncommitted work included, because that is the only state anyone has ever reasoned about. Three reasons: 1. **Undo needs a known starting point.** Undo applies before-images and logical reversals recorded in the log. Those were recorded against a specific page state. If redo skipped a loser's change, the page would be in a state that occurred at no point in real history, and the reversal would be applied to the wrong thing. 2. **Page-internal structure is shared.** Slots, free space, and index page splits are affected by everyone's changes interleaved on the same page. You cannot cleanly extract one transaction's effects from a page, because a later committed change may sit in a slot the loser's change created. 3. **One code path.** After repeating history, recovery's undo is exactly the runtime rollback path. Rollback of a live transaction and rollback during recovery use the same logic, which is a large correctness win. The cost is bounded: redo replays only from the oldest unwritten change, and reapplied loser work is usually small.

go deeper

for a junior

Recall the slogan and one reason: redo reapplies everything so the pages match the crash state, then undo removes the uncommitted work.

for a middle

Explain that before-images and page slot layout only make sense against the real historical state, so selective redo would leave pages in a state that never existed.

for a senior

Add index-structure interleaving and the engineering argument that recovery reuses the well-tested runtime rollback path; quantify the bounded cost.

for a principal

Frame it as a correctness-versus-micro-efficiency tradeoff in the least-tested code in the engine, and connect recovery duration to checkpoint policy and to limits on transaction size rather than to redo scope.

## What repeating history means ARIES redo is deliberately transaction-agnostic. It walks the log forward from the redo start point and reapplies every redoable change to every page that is behind, without asking whether the owning transaction committed. When redo finishes, the data files are byte-for-byte in the state they were in at the instant of the crash, as if the buffer pool had been flushed completely just before the power went out. Only then does undo run and remove the losers. The alternative, sometimes called selective redo, would replay winners only. It sounds strictly cheaper. It is also much harder to make correct, and here is why. ## Reason 1: undo's before-images assume a specific state Undo works by applying the reversal that was recorded alongside the original change: the old value of a field, the tuple to reinsert, the key to remove. These reversals are meaningful only relative to the state the change produced. Suppose loser T2 updated a row from value B to value C and the log holds the before-image B. If redo skipped that update, the page might hold B already (if the change never reached disk) or C (if it did) or something else if other transactions touched the row afterwards. Undo now has to reason about whether its own reversal is needed, and answering that in general is exactly the LSN bookkeeping problem redo already solves. Repeating history collapses all of those cases into one: the page holds C, apply the reversal. ## Reason 2: pages are shared, changes interleave A data page holds rows from many transactions and its internal structure evolves as a whole. Consider a page where loser T2 inserted a tuple into slot 5 and, later, winner T7 inserted into slot 6, with the page's free-space pointer and slot array reflecting both. Selective redo would have to reproduce T7's insert on a page where slot 5 was never created. Slot numbering and free-space layout would diverge from what the log records for T7 assume, so T7's own record, which says *insert into page 7 at slot 6*, becomes meaningless or wrong. The problem is worse for index structures. Page splits, merges and sibling-pointer updates are done as part of some transaction's work but they restructure shared data. Skipping a loser's split while replaying a later winner's insert into the page that the split created is not merely inconvenient, it is incoherent: the target page does not exist. ## Reason 3: one rollback implementation After repeating history, the database is in the same situation as a running system that decides to abort a transaction. So the undo pass can call the same routine the engine uses for a normal ROLLBACK, including its use of compensation log records. Recovery code is the least-exercised, hardest-to-test code in a storage engine; sharing it with a path that runs thousands of times a second in production is a major reliability advantage. Selective redo would need a second, separate, rarely-exercised rollback that understands partially-reconstructed pages. ## Reason 4: it composes with logical undo and nested operations Some operations cannot be undone physically, only logically. Reversing an index insert may require a delete that itself restructures pages; the reversal of a page split is not simply putting bytes back. ARIES handles these by treating them as nested top actions, logged so that they are redone but never undone once complete. That whole scheme presumes the page state is the real historical state. Selective redo undermines the assumption at its foundation. ## What it costs, and why the cost is acceptable The extra work is: reapplying loser changes that lie between the redo start point and the end of the log, then reversing them. Two bounds keep this small. - Redo does not start at the beginning of the log; it starts at the oldest change that might not be on disk, which checkpointing and background page writing keep close to the log tail. - Uncommitted work at any instant is bounded by what is in flight. Short OLTP transactions leave little to redo and undo. The pathological case is a huge long-running transaction (a bulk update) killed near completion, which is expensive to undo regardless of the redo policy. In exchange, recovery becomes a simple forward scan with an LSN test, needing no knowledge of transaction outcomes, and is therefore trivially restartable and parallelizable. ## How to say it in an interview "Redo reconstructs the exact crash-time state so undo has a state it can reason about, because before-images and page-internal structure are only meaningful against real history. It also lets recovery reuse the normal rollback path. The redundant work is bounded by the checkpoint distance and by how much was in flight."

  • Does repeating history mean uncommitted data is briefly visible to users?
    No. Redo runs before the database accepts connections, so no session can observe the intermediate state. Engines that open early do so only after redo, and analysis has rebuilt the locks held by loser transactions, so other sessions block on the rows still being rolled back rather than reading them.
  • What kinds of operations cannot be undone by simply restoring a before-image, and how does ARIES handle them?
    Structural changes such as index page splits and merges, where reversing the bytes on one page is not enough because sibling pointers and parent entries also changed. ARIES treats such sequences as nested top actions: they are logged so that they are redone but never undone once complete, and the enclosing transaction's rollback uses a logical operation instead. This scheme only makes sense on top of a faithfully reconstructed page state.
  • Where does the real cost of recovery come from, if not from redoing losers?
    From the distance between the redo start point and the end of the log, which is set by how far behind the dirty pages were allowed to fall, and from any very large in-flight transaction that must be rolled back. Frequent checkpoints and aggressive background page writing shorten redo; bounding transaction size bounds undo.

To un-bake a mistake out of a shared cake you first have to rebuild the cake exactly as it was; you cannot remove one baker's layer from a cake that was never assembled.

saying these in an interview costs you the question

  • Saying redo replays only committed transactions
  • Claiming skipping losers during redo would be equally correct and simply faster
  • Believing repeating history exposes uncommitted data to clients
  • Assuming every undo is a byte-level before-image restore, with no logical or structural cases

context