Core idea

At the moment a transaction requests a lock held by someone else, decide immediately: wait, kill the other transaction and take its locks, or kill yourself. No background worker, no waits-for graph, no cycle search — because the ordering of who may wait for whom makes cycles impossible 39:39.

Priority by age

Transactions get a timestamp on arrival; older = higher priority. Two transactions can never have the same age, or they would be the same transaction 40:28, 40:44. The protocol then specifies what you do when you are younger than the holder, and what you do when you are older 41:01.

The two variants

ProtocolSloganRequester older than holderRequester younger than holder
Wait-Dieold waits for young 41:01wait for the lock 41:01abort itself ("die") 41:25
Wound-Waityoung waits for old 41:25abort the holder ("wound") and take the lock 41:25wait for the lock 41:25

Worked cases

T1 is older than T2 (timestamp 1 < 2) 41:53:

  • T2 holds X on A, T1 requests it → Wait-Die: T1 (older) waits. Wound-Wait: T1 (older) aborts T2 and takes the lock 41:53, 42:32.
  • T1 holds the lock, T2 requests it → Wait-Die: T2 (younger) aborts itself. Wound-Wait: T2 (younger) waits for T1 42:32, 42:59.

Why no deadlocks are possible

Same argument as B+Tree latch crabbing without sibling pointers: all waiting goes in one direction only (always young→old, or always old→young). With no waits in the opposite direction, there can be no cycle 42:59, 43:29, 43:42.

Avoiding starvation on restart

An aborted transaction reuses its original timestamp when restarted. Without this it would keep getting fresh (younger) timestamps and could be killed forever. With it, the transaction eventually becomes the oldest in the system and is guaranteed to get its locks or be allowed to wait for them 43:42, 44:21.