Skip to content
About
Main content

Design a commit

The decision

You are building or choosing the 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

1

Name the single atomic write

The one write that makes the commit happen: forcing a log record to disk, a conditional swap of a pointer, a create-if-not-exists, a rename. If you cannot name it: you do not have transactions, you have a hope.

2

Compute the commit-rate ceiling

1 ÷ the of that write is the most ordered commits per second one committer can make. An 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 for the write. Batching commits together () raises , 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.

3

Decide in place or out of place

In place (new values overwrite old ones, with an undo log): commit is cheap, 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.

4

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.

5

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?"

6

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 . And with n writers retrying on one pointer at commit latency T, to land them all: 10 writers at 50 ms spend 2.5 s just coordinating.

7

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 , allocates no transaction ID and writes no . It is cheap, not free: under isolation it can still take part in an anomaly, which is why some engines make it wait for a provably .


If the limits do not fit

EscapeWhat it costs
Group commitLatency for throughput (and it tunes itself)
A bounded, explicitly sized window in which acknowledged commits can be lost
Out-of-place placementSpace and a garbage collector, in exchange for free aborts
A single writerA throughput ceiling and , in exchange for zero conflict
Writers on disjoint partitionsA modelling constraint you must defend forever
Deduplication state with its own retention window