Learn
Lesson · Replication and Consistency · Consistency, counted

Linearizability by Enumeration

A history of operations, each occupying an interval, is linearizable exactly when some total order of them respects real time — an operation that finished before another started must come first — and replays legally against the object. So enumerate the orders and count the survivors. Three operations give 6 orders, of which 3 respect real time and 0 are legal: a violation. Seven operations give 5040, and the lab refuses, because the refusal is the lesson.

linearizable ⟺ some total order is real-time respecting and legal real time: if a ends before b starts, a must come before b legal: replay against the object and every read returns what was written 3 operations: 6 orders, 3 allowed by real time, 0 legal → a violation 6 operations: 720 orders. 7: 5040, and the lab refuses to enumerate them
Two filters, and the count that survives both

Core ideas

What this lesson establishes

An operation is an interval rather than an instant, two filters cut the orders down, and the number that survives is the verdict.

1

An operation occupies an interval, not an instant

A call starts when the client issues it and ends when the response arrives, and the operation may be considered to take effect at any single moment inside that interval. Two operations whose intervals overlap may therefore be placed in either order; two whose intervals do not overlap may not. This is the only role real time plays.

2

Real time filters the orders, the object decides which survive

The first filter is mechanical: for every pair where one operation ended before the other started, keep only the orders putting them that way round. The second is a replay: run the surviving orders against the object — for a register, each read must return the value last written — and keep the ones that never contradict themselves.

3

Zero legal orders is the verdict, not an accusation

If nothing survives both filters, the history is not linearizable, and that is a property of the history as a whole. It does not mean one particular replica returned a value it never held; every read in the violating history here returns a value that genuinely existed. The defect is that no single sequence of instants can explain all of them at once.

The material

Two filters, a count, and the cap that is a lesson

What linearizability asks, how the enumeration answers it, and why no real checker works this way.

Definition · History, real-time order, and a linearization

A history is a set of operations, each with a start time, an end time and a return value. A linearization is a total order of those operations such that a precedes b whenever a ended before b started, and such that replaying them in that order against the object is legal — every read returns the most recently written value. A history is linearizable if at least one linearization exists.

The definition is an existence claim, and that is what makes the enumeration a decision procedure: generate every total order, apply the two filters, and count. A count of zero settles the question in the negative, and any count above zero settles it in the positive.

the register starts at 0 A write 1 [0, 4] B read → 1 [2, 6] C read → 0 [5, 9] real time: A ends at 4 and C starts at 5, so A must precede C A and B overlap; B and C overlap; no other constraint

Nothing about this history looks wrong operation by operation. B read 1, which was written. C read 0, which was the initial value. Both are values the register genuinely held, and a system that checked each response individually would report no problem at all.

order real time replay against a register starting at 0 A B C A before C w1, r→1 ✓, r→0 ✗ C reads 0 after the write A C B A before C w1, r→0 ✗ B A C A before C r→1 ✗ nothing written yet B C A C before A rejected by real time C A B C before A rejected by real time C B A C before A rejected by real time total orders 6 allowed by real time 3 legal 0 the history is NOT linearizable

The verdict comes from the combination. C reading 0 would be fine if it could be placed before the write, and real time forbids that because A had already returned when C was issued. B reading 1 would be fine anywhere after the write. It is the pair of constraints together that leaves nothing, which is why linearizability is a property of histories and not of responses.

Why the lab stops at six operations

k k! what the enumeration costs 3 6 4 24 5 120 6 720 the cap the lab enforces 7 5040 refused, with the number printed 10 3 628 800 20 2.4 × 10¹⁸

The growth is factorial, so the cap is not a limitation of the page, it is the shape of the problem. Real checkers do not enumerate: they search with pruning, commit operations greedily and backtrack, or check a weaker property that is cheaper to decide. The lab refuses a seventh operation and prints 5040 rather than quietly truncating, because a silent truncation would teach the opposite of the thing worth learning.

Example · One return value makes it legal

Change C to read 1 instead of 0 and nothing else about the history moves — same intervals, same real-time constraint. Now A B C replays as w1, r→1, r→1, which is legal, and A C B does too. Two of the three real-time-respecting orders survive, the count is 2, and the history is linearizable. A single returned value flipped the verdict, which is the sense in which linearizability is a property of the whole history and a very sharp one.

It is worth being precise about what this buys. Linearizability is the guarantee that the system behaves as though there were one copy of the data and every operation took effect at a single instant between its call and its return. “Quorums Overlap” gave a much weaker property — no acknowledged write is missed entirely — and the gap between the two is the whole reason this lesson exists.

Interactive

Linearizability by enumeration

Count the legal total orders — and see why six is the cap

