Systems · Week 2

Pessimistic vs optimistic locks

When to serialize with locks versus version checks — and the failure modes of each.

Pessimistic vs optimistic locks

Business constraint

Two agents edit the same booking row. Finance forbids lost updates. UX forbids long freezes.

Naive v0

Always SELECT FOR UPDATE. Or always blind UPDATE with no version. Or app-level mutex on one node only.

Failure drill

Pessimistic locks under contention create convoys and deadlocks. Optimistic updates silently overwrite without versions. Single-node mutex lies under multi-replica deploy.

Evolution path

Iteration 1

Classify conflicts: high contention short critical sections → pessimistic or lease; low contention → optimistic version column.

Iteration 2

Optimistic: UPDATE … WHERE id=? AND version=?; bump version; on 0 rows, reload and retry with budget.

Iteration 3

For distributed writers, add lease + fencing token (lab lease-lock) so a timed-out holder cannot write after losing the lease.

Implementation cut

Document the conflict rate you expect. Prefer optimistic for user edits; leases for exclusive workers. Never mix "TTL lock" without fencing.

Numbers

Optimistic retry rate under load tests. Lock wait p99. Lost-update incidents = 0 in soak tests with adversarial concurrency.

Pattern tags

Self-check

  1. What does a version column prevent?
  2. When do pessimistic locks win?
  3. What is a fencing token?
  4. Why is a TTL lock alone unsafe?
  5. How do you bound optimistic retries?

Walkthrough

Recordings will appear here when published. Until then, work the failure drill and lab locally — pause after each iteration and write the metric that moved.

Lab package: see /systems/labs/lease-lock/.

Open lab: lease-lock