B4.3 · dive 3 — the storm drill
A fill fired mid-storm completed in 0 ms.
Five hundred invalidations published on the real wire — push frames into the owner, which now only parses and publishes; the ring's applier does the applying. The committed gate: 500 invalidations crossed the wire and the ring in 25 ms with nothing dropped; every stormed row left L1, the one rewritten name answers px=109.00 from the shared L2, and a fill fired mid-storm completed in 0 ms — the owner parses and publishes while the applier applies, and neither waits for the other. That zero is the chapter's reason to exist. The race underneath is gated adversarially: 500 shuffled messages converging on exactly 100 applied and 400 stale.
Source: content/bcs4.3.md, quoting bcs_rung_4_3_check.out; the modules
are committed at runtimes/elixir/lib/echo_store/ring.ex and the grown
lib/echo_store/table.ex.
The transcript
bcs_rung_4_3_check.out · verbatim · this dive reads the storm and convergence lines… derive (storm): 500 invalidations published on the wire ride push frames at the committed 72 us median into the owner, which only parses and publishes -- application happens on the ring's applier, so a fetch fired mid-storm answers without queueing behind 500 applies; expect the storm applied within two seconds and the mid-storm fill well under 50 ms G5 storm ok -- 500 invalidations crossed the wire and the ring in 25 ms with nothing dropped; every stormed row left L1, the one name whose writer placed a new value answers px=109.00 from the shared L2, and a fill fired mid-storm completed in 0 ms -- the owner parses and publishes while the applier applies, and neither waits for the other derive (convergence): for each of 200 names holding version v2, a shuffled stream delivers either v1,v3,v1 or v1,v1 -- whatever the arrival order, a row is dropped if and only if a version newer than v2 appeared, and the per-name verdict counts are invariant under permutation: exactly 100 applied and 400 stale G6 convergence ok -- 500 shuffled messages converged: the 100 names that saw a newer version lost their rows, the 100 that saw only older versions still answer :hit, and the verdict counters landed exactly on 100 applied and 400 stale -- arrival order changed nothing, because every application is the same comparison PASS 6/6
The elided lines hold the header, the surface and order drills, and the occupancy and full drills — dive 1 and dive 2 read them, and the module hub freezes the record whole. The derive lines are part of the record: each measurement is bounded before it is taken, and the committed line then lands inside its own band.
The storm, with the owner decoupled
content/bcs4.3.md · Why · What · WhereIn 4.2 the table's owner did two jobs: it served fills and puts, and it applied every coherence push inline. At 72 microseconds a message that coupling is invisible — until the storm: a halted market segment, a bulk reprice, a reconnect replay, thousands of invalidations in one burst. An owner that applies inline queues its fills behind them; an owner that spawns per message buys unbounded process churn for work that is one ETS comparison each.
The drill runs the storm on the real wire: "500 invalidations published on the wire
ride push frames at the committed 72 us median into the owner, which only parses and publishes --
application happens on the ring's applier, so a fetch fired mid-storm answers without queueing behind
500 applies". The derive line bounds the outcome — "expect the storm applied within two seconds and the
mid-storm fill well under 50 ms" — and the committed line lands far inside it: 25 ms for the whole
storm, nothing dropped, every stormed row out of L1, the one rewritten name answering
px=109.00 from the shared L2, and the mid-storm fill at 0 ms.
The wiring is the chapter's Where: the push handler reduced to parse-and-publish, the
:broadcast init starting the ring before the subscription that feeds it, the spec carrying
ring and ring_capacity, the terminate stopping the ring with the table.
Convergence is order-independent
content/bcs4.3.md · What · Who · quoting G6The applier races the owner's fills with no coordination, and the proof that this is
safe is 4.2's own theorem run adversarially: for each of 200 names holding version v2, a shuffled stream
delivers either v1,v3,v1 or v1,v1 — "whatever the arrival order, a row is dropped if and only if a
version newer than v2 appeared, and the per-name verdict counts are invariant under permutation: exactly
100 applied and 400 stale". The committed gate: 500 shuffled messages converged — the 100 names where a
newer version arrived lost their rows, the 100 where only older versions arrived still answer
:hit, and "the verdict counters landed exactly on 100 applied and 400 stale -- arrival
order changed nothing, because every application is the same comparison".
The ring preserves arrival order as a courtesy to observability, not as a correctness
requirement. And the lanes stay separate: the broadcast lane rides receipt-to-ring-to-applier end to
end, while the job lane deliberately does not — its consumer still applies through the owner's
apply_coherence, because a lane sold as at-least-once cannot pass through a structure
licensed to drop. The table's owner returns to its 4.1 job description: fills, puts, and nothing
else.
The module hands forward: B4.4 · The Lane That Remembers — the journal writer is the next single-writer candidate; one owner draining ordered work is about to become a habit.
References
sources · relatedSources
- Fowler — The LMAX Architecturereceipt decoupled from application: the single-threaded processor fed by a ring
- LMAX Disruptor — technical paperone consumer draining batches in order while producers keep publishing
- Erlang/OTP — atomicsthe mutual ordering that keeps the applier's reads safe against the producer's writes
Related
- B4.3 — The Single Writer and the Ringthe module hub; the full rung in context
- B4.2 — Coherence by Mint Timethe theorem the drill runs adversarially
- B4.1 — Cache-Aside at ETS Speedthe owner's job description restored
- B4 — EchoStorethe chapter landing
- B3 — The Busthe wire the storm rides
- EchoMQ — the coursethe bus protocol in rung-level depth