Introduction

A concurrency-control protocol decides, operation by operation, whether a transaction may proceed, must wait, or must abort, so that every schedule it lets through is serializable. Locking is the most widely used approach: a transaction must hold a lock on an item before accessing it, and incompatible locks make other transactions wait. Locks alone do not guarantee serializability; the two-phase locking (2PL) rule about when locks are released does.

The questions to answer are whether a lock sequence obeys 2PL or strict 2PL, whether a schedule could have been produced by 2PL, what 2PL guarantees (serializability) and what it does not (freedom from deadlock and from cascading aborts).

Prerequisites

Core concepts

Lock modes.

  • Shared (S) lock on XX: needed to read XX. Several transactions may hold S locks on the same item.
  • Exclusive (X) lock on XX: needed to write (and read) XX. No other transaction may hold any lock on XX.

A request is granted only if it is compatible with every lock other transactions hold on the item; otherwise the requester waits.

Two by two lock compatibility matrix: requested S against held S is compatible; every pair involving X is incompatible
Figure 1. Lock compatibility: only shared with shared is compatible.

Notation: SLi(X)SL_i(X) and XLi(X)XL_i(X) request locks, Ui(X)U_i(X) releases one.

Two-phase locking (2PL). Each transaction has a growing phase, in which it may acquire locks but not release any, followed by a shrinking phase, in which it may release locks but not acquire any. The moment it acquires its last lock is its lock point. Upgrading S to X is allowed only in the growing phase, downgrading X to S only in the shrinking phase.

Variants.

  • Basic 2PL: the rule above. Guarantees conflict serializability.
  • Strict 2PL: additionally holds every X lock until commit or abort. Schedules are conflict serializable and strict, so there are no cascading aborts.
  • Rigorous 2PL: holds all locks until commit or abort. Transactions serialize in commit order.
  • Conservative (static) 2PL: acquires all locks before the first operation (it must predeclare its read and write sets). It never deadlocks, because a transaction never waits while holding a lock.
Number of locks held by one transaction against time: rising through the growing phase to a peak at the lock point, then falling in the shrinking phase; under strict 2PL the exclusive locks fall only at the commit
Figure 2. Locks held by T1T_1 of Example 1 under basic 2PL and strict 2PL; the lock point separates the growing and shrinking phases.

How it works

Why 2PL gives conflict serializability. If Ti→TjT_i \to T_j is an edge of the precedence graph, some item was locked incompatibly by TiT_i first and released by TiT_i before TjT_j could lock it. TiT_i released a lock, so it had passed its lock point; TjT_j then acquired one, so its lock point comes later. Every edge goes from an earlier lock point to a later one, so the graph is acyclic and the lock-point order is an equivalent serial order.

Deadlock. 2PL does not prevent deadlock: T1T_1 holds X(A)X(A) and requests BB while T2T_2 holds X(B)X(B) and requests AA. Systems handle it by:

  • detection: a wait-for graph with an edge Ti→TjT_i \to T_j when TiT_i waits for a lock held by TjT_j; a cycle means deadlock, and a victim is rolled back;
  • prevention: conservative 2PL, ordering the items and locking in that order, or timestamp schemes such as wait-die and wound-wait (see Timestamp-Based Concurrency Control);
  • timeouts: abort a transaction that waits too long.

Starvation is a separate risk: a transaction can wait forever if the lock manager keeps granting S locks to newcomers while it waits for X, or if it is always chosen as the deadlock victim. Fair (FIFO) granting and counting how often a transaction has been a victim prevent it.

Mathematical explanation

2PL produces a strict subset of CSR. Every 2PL schedule is conflict serializable, but not every conflict-serializable schedule can be produced by 2PL, because 2PL also fixes the serial order to the lock-point order and forbids a transaction from releasing one lock before acquiring another.

