Programming & Compilers

Linearizability and legal operation histories

Linearizability tests concurrent operation histories against a sequential contract. Examine linearization points, overlapping calls and pending responses.

By Republeq Editorial · 9 min read ·
Linearizability compares concurrent operation histories, legal sequential order and linearization points, showing valid overlap, impossible duplicate results and pending-call proof completion.

Two calls can overlap even though an application's object is specified through one-at-a-time operations. The correctness question is whether their observed results fit some legal sequential order that also respects the ordering imposed by nonoverlapping calls.

linearizability asks whether the whole relevant history admits that explanation. Overlapping calls can be ordered differently from their invocation or response order when their results and the sequential contract permit it. Nonoverlapping calls still impose the real-time relationships the explanation must preserve.

The examples use a hypothetical queue and explicit invocation and response times. They are history checks, not a tested queue implementation, a memory-publication argument or a progress guarantee.

Define concurrent operation histories against a queue contract

Start with an empty queue. Enqueue(v) appends v to the tail and returns success. Dequeue removes and returns the oldest stored value, or returns Empty if the queue has no value. Values A and B are distinct.

Under this sequential specification, enqueue(A), enqueue(B), dequeue must return A on the dequeue. Reversing the enqueue order makes the first dequeue return B. After either ordering, a second successful dequeue returns the other value.

Each call has an invocation event and, if it completes, a response event. The response includes the actual result, such as success, A, B or Empty. A call with no response yet is pending.

Record the result returned by each completed call against its matching invocation. The public queue specification determines whether that result is legal. An internal trace can support the event account when its relationship to the complete calls is established.

The cancellation-safety guide provides an observation-boundary comparison for concurrent operation histories. It distinguishes the cancellation request, actual interruption point, committed document change and caller report. A committed effect can exist before its response reaches the caller. Those distinct observations matter when defining a history; the queue examples still require their own sequential specification and legal ordering proof.

Extract precedence from invocation and response intervals

If one operation responds before another is invoked, the first must precede the second in the sequential explanation. That ordering is visible in the external history and cannot be reversed merely to make a returned value convenient.

If two calls overlap, their interval relationship alone does not force either order. Other results and the object specification can still restrict which ordering is legal.

In the first history, enqueue(A) runs from time zero to six, and enqueue(B) runs from time two to four. A dequeue runs from time seven to nine and returns B. Both enqueues return success. These times specify the observed intervals; they do not assign a particular internal instruction to either enqueue.

Both enqueues completed before the dequeue began. Each must therefore precede that dequeue. The enqueue intervals overlap, so their relative order remains a candidate choice.

Enqueue(A) began first but completed later. Neither fact by itself forces it ahead of enqueue(B). The interval overlap is why the history admits more than one possible ordering to inspect.

Enumerate the two sequential explanations

Candidate one orders enqueue(A), enqueue(B), dequeue. The queue would return A, so this candidate contradicts the observed B result.

Candidate two orders enqueue(B), enqueue(A), dequeue. It returns B and leaves A queued. That matches the observed result and respects both enqueues preceding the dequeue.

A proof for an implementation must establish suitable explanations for all histories it admits. Finding one explanation for this illustrative history is not a general implementation proof.

In a second history, enqueue(A) responds before enqueue(B) is invoked, and both finish before a dequeue returning B. The first enqueue is forced ahead of the second. With no earlier dequeue, the observed B has no legal explanation under the stated queue contract.

Invocation-response relationships can make this B result legal or illegal under the same queue rules. The history cannot be replaced by a list of results without their ordering evidence.

Duplicate dequeue results can defeat every candidate order

Use the overlapping enqueue intervals from the first history and add two dequeues after both enqueues responded. D1 runs from time seven to ten and returns A. D2 runs from eight to eleven and also returns A. The queue began empty, with A and B each enqueued once.

The two dequeues overlap, so either dequeue order is permitted by their intervals. The enqueues can also be ordered either way. There are four candidate combinations: A-before-B or B-before-A, each paired with D1-before-D2 or D2-before-D1.

For this empty-queue prefix, the one enqueue of A supplies only one A item for removal. The pair of A returns violates that input-and-result account. Individually atomic internal instructions cannot supply the missing second item in the stated sequential specification.

The initial state and input values are essential to this contradiction. A queue initially holding two A values, or two completed enqueues of A, can legitimately return A twice. Our history instead starts empty and supplies distinct A and B exactly once. The claim concerns those inputs and that prefix, not a general rule that equal dequeue values prove corruption. Keep the input records as well as the result values when examining a duplication report.

For A-before-B, the legal per-call results are D1=A/D2=B or D2=A/D1=B according to dequeue order. For B-before-A, they are D1=B/D2=A or D2=B/D1=A. All four assignments contradict the pair of observed A results. This per-call check keeps the duplicate claim tied to the empty initial queue and distinct input values.

