Welcome to the next step in our journey toward building collaborative applications. In the last lesson, we established that by adopting an optimistic replication model, we gain incredible performance and offline capabilities. However, this architectural choice inevitably leads to the "merge problem," where concurrent edits from different users can create conflicting versions of our data.
To resolve these conflicts systematically, we first need a way to talk about the order of events. Did User A's edit happen before User B's? Or did they happen independently, without knowledge of one another? This lesson introduces the fundamental concept for answering that question: the happens-before relation. This concept, conceived by Leslie Lamport in 1978, provides a way to reason about the order and causality of events in a distributed system without relying on the fickle nature of physical clocks.
The Trouble with Physical Clocks
Your first instinct as an engineer might be to simply attach a timestamp to every operation. When a conflict arises, just pick the one with the later timestamp. This seems simple enough, but which machine's clock do you trust? In a distributed system, there is no single, perfectly synchronized source of time.
Relying on physical clocks leads to several problems:
- Clock Skew: The clocks on different computers drift at different rates. Even with synchronization protocols like NTP (Network Time Protocol), there's always a margin of error. One user's machine might be a few milliseconds ahead of another's.
- Network Latency: A message's travel time across the network can be greater than the clock skew between two machines. This can lead to situations where a reply is timestamped before the original message it's replying to.
Distributed Systems 3.3: Causality and happens-before
Martin Kleppmann's lecture on Distributed Systems provides a crystal-clear example of why physical timestamps fail us. He uses a simple discussion thread to illustrate how clock skew and network latency can cause a reply to appear before the message it's replying to, completely breaking the logical order.
Please watch the segment from the beginning until the end of the example. This will solidify your intuition for why we need a more robust model of time.
The core issue is that physical time doesn't accurately capture causality. A reply is caused by the original message, so it must logically happen after it, regardless of what any wall-clock says. This is why we need to shift our thinking from physical time to logical time.
The "Happens-Before" Relation (→)
Instead of relying on physical clocks, we can define a logical ordering based on a simple, observable principle: a message must be sent before it can be received. Leslie Lamport used this idea to define the happens-before relation, denoted by an arrow (→). The expression a → b is read as "a happens-before b."
This relation is built on three straightforward rules.
CSE138 (Distributed Systems) L2: time and clocks, causality and happens-before, network models
Professor Lindsey Kuper's lecture on distributed systems offers an excellent introduction to the happens-before relation and the visual language used to describe it.
First, watch her introduce the concept and its importance for understanding causality in the segment from logical clocks to the start of Lamport diagrams. Next, watch her define the three rules that constitute the happens-before relation, using space-time diagrams to illustrate them. Pay close attention to this segment from the definition. I will summarize the rules below.
As explained in the video, we can say that event a happens-before event b (a → b) if any of the following conditions are true:
- Same Process: If
aandbare events within the same process (e.g., on the same user's device), andaoccurred beforeb, thena → b. This is the natural order of execution on a single machine. - Message Passing: If
ais the event of sending a message, andbis the event of receiving that same message, thena → b. A message cannot be received before it is sent. - Transitivity: If we know that
a → candc → b, then we can infer thata → b. This allows us to chain causal relationships across multiple processes and messages.
This definition is powerful because it's based entirely on the flow of information within the system, not on any external, unreliable clock.
Visualizing Order: Lamport Diagrams
To make this abstract definition concrete, we use space-time diagrams, also known as Lamport diagrams. These diagrams are the standard visual language for reasoning about events in a distributed system.

Let's analyze the diagram above using our rules:
- Rule 1 (Same Process): Within Process P,
p1 → p2. - Rule 2 (Message Passing): A message is sent from Process P at event
p1and received by Process Q at eventq1. Therefore,p1 → q1. - Rule 3 (Transitivity): We know
p1 → q1(from Rule 2) andq1 → q2(from Rule 1). Therefore, we can conclude thatp1 → q2. You can think of this as following a "causal path" fromp1toq2.
Partial Order and Concurrency
What happens if we try to relate p1 and r1 in the diagram?
- There's no path from
p1tor1. - There's no path from
r1top1.
According to our definition, neither p1 → r1 nor r1 → p1 is true. When two events are not ordered by the happens-before relation, we say they are concurrent, written as p1 || r1.
This is the most important consequence of the happens-before relation. It defines a partial order, not a total one. It can definitively tell us if one event caused another, but it also identifies events that are causally independent.
Crucially, concurrent does not mean simultaneous. It means the events occurred without knowledge of one another. In your collaborative canvas, if User A moves a node while offline, and User B edits the color of that same node while online, those two operations are concurrent. The happens-before relation cannot order them. These are precisely the situations that CRDT merge functions are designed to handle.
Introduction to CRDTs for Realtime Collaboration - DEV Community
This DEV Community article provides a concise summary of these core concepts.
Please read the definitions for Causal Relation and Concurrent. Then, skip down to the section on Logical Timestamps and read the paragraphs describing the happens-before concept. This will help reinforce the terminology.
Causality and Causal Anomalies
The happens-before relation is fundamentally about causality.
- If
a → b, thenamight have causedb. There is a causal pathway for information to flow fromatob. - If
a || b, thenacould not have causedb, andbcould not have causeda.
When a system displays events in an order that violates the happens-before relation, it leads to confusing "causal anomalies."
CSE138 (Distributed Systems) L2: time and clocks, causality and happens-before, network models
Professor Kuper provides a memorable example of a causal anomaly involving a chat between Alice, Bob, and Carol.
Watch the segment from this classic example. Notice how Carol receives Bob's reply before Alice's original message, leaving her confused. This is exactly the kind of confusing user experience we want to prevent in our applications by respecting the causal order.
Conclusion
In this lesson, we have established a formal, reliable way to reason about the order of events in our distributed system.
Here are the key takeaways:
- Physical clocks are unreliable for ordering events in a distributed system due to clock skew and network latency.
- The happens-before relation (→) provides a partial ordering of events based on causality, not physical time.
- It is defined by three rules: order within a single process, the sending and receiving of messages, and transitivity.
- Events that are not ordered by the happens-before relation are concurrent (||). This means they are causally independent, not necessarily simultaneous.
- Recognizing concurrent operations is the first step toward resolving the "merge problem" we identified in the previous lesson.
You now have the theoretical foundation to understand how events relate to each other in time. However, a partial order isn't always enough. Sometimes, we need to enforce a single, consistent, total order across all users.
In the next lesson, we will build directly on this foundation to implement Lamport timestamps. This is a simple but brilliant algorithm that uses the happens-before logic to assign a number to every event, allowing us to create a total ordering. This will be our first piece of practical, hands-on code for managing time in a distributed system.