Testing whether a schedule could come from 2PL. Choose a lock point for each transaction; then each lock is held over the shortest interval allowed: from the earlier of its first use and the lock point, to the later of its last use and the lock point (for strict 2PL, X locks to the commit). Check interval compatibility per lock mode: S-to-X upgrades occur in the growing phase and X-to-S downgrades in the shrinking phase. A later write does not make the entire item interval X-locked. The schedule is 2PL-producible only when a compatible phase-respecting mode schedule exists; use mode-specific intervals, not one blanket X interval for an eventually written item.

Cascading aborts under basic 2PL. A transaction may release an X lock after its lock point but before commit; another transaction can then read the uncommitted value. Strict 2PL closes exactly this gap, which is why it is the variant used in practice.

Worked examples

Example 1: a 2PL transaction (Figure 2). T1T_1 reads CC and moves an amount from AA to BB:

SL1(C)  R1(C)  XL1(A)  R1(A)  W1(A)  XL1(B)  U1(C)  U1(A)  R1(B)  W1(B)  U1(B)  C1.SL_1(C)\; R_1(C)\; XL_1(A)\; R_1(A)\; W_1(A)\; XL_1(B)\; U_1(C)\; U_1(A)\; R_1(B)\; W_1(B)\; U_1(B)\; C_1.

Locks held rise 1,2,31, 2, 3; the lock point is XL1(B)XL_1(B); then 2,1,02, 1, 0. This is 2PL but not strict: U1(A)U_1(A) releases an X lock before C1C_1. The strict version keeps U1(C)U_1(C) where it is and moves both U1(A)U_1(A) and U1(B)U_1(B) after C1C_1. Releasing AA right after W1(A)W_1(A), before XL1(B)XL_1(B), would break 2PL.

Example 2: locking without 2PL is not enough. T1T_1: XL1(A) W1(A) U1(A) XL1(B) W1(B) U1(B)XL_1(A)\, W_1(A)\, U_1(A)\, XL_1(B)\, W_1(B)\, U_1(B); T2T_2: XL2(A) XL2(B) W2(A) W2(B) U2(A) U2(B)XL_2(A)\, XL_2(B)\, W_2(A)\, W_2(B)\, U_2(A)\, U_2(B). The lock table allows T2T_2 to run entirely between U1(A)U_1(A) and XL1(B)XL_1(B), giving W1(A) W2(A) W2(B) W1(B)W_1(A)\, W_2(A)\, W_2(B)\, W_1(B): edges T1→T2T_1 \to T_2 on AA and T2→T1T_2 \to T_1 on BB, a cycle. T1T_1 is not two-phase (it acquires BB after releasing AA).

Example 3: CSR but not producible by 2PL. S=R1(A) W2(A) R3(B) W1(B)S = R_1(A)\, W_2(A)\, R_3(B)\, W_1(B). Edges T1→T2T_1 \to T_2 and T3→T1T_3 \to T_1: conflict serializable, equivalent to T3T1T2T_3 T_1 T_2. Under 2PL, T1T_1 must release its lock on AA before W2(A)W_2(A) (second operation) but cannot hold its X lock on BB before R3(B)R_3(B) (third operation), so it would acquire after releasing. No 2PL execution produces SS.

Example 4: basic but not strict 2PL. S=R1(A) W1(A) R2(A) C1 C2S = R_1(A)\, W_1(A)\, R_2(A)\, C_1\, C_2 is producible by basic 2PL (T1T_1 unlocks AA after W1(A)W_1(A)) but not by strict 2PL, which keeps X(A)X(A) until C1C_1 and so blocks R2(A)R_2(A). Moving C1C_1 before R2(A)R_2(A) gives a schedule strict 2PL allows.

Example 5: deadlock. T1T_1: XL1(A)XL_1(A), then requests XL1(B)XL_1(B); T2T_2: XL2(B)XL_2(B), then requests XL2(A)XL_2(A). Wait-for graph: T1→T2T_1 \to T_2 and T2→T1T_2 \to T_1, a cycle. Both obey 2PL. Conservative 2PL (lock both items before starting) or locking items in a fixed order (AA before BB) would prevent it.

