Purpose

These are notes on Lamport’s 1978 paper. The paper defines what “before” even means in a system with no shared clock, then builds logical clocks that respect that ordering. It closes by deriving how closely physical clocks must be synchronized to avoid ordering anomalies.

Problem

We would like to order the events in a distributed system by when they actually occurred. No process can observe that order directly, since processes only see their own events and the messages they exchange. What we can do is define a partial ordering that captures every ordering the system itself could observe, and then extend it to a total ordering that stays consistent with the partial one.

A partial ordering of objects is a relation that is reflexive, antisymmetric, and transitive. A total ordering is a partial ordering where every pair is comparable, so for any two objects and , either or .

Notation

  • : event happened before event .
    • is an irreflexive, transitive relation that defines a partial order over the events in the system.
    • If and are events in the same process and comes first, then .
    • If is the sending of a message and is the receipt of that message, then .
    • If and , then .
    • .
  • : the clock value of process when event occurs.
  • : the total order built from the clocks. Break ties with an arbitrary total order on processes (lexicographic order of process identifiers works). For in and in :

Provided the clocks satisfy the clock condition below, , so the total order extends the partial one. The reverse implication fails, since also orders concurrent events.

The diagram below shows three processes with local events and two messages. Every path along a process line or a message arrow gives a happened-before chain; events with no such path between them are concurrent.

sequenceDiagram
    participant P1 as Process P1
    participant P2 as Process P2
    participant P3 as Process P3

    Note over P1: a (local event)
    P1->>P2: m1 (send = b, receive = c)
    Note over P3: d (local event)
    Note over P2: e (local event)
    P2->>P3: m2 (send = f, receive = g)
    Note over P3: h (local event)
    Note over P1,P3: a → b → c → e → f → g → h is a happened-before chain
    Note over P1,P3: d is concurrent with a, b, c, e, and f (no message path connects them)

Clock condition

For any events : if , then .

Two implementation rules make this hold. Each process increments its clock between any two of its own events. And when event sends a message carrying the timestamp , the receiving process sets its clock at the receipt event to some value greater than (and at least its current value).

Synchronized access to a shared resource

The paper uses the total order to solve mutual exclusion. We want an algorithm for granting a resource to processes that satisfies three conditions:

  • (I) A process which has been granted the resource must release it before it can be granted to another process.
  • (II) Different requests for the resource must be granted in the order in which they are made.
  • (III) If every process which is granted the resource eventually releases it, then every request is eventually granted.

Assumptions

For any two processes and , messages sent by are received in the order they were sent. Stop-and-wait or sliding window protocols give you this. We also assume every message is eventually received.

The protocol requires active participation from every process. If any one process fails the whole system stops, because a request cannot be granted until every process has responded.

Algorithm

  1. To request the resource, process sends a message request to all other processes and puts that message on its own request queue, where is the current clock value of .
  2. When process receives request, it places it on its request queue and sends a reply message to with its current clock value.
  3. To release the resource, removes request from its request queue and sends a release message with its current clock value to all other processes.
  4. When process receives a release message, it removes request from its request queue.
  5. is granted the resource when both conditions hold:
    • Its own request is ordered by before every other request in its queue.
    • has received a message timestamped later than from every other process.
sequenceDiagram
    participant P1
    participant P2
    participant P3

    Note over P1: enqueue T1:P1 request locally
    P1->>P2: request (T1)
    P1->>P3: request (T1)
    Note over P2: enqueue T1:P1 request
    Note over P3: enqueue T1:P1 request
    P2-->>P1: reply (T2 > T1)
    P3-->>P1: reply (T3 > T1)
    Note over P1: T1:P1 is earliest request in queue and P1 has messages later than T1 from P2 and P3 → granted
    Note over P1: uses the resource
    Note over P1: dequeue T1:P1 request
    P1->>P2: release (T4)
    P1->>P3: release (T4)
    Note over P2: dequeue T1:P1 request
    Note over P3: dequeue T1:P1 request

State machine perspective

The algorithm is an instance of replicated state machines. Take to be a set of commands and a set of states, with a transition function

where means executing command in state moves the machine to state . Here the state is the request queue and the commands are the request and release messages:

Executing adds the request to the queue, and removes it. Each process runs its own copy of the state machine and executes a command timestamped only once it has received messages with timestamps at least from every process, which guarantees it has seen every command ordered before . Since every copy executes the same commands in the same total order, every copy stays in agreement.

Anomalous behavior of the total ordering

Consider a nationwide system. A person issues request at node , then phones a friend in another city who issues request at node . The total ordering can place even though was issued first, because the message that establishes the real ordering (the phone call) is external to the system.

Lamport on anomalous behavior ( Time, Clocks, §Anomalous Behavior)

Paraphrasing the paper’s example: in a nationwide network, a user can issue request at computer , then telephone a friend in another city who issues request at computer . It is quite possible for to receive a lower timestamp and be ordered before , because the causal link between them, the phone call, is invisible to the system. The relevant happened-before relation is the one over all events in the world, not just the ones the system can see.

More concretely, let be the set of all relevant events in the world and the set of events inside our system, so . In the scenario above, but . No algorithm based solely on the events in , without knowledge of , can be guaranteed to order before .

There are two ways out:

  1. Users manually carry timestamps across the external channel, so the person at tells the person at a timestamp and the second request is issued with a later one. This pushes the burden onto users.
  2. Build clocks that satisfy a strong clock condition: if , then . This requires physical clocks.

Physical clocks

Let be the value of clock at physical time . Assume is continuous and differentiable except at isolated points where it jumps on reset. A discrete clock fits this model with an error of up to half a tick.

is the rate the clock runs at time , and a perfect clock runs at rate 1. Assume every clock runs at nearly the correct rate:

The paper notes for typical crystal controlled clocks.

Rate accuracy alone is not enough, since independent clocks drift apart. We also want the clocks synchronized to within some bound :

Physical clocks never run at exactly the same rate, so drift accumulates and a synchronization algorithm has to periodically bring them back within .

Now let be a lower bound on interprocess message delay: if event occurs at physical time and event in another process satisfies , then occurs after . To avoid the anomalous behavior above, an event at time must get a larger timestamp than any event at time :

The rate bound gives , and the synchronization bound gives . Adding these, , which is positive exactly when

So the required synchronization tightness is set by the minimum message delay. Faster networks demand tighter clocks.

The punchline

: how tightly clocks must be synchronized () is set by the minimum interprocess message delay (), discounted slightly by the clock rate error (). If information can cross the system faster than the clocks agree with each other, anomalous orderings become possible.

Clock synchronization algorithm

Never set a clock backward

Clocks must only ever be adjusted forward. Setting a clock backward can violate the clock condition for events the clock has already timestamped, since a later event could receive a smaller timestamp than an earlier one.

Let be a message sent at time and received at time . Let be the total delay of the message. The receiver does not know , but it knows some lower bound on the delay. Define as the unpredictable delay of the message.

The rules for the physical clocks:

  1. For each , if does not receive a message at physical time , then is differentiable at and .
  2. If sends a message at physical time , then contains a timestamp . Upon receiving at physical time , sets .

The paper proves that with these rules, clocks that communicate often enough converge to within an determined by the unpredictable delay, so the anomaly-freedom condition above can be met.

Sources