Introduction

Serializability ignores failures: it assumes every transaction commits. A real system must also handle a transaction that aborts after other transactions have read what it wrote. Recoverability classifies schedules by how safely they survive such aborts, using the positions of commits and aborts. A schedule can be serializable and still unacceptable because an abort would force the system to undo a committed transaction.

The tasks are to decide whether a given schedule is recoverable, cascadeless or strict, and how these classes relate to each other and to conflict serializability.

Prerequisites

Core concepts

Reads from. TjT_j reads XX from TiT_i if Rj(X)R_j(X) reads the value written by the latest Wi(X)W_i(X) before it, and Ti≠TjT_i \ne T_j. A write by a transaction that has already aborted has been undone, so a later read does not read from it.

Recoverable. Whenever TjT_j reads from TiT_i, TiT_i commits before TjT_j commits. (If TjT_j never commits, the condition places no constraint.) In a non-recoverable schedule, an abort of TiT_i after TjT_j has committed cannot be handled correctly: TjT_j read a value that is being undone, but a committed transaction cannot be rolled back.

Cascading rollback. In a recoverable schedule an abort of TiT_i may still force every transaction that read from TiT_i to abort, then every transaction that read from those, and so on.

Cascadeless (avoids cascading aborts, ACA). A transaction reads an item only after any other transaction whose still-uncommitted value it would read has committed (or its aborted write has been undone). No dirty reads, so no cascading rollback.

Strict. No transaction reads or writes XX until the other transaction that last wrote XX has committed or aborted. Undo can then simply restore before-images.

Hierarchy:

serial⊂strict⊂cascadeless⊂recoverable⊂all schedules.\text{serial} \subset \text{strict} \subset \text{cascadeless} \subset \text{recoverable} \subset \text{all schedules}.

Each inclusion is strict. Recoverability is independent of serializability: a schedule can be conflict serializable but not recoverable, or strict but not conflict serializable.

Nested regions: all schedules, recoverable, cascadeless, strict, serial; one example schedule in each band
Figure 1. Recoverable, cascadeless and strict schedules are nested; each band holds one schedule from the worked examples.

How it works: testing a schedule

Text
for each read R_j(X) reading from W_i(X), i != j:
    recoverable  needs: if T_j commits, then C_i comes before C_j
    cascadeless  needs: C_i (or A_i) comes before R_j(X)
for each read or write by T_j of X after W_i(X), i != j, with no write of X in between:
    strict       needs: C_i (or A_i) comes before that operation

Check the strongest property first: a strict schedule is automatically cascadeless and recoverable.

Mathematical explanation

Why strict implies cascadeless. Cascadeless restricts reads of uncommitted data; strict restricts both reads and writes, so it forbids more.

Why cascadeless implies recoverable. If TjT_j reads from TiT_i only after CiC_i, then CiC_i precedes Rj(X)R_j(X) and therefore precedes CjC_j.

Why strict matters for recovery. If T2T_2 overwrites an uncommitted W1(X)W_1(X) and then T1T_1 aborts, restoring T1T_1's before-image would wipe out T2T_2's write. Strictness rules this out, so undo by before-images is always correct.

Which transactions a cascade reaches. Draw a reads-from graph with an edge Ti→TjT_i \to T_j when TjT_j reads from TiT_i and TiT_i has not yet ended at the time of the read. When TiT_i aborts, every transaction reachable from TiT_i in this graph that has not committed must abort too. For W1(A) R2(A) R3(A) W3(C) R4(C) W5(D)W_1(A)\, R_2(A)\, R_3(A)\, W_3(C)\, R_4(C)\, W_5(D), the edges are T1→T2T_1 \to T_2, T1→T3T_1 \to T_3 and T3→T4T_3 \to T_4, so an abort of T1T_1 forces T2T_2, T3T_3 and T4T_4 to abort, while T5T_5, which read nothing, is unaffected. In a cascadeless schedule the graph has no edges, so an abort affects only the aborting transaction.

Link to locking. Strict two-phase locking holds exclusive locks until commit, which makes every schedule it allows strict (and conflict serializable); see Lock-Based Concurrency Control.

Worked examples

Example 1: not recoverable. S1=R1(A) W1(A) R2(A) C2 C1S_1 = R_1(A)\, W_1(A)\, R_2(A)\, C_2\, C_1. T2T_2 reads AA from T1T_1 and commits first. If T1T_1 aborted instead of committing, the committed T2T_2 would hold a value that never existed. S1S_1 is conflict serializable (edge T1→T2T_1 \to T_2 only) but not recoverable.

Example 2: recoverable, not cascadeless. S2=R1(A) W1(A) R2(A) C1 C2S_2 = R_1(A)\, W_1(A)\, R_2(A)\, C_1\, C_2. T1T_1 commits before T2T_2, so it is recoverable; R2(A)R_2(A) is a dirty read, so it is not cascadeless.

Example 3: cascadeless, not strict. S3=R1(A) W1(A) W2(A) C1 C2S_3 = R_1(A)\, W_1(A)\, W_2(A)\, C_1\, C_2. Nobody reads uncommitted data, so it is cascadeless (and recoverable); W2(A)W_2(A) overwrites an uncommitted write, so it is not strict.