Example 6: shared locks allow concurrency. T1T_1 and T2T_2 both execute SL(A) R(A)SL(A)\, R(A). Both locks are granted at once. If T3T_3 then requests XL3(A)XL_3(A), it waits until both release.

Example 7: strict but not rigorous. S=R1(A) W2(A) C2 W1(B) C1S = R_1(A)\, W_2(A)\, C_2\, W_1(B)\, C_1. Precedence: T1→T2T_1 \to T_2 only, so SS is CSR, equivalent to T1T2T_1 T_2, although T2T_2 commits first. Strict 2PL can produce it:

SL1(A) R1(A) XL1(B) U1(A) XL2(A) W2(A) C2 U2(A) W1(B) C1 U1(B)SL_1(A)\, R_1(A)\, XL_1(B)\, U_1(A)\, XL_2(A)\, W_2(A)\, C_2\, U_2(A)\, W_1(B)\, C_1\, U_1(B)

T1T_1 reaches its lock point when it gets XL1(B)XL_1(B), then releases its shared lock on AA, which strict 2PL permits; its X lock on BB is held to C1C_1. Rigorous 2PL cannot produce SS: T1T_1 would hold SL1(A)SL_1(A) until C1C_1, so W2(A)W_2(A) could not run before C1C_1. This matches the rule that rigorous 2PL serializes in commit order, and here the serial order T1T2T_1 T_2 is the reverse of the commit order.

Example 8: one table for the three variants. Can the schedule be produced?

ScheduleBasic 2PLStrict 2PLRigorous 2PL
R1(A) W1(A) R2(A) C1 C2R_1(A)\, W_1(A)\, R_2(A)\, C_1\, C_2 (Example 4)yesnono
R1(A) W2(A) C2 W1(B) C1R_1(A)\, W_2(A)\, C_2\, W_1(B)\, C_1 (Example 7)yesyesno
R1(A) R2(A) C1 W2(A) C2R_1(A)\, R_2(A)\, C_1\, W_2(A)\, C_2yesyesyes
R1(A) W2(A) R3(B) W1(B) C1 C2 C3R_1(A)\, W_2(A)\, R_3(B)\, W_1(B)\, C_1\, C_2\, C_3 (Example 3)nonono

In the third row both shared locks coexist and T2T_2 upgrades to an X lock on AA after C1C_1. The last row is conflict serializable, which shows again that CSR does not imply producible by 2PL.

Important properties and observations

  • S is compatible only with S; X is compatible with nothing.
  • 2PL guarantees conflict serializability; the lock-point order is a serial order.
  • 2PL allows deadlock and, in the basic form, cascading aborts.
  • Strict 2PL gives strict, conflict-serializable schedules; rigorous 2PL serializes in commit order.
  • Conservative 2PL is deadlock-free but needs read and write sets in advance.
  • Not every CSR schedule is a 2PL schedule (Example 3).
  • Deadlock is a cycle in the wait-for graph.

Common misconceptions.

  • "2PL prevents deadlock." Only the conservative variant does.
  • "2PL means locks are released only at commit." That is strict or rigorous 2PL.
  • "Any CSR schedule can be produced by 2PL." Example 3 is a counterexample.
  • "Strict 2PL holds shared locks to commit." Only X locks; holding all is rigorous 2PL.

GATE examination perspective

  • Check a lock sequence. Apply this to 2PL, strict 2PL or rigorous 2PL.
  • Decide. Determine whether a schedule can be produced by 2PL or strict 2PL.
  • Properties. Serializability, deadlock freedom, cascadeless behaviour of each variant.
  • Deadlock. Draw the wait-for graph and find the cycle.
  • Compatibility. Which requests are granted given the current locks.

Summary

Sources

  1. A. Silberschatz, H. F. Korth, S. Sudarshan, Database System Concepts, 7th ed., McGraw-Hill, 2019 (2020 copyright), 18.1 Lock-Based Protocols, 18.2 Deadlock Handling.
  2. R. Elmasri, S. B. Navathe, Fundamentals of Database Systems, 7th ed., Pearson, 21.1 Two-Phase Locking Techniques for Concurrency Control.

Next steps