Design a commit
You are building or choosing the commit path of a store: a database, a table format on object storage, or a pipeline that publishes results. No storage below a transaction can perform many writes at once, so a commit always rests on one small write that stands for all the others. What is that write, and what limits does it set?
You will end with the commit path's atomic write, its commit-rate ceiling, the cost of an abort, and a retry policy.
Work through these in order: each answer feeds the next.
Work through it
Name the single atomic write
The one write that makes the commit happen: forcing a log record to disk, a conditional swap of a catalog pointer, a create-if-not-exists, a rename. If you cannot name it: you do not have transactions, you have a hope.
Compute the commit-rate ceiling
1 ÷ the latency of that write is the most ordered commits per second one committer can make. An fsync on an SSD takes tens of microseconds; an object-store round trip about 10–50 ms. At 50 ms: 1 ÷ 0.05 = 20 commits per second. Compare it with your requirement before anything else.
Why
Each commit waits for the write. Batching commits together (group commit) raises throughput, but not the rate of individually ordered commits. The object-store round trip is three orders of magnitude slower than an fsync, which is why table formats on object storage commit tens of times per second per table, not tens of thousands.
Decide in place or out of place
In place (new values overwrite old ones, with an undo log): commit is cheap, abort is expensive. Out of place (new data written elsewhere, then a pointer swapped): abort is free, commit pays in space and a garbage collector.
Why
In place, the new data is already in the table, so an abort must undo every change. Out of place, nothing is visible until the pointer moves, so an abort just abandons the writes. That decides whether optimistic schemes, which abort often, are affordable at all.
Estimate conflicts in your conflict unit, not in rows
Find the granularity at which the system detects conflicts: rows, files, partitions or whole tables. Count the chance of two writers touching the same unit in those terms. A log that tracks files cannot see that two writers touched different rows of the same file. Expect it to differ from your intuition by up to three orders of magnitude.
Decide what a failed commit loses
If the write can be rebased (blind appends that touched different files): keep the data files and retry only the metadata step. If it cannot (a MERGE that read files another writer deleted): the whole write is lost, so aborts cost I/O and money, and optimism gets expensive fast.
Why
In a database an abort wastes CPU time. On object storage it may waste gigabytes of files already written. The practical question is not "will it conflict?" but "if it conflicts, can it be rebased?"
Make sure something can re-execute it
If nothing can re-execute the transaction: there is no retry, only failure. For a read-modify-write: the retry must re-read inside its loop, with backoff and random jitter between attempts.
Why
Retrying with the values read the first time is a lost update. And with n writers retrying on one pointer at commit latency T, naive retry needs about n²T ÷ 2 to land them all: 10 writers at 50 ms spend 2.5 s just coordinating.
Declare read-only transactions
Mark transactions that only read as READ ONLY. It is the cheapest correctness-preserving win available.
Why
In a multiversion database a declared read-only transaction takes no locks, allocates no transaction ID and writes no commit record. It is cheap, not free: under snapshot isolation it can still take part in an anomaly, which is why some engines make it wait for a provably safe snapshot.
If the limits do not fit
| Escape | What it costs |
|---|---|
| Group commit | Latency for throughput (and it tunes itself) |
| Asynchronous commit | A bounded, explicitly sized window in which acknowledged commits can be lost |
| Out-of-place placement | Space and a garbage collector, in exchange for free aborts |
| A single writer | A throughput ceiling and availability, in exchange for zero conflict |
| Writers on disjoint partitions | A modelling constraint you must defend forever |
| Idempotency keys | Deduplication state with its own retention window |