shreyansh

Atomic Commit and Two-Phase Commit (2PC)

30-Second Glance

  • Atomic commit means a multi-object write (data + its secondary index) either lands everywhere or nowhere — no half-finished litter.
  • The note's motivating case: primary data updated but the secondary index not (or vice versa) leaves the index lying about the data.
  • Single-node atomicity is solved; the open question the note hands off is distributed atomic commit across nodes/partitions.
  • Expect the classic cost: coordination buys correctness and charges latency and availability.
  • Natural next step flagged by the sibling partitioning note: 2PC, distributed transactions, compensating rollbacks, or eventual repair.

Atomicity prevents failed transactions from littering the database with half-finished results and half-updated state. This is especially important for multi-object transactions and databases that maintain secondary indexes.
If you modify some data, the corresponding change needs to also be made in the secondary index. Atomicity ensures that the secondary index stays consistent with the primary data.

From Single-Node to Distributed Atomic Commit:

On one node, atomicity is easy: write-ahead log + commit record. Across shards, no single disk holds the whole transaction, so the shards must vote. That vote is two-phase commit: one coordinator, N participants, two rounds.

How 2PC runs

  1. Prepare (vote). Coordinator sends prepare(T) to every participant shard. Each shard force-writes the updates to its WAL, replies YES (promising it can commit) or NO.
  2. Commit/abort (decide). If all vote YES, the coordinator force-writes a commit record and sends commit(T); any NO (or timeout) → force-write abort record, send abort(T). Participants apply on commit, roll back on abort.
  3. Recovery. A crashed participant replays its WAL on restart: if it logged a commit/abort decision, it follows it; if it voted YES but never heard the decision, it must ask the coordinator — it cannot unilaterally decide.

The blocking problem (the interview question)

If the coordinator crashes after collecting YES votes but before broadcasting the decision, participants that voted YES are blocked: they hold locks, cannot abort (someone else may have committed), cannot commit (no decision). They wait for the coordinator to recover. dishonest-sounding but precise: 2PC is safe (never disagrees) but not live (can stall forever).

Mitigations, each with a price: coordinator replication (consensus-backed coordinator — see Distributed Consensus); timeout-based unilateral abort (risks disagreement — only safe before voting YES); three-phase commit (adds a pre-commit round to make aborts unanimous, still blocks under partitions, rarely used in production).

When to use it (and what replaces it)

  • Use 2PC when shards share one administrative domain and brief blocking is acceptable (single-cluster sharded SQL: Spanner uses a variant with Paxos-replicated coordinators).
  • Avoid across services/companies: a slow participant holds everyone else's locks. Use sagas (sequence of local transactions + compensating actions, eventual atomicity) or TCC (try-confirm-cancel) instead — say this sentence when the interviewer asks about microservices transactions.
  • Read path is free: 2PC only coordinates writes; reads use snapshot isolation (Snapshot Isolation) without joining the protocol.

Trade-offs

Approach Pros Cons Use when
No atomicity (best-effort fan-out) Fastest, no coordination Half-applied writes; index disagrees with primary Throwaway or self-healing indexes
Single-node transaction Cheap, well-understood atomicity Doesn't span partitions All objects live on one node
Distributed atomic commit (2PC-style) All-or-nothing across nodes Multi-round latency; coordinator bottleneck and blocking risk Index and data must agree immediately
Async repair / eventual convergence Writes stay fast Temporary index staleness and inconsistency windows Search/index views that tolerate lag

Interview One-Liners

Q: What does atomicity guarantee here? A: A transaction touching data plus its secondary index commits everywhere or nowhere — never half-finished.

Q: What breaks without it? A: The primary write succeeds while the index write fails (or reverse), so the index permanently misdescribes the data.

Q: Why is this harder in a distributed DB? A: The objects live on different nodes/partitions, so one local commit can't cover them — you need cross-node commit machinery.

Q: What does distributed atomicity cost? A: Extra coordination rounds (latency) and reduced availability during the commit window.

Q: If you can't pay for 2PC, what are the fallbacks? A: Compensating rollback transactions, eventual background repair, or bounded retries — per the companion partitioning note.