Candidate results for the empty queue with one A and one B
Enqueue orderDequeue orderRequired D1 resultRequired D2 resultFits observed A and A?
A then BD1 then D2ABNo
A then BD2 then D1BANo
B then AD1 then D2BANo
B then AD2 then D1ABNo

The rejection is based on the public outcomes and all permitted sequential orders. It does not depend on guessing which line of implementation code caused the duplication.

How linearization points support the history proof

A linearization point can represent where an operation takes effect in a correctness argument. For a completed call, the proposed point must lie within its invocation-response interval and fit the legal ordering and results.

For the valid first history, choose an illustrative point at time three for enqueue(B), five for enqueue(A), and eight for dequeue. Each lies inside its call, and their order produces the legal B-first explanation.

Those chosen times explain this abstract history. They do not identify actual implementation instructions. A real proof may associate an effect with a particular transition, but it must justify the relation between that transition, the object's state and the returned result.

Declaring every response instant a linearization point can fail when earlier internal decisions are what make overlapping outcomes legal. Likewise, picking an arbitrary atomic instruction inside each call does not establish that the resulting order satisfies the specification.

The runtime-code-replacement guide supplies a transition-boundary comparison for linearization points. Its state-migration example prepares and validates a new representation before changing the authoritative format under a stipulated access discipline. A visible marker can support an effect-point argument only if the object contract and every relevant observer follow that discipline. The guide also tracks retained callers and callbacks; it does not prove that one marker instruction linearizes an entire replacement protocol.

This comparison concerns the proof obligation, not distributed availability or a partition-handling policy. The queue examples remain local history models.

Pending calls need explicit treatment

Suppose enqueue(C) has been invoked but has not responded when a completed dequeue returns C. The recorded prefix contains one pending call and a completed result that depends on its effect.

Under the conventional history treatment used here, a pending operation can be omitted when the completed behavior does not require it, or included through an appropriate completion of the history. Explaining the completed dequeue(C) requires including enqueue(C) as taking effect before it. Its proposed completion must preserve the queue specification and the required history relationships.

Completing a history for the mathematical check does not claim that the real caller received a response. It is a proof device for analysing the observed prefix. The operational receipt remains pending until its actual response is observed.

A pending dequeue with no returned value similarly does not supply an observed output to invent. The argument must state which pending operations it includes and why their permitted completions fit the completed behaviour.

Ignoring all pending calls can wrongly reject a prefix whose completed dequeue reflects an already effective enqueue. Treating all pending calls as completed with arbitrary values can wrongly accept a history by fabricating outcomes. The completion choices must remain explicit in the argument.

Herlihy and Wing's original definition extends a recorded history by appending zero or more response events, then asks whether its completed part is equivalent to a legal sequential history that preserves the original real-time precedence. Their queue examples include an enqueue whose value is dequeued before the enqueue response returns. This supports the mathematical treatment of pending calls used here. The explicit Empty response belongs to this article's supplied queue specification; it does not redefine every queue implementation.

Keep implementation evidence and the specification separate

For a proposed concurrent object, preserve the sequential rules, initial state, invocation events and actual responses. Extract every mandatory nonoverlap edge before choosing candidate orderings.

Test results against the legal state transitions in those orders. If none works, retain the contradictory history. If one works, identify the reasoning and its scope rather than labelling the whole implementation correct from that one example.

A proof-associated point must explain the operation's effect under the same contract. A source-code location, state badge or response timestamp can support the argument only when its relationship to the history has been established.

Keep call identifiers, invocation and response times, and returned values in separate columns when examining a queue history. A 15.6-inch FHD Touch display is specified for the Lenovo IdeaPad touch laptop, whose catalogue entry also identifies 512GB SSD storage and 16GB DDR4 memory. The listing also identifies a Core i5-1334U processor. Keep the original invocation-response log in a separate file from its proposed sequential explanation. The table needs the actual recorded calls and initial queue state before any candidate ordering can be judged.

The ASUS Vivobook 14 laptop has a catalogue-listed FHD screen and 16GB DDR4 memory; its processor is identified as the Core 5 120U. When viewing the same history on that computing workspace, retain the sequential queue rules beside the log. Equal outputs become a contradiction only after the initial contents, enqueued values and permitted call orders have been checked.

For the first history, B-before-A followed by dequeue(B) satisfies the mandatory edges. The duplicate-A history admits none of its four candidate assignments. In the pending-C case, a proof completion can include enqueue(C) before the observed dequeue, while the actual enqueue response remains unobserved. These are different history conclusions under the same explicitly stated queue contract.

Linearizability and legal operation histories