Recipe

Lamport Clocks Primer

Lamport clocks give you a partial ordering of events across distributed processes without any shared clock. They are the cheapest correctness tool you can wire into a multi-node system, and they cost one integer per node plus one integer per message.

1.The happens-before relation

Each process keeps a local counter. The counter ticks on every local event, every send, and every receive. On receive, the counter jumps to one past the maximum of its current value and the timestamp embedded in the inbound message. That single rule yields a clock consistent with causality.

If event A happens-before event B, then the Lamport timestamp of A is strictly less than that of B. The converse does not hold, which is the trade for keeping the protocol cheap.

2.Reference implementation

The whole protocol fits in fifteen lines. Treat the counter as a monotonic integer and never decrement it.

class LamportClock:
    def __init__(self):
        self.t = 0

    def local_event(self):
        self.t += 1
        return self.t

    def send(self):
        self.t += 1
        return self.t

    def recv(self, incoming_t):
        self.t = max(self.t, incoming_t) + 1
        return self.t

3.When to reach for something stronger

Lamport clocks cannot detect concurrency. If you need to know that two events are causally independent, you need vector clocks, which cost O(n) per message instead of O(1). For a system where the only question is "did this happen before that on the path I care about", Lamport is enough. For conflict resolution in a CRDT or a multi-leader datastore, move up to vector clocks or interval tree clocks.

In Meridian we ship Lamport clocks on every inter-shard message and attach vector clocks only on the replication path where divergence detection actually matters.