Time, clocks, and the ordering of events.
Leslie Lamport's 1978 paper introduced logical clocks and the happened-before relation. It is the paper every distributed system written since has built on — Cassandra, Spanner, Kafka, every CRDT, every replicated state machine. Ten pages in Communications of the ACM. World-changing.
TL;DR
There is no single "now" in a distributed system. Physical clocks drift — commodity NTP-disciplined clocks typically hold to within a few milliseconds, but unsynchronised hardware oscillators drift by tens of parts per million, meaning two machines can disagree on wall time by seconds within a day. Message delays are unbounded. Lamport's insight is that you do not need real time to reason about a distributed system; you need a partial order consistent with causality. The paper defines that order formally as the happened-before relation (denoted →), gives a logical-clock algorithm that respects it, extends the partial order to a total order, and uses the total order to build a distributed mutual-exclusion algorithm. Those three ideas — happened-before, logical clocks, replicated state machines via total order — became the conceptual foundation of the field.
The problem
Before 1978, distributed systems literature treated time informally. Programs running on separate machines could not agree on the order of events because there was no shared frame of reference. Two events on two different machines might appear in either order depending on whose clock you trusted, and neither clock was trustworthy: quartz oscillators in commodity machines drift on the order of 10 to 100 parts per million, NTP can correct that to a few milliseconds under good network conditions and tens of milliseconds under bad ones, and even a synchronised wall clock can step backwards when ntpd makes a correction.
Without an ordering of events, you cannot implement anything stateful across nodes. Mutual exclusion needs to know which request for the lock came first. Leader election needs the cluster to agree on a winner. Replicated state machines — the foundational pattern behind every replicated database — depend on every replica applying the same operations in the same order so they end up in the same state. Pre-Lamport, these problems were either solved ad-hoc with a central coordinator (creating a single point of failure) or papered over with timeouts and luck. The paper's contribution was to show that you do not need a central clock, you need a discipline for assigning timestamps that respects causality, and that discipline costs almost nothing.
The key idea
Lamport defines the happened-before relation, written a → b, by three rules. First, if events a and b occur on the same process and a precedes b in the process's local order, then a → b. Second, if a is the sending of a message and b is the receipt of that same message, then a → b — the message itself is what relates them. Third, the relation is transitive: if a → b and b → c, then a → c. Two events that are not related by → in either direction are concurrent, written a ∥ b. Concurrency is the key concept the paper introduces: events that are concurrent could have happened in either order as far as any observer in the system can tell, and the system should not depend on a particular ordering between them.
The Lamport timestamp implements this relation operationally. Each process keeps an integer counter C. On every local event, the process increments C. When sending a message, the process attaches C as a timestamp. When receiving a message with timestamp t, the process sets C := max(C, t) + 1. The resulting timestamps respect the happened-before relation: if a → b then C(a) < C(b). The converse, crucially, does not hold — you can have C(a) < C(b) for two concurrent events, because the counters were independently advanced. So Lamport timestamps give you a consistent ordering but they lose information about which events were actually causally related.
To turn the partial order into a total order — needed for algorithms like mutex that must resolve every tie — break ties with the process ID. Define a ⇒ b as either C(a) < C(b), or C(a) = C(b) and pid(a) < pid(b). The result is a total order over all events in the system, consistent with happened-before, and computable locally by each process from messages alone.
Contributions
The first contribution is the formal definition of happened-before. Until this paper, "before" was a wall-clock concept; after it, "before" in a distributed system meant something precise and computable from message exchange alone. Every subsequent paper on distributed algorithms could assume this vocabulary, and the field's textbooks — Tanenbaum, Lynch, Cachin — treat → as a primitive.
The second contribution is the logical-clock algorithm itself. Three rules, one integer per process, one extra field per message. The cost is essentially free: in a system already sending messages, attaching an integer adds 4 or 8 bytes per message, and the max-plus-one update is a single comparison. Despite the cost being trivial, the algorithm is sufficient to drive correct total-order multicast and replicated state machines.
The third contribution is a distributed mutual-exclusion algorithm built on the total order. To request the lock, a process broadcasts a request with its Lamport timestamp; every process maintains a queue of pending requests ordered by (timestamp, pid); a process holds the lock when its own request is at the head of the queue and it has received acknowledgements from all other processes with timestamps greater than its own. The algorithm uses 3(N−1) messages per critical section for N processes and assumes FIFO message channels — neither cheap nor practical for production, but a proof that the partial-order abstraction is strong enough to build the whole stateful layer.
The fourth contribution, often overlooked, is the observation about anomalous behaviour. If two processes in the system communicate through a channel outside the system — a user who phones a colleague, or two services that read a shared database — events on those external channels can violate the logical order. The paper acknowledges this as a fundamental limit: logical clocks order only what they can see. To order events that pass through external channels you need to extend the timestamp into those channels too, which is exactly the design challenge that led decades later to Google's TrueTime in Spanner.
Criticisms and limitations
Lamport timestamps are not sufficient to detect concurrency. Given two timestamps t(a) and t(b), you cannot tell whether a → b, b → a, or a ∥ b — you only know one is smaller than the other. Vector clocks, introduced independently by Fidge in 1988 and Mattern in 1989, fix this by giving each process an N-vector of counters and updating component-wise on send and receive. With vector clocks you can decide concurrency in constant time per comparison, at a cost of O(N) space per timestamp where N is the number of processes. Version vectors, the variant used by Dynamo and Riak, optimise this further by tracking only writers rather than all processes. Lamport's paper does not need this — total order is sufficient for mutex and state-machine replication — but anyone implementing causal consistency or conflict detection (collaborative editing, Dynamo-style multi-master writes, Bayou-era eventual consistency) needs vector or version vectors instead.
The mutex algorithm in the paper assumes reliable, FIFO point-to-point channels. Production systems do not get these for free: TCP gives you FIFO and reliable per connection, but a connection can die, and a process can crash and lose its queue. The paper also requires every process to participate in every request, which scales poorly past a handful of nodes. Real distributed locks use leases (Chubby, etcd, ZooKeeper) or consensus (Raft, Paxos) and treat Lamport's algorithm as a teaching example rather than a deployable artefact. The deeper limitation foreshadowed but not solved by the paper is external causality — events the system cannot observe — which remains the main reason real-world systems combine logical and physical clocks rather than relying on either alone.
Where it shows up today
Cassandra's last-write-wins conflict resolution uses a 64-bit timestamp on every cell, advanced in a Lamport-like fashion when nodes exchange writes — the timestamp is a microsecond-precision wall clock by default, but the comparison-and-merge logic is straight from this paper. Riak and the original Dynamo paper (DeCandia et al, 2007) use vector clocks, the Mattern/Fidge descendant of Lamport's idea, to detect concurrent writes and surface conflicts to the application. CockroachDB and YugabyteDB use hybrid logical clocks (HLC, Kulkarni et al 2014) which combine a physical wall-clock component with a Lamport-style counter: timestamps stay close to real time when clocks agree, but fall back to the logical counter when they don't, preserving causal ordering even across NTP skew.
Google Spanner takes the opposite turn — toward real time rather than logical time — with TrueTime, an API that returns a wall-clock interval [earliest, latest] guaranteed to contain true time, backed by GPS receivers and atomic clocks in every data centre. Spanner uses TrueTime to assign timestamps to transactions and then waits out the uncertainty interval before acknowledging commits, achieving external consistency that Lamport's pure logical scheme cannot. But under the hood, TrueTime's correctness argument still uses the happened-before relation as its primitive: a transaction T1 happens-before T2 if and only if T1's commit timestamp is less than T2's start timestamp. The vocabulary is Lamport's.
Kafka's per-partition log offsets are essentially Lamport timestamps over a single producer chain, and the entire idea of a strictly-ordered append-only log — the basis of every event-sourced system, every replicated state machine in production, and every CRDT framework like Automerge or Yjs — descends from the realisation that a total order over events is the right primitive. Git's commit graph is a happened-before relation made explicit. The pattern shows up everywhere because the underlying problem — agree on order without agreeing on time — is everywhere.
How to read the paper itself
The paper is short — ten pages including references — and reads cleanly if you take the sections in order. Sections 1 and 2 set up the model and define happened-before; this is the core, and worth reading slowly. Section 3 introduces logical clocks and proves the clock condition. Section 4 builds the mutual-exclusion algorithm; the proof of correctness is a pleasant exercise in invariant reasoning. Section 5 discusses anomalous behaviour and external channels. Section 6 sketches physical clocks and bounds the synchronisation error, which is the bridge to later work on hybrid clocks. The references are minimal because there was almost nothing to cite — the paper essentially defined the field.
Reading guide: skip nothing on the first pass, then come back and re-read section 2 once you have implemented a small distributed simulation. The intuition for partial vs total order is best built by drawing space-time diagrams (which Lamport does in figure 1) and tracing message exchanges by hand. The 2013 Turing Award citation for Lamport credits this paper as the foundational work; if you read only one distributed-systems paper, read this one.
Follow-up reading
- Vector Clocks — Fidge (1988), Mattern (1989) — extended Lamport timestamps to detect concurrency. The natural next paper after this one.
- Hybrid Logical Clocks — Kulkarni, Demirbas, Madappa, Avva, Leone (2014) — combine wall clock and logical counter. The clock scheme used by CockroachDB and YugabyteDB.
- The Part-Time Parliament — Lamport (1998) — Paxos. The other paper that defined the field, by the same author, twenty years later.
- Dynamo — DeCandia et al (2007) — production use of vector clocks for conflict resolution at Amazon.
- Spanner — Corbett et al (2012) — TrueTime as the descendant in the opposite direction, toward real time.
- Eventually Consistent — Werner Vogels (2008) — Amazon CTO's essay on consistency models that depend on Lamport's foundations.
- Lamport's publications page — the author's own annotated bibliography, including his commentary on this paper.