← Workflows

阅读中文版本

Deadlock Diagnosis Workflow

Diagnose a deadlock by capturing the lock wait graph at the moment of deadlock, identifying the cycle, and breaking it by ordering lock acquisition.

advanced~45 mindeadlockdiagnosisconcurrency

Objective

Identify the set of transactions and locks that form a deadlock cycle, and fix the code so the cycle cannot recur by imposing a lock acquisition order.

Environment

  • A system with lock-based concurrency
  • A way to dump the lock wait graph on deadlock
  • Reproducing traffic that triggers the deadlock

Steps

1. Capture the wait graph

On a deadlock detection, dump the lock wait graph: which transaction holds which lock and waits for which.

Expected state: A graph with a cycle that is the deadlock.

2. Identify the cycle

Find the cycle in the wait graph; the transactions in the cycle are the deadlocked set, and the locks are the contested resources.

Expected state: A cycle of transactions and locks that explains the deadlock.

3. Impose lock order

Pick a total order on the locks and ensure all transactions acquire them in that order, so a cycle cannot form.

Expected state: The cycle is broken because no two transactions acquire locks in conflicting orders.

4. Verify no recurrence

Run the reproducing traffic and assert no deadlock occurs over a sustained period.

Expected state: The deadlock does not recur under the same traffic.

Decision points

Lock order by what?

  • By lock id
  • By resource name

By resource name, so the order is stable and readable across code changes.

Enforce order how?

  • Runtime check that asserts order
  • Code review only

Runtime check in test, code review in production, because a runtime check in production adds overhead.

Expected outcome

The deadlock cycle is identified and broken by a lock acquisition order, and the reproducing traffic no longer deadlocks.

Verification

Run the reproducing traffic for 10000 iterations and confirm no deadlock is detected, and the lock order is enforced by a runtime check or a code review.

Cleanup

Keep the lock order and the wait-graph dump tool; remove the reproducing traffic artifacts.

Capture the wait graph

A deadlock is a cycle in the lock wait graph: transaction A holds lock 1 and waits for lock 2, while transaction B holds lock 2 and waits for lock 1. The graph at the moment of deadlock has the cycle, and dumping it is the first step.

dump-wait-graph > graph.dot
cycle-detect graph.dot

Identify the cycle

The cycle in the wait graph is the deadlock. The transactions in the cycle are the deadlocked set, and the locks are the contested resources. The cycle explains who holds what and waits for what, which is the diagnosis.

Impose a lock order

A cycle forms because two transactions acquire locks in different orders. Impose a total order on the locks and ensure all transactions acquire them in that order, so a cycle cannot form: if every transaction acquires lock 1 before lock 2, no transaction can hold lock 2 and wait for lock 1.

// Always acquire locks in ascending id order
const locks = [l1, l2].sort(byId);
for (const l of locks) await l.acquire();

Verification

The reproducing traffic runs for 10000 iterations with no deadlock. The lock order is enforced by a runtime assertion in test and a code review in production, so a future change that violates the order is caught before it ships.