Every request handler reads one shared routing-table value that is never modified after it is built; why does no handler need a lock?
answer
- nothing changes, nothing to guard
- locks protect transitions
- one state, no window
- readers never see half a change
- change becomes a reference swap
basics
~20 sA value that never changes has no intermediate state to hide, so concurrent readers have nothing to exclude each other from. Locks guard transitions, and this value makes exactly one: from unbuilt to finished, before anybody can see it.
solid answer
~40 sMutual exclusion exists to hide a transition. While a structure is edited in place, part of it holds the old state and part the new one, and a reader that arrives inside that window sees something nobody intended. An immutable routing table has no such window: it is complete before it becomes reachable and is never written again, so there is no event a lock could usefully exclude. Any number of handlers can hold it at once and every one of them sees the same contents. Change has not disappeared, though — it has moved. Routes change by building a whole new table off to the side and pointing one shared reference at it, so the only write left in the design is that single handover.
code
pseudocode · 12 lines// edited in place: readers must be excluded during the edit
function addRouteInPlace(table, route)
lock(table)
table.entries.append(route)
table.index[route.prefix] = route // a reader landing here sees list and index disagree
unlock(table)
// rebuilt and handed over: readers are never excluded
function publishRouteAdded(route)
old = currentTable // read the shared reference
fresh = buildTableFrom(old, route) // built where nobody else can reach it
currentTable = fresh // one handover: readers see old or freshgo deeper
Recall the one-line reason: a lock keeps readers out of a half-finished change, and a value that is never changed has no half-finished state for anyone to see.
Explain where the change went. Updates build a whole new value privately and hand it over by pointing one shared reference at it, which leaves exactly one write that concurrent participants meet on.
Show the accounting. Name what survives after the value stops needing protection: an indivisible handover, publication of a fully built value, and serialised publishers, all on a cold path rather than the read path.
Frame it as a cost decision. You are moving contention off a path taken millions of times onto one taken rarely, and paying for it in allocation and staleness; be able to say when that trade stops being worth it.
## What a lock is actually for A lock does not protect data; it protects a **transition**. When a structure is edited in place there is a window in which some of its parts hold the old state and some hold the new one: the entry list already extended, the lookup index not yet updated, the size counter disagreeing with both. A reader that arrives inside that window sees a value nobody ever intended to exist. Mutual exclusion buys exactly one thing: no reader is ever inside that window, because the writer holds the only key to it. That purchase carries a standing cost: - every read pays, on every request, for a hazard that exists only while a writer is present; - readers wait behind one another even though no reader changes anything; - the hot path of the process now contains a single point that every core must agree about. On a routing table that every request handler reads and that changes a handful of times a day, that is the wrong trade by orders of magnitude. ## Why an unchanging value removes the question An immutable value is complete before anyone else can reach it and is never written afterwards. The sequence of states it passes through has length one. From that single fact: - there is no interleaving to forbid, because the only writes happened during construction, before publication; - a reader cannot catch a half-applied change, because no change is ever applied to this value; - any number of readers may hold it simultaneously, and each sees identical contents; - no reader delays a writer and no writer delays a reader, so read throughput scales with cores instead of queueing on one cell. The argument is not the weak one, that locking is unnecessary because updates are rare. It is the strong one: for this value there is no event that a lock could exclude. ## Change becomes replacement Change does not vanish; it relocates. When routes change, the publisher builds a **new** table off to the side, where no other participant can reach it, and then makes one assignment: the shared reference now names the new table. Handlers already holding the old table carry on using it; handlers arriving later get the new one. Nothing is ever rewritten under a reader's feet. | | Edited in place | Rebuilt, then swapped | |---|---|---| | What a reader can observe | any intermediate state during an edit | one complete version, old or new | | What a reader must do | acquire and release on every read | read one reference | | What a writer must do | exclude every reader for the edit | build privately, then hand over once | | Where contention lives | on the hottest path in the process | on one reference, between publishers | ## Where the coordination went Honest accounting matters here, because *immutable therefore no synchronisation* is the overstatement this material invites. Two coordination points survive, and both concern the reference rather than the value: 1. **The handover.** The shared reference is mutable. A reader must see either the old value or the new one in full, and must not be able to reach a value through that reference before its construction finished. The primitive that guarantees an indivisible handover, and the rules about when a freshly built value is safely visible, belong to the concurrency toolbox rather than to this paradigm. 2. **Derivation.** Two publishers that both start from the current table and both install their result can silently lose one of the two changes, so publication itself has to be serialised or guarded. The paradigm-level point is the shape of the result: the design has exactly **one** coordination point, sitting on a rare path, instead of one per structure sitting on the busiest path in the process. ## What the design does not buy you - **Freshness.** A handler that already holds a version keeps that version until it reads the shared reference again. Unchanging is not the same as current. - **A guarantee about what is inside.** The reasoning covers this value's own contents; whatever those contents point at must carry the same property for the same reasoning to reach them. - **Free updates.** Every publication produces a whole new value, and how much of the previous one it reuses is a separate design question about the structure itself. - **Consistency across values.** One handover makes one value's replacement indivisible, and nothing beyond that. Said compactly in an interview: locks serialise access to a thing that changes; this thing never changes, so the only place left to coordinate is the one reference that decides which version is current.
- If no handler ever blocks, what stops two handlers from disagreeing about the routes?Nothing, and that is the design. Two handlers may hold different versions at the same instant. Each version is internally consistent and each handler makes every decision against the one it holds, so the disagreement is between requests rather than inside one. Narrowing the gap means re-reading the shared reference more often, not locking.
- In this design, which write is the only one that readers and writers meet on?The assignment that points the shared reference at the newly built table. Everything else a publisher does happens on a value no other participant can reach yet, so it is effectively private work. That single assignment is where the concurrency requirements of the whole design collect.
- Does the absence of a lock mean handlers can read the reference whenever they like?They can read it safely at any time, but where they read it is a design decision rather than a free choice. Reading it once and passing the value down gives one consistent version for the whole unit of work; reading it repeatedly gives fresher data and a chance of mixing versions within one unit.
A printed timetable already handed out cannot be edited in a traveller's hands. When the schedule changes the operator prints a new edition and puts it on the rack; nobody reading last month's edition is ever confused mid-page.
saying these in an interview costs you the question
- Says reads of shared data always need a lock, even when nothing writes
- Claims each reader needs its own copy of the value to be safe
- Thinks immutability removes every coordination point, including the handover
- Assumes a value is safe to share before its construction has finished
- Confuses never changes with always current
- Says the lock is skipped because updates are rare rather than absent