Learn
Lesson · Replication and Consistency · Clocks and order

Vector Clocks and Concurrency

A vector clock carries one counter per process, merged by elementwise maximum, and it makes happens-before decidable in both directions: e → f exactly when V(e) ≤ V(f) componentwise and the vectors differ. When neither vector dominates the other the events are concurrent — unordered by any chain of messages. On the same eleven-event diagram, 23 of the 55 pairs are concurrent, and those are precisely the pairs a merge will have to decide.

V(e) ≤ V(f) componentwise and V(e) ≠ V(f) ⟺ e → f neither vector dominates the other ⟺ concurrent on a receive: elementwise max, then increment your own component same 11 events: 55 pairs, 32 ordered, 23 concurrent concurrent means unordered by information, not simultaneous in time
A partial order, and the pairs it leaves unordered

Core ideas

What this lesson establishes

One counter per process, a comparison that can fail in both directions, and a word that does not mean what it sounds like.

1

One counter per process, merged by elementwise maximum

Process i keeps a vector V and increments V[i] at each of its own events. A message carries the sender's whole vector; on receipt the receiver takes the elementwise maximum with its own and then increments its own component. The vector is therefore a record of how much of each process's history this event knows about.

2

Comparison is componentwise, and it can fail both ways

V(e) ≤ V(f) means every component of V(e) is at most the matching component of V(f). If that holds and the vectors differ, e → f. If neither V(e) ≤ V(f) nor V(f) ≤ V(e), there is no chain either way and the events are concurrent. Unlike a single integer, a vector can simply refuse to compare, and that refusal is the answer.

3

Concurrent is a statement about information, not about time

A3 and C3 on this diagram are concurrent, and they may have occurred a minute apart on any wall clock. What makes them concurrent is that neither process had heard anything of the other's event when its own occurred. Concurrency here means “unordered by any chain of messages”, and it is exactly the condition under which two updates conflict.

The material

Vectors, comparison, and the pairs that refuse to order

How the vectors propagate, what the componentwise comparison decides, and why the count of concurrent pairs is the useful output.

Definition · Vector clock, and concurrency

A vector clock on n processes assigns each event a vector V of n counters. Process i increments V[i] at each of its events; a receive first takes the elementwise maximum with the vector carried by the message. Then e → f if and only if V(e) ≤ V(f) componentwise with V(e) ≠ V(f), and e and f are concurrent if neither comparison holds.

The “if and only if” is what a Lamport stamp could not offer. A single integer can be compared with any other integer, so it always produces an answer even when there is no answer to produce; a vector produces three possible outcomes — before, after, or neither — and the third is as informative as the others.

components in the order (A, B, C) messages A2 → B2 B3 → C2 C1 → A4 A A1 (1,0,0) A2 (2,0,0) A3 (3,0,0) A4 (4,0,1) B B1 (0,1,0) B2 (2,2,0) B3 (2,3,0) B4 (2,4,0) C C1 (0,0,1) C2 (2,3,2) C3 (2,3,3) the three receives, worked B2 = max((0,1,0), (2,0,0)) then +1 in B = (2,2,0) C2 = max((0,0,1), (2,3,0)) then +1 in C = (2,3,2) A4 = max((3,0,0), (0,0,1)) then +1 in A = (4,0,1)

Read C3 = (2,3,3) as a sentence: this event knows about the first two events of A, the first three of B, and is C's own third. That is the whole content of a vector clock, and every ordering question is answered by comparing two such sentences.

Counting the concurrent pairs

pairs in total C(11,2) = 55 ordered, one dominates the other 32 concurrent, neither dominates 23 = 41.8% of all pairs a worked comparison A2 (2,0,0) vs B1 (0,1,0) A2 ≤ B1 ? 2 ≤ 0 is false B1 ≤ A2 ? 1 ≤ 0 is false neither: concurrent and one that does order A1 (1,0,0) vs C3 (2,3,3) 1 ≤ 2, 0 ≤ 3, 0 ≤ 3, and the vectors differ so A1 → C3, along A1 → A2 → B2 → B3 → C2 → C3

Twenty-three of fifty-five is not an anomaly of this diagram, it is what a system with few messages looks like. Concurrency is the default and ordering is what communication buys, so a system that gossips rarely has a great many concurrent pairs and a system that synchronises constantly has few — and pays for the difference in messages.

Example · Concurrent is not simultaneous

A3 = (3,0,0) and C3 = (2,3,3). Compare: 3 ≤ 2 fails, so A3 does not precede C3; and 3 ≤ 0 fails in the middle component, so C3 does not precede A3. They are concurrent — and C3 is the last event on its process while A3 is in the middle of another, so on a wall clock they could be seconds or minutes apart. The vectors are not claiming they happened at the same moment. They are claiming that neither process could possibly have known about the other's event, which is the condition under which two updates to the same key are a conflict rather than an overwrite.