Example 4: strict. S4=R2(B) W1(A) C1 R2(A) W2(A) C2S_4 = R_2(B)\, W_1(A)\, C_1\, R_2(A)\, W_2(A)\, C_2. Item AA is touched by T2T_2 only after C1C_1. Strict, hence cascadeless and recoverable, though not serial.

Example 5: cascading rollback. S5=W1(A) R2(A) W2(B) R3(B) A1S_5 = W_1(A)\, R_2(A)\, W_2(B)\, R_3(B)\, A_1. T2T_2 read AA from T1T_1, and T3T_3 read BB from T2T_2. When T1T_1 aborts, T2T_2 must abort, and then T3T_3 must abort. The schedule is recoverable (nobody has committed) but not cascadeless.

Example 6: independence from serializability.

  • S6=R1(A) R2(A) W1(A) W2(A) C1 C2S_6 = R_1(A)\, R_2(A)\, W_1(A)\, W_2(A)\, C_1\, C_2: not conflict serializable (cycle T1↔T2T_1 \leftrightarrow T_2), yet cascadeless, because both reads see the initial value. It is not strict, because W2(A)W_2(A) overwrites the uncommitted W1(A)W_1(A).
  • S7=R1(A) R2(B) W1(B) C1 W2(A) C2S_7 = R_1(A)\, R_2(B)\, W_1(B)\, C_1\, W_2(A)\, C_2: strict, since no item written by an uncommitted transaction is touched, but not conflict serializable (R2(B)R_2(B) before W1(B)W_1(B) gives T2→T1T_2 \to T_1; R1(A)R_1(A) before W2(A)W_2(A) gives T1→T2T_1 \to T_2).

Example 7: placing commits. The operations W1(A) R2(A) W2(B) R3(B)W_1(A)\, R_2(A)\, W_2(B)\, R_3(B) are followed by the three commits in some order. T2T_2 reads from T1T_1 and T3T_3 reads from T2T_2, so recoverability needs C1C_1 before C2C_2 and C2C_2 before C3C_3: of the 3!=63! = 6 commit orders only C1 C2 C3C_1\, C_2\, C_3 gives a recoverable schedule. No commit order makes it cascadeless, because the dirty reads have already happened before any commit.

Example 8: a read from a transaction that aborts. S8=W1(A) R2(A) A1 C2S_8 = W_1(A)\, R_2(A)\, A_1\, C_2. T2T_2 read a value written by T1T_1, and T1T_1 aborted, yet T2T_2 commits: not recoverable. A recoverable system must abort T2T_2 when T1T_1 aborts, giving W1(A) R2(A) A1 A2W_1(A)\, R_2(A)\, A_1\, A_2, which is recoverable.

Summary of the examples.

ScheduleRecoverableCascadelessStrictConflict serializable
S1S_1nononoyes
S2S_2yesnonoyes
S3S_3yesyesnoyes
S4S_4yesyesyesyes
S6S_6yesyesnono
S7S_7yesyesyesno
S8S_8nononoyes

Making a schedule safer. A non-recoverable schedule becomes recoverable by delaying the reader's commit until the writer commits (Example 1 with C1C_1 moved before C2C_2). It becomes cascadeless only by delaying the read itself until the writer commits, which is what holding exclusive locks to commit achieves.

Related material. A schedule is rigorous if no transaction may perform any operation that conflicts with an operation of an uncommitted transaction, including overwriting an item that an uncommitted transaction has only read. Rigorous two-phase locking, which holds all locks to commit, produces such schedules; the commit order is then also a valid serialization order.

Important properties and observations

  • Recoverable: writers commit before their readers commit.
  • Cascadeless: read only committed data.
  • Strict: neither read nor overwrite uncommitted data.
  • Serial ⊂\subset strict ⊂\subset cascadeless ⊂\subset recoverable.
  • Recoverability and serializability are independent; a correct protocol needs both.
  • Strict 2PL produces schedules that are both strict and conflict serializable.

Common misconceptions.

  • "Cascadeless means no aborts." It means an abort never forces other aborts.
  • "A conflict-serializable schedule is recoverable." Example 1 is serializable and not recoverable.
  • "Recoverable only concerns reads of committed data." It concerns the order of commits; dirty reads are allowed.

GATE examination perspective

  • Classify a schedule. As non-recoverable, recoverable, cascadeless or strict.
  • Combine. Combine this with conflict serializability: four combinations are all possible.
  • Cascading rollback. Which transactions must abort when one aborts.
  • Protocol links. Strict 2PL gives strict schedules; basic 2PL may give cascading aborts.

Summary

Sources

  1. A. Silberschatz, H. F. Korth, S. Sudarshan, Database System Concepts, 7th ed., McGraw-Hill, 2019 (2020 copyright), 17.7 Transaction Isolation and Atomicity.
  2. R. Elmasri, S. B. Navathe, Fundamentals of Database Systems, 7th ed., Pearson, 20.4 Characterizing Schedules Based on Recoverability.

Next steps