Linearizability by enumerationcount the total orders that real time allows and a register would accept
an operation’s intervala legal orderno legal order existsthe search space

Method

Deciding a short history

Two filters in a fixed sequence, and a verdict that is a count rather than an opinion.

1

Write each operation as an interval with its return value

Start, end, what it did, what it returned. A history without return values cannot be checked, and a history without intervals has no real-time constraints to apply.

2

Derive the real-time constraints pairwise

For every pair, if one ended before the other started, that order is forced. If the intervals overlap, both orders remain open. Write the forced pairs down; they are usually far fewer than the pairs.

3

Enumerate the total orders and keep those respecting the constraints

k! orders, filtered by the forced pairs. For small k this is a short list and worth writing out, because seeing which orders survive is what makes the next step meaningful.

4

Replay each survivor against the object and count the legal ones

For a register: track the current value, and reject at the first read that disagrees with it. Zero survivors means the history is not linearizable. More than zero means it is, and the count itself has no further meaning.

Histories, orders and verdicts

Score 0 / 0

Three operations, six orders, no explanation

A register starting at zero. One client writes 1; two others read it, one returning 1 and one returning 0. Every response is a value the register really held, and the system is nonetheless wrong. The question is how to demonstrate that rather than assert it.

initial value 0 A write 1 [0, 4] B read → 1 [2, 6] C read → 0 [5, 9] real-time constraints A ends 4, C starts 5 A must precede C A [0,4] and B [2,6] overlap no constraint B [2,6] and C [5,9] overlap no constraint the six total orders A B C real time ok w1 → r1 ✓ → r0 ✗ A C B real time ok w1 → r0 ✗ B A C real time ok r1 ✗ (register still 0) B C A C before A — rejected C A B C before A — rejected C B A C before A — rejected 6 orders, 3 survive real time, 0 survive the replay verdict: NOT linearizable change C's return value from 0 to 1 and re-run A B C w1 → r1 ✓ → r1 ✓ legal A C B w1 → r1 ✓ → r1 ✓ legal B A C r1 ✗ 2 legal orders — linearizable

The violation is C, and it is worth saying exactly why rather than pointing at it. C was issued after A had already returned, so whatever instant C took effect at, it was after the write took effect; and it returned the value from before the write. No amount of reordering the two overlapping reads changes that, which is what the three surviving orders demonstrate by all failing.

The second run is the faded half of the example and it is a single character's difference. Two legal orders exist, so the history is linearizable, and nothing about the timings changed. The lesson is that linearizability is decided by the combination of intervals and returned values, and that neither alone is enough to look at.

For a faded rehearsal, take the four-operation history with two concurrent writes: A w1[0,3], B w2[1,5], C r1[4,8], D r2[6,10]. The supplied first move is that there are 24 total orders and the forced pairs are A before C and A before D. Work out how many survive real time, predict whether any are legal, then check both in the lab and explain the result in one sentence about where B had to be placed.

Common mistakes

1
Checking operations one at a timeEvery response in the violating history is a value the register held, so per-operation checking passes it. Linearizability is a property of the history taken together, and the only way to refute it is to show that no total order explains all of it. That is why the output is a count over orders rather than a verdict on a response.
2
Reading overlapping intervals as permission to do anythingAn overlap removes a constraint, it does not add a freedom. The two overlapping reads in the worked history could be placed either way round and it made no difference, because the constraint that killed the history came from the non-overlapping pair. Look for the forced pairs first; they are where the verdict comes from.
3
Expecting enumeration to be how this is checked in practicek! reaches five thousand at seven operations and 2.4 × 10¹⁸ at twenty. Real checkers search with pruning and backtracking, commit operations as soon as the object's state permits, or check something weaker and cheaper. The enumeration here exists because it makes the definition concrete, and the cap exists to make sure you notice it could not scale.

Check your understanding

✓
Finish when “every replica returned a value it held” sounds like an answer to a different question.

You should be able to write a history as intervals with return values, derive the forced pairs, enumerate and filter the total orders, replay the survivors against a register, report the count with zero as a violation, and say why the procedure does not scale.

Note: Linearizability rules out disagreement by insisting there was only ever one story. Systems that accept writes in more than one place give that up on purpose, and then have to decide what to do with two updates that genuinely conflict. “Conflict Resolution, Counted” closes the course by counting what each answer throws away.

Kept in this browser only, for you. Nothing is sent anywhere and nothing checks it. Carry it to another device.

Feedback and recommendations

Something to change about this lesson? Write it down, tick it off when it is handled, and export the list when you want to act on it. Kept in this browser only: nothing is sent anywhere, and nobody is notified.

No recommendations yet for this lesson.