That is what the count is for. Every concurrent pair touching the same data is a decision somebody has to make — keep one, keep both, merge them — and “Conflict Resolution, Counted” is where those decisions get priced. The vector clock's job ends at identifying them, and it does that exactly, which is more than any single number can do.

Interactive

Vector clocks and concurrency

Happens-before as a partial order, with every incomparable pair listed

Vector clocks and concurrencyincomparable means concurrent, and the concurrent pairs are the conflicts
an event, with its vectora messagea concurrent pair

Method

Stamping with vectors and reading off the conflicts

The propagation is mechanical. The part worth slowing down for is the comparison, which has three outcomes and not two.

1

Fix the component order and keep it

Decide once that the vector is (A, B, C) and write every vector that way. Most arithmetic errors here are a component written in the wrong slot, and they are invisible until a comparison comes out strangely.

2

Increment your own component at every event, including sends and receives

A send is an event on the sender and a receive is an event on the receiver, so both increment. Forgetting the increment on a send makes the send and the message's previous event compare as equal.

3

On a receive, take the elementwise maximum first, then increment

Maximum with the message's vector, then +1 in your own slot. The order matters: incrementing first and then taking the maximum can lose your own increment if the message was ahead in your component, which it should never be but will be if an earlier step was wrong.

4

Compare in both directions before concluding anything

Ask whether V(e) ≤ V(f), then whether V(f) ≤ V(e). Two failures mean concurrent; one success means ordered; two successes mean the vectors are equal and you have compared an event with itself.

Vectors, comparison and conflict

Score 0 / 0

The same diagram, stamped with vectors

The same three processes and three messages as before. The stamps this time are vectors, and the output is not an order but a census: how many of the fifty-five pairs are ordered and how many are conflicts waiting to happen.

components (A, B, C); messages A2 → B2, B3 → C2, C1 → A4 A1 (1,0,0) A2 (2,0,0) A3 (3,0,0) A4 (4,0,1) B1 (0,1,0) B2 (2,2,0) B3 (2,3,0) B4 (2,4,0) C1 (0,0,1) C2 (2,3,2) C3 (2,3,3) three comparisons A2 (2,0,0) vs B1 (0,1,0) 2 ≤ 0 no, 1 ≤ 0 no concurrent A1 (1,0,0) vs C3 (2,3,3) 1 ≤ 2, 0 ≤ 3, 0 ≤ 3 A1 → C3 A3 (3,0,0) vs C3 (2,3,3) 3 ≤ 2 no, 3 ≤ 0 no concurrent the census pairs in total C(11,2) = 55 ordered 32 concurrent 23 and the comparison with the previous lesson's stamps Lamport ordered 49 of these pairs by stamp, of which 17 were pairs the vectors call concurrent

The second and third comparisons are the ones to sit with. A1 and A3 are two events on the same process, one before the other, and the vectors say that the earlier one precedes C3 while the later one does not. That is not a contradiction: A1's information reached C through the chain of messages and A3's did not, because A3 happened after A had already sent everything it was going to send.

Twenty-three concurrent pairs on eleven events is the real output. If those events were updates to one key, twenty-three of the pairs would need a merge rule and thirty-two would not — and no amount of clock accuracy changes that split, because it is a fact about which messages were sent.

For a faded rehearsal, delete the message C1 → A4 from the diagram. The supplied first move is that A4 becomes a local event, so its vector is (4,0,0) rather than (4,0,1). Restamp what changes, predict whether the concurrent count rises or falls, then compute it and check against the lab.

Common mistakes

1
Reading concurrent as simultaneousThe word is borrowed and it misleads. Two concurrent events can be minutes apart in real time; what they cannot be is causally connected. Conversely two events at the same instant on synchronised clocks may be perfectly ordered if a message ran between them. The vectors know nothing about clocks and everything about messages.
2
Comparing vectors by their sum, or by one componentA3 = (3,0,0) sums to 3 and C3 = (2,3,3) sums to 8, which would order them — and they are concurrent. Any collapse of the vector to a single number reintroduces exactly the defect of a Lamport stamp, because a single number is always comparable. The comparison must be componentwise and it must be tried in both directions.
3
Expecting the vector to say which concurrent update is rightIt says they conflict and nothing more, which is its job done correctly. Choosing between them, or merging them, is a decision about the data rather than about the ordering — and a merge that always picks the larger vector, or the later arrival, is making that decision by accident rather than by design.

Check your understanding

✓
Finish when an incomparable pair of vectors reads as “a merge decision”, not as an error.

You should be able to propagate vectors along a diagram including sends and receives, compare two vectors in both directions and report one of three outcomes, count the concurrent pairs, and say what a concurrent pair implies about two updates to one key.

Note: Both clocks so far count events rather than seconds, which is what makes them exact. The temptation is always to use the machine's own wall clock instead, since it needs no messages at all. “Physical Clocks and Drift” computes how wrong that is: a drift rate and a sync interval give an uncertainty window, and any two events closer together than the window cannot be ordered by a timestamp at all.

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.