Chandy–Lamport Algorithm
The Chandy–Lamport algorithm is a foundational distributed snapshot algorithm introduced by K. Mani Chandy and Leslie Lamport in 1985 that records a causally consistent global state of an asynchronous message-passing system over FIFO channels without pausing application execution.
Chandy–Lamport Algorithm is a distributed snapshot algorithm in computation and algorithms that captures a causally consistent global state—comprising the local memory state of every process and the in-transit message state of every communication channel—across an asynchronous distributed system without synchronized physical clocks or global execution freezes. Formulated by K. Mani Chandy and Leslie Lamport in 1985, the protocol coordinates state capture by propagating lightweight control tokens called marker messages along first-in, first-out (FIFO) directed communication channels.
In distributed systems and computational complexity theory, asynchronous nodes lack a shared global clock and communicate via variable-latency networks, making it impossible to instruct all processes to record their local states at an identical physical instant. If processes record their states independently at uncoordinated times, the combined snapshot can violate causality—for example, recording that process q received a bank transfer message m from process p while recording the state of p before p ever sent m (an orphan message that duplicates funds). By aligning local state capture with FIFO marker boundaries under Leslie Lamport's happens-before relation (→), the Chandy–Lamport algorithm constructs a consistent cut that underpins distributed deadlock detection, garbage collection, fault-tolerant checkpointing in Apache Flink stream processors, and vector clock debugging.
System Model, Causal Cuts, and Consistent Global States
Asynchronous Process-Channel Graph and FIFO Assumptions
The Chandy–Lamport model represents a distributed system as a strongly connected directed graph G = (P, C), where P = {p1, p2, ..., pN} is a finite set of N processes and C ⊆ P × P is a set of directed communication channels ci,j = (pi, pj). The system satisfies four operational assumptions:
- No Shared Memory or Global Clock: Processes share no physical memory and have no synchronized wall-clock time; all interaction occurs via message passing over channels in C.
- Reliable, Error-Free Channels: Neither processes nor channels fail during the snapshot, and every sent message is eventually delivered intact with finite (but arbitrary and unbounded) delay.
- FIFO Channel Ordering: Each directed channel ci,j delivers messages in First-In, First-Out order: if pi sends message m1 before m2 on ci,j, then pj receives m1 before m2.
- Non-Blocking Application Execution: Snapshot recording runs concurrently with normal application computation and never delays or reorders application messages.
Consistent Cuts and the Happens-Before Invariant
Let ei(1), ei(2), ... denote the sequence of local events (internal state transitions, send(m), and recv(m)) executed by process pi, partially ordered by Lamport's happens-before relation (→). A cut of a distributed execution is a tuple of local prefix histories K = (h1, h2, ..., hN), where hi contains all events at process pi up to the instant pi records its local state σi.
A cut K is causally consistent if and only if it is closed under causal precedence:
In message-passing terms, a global state S* = ({σi}i∈P, {Φi,j}(i,j)∈C) is consistent if:
- No Orphan Messages: Whenever recv(m) at pj belongs to the recorded prefix hj (a post-recording event cannot cause a pre-recording effect), the corresponding send(m) at pi must also belong to the recorded prefix hi.
- Precise Channel In-Transit State: For each channel ci,j, the recorded channel state Φi,j equals the precise sequence of messages that were sent by pi before pi recorded its state σi, but received by pj after pj recorded its state σj:
Marker-Sending and Marker-Receiving Rules
Initiation and the Two Atomic Protocol Rules
Any single process pinit ∈ P (or multiple processes concurrently) can initiate a global snapshot without prior coordination. The protocol is governed by two deterministic rules executed atomically with respect to local message handling:
- Marker-Sending Rule for Process pi:
- Process pi records its own local process state σi.
- Before pi sends any further application messages on any outgoing channel, pi sends one marker message 〈MARKER〉 along every outgoing channel ci,k (k = 1 .. dout).
- Process pi initializes a message-logging buffer Lj,i ← ∅ for each of its incoming channels cj,i and begins recording incoming application messages on those channels.
- Marker-Receiving Rule for Process pj (upon receiving 〈MARKER〉 on incoming channel ci,j):
- Case A (pj has NOT yet recorded its local state σj):
- Process pj records its local process state σj.
- Process pj records the state of the incoming channel ci,j on which this first marker arrived as empty: Φi,j ← ∅.
- Process pj executes the Marker-Sending Rule (sending 〈MARKER〉 on all its outgoing channels) and starts logging all application messages arriving on every other incoming channel ck,j (k ≠ i).
- Case B (pj HAS ALREADY recorded its local state σj earlier):
- Process pj stops logging on incoming channel ci,j and finalizes the recorded state Φi,j of channel ci,j as the sequence of application messages received on ci,j since pj recorded its local state σj and before receiving 〈MARKER〉 on ci,j.
When a process pj has received a 〈MARKER〉 on every one of its incoming channels, its local snapshot (σj and all incoming channel states Φk,j) is complete and can be forwarded to an external collector.
Why FIFO + Markers Guarantee Consistency and Termination
Consider any channel ci,j. Because pi sends 〈MARKER〉 on ci,j at the precise instant pi records σi, and because ci,j is FIFO, the marker partitions all messages ever sent on ci,j into pre-snapshot messages (sent before pi recorded σi, arriving at pj before the marker) and post-snapshot messages (sent after pi recorded σi, arriving at pj after the marker).
- Impossible Orphan Message: Suppose pi sends m after recording σi (so m follows 〈MARKER〉 on ci,j). By FIFO ordering, pj receives 〈MARKER〉 on ci,j before receiving m. Upon receiving 〈MARKER〉, pj records σj if it has not already done so; thus m is always received by pj after pj records σj, proving zero orphan messages.
- Precise In-Transit Capture: Any message m sent by pi before σi (preceding the marker) that has not yet been received when pj records σj (triggered by a marker from another channel ck,j) arrives at pj during the interval between σj and the arrival of the marker on ci,j, and is therefore captured in Φi,j.
Across a strongly connected graph G = (P, C) with |P| = N vertices, |C| = E directed edges, and diameter D, every process sends 1 marker on each outgoing edge, yielding a total message complexity of O(E) = |C| marker messages and snapshot completion within O(D) max-hop message delays.
| Distributed Snapshot / State Algorithm | Channel Requirement | Control Message Overhead | Application Blocking? | Primary Mechanism & Use Case | ||
|---|---|---|---|---|---|---|
| Chandy–Lamport (1985) | FIFO reliable channels | ** | C | = E markers (1 per edge)** | Zero blocking | Marker-delimited local + incoming channel logging |
| Lai–Yang Snapshot (1987) | Non-FIFO channels | 0 dedicated markers (1-bit piggyback + history) | Zero blocking | Red/white coloring bit on messages + message history diff | ||
| Mattern Vector-Clock Snapshot (1989) | Non-FIFO channels | O(N) control broadcasts | Zero blocking | Vector clock cut synchronization and message counters | ||
| Apache Flink ABS (Carbone et al., 2015) | FIFO DAG datastreams | 1 barrier per DAG stream edge | Unaligned or brief barrier alignment | Stream checkpoint barriers derived from Chandy–Lamport | ||
| Two-Phase Commit / Paxos | Asynchronous channels | O(N) to O(N2) per round | Blocks transaction state until commit/quorum | Mutating state consensus rather than read-only observation |
Stable Property Detection and Modern Stream Processing (Apache Flink)
Reachability and Stable Predicate Detection
An important caveat analyzed by Chandy and Lamport is that the recorded global state S* need not have occurred at any single physical instant during the actual execution e1, e2, ... Instead, Chandy and Lamport proved that if the snapshot starts in global state Sinit and finishes in global state Sfinal, there exists a causally equivalent permutation of the execution's events—preserving every local process history and every happens-before dependency—that passes through Sinit → S* → Sfinal.
Consequently, the Chandy–Lamport snapshot is particularly suited for detecting stable properties—predicates P(S) that, once true in a system state S, remain true in all reachable future states S′ (such as distributed termination, deadlock, token loss, or unreferenced garbage objects):
- If P(S*) is true in the recorded snapshot, then P(Sfinal) is guaranteed to be true when the snapshot finishes.
- If P(S*) is false in the recorded snapshot, then P(Sinit) was guaranteed to be false when the snapshot began.
In modern distributed stream processing engines such as Apache Flink, Asynchronous Barrier Snapshotting (ABS) (Carbone et al., 2015) adapts the Chandy–Lamport algorithm to directed acyclic dataflow graphs (DAGs): sources periodically inject checkpoint barriers (〈MARKER〉) into data streams, enabling precisely-once fault-tolerant state recovery across thousands of stateful operators without stopping high-throughput ingestion, complementing Byzantine fault tolerant replication and conflict-free replicated data type state stores.
Frequently Asked Questions
What happens if communication channels are not FIFO?
If a channel ci,j can reorder messages, a post-snapshot message m sent by pi after 〈MARKER〉 could overtake 〈MARKER〉 in transit and arrive at pj before pj records σj, creating an orphan message and an inconsistent cut. For non-FIFO networks, the Lai–Yang algorithm (1987) replaces markers by coloring every process and its outgoing messages "white" (pre-snapshot) or "red" (post-snapshot); the first red message received by pj triggers σj directly before processing that message, and channels are reconstructed by subtracting received white message counts from sent white message counts.
Why did the recorded global state S* not necessarily exist at any single wall-clock time?
Suppose process p1 records σ1 at t = 10 ms and process p2 (which exchanges no messages with p1 between t = 10 ms and t = 50 ms) records σ2 at t = 50 ms after executing several purely internal events. No single wall-clock instant simultaneously held (σ1, σ2), yet because the internal events at p2 between 10 ms and 50 ms are causally concurrent with p1's snapshot, shifting them before t = 10 ms yields a valid causal execution that passes through S*.
References
- Chandy, K. M., & Lamport, L. (1985). "Distributed snapshots: Determining global states of distributed systems." ACM Transactions on Computer Systems, 3(1), 63–75. https://doi.org/10.1145/214451.214456
- Lamport, L. (1978). "Time, clocks, and the ordering of events in a distributed system." Communications of the ACM, 21(7), 558–565. https://doi.org/10.1145/359545.359563
- Lai, T. H., & Yang, T. H. (1987). "On distributed snapshots." Information Processing Letters, 25(3), 153–158. https://doi.org/10.1016/0020-0190(87)90125-690125-6)
- Mattern, F. (1989). "Virtual time and global states of distributed systems." Proceedings of the International Workshop on Parallel and Distributed Algorithms, 215–226. https://doi.org/10.5555/646210.683629
- Carbone, P., Fóra, G., Ewen, S., Haridi, S., & Tzoumas, K. (2015). "Lightweight asynchronous snapshots for distributed dataflows." arXiv Preprint / Apache Flink Foundation, arXiv:1506.08603. https://doi.org/10.48550/arXiv.1506.08603