Definition · Vector clock, and concurrencyA 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 simultaneousA3 = (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.