Skip to main content

Lecture 7: More Virtual Clocks — Notes

These are notes from the lecture on April 13, 2026. See also the whiteboard descriptions and the whiteboard PDF.

These materials were drafted by AI based on the live whiteboard PDF and audio transcript from the corresponding lecture and then reviewed and edited by course staff. They may contain errors. Please let us know if you spot any.

Context

This lecture continues the material from Friday on Lamport's paper "Time, Clocks, and the Ordering of Events in Distributed Systems" (1978). The happens-before definition was introduced at the end of the previous lecture; today finishes that discussion and covers logical clocks.

All four labs this quarter operate without physical clocks — algorithms will not use the ability to look at what time it is. This makes Lamport's paper especially interesting: it has "clocks" in the title, but the clocks it describes are virtual (logical) clocks, not physical ones.

Terminology:

  • Virtual clock / logical clock / Lamport clock: a software abstraction that assigns timestamps to events based on causal relationships, not hardware timekeeping
  • Physical clock: the actual quartz oscillator in a computer — what normal people mean by "clock"

Simultaneity in Distributed Systems

Lamport asks: when does it make sense to say two things happened at the same time?

Without synchronized physical clocks, the naive answer ("look at the clock") doesn't work. Lamport draws an analogy to special relativity, where certain pairs of events can appear to happen in different orders to different observers. The same thing happens in distributed systems — and it doesn't require anything exotic like the speed of light.

Space-Time Diagrams

A space-time diagram shows nodes as vertical lines (space) with time flowing downward. Messages are drawn as arrows between nodes, always sloping downward because you cannot receive a message before it was sent.

Note: Lamport's paper draws time flowing up. Other authors draw time flowing to the right. In this course, time always flows down.

Example: Four Nodes

Consider four nodes A, B, C, D. Node A sends a message to B (events e1 → e2). Node D sends a message to C (events e3 → e4). The question: which is first, e2 or e4?

Space-time diagram with four nodes A, B, C, D. Event e2 appears to happen before e4.

The answer is that e2 and e4 are concurrent — neither happened before the other. There is no chain of arrows connecting them. You can redraw the diagram by bumping e2 down and e4 up (adjusting the message slopes), and no node in the system can tell the difference. The two scenarios are indistinguishable from inside the system.

Same diagram redrawn with e4 appearing to happen before e2. Both versions are indistinguishable from inside the system.

This is the key insight: the bird's-eye view is not privileged. Lamport says you should treat these scenarios as equivalent.

The Happens-Before Relation

An event e1 happens before e2 (written e1 → e2, or e1 HB e2) if:

  1. They happen on the same machine and e1 is executed first
  2. e1 is the send event and e2 is the corresponding receive event for the same message
  3. There exists some e3 such that e1 HB e3 and e3 HB e2 (transitivity)

Two events are concurrent (simultaneous) if neither one happens before the other.

Caveat: "happens before" is a technical term with a precise definition. It is related to but not identical to the colloquial English meaning.

Graphical Intuition

In a space-time diagram, e1 HB e2 if and only if there is a directed path from e1 to e2 — following arrows forward and process lines downward. Two events are concurrent if there is no directed path in either direction.

  • To prove happens-before: exhibit the path
  • To prove concurrency: show there is no path in either direction (harder — you must rule out all possible paths)

Worked Example: Lamport's Figure (P, Q, R)

Three processes P, Q, R with events labeled p1–p4, q1–q7, r1–r4 and several messages between them. (This is Lamport's Figure 1, drawn with time flowing down.)

Space-time diagram with three processes P, Q, R showing events and message arrows

p1 vs r4: p1 HB r4. The chain: p1 → q2 (message), q2 → q4 (same process), q4 → r3 (message), r3 → r4 (same process). This shows why transitivity matters — you chain message relationships with same-machine ordering.

q5 vs r3: Concurrent. From q5, you can only reach q6, q7, or p4 — none of which is r3. From r3, you can only reach r4. No directed path in either direction.

An important detail: you cannot walk backwards across a message arrow. The path must follow arrows in the forward direction.

Computing Happens-Before from Inside the System

Lamport then asks: can we compute the happens-before relation from within the distributed system, without a bird's-eye view?

Why this is useful:

  • Database transaction ordering: if two client transactions are concurrent (no information exchanged between them), a database can execute them in either order and no one will know the difference
  • Causal consistency: Amazon's distributed systems guarantee that operations are visible to any causally dependent future operations — this uses happens-before

Logical Clocks

A logical clock is a function C that maps events to timestamps (non-negative integers):

  • C(e) = the logical timestamp of event e

The point is to approximate what a physical clock would give you, but based only on things that are robust to the "squishing" of events — i.e., based on the happens-before relation rather than physical time.

The Clock Condition

Clock Condition: if e1 HB e2, then C(e1) < C(e2).

This is a one-way statement (if-then, not if-and-only-if). It says the clock cannot contradict the happens-before relation:

  • If e1 happens before e2, then e1 must have a smaller timestamp ✓
  • But if e1 has a smaller timestamp, that does not mean e1 happens before e2 ✗

Lamport clocks give ordered timestamps to concurrent events all the time — it is genuinely a one-sided guarantee.

The Lamport Clock Algorithm

The algorithm is derived directly from the clock condition and the definition of happens-before. Each of the three cases in the HB definition requires something:

  1. Local events: each node timestamps its own events with incrementing integers. This handles the same-machine ordering rule.

  2. Messages: attach the logical timestamp of the send event to every message. This handles the message send/receive rule.

  3. On receive: consider two values — the timestamp of the previous local event, and the timestamp carried by the incoming message. Take the maximum of these two values, then add 1. This is the timestamp of the receive event.

Worked Example

On the P/Q/R diagram, starting with naive instruction numbering (p1=1, p2=2, etc.), the labeling breaks at q4 → r3: q4 has timestamp 4 but r3 has timestamp 3, violating the clock condition.

The fix: when r3 receives the message from q4 (carrying timestamp 4), it compares 4 with its previous local timestamp (r2=2), takes the max (4), and adds 1, giving r3 a timestamp of 5.

Another example: q7 receives a message from r2 carrying timestamp 2, but q7's previous local event q6 has timestamp 6. The max is 6, so q7 gets timestamp 7. Here the local value "wins" over the incoming message.

Space-time diagram with Lamport clock timestamps annotated on each event

Limitations and Preview

The clock condition is one-directional, which means Lamport clocks are an approximation of the happens-before relation with one-sided error. You can conclude "not happens-before" from the contrapositive (if C(e1) ≥ C(e2) then e1 does not happen before e2), but you cannot conclude "happens-before" from ordered timestamps alone.

Next time: vector clocks, which use a more complex clock structure (a vector of integers instead of a single integer) to recover a two-sided correctness condition — an if-and-only-if relationship between the clock ordering and the happens-before relation.