THIS EXPLANATION
THE ROOM
CDA·221 Computing, Data & AI 6 MIN · 8 STATIONS

The blocking commit

A Socratic walk-through of the blocking commit — reasoned out one step at a time, not lectured.

abcdefgh
a

The question we started with

THE QUESTION #

Why can one coordinator crashing leave every other participant waiting indefinitely?

Two-phase commit is the classic way to make several databases agree on one outcome. A coordinator asks everyone "can you commit?", collects the votes, and then tells everyone the decision. It is simple enough to sketch on a napkin, and it is genuinely correct: no participant ever commits while another aborts.

So why do practitioners speak about it the way they speak about a loaded weapon? The usual answer is "it blocks", which is true but not yet an explanation. What is worth working out is where the waiting comes from — because it turns out not to be a slow network or a bad implementation, but a place in the protocol where a participant genuinely does not have enough information to act, no matter how long it thinks about it.

b

Reasoning it through

REASONING #

Trace a participant's own knowledge, step by step, and ask at each point: could it decide alone?

Before it votes, easily. It has promised nothing, so if everything goes silent it can abort, safe in the knowledge that nobody could have committed — a commit requires all votes and its own was never given. After it hears the decision, also easily: it knows the outcome and applies it.

Now the interval between. It has voted yes. What does a yes mean? It is not an opinion — it is a promise. It says: I have durably prepared this transaction, I will not fail to commit it, and I have surrendered my right to abort unilaterally. To keep that promise it must hold its locks, because releasing them would let another transaction see or overwrite rows it may still have to commit.

Ask now what this participant knows about the outcome. It knows its own vote. It does not know the others'. So the transaction might commit — if everyone else also voted yes — or abort, if any one of them voted no. Both futures are live, and nothing in local state distinguishes them.

Then the coordinator crashes.

Here is the uncomfortable part. Can the participant guess? Suppose it commits. If some other participant voted no, it has just violated atomicity in the worst way — a partial commit that no recovery can undo. Suppose instead it aborts. If everyone voted yes and the coordinator had already told a faster participant to commit, it has again produced a split outcome. Either guess can be wrong, and the participant cannot tell which. So it waits. Not out of politeness, and not for a timeout to expire — it waits because acting would be unsafe, and it is holding locks the whole time. That is what "blocking" means, and it is a property of the protocol, not of any implementation.

Can the participants help each other? Somewhat. The cooperative termination protocol lets a stuck participant ask its peers what they know. If any of them heard the decision, the answer propagates. But if every reachable participant is in the same uncertain prepared state, the group learns nothing and they wait together.

Notice what is really scarce here. It is not agreement — the votes were unanimous. It is the decision record: the one durable fact saying which way the transaction went. That record lived in exactly one place, and that place died. The flaw is structural: a protocol whose outcome is known by a single node inherits that node's availability.

Which points straight at the fix. Do not entrust the decision to one machine. Replicate it. Modern systems put the commit decision into a consensus log — Raft or Paxos across an odd number of nodes — so the decision survives any minority failure, and any participant can read it back from whoever is up. Two-phase commit as a data protocol is retained; the coordinator as a single point of knowledge is not.

And what of three-phase commit, offered by textbooks as the non-blocking alternative? It does remove blocking, but only under an assumption we do not have: that failures are crashes rather than partitions, and that message delays are bounded. Under a partition it can produce inconsistency, which is worse than waiting. No commit protocol can be both non-blocking and safe against arbitrary partitions, so the honest framing is that you choose which failure you prefer, not that you escape both.

c

The analogy

THE ANALOGY #
THE FIGURE

Think of an auction where several bidders have each signed a binding commitment to buy their part of a lot, conditional on every other part being taken. The signatures are in, and each bidder is holding their money aside. Only the auctioneer has seen all the signatures, so only the auctioneer knows whether the lot sold.

Then the auctioneer walks out with the paperwork and does not return. No bidder can release their money, because the sale may have closed. No bidder can pay, because it may not have. They stand there, funds frozen, until the auctioneer comes back — and asking each other does not help, since none of them saw the other signatures either.

WHERE IT BREAKS DOWN

the bidders could eventually agree among themselves to call the whole thing off and walk away, whereas participants that have voted yes may already have a peer that heard "commit" and applied it, so abandoning the transaction is not a safe collective option the way abandoning the auction is.

d

Clarifying the model

THE MODEL #

Three refinements.

First, the misconception worth correcting: blocking is often read as slowness, as though a longer timeout or a faster network would fix it. It is not a latency problem. A prepared participant that guesses is unsafe at any speed, so the wait is doing real work — it is the protocol preferring unavailability over a possible split outcome.

Second, the cost is not the waiting itself but the locks held while waiting. A prepared transaction pins rows, and other transactions queue behind them. One coordinator outage can therefore stall traffic that has nothing to do with the stuck transaction, which is why the operational damage is usually far wider than the transaction's own footprint.

Third, "two-phase commit is bad" is too coarse. What is fragile is a single, unreplicated coordinator. Once the decision is stored in a replicated log the failure that causes indefinite blocking requires losing a majority, and the protocol becomes ordinary engineering rather than a liability.

e

A picture of it

THE PICTURE #
The blocking commit
The blocking commit Read the three boxes on the requirement side as the three things a commit protocol is asked to deliver. Then follow the arrows out of the two elements at the bottom. Plain two-phase commit with one coordinator reaches the first two requirements and never reaches the third -- that missing arrow is the blocking property, drawn as an absence. Adding a replicated decision log is what supplies the bounded wait, and it derives from the single-coordinator design rather than replacing the voting protocol. {"generator":"mermaid-svg-renderer@3.2.1","source":"../Socrates/.diagram-cache/_src/the-blocking-commit.md","sourceIndex":1,"sourceLine":4,"sourceHash":"15b7806598db9cdeb0c96c027e0f4643d4b9222c1e7f7acd3c15024193e9b58b","diagramType":"requirement","layoutVariant":"source","repairedDuplicateIds":[],"motion":"entrance-with-reduced-motion-fallback","presentation":"editorial","attempt":1,"viewBox":{"x":0,"y":0,"width":1035,"height":828},"qa":{"passed":true,"findings":[]}} satisfies satisfies satisfies derives <<Requirement>> atomicOutcome ID: R1 Text: every participant reaches the same outcome Risk: High Verification: Analysis <<Functional Requirement>> durableVote ID: R2 Text: a yes vote survives a participant crash Risk: Medium Verification: Test <<Performance Requirement>> boundedWait ID: R3 Text: no participant waits without bound for a decision Risk: High Verification: Analysis <<Element>> singleCoordinator Type: protocol <<Element>> replicatedLog Type: protocol

How to readRead the three boxes on the requirement side as the three things a commit protocol is asked to deliver. Then follow the arrows out of the two elements at the bottom. Plain two-phase commit with one coordinator reaches the first two requirements and never reaches the third — that missing arrow is the blocking property, drawn as an absence. Adding a replicated decision log is what supplies the bounded wait, and it derives from the single-coordinator design rather than replacing the voting protocol.

f

What became clearer

WHAT CLEARED #
WHAT CLEARED

Blocking is not a defect in two-phase commit's design but the honest consequence of a participant that has surrendered its right to abort and cannot learn the outcome. The scarce resource is the durable decision record, and once that record is replicated rather than held by one coordinator, the indefinite wait requires a majority failure instead of a single one.

g

Where to go next

ONWARD #
  • The cooperative termination protocol, and precisely when it rescues a stuck participant.
  • How a consensus-backed coordinator changes the failure modes rather than removing them.
  • Sagas, which give up atomicity entirely and compensate afterwards instead.
h

Key terms

TERMS #
TermWhat it means
Two-phase commita protocol in which a coordinator collects prepare votes and then broadcasts a single commit or abort decision.
Prepared statethe durable condition of a participant that has voted yes, holds its locks, and can no longer decide the outcome alone.
Blocking protocolone in which a failure can leave correct participants unable to proceed safely until the failed component recovers.
Cooperative terminationparticipants querying each other for the decision when the coordinator is unreachable.
Three-phase commita variant that avoids blocking under bounded-delay crash failures but is unsafe under network partitions.

Every term the collection defines is gathered in the glossary.

Nearby on the shelf

4