Distributed Systems · Distributed Transactions
Presumed Abort and Presumed Commit: Two Defaults for Missing Decisions
How a participant resolves a transaction when no decision record exists anywhere, what each presumption costs in log writes and retained state, and why presumed abort dominates in practice.
A participant in two-phase commit can reach a state where it has voted yes, holds locks, and can find no decision anywhere: not at the coordinator, not at any sibling participant. The protocol must still define what happens, and there are exactly two coherent answers. Either the absence of a decision is treated as an abort, or it is treated as a commit. Both are correct protocols. They differ in which records must be written, which must be retained, and how much work a crash imposes on recovery.
The information asymmetry that makes a default possible
The key observation is that a missing decision record is not symmetric between the two outcomes. Consider what each participant knows at each point.
A participant that has not yet voted knows nothing about the outcome, and no decision can exist that includes it, because a commit requires every vote. A participant that has voted yes knows that the outcome may be either. The coordinator, at the moment it decides, knows the votes of all participants.
Now consider the two decisions as facts to be recorded. A commit decision must be recorded by the coordinator, because if the coordinator forgets a commit, some participant may have already committed on the strength of it and the transaction is now partially applied. An abort decision need not be recorded by the coordinator at all, because aborting is the state every participant starts in. An abort is the absence of a commit; a participant that never hears anything and rolls back is doing what it would have done had the transaction never existed.
This asymmetry is the whole basis of presumed abort. The coordinator writes a commit record and nothing else. If a participant asks about a transaction and the coordinator has no record, the coordinator’s answer is “abort”, and that answer is truthful in the sense that no commit record exists, so no participant can have committed. A coordinator that crashed and lost the transaction entirely from its log will answer abort for everything it once coordinated, which is safe.
The catch is that the coordinator cannot distinguish “I decided abort” from “I never heard of this transaction”. Under presumed abort both answers are abort, so the distinction does not matter for correctness, but it does matter for duplicate suppression: a participant that has already forgotten the transaction will receive a repeated abort and must not treat it as a new transaction.
What presumed abort buys
Presumed abort removes the abort record from the coordinator’s log and removes the final acknowledgement from the protocol. After the votes are counted, if any vote was no, the coordinator sends abort to all participants and is finished. It writes nothing. Participants roll back and forget.
For a commit, the coordinator writes a commit record and sends commit. Participants commit, then send an acknowledgement, and the coordinator can then write an end record and forget. That final acknowledgement round exists only for commits, and only so the coordinator knows when it can discard its commit record and stop answering queries about the transaction.
The savings are large when aborts are common. Read-only transactions, constraint violations, deadlock victims, and application-level rollbacks all produce aborts, and in a mixed workload they frequently outnumber commits. Each abort under presumed abort costs zero coordinator log writes and zero acknowledgement messages, against the four messages per participant that the base protocol spends in two-phase commit and the coordinator decision record. Under a protocol that logged aborts, every one of them would pay for a durable write and a message.
The cost of presumed abort is on the participant side: a participant must retain its prepare record, and its locks, until it is certain that no commit decision can still arrive. That certainty requires either hearing from the coordinator or reaching a state where no coordinator decision can exist. Since a coordinator crash can make the commit record temporarily unavailable rather than absent, participants cannot always distinguish the two. This is the origin of the blocking behaviour discussed in in-doubt transactions and blocking, and presumed abort does not remove it. It only removes the abort record.
Presumed commit and its retained-state problem
Presumed commit inverts the default: a missing decision means commit. For this to be safe, the coordinator must ensure that no participant can be in a position where “no record” would be read as commit unless a commit is genuinely the outcome. The mechanism is a commit-presumption record written before the prepare messages are sent.
The sequence is: write a record saying “this transaction exists and if you hear nothing more, commit it”, then send prepares. If the coordinator decides to abort, it writes an abort record, because now the default no longer applies. If it decides to commit, it can write nothing further, because the default already covers the case. A participant that asks and gets no answer commits.
The trade is the mirror image. Under presumed commit, aborts cost a coordinator write and commits do not. Commits are usually the majority in an online transaction workload, so at first glance presumed commit looks better. Two properties spoil it.
First, the presumption record must be written before the prepares, so it exists for transactions that later abort for trivial reasons, including transactions that were never going to reach a participant at all. The write cannot be avoided by knowing the outcome early.
Second, and more seriously, presumed commit makes recovery harder in the direction that matters. A coordinator that loses its log after deciding abort, but before informing participants, leaves participants holding locks and a default of commit. Recovery cannot simply declare abort, because the participants will not accept it: their rule says commit. The system must reconstruct the abort decision, which requires the presumption record to have been durable in the first place, which brings back the write it was trying to avoid. And a participant that has prepared and lost contact must retain enough state to distinguish “this transaction existed and was aborted” from “I have never heard of this transaction”, because the default for the first is commit-by-rule and for the second is nothing at all. That means the participant must keep abort records, not just prepare records.
So presumed commit moves durable writes from the coordinator’s commit path to the coordinator’s abort path and the participants’ abort path. In a system where commits dominate, it can reduce total log traffic. In a system where the coordinator is a single process and participants are many, it multiplies the per-transaction records by the number of participants, which usually dominates.
Comparing the two by what must survive
The cleanest way to compare is to list the records that must exist after a crash, for each protocol, for each outcome.
| Outcome | Presumed abort | Presumed commit |
|---|---|---|
| Commit, coordinator crashed | Coordinator commit record, participants’ prepare records | Coordinator presumption record, participants’ prepare records |
| Abort, coordinator crashed | Nothing; participants roll back | Coordinator abort record, participants’ abort records |
| Commit, participant crashed | Participant prepare record; coordinator resends | Participant prepare record; coordinator resends |
| Abort, participant crashed | Nothing | Participant abort record |
Read the abort rows: under presumed abort, an abort is recoverable from the absence of information, so a coordinator that loses its log entirely can still tell every participant to roll back, and they will comply because rollback is always permitted in the absence of a commit record. Under presumed commit, the same total loss of the coordinator log leaves participants with a commit default they cannot override and no way to learn that an abort was decided. The transaction’s fate is then decided by whichever participant has the most complete record, which is a consistency hazard.
This is the reason presumed abort is the near-universal choice. It makes the failure of the coordinator’s storage degrade to “everything aborts”, which is a consistent and atomic outcome, rather than to “some participants commit and some cannot decide”. Atomicity survives a total loss of the decision site.
Where the distinction shows up in real systems
The presumption is visible in the interface. A participant that can be told to commit a transaction it has never heard of is running presumed commit; a participant that refuses, because no commit record exists, is running presumed abort. In PostgreSQL, COMMIT PREPARED requires the transaction to have been prepared on that server, and a ROLLBACK PREPARED for an unknown identifier is an error rather than a silent success, because the participant does not accept a decision it has no state for. That is consistent with presumed abort at the protocol level, with the participant’s prepared state acting as the record of its vote.
The read-only optimisation in the R* protocol is a further refinement worth noting, because it is often confused with presumption. A participant that has only read, taken no locks that matter, and written nothing can vote “read-only” instead of “yes”. The coordinator then omits it from the second phase entirely: a read-only participant has nothing to commit and nothing to roll back. This is orthogonal to presumed abort but compounds with it, since both reduce the second phase to the participants that actually hold write locks.
The two ideas combine into the shape most production systems have: prepares only for participants with writes, commit records only for commits, and a default of abort for anything unknown. The remaining cost is the blocking window, which no presumption removes because the uncertainty is about a record that may exist rather than about a default.
Choosing when a commit default is defensible
Presumed commit has a defensible niche: systems where the coordinator is highly available, participants are few, and aborts are the common case. A coordinator that is co-located with a reliable replicated log and a small participant set can absorb the extra records, and if the workload is dominated by transactions that abort, moving the write to the abort path is a real gain.
The condition that must hold is that no participant can ever be in a state where the commit default applies to a transaction that was actually aborted. That requires the abort record to reach the participant before the participant’s presumption expires, which in practice means the coordinator must not lose its log while participants are prepared. Any deployment where the coordinator’s storage is a single unmirrored disk fails that condition, and the protocol’s correctness becomes conditional on hardware the protocol cannot inspect.
For a system that has to survive the loss of its decision site, presumed abort is the answer, and the reason is not efficiency but the direction the failure degrades in. Abort is always available as a consistent outcome; commit is not.
References
- Transaction Processing: Concepts and Techniques — Jim Gray and Andreas Reuter, Morgan Kaufmann, 1992
- Transaction Management in the R* Distributed Database Management System — C. Mohan, Bruce Lindsay and Ron Obermarck, ACM TODS, 1986
- Efficient Commit Protocols for the Tree of Processes Model of Distributed Transactions — C. Mohan and Bruce Lindsay, ACM PODC, 1983