Key Question
How do events on three or more processes relate through chains of causality, and why does this matter for conflict detection?
Deep Dive
We have built the happened-before relation piece by piece: same-process ordering, message causality, transitivity, and concurrency. Now we put it all together on a complex multi-process scenario. Walk through the space-time diagram below and trace every causal relationship:
Process A Process B Process C
| | |
a1 | |
| b1 |
a2ββββββββββββββb2 |
| | c1
a3 | |
| b3ββββββββββββββc2
a4ββββββββββββββb4 |
| | c3
| b5ββββββββββββββc4
| | |
Let us trace the causal chains systematically:
Within each process (rule 1):
- A: a1 β a2 β a3 β a4
- B: b1 β b2 β b3 β b4 β b5
- C: c1 β c2 β c3 β c4
Send-receive (rule 2):
- a2 β b2 (A sends to B)
- c2 β b3 (C sends to B)
- a4 β b4 (A sends to B)
- b5 β c4 (B sends to C)
Transitive chains (rule 3):
Let us build chains starting from a1:
- a1 β a2 β b2, so a1 β b2
- a1 β a2 β b2 β b3 β b4 β b5 β c4, so a1 β c4
- a1 β a2 β b2 β b3 (wait, can we say a1 β b3? a1 β a2 β b2 β b3, yes)
- a1 β a2 β b2 β b3 β b4, yes
- a1 β a4? No, a1 β a4 is true but only within A. a1 β a4 by rule 1.
What about a4?
- a4 β b4 β b5 β c4, so a4 β c4
What about c1?
- c1 β c2 β b3, so c1 β b3
- c1 β c2 β b3 β b4 β b5 β c4, so c1 β c4
Concurrent events (neither β holds):
-
a3 and c1: a3 β a4 β b4 β b5 β c4, but does a3 relate to c1? c1 β c2 β b3 β b4. a3 and c1: there is no path from a3 to c1 (no message from A to C directly, and the chain through B goes a4 β b4, but a3 β a4 and a3 is before the chain starts on B, soβ¦). Actually letβs check: is there a path a3 β c1? a3 β a4 β b4 β b5 β c4. c1 is before c4, but that doesnβt give us a3 β c1. We need a3 β β¦ β c1. We donβt have that. And c1 β β¦ β a3? c1 β c2 β b3 β b4 β b5 β c4. That doesnβt reach a3 either. So a3 || c1.
-
a2 and b1: a2 β b2, and b1 β b2. a2 and b1: do we have a2 β b1? No, a2 β b2 and b1 β b2, but we need a2 β (something) β b1. a2 sends to B where itβs received as b2, not b1. And b1 β b2. Can we say a2 β b1? No path. b1 β a2? No path. So a2 || b1.
Conflict detection relevance:
Now consider a practical scenario. Process A and Process C are both writing to a distributed key-value store. A writes value X (at a4), and C writes value Y (at c3). The store must determine whether these writes conflict.
- If a4 β c3: Cβs write happened after Aβs, so the store can safely apply Cβs write (or use βlast writer winsβ).
- If c3 β a4: Aβs write happened after Cβs.
- If a4 || c3: the writes are concurrent, meaning neither writer knew about the other. This is a conflict.
From our diagram, is a4 β c3? a4 β b4 β b5 β c4. c3 β c4. We have a4 β β¦ β c4, but c3 β c4, not the other way. We donβt have a4 β c3. And c3 β a4? c3 β c4, no path to a4. So a4 || c3 β these writes are concurrent and conflict.
This is exactly the problem that Dynamo-style databases solve with vector clocks. The happened-before relation tells us whether events are causally related or concurrent. For concurrent events, the database cannot automatically resolve the conflict β it must present both versions to the application (or use a tiebreaker like timestamp, which may be wrong).
Check Your Understanding
- In the 3-process diagram above, is a2 causally related to c4? Trace the full chain.
- Are b2 and c2 concurrent or causally related? Justify your answer.
- Why do concurrent writes create a βconflictβ in a distributed database?
The βSo What?β
When you are debugging a distributed application and see surprising behavior β a userβs edit was lost, a counter was decremented twice, a notification was sent for an unread message β you are almost certainly looking at the consequences of unhandled concurrency. Tracing causal chains through the system reveals which events were aware of each other and which were not. This is the fundamental skill for understanding distributed behavior, and it is entirely independent of clocks, timestamps, or time synchronization.
βοΈ Exercises
Topic 3: Happened-Before Relation β Exercises
Exercise 1: Identifying Causal Relationships
Given the space-time diagram below, list ALL pairs of events that are causally related (a β b) and ALL pairs that are concurrent (a || b).
Process A Process B Process C
| | |
a1 | |
| b1 |
a2ββββββββββββββb2 |
| | c1
a3ββββββββββββββb3 |
| | c2
| | |
Use the notation (a1, b1) to mean βa1 and b1.β Include all pairing combinations across processes, not just within them. (You do not need to list same-process pairs β they are all ordered by rule 1.)
Exercise 2: Message Chain Causality
Process A sends a message M1 to Process B. After receiving M1, Process B sends a message M2 to Process C. After receiving M2, Process C performs an internal event.
(a) Draw the space-time diagram of this scenario (3 processes, 2 messages). (b) Is Aβs send of M1 causally related to Cβs internal event? Explain using the happened-before rules. (c) Would the answer change if B sent M2 before receiving M1? Why?
Exercise 3: Network Delay and Causality
Two events occur on different machines:
- Event a: A sends a message to B.
- Event b: B receives the message 5 seconds later (due to network congestion).
After receiving the message, B performs event c.
(a) Is b β c? Why? (b) Is a β b? Why? (c) Now suppose after sending the message, A performs event d (a local computation) 2 seconds before the message is delivered. Is d β c? Trace the chain. (d) What if A and Bβs clocks were perfectly synchronized, and the timestamps showed d at T=10:00:00.003, c at T=10:00:00.001? Does this contradict the happened-before relation? Why would clock-based ordering give the wrong answer?
Exercise 4: Concurrent Writes in Practice
A distributed key-value store has three replicas: R1, R2, R3. A client writes value βXβ to key βkβ and receives acknowledgment from R1. The write propagates to R2 and R3. Meanwhile, another client (unaware of the first write) writes value βYβ to the same key βkβ and receives acknowledgment from R2.
(a) Are the two writes concurrent? Why? (b) R3 receives the write of βYβ after it has already received βX.β From R3βs perspective, which value is βcorrectβ? (c) If the system uses last-writer-wins (LWW) based on physical timestamps, and the clocks on client 1 and client 2 differ by 50 seconds, what could go wrong? (d) What does the happened-before relation tell us that timestamps do not, in this scenario?
ποΈ View Solutions
Topic 3: Happened-Before Relation β Solutions
Solution 1
Within-process relationships (all by rule 1):
- A: a1 β a2 β a3
- B: b1 β b2 β b3
- C: c1 β c2
Send-receive relationships (rule 2):
- a2 β b2 (message from A to B)
- a3 β b3 (another message from A to B)
Transitive relationships (rule 3):
From a1:
- a1 β a2 β b2, so a1 β b2
- a1 β a2 β b2 β b3, so a1 β b3
- a1 β a2 β b2 β b3 β b3 β β¦ actually b3 is followed by nothing in B that reaches C. But wait, a3 β b3, not a2 β b2 β b3. Let me re-trace.
Actually letβs reconsider. The diagram shows a2 β b2 and a3 β b3. There is no message from B to C.
So transitive relationships:
- a1 β b2 (a1 β a2 β b2)
- a1 β b3 (a1 β a2 β b2 β b3? No, a2 β b2, and b2 β b3 in B, so a1 β a2 β b2 β b3, yes)
- a1 β b3 also via a1 β a3 β b3 (a1 β a3, a3 β b3, so a1 β b3)
- a2 β b3 (a2 β b2 β b3)
- a2 β b3 also via a2 β a3 β b3
- a3 β b3 directly (message)
- No relationships with C β there is no message from A or B to C, and no message from C to A or B.
Concurrent pairs:
All pairs involving C are concurrent (no messages to/from C):
- a1 || c1, a1 || c2
- a2 || c1, a2 || c2
- a3 || c1, a3 || c2
- b1 || c1, b1 || c2
- b2 || c1, b2 || c2
- b3 || c1, b3 || c2
Also concurrent across A and B:
- a1 || b1 (no path either direction)
- a2 || b1 (a2 β b2, and b1 β b2, but no path a2 β b1 or b1 β a2)
- a3 || b1 (similar reasoning)
- a3 || b2 (a3 β b3, b2 β b3, no path between a3 and b2 directly)
Any pair not connected by a β b chain is concurrent.
Solution 2
(a)
Process A Process B Process C
| | |
a1 (send M1)ββββb1 (recv M1) |
| | |
| b2 (send M2)ββββc1 (recv M2)
| | |
| | c2 (internal)
(b) Yes, Aβs send (a1) is causally related to Cβs internal event (c2).
- a1 β b1 (rule 2: send-receive of M1)
- b1 β b2 (rule 1: same process)
- b2 β c1 (rule 2: send-receive of M2)
- c1 β c2 (rule 1: same process)
- By transitivity (rule 3): a1 β b1 β b2 β c1 β c2, therefore a1 β c2
(c) If B sent M2 before receiving M1, then b2 (send M2) would come before b1 (receive M1) in process B. In that case:
- a1 β b1 (send-receive of M1)
- b2 β c1 (send-receive of M2)
- But a1 and b2? We have b2 β b1 (b2 before b1 in B). And a1 β b1. But do we have a1 β b2? No. a1 β b1 and b2 β b1, but we need a1 β β¦ β b2. b2 happens before b1, so a1 cannot β b2. And b2 β a1? No, b2 β c1, no path to a1. So a1 and b2 are concurrent. And since b2 β c1 β c2, we have a1 || c2.
The answer changes completely: if B sends M2 before receiving M1, then M2 was sent without knowledge of M1, and Cβs internal event is not causally dependent on Aβs send.
Solution 3
(a) Yes, b β c. Both events are in the same process (B), and b (receive) happens before c (internal event). Rule 1: same-process ordering.
(b) Yes, a β b. a is the send event and b is the receive event of the same message. Rule 2: send happens before receive. The 5-second delay does not affect this β the relationship holds regardless of how long the message takes.
(c) Yes, d β c. Here is the chain:
- a (send) happens before d (local event after send) on process A: a β d (rule 1)
- a β b (rule 2: send-receive)
- d and b: a β d and a β b. Is d β b? We donβt know d β b directly. But d happens after a on the same process. b happens after a (message receive after send). But do we have a relation between d and b? a β d and a β b. But do we know d β b? No, d happens after a on A, but we donβt have a message from A to B after d. d and b are either concurrent orβ¦ wait.
Actually let me reconsider. a β d (same process). a β b (send-receive). We have a β d and a β b. But no path from d to b. And b happens when it happens β we donβt have b β d either (b is in B, d is in A, no message). So d and b are concurrent.
d β c? We need d β β¦ β c. We have b β c (same process). But if d || b, then d β c is not guaranteed.
Hmm, I was too hasty. Let me reconsider the scenario. The key is: did A send another message after d? The scenario says: A sends a message (a), then performs local computation d (2 seconds before delivery). No second message is sent. So d is not connected to Bβs events. Therefore d and b are concurrent, and d and c are concurrent.
Wait, but is d β b possible? d occurs on A after the send. The send is a β B. The message is in transit. d happens before the message is received. But d is on A, b is on B. No message from d to b. So no causal link.
Actually I realize the scenario might be interpreted differently. Let me re-read: βafter sending the message, A performs event d (a local computation) 2 seconds before the message is delivered.β So timeline: a (send), then d (local), then b (receive on B). d occurs on A before the message is received on B.
Is d β c? We need a chain. d β β¦ β c. d is on A. Nothing connects d to B (no message from d). So d || b and d || c. The answer is no, d β c is NOT guaranteed.
Wait, but can we say a β d β β¦ and a β b β c? We know a is before both d and b. So a β d and a β b. But from d, is there any path to b or c? No. So d || c.
(d) If timestamps showed c at T=10:00:00.001 and d at T=10:00:00.003, clock-based ordering would say d happened after c. But the happened-before relation says they are concurrent β they have no causal link. If the clocks are not perfectly synchronized (which they never are), the timestamp ordering is meaningless. Even with perfect clocks, the ordering βc at 0.001, d at 0.003β does not mean c β d β causality cannot be established by timestamps alone. The events are on different machines with no message between them, so they are concurrent regardless of what the clocks say.
Solution 4
(a) Yes, the two writes are concurrent. Client 1 writes to R1, and Client 2 writes to R2. Neither client knew about the otherβs write β there is no causal chain connecting the two writes. No message, no shared state, no happened-before relation. They are concurrent (w1 || w2).
(b) From R3βs perspective, both values are βcorrectβ in the sense that both writes happened without knowledge of the other. R3 cannot automatically determine which value is the βlatestβ because there is no causal relationship between the writes. R3 has a conflict: two concurrent values for the same key.
(c) With LWW based on physical timestamps: if Client 1βs clock is 50 seconds ahead of Client 2βs clock, then Client 1βs write of X will have a timestamp 50 seconds βin the futureβ compared to Client 2βs write of Y. Even if Client 2βs write actually happened later in real time, the timestamp will make it appear older. LWW would select X (the βlaterβ timestamp), even though the correct behavior depends on application semantics, not clock readings.
(d) The happened-before relation tells us that the writes are concurrent β they are causally independent. This means the system cannot automatically resolve the conflict without application help. Timestamps (even with NTP) might assign an arbitrary ordering that could be wrong due to clock drift. The happened-before relation forces the system to acknowledge the conflict and either present both versions to the application or use a deterministic but semantically meaningful tiebreaker (like the applicationβs own merge logic).