Skip to content
About
Main content

External consistency, and what is verifiable

How is external consistency's real-time anchor bought?

External consistency, and why it exists

Strict serializability is serializability plus real time: if T1 before T2 begins in wall-clock terms, every observer sees T1 first. Equivalently, it is generalized from operations to transactions. Spanner calls it .

It needs its own name because neither parent is enough. Serializability has no recency: Transactional isolation showed that a system returning the initial state forever is . Linearizability has no multi-object atomicity: Distributed consistency showed that it is defined per object. Their conjunction is strictly stronger than either, and it is the only cell in the combined table with no anomalies left.

It costs the union of both bills. The real-time anchor is bought in exactly one of three ways:

  1. Bounded clock uncertainty, paid as commit wait (Spanner).
  2. A communication round to an authority (a timestamp oracle; Percolator).
  3. Optimism, paid as restarts (CockroachDB's uncertainty intervals).

How commit wait and uncertainty restarts work is Bounded clock uncertainty.

The justification most people never hear: almost nobody needs external consistency for reasons internal to the database. They need it because of a second channel (a human, a message queue, a separate service) that carries information faster than replication does. That is exactly the hidden-causality problem of Distributed consistency, and external consistency is the only model that closes it, because Buying external consistency is buying immunity to the causality you cannot observe.

So "do we need it?" becomes answerable: do information paths exist around your system that are faster than your ? For anything user-facing across two regions, yes. (Example: Anika sends money, her app shows "sent", she phones Sam, and Sam opens his app in another region.)


What is actually verifiable

Closing this mechanism requires admitting how little of it can be checked.

Linearizability checking is for general histories, and search-based checkers blow up on realistic traces. The practical approach inverts the problem. Record operations designed so that the version order can be recovered afterwards (list-append, counters). Infer the . Look for cycles. Then classify the cycles using exactly the shapes from Transactional isolation.

Example of a list-append test. Each transaction appends a unique number to a list stored in a row, and reads other lists. After the run, each list's final order reveals the order in which writes were applied, so the checker knows every write-write and write-read dependency without trusting the database. It then looks for a cycle and names it (for example a cycle with two edges is ).

What cannot be checked at all: any claim, and any property requiring knowledge of operations that did not occur.

The operational consequence, stated bluntly: a vendor's is a hypothesis, and a cheap one to test. Independent testing has repeatedly found claimed levels unmet. The pattern is not incompetence. The levels were specified against one family of mechanisms and implemented with another, which is the same root cause as the naming mess in Transactional isolation. How to build a testing method is measurement's subject; this mechanism's contribution is knowing what to look for.