B8.1 · The Engine — the trading corpus, docs/trading/
Two questions: in what order, and what it means.
The match path answers exactly two questions, and they are different. In what order, and
at what cost of admission — a question of sequencing and overload, answered by a Disruptor-style ingress:
EchoCache.Ring, real umbrella source at
echo/apps/echo_cache/lib/echo_cache/ring.ex, a bounded buffer whose publish/2
answers :ok or :dropped with the drop counted. What a command means when it
meets a book — a question of decision, answered by a functional Decider: decide and
evolve, pure, events out. The Ring exists, is tested, and is hardened; what is PROPOSED
is the trading engine on top of it — the Book and the Decider — never the substrate.
The Ring is shipped Elixir, hardened by the rung-gated EchoMQ program
(docs/echo_mq/emq.roadmap.md); its committed behavior is also on the B4.3 record
(bcs_rung_4_3_check.out, PASS 6/6), and every ring figure is verbatim from there.
What is PROPOSED is only the trading engine — the Exchange.* suite (docs/trading/)
— taught as design because it has run no rung, with no match or fill number invented.
The three dives
fixed by the chapter spec · the trading corpusThe engine is one module in three dives — the ingress seat, the pure core, and the order book whose priority falls out of the id law. The ring each dive quotes is committed; the Book, the Decider, and the order book are PROPOSED design objects, taught as design and never as a measured result.
The Disruptor Seat
The Ring as bounded ingress: publish/2 answers :ok/:dropped,
the drop counted — 64 accepted, 136 refused with :dropped and counted. One drainer; what
transfers from LMAX and what the BEAM does not copy; the chase sequence is the branded Snowflake
inside the data.
The Decider
The pure core: initialState / decide / evolve (Chassaing).
Event sourcing, not command sourcing; testability, replay, and audit as corollaries of
the signatures; functional core / imperative shell — the Book a GenServer shell, the cores pure (all
PROPOSED).
Price-Time by Mint Order
The order book as a price ladder per side over gb_trees, each level a FIFO resolved by
branded mint order — price-time priority falling out of the id law rather than a comparator. The
single-writer reconcile: publishes equal applies plus counted drops (a PROPOSED gate).
The module hands forward inside the capstone: B8.2 · The Log and the
Ledger — the journal the Decider's facts land in, Chapter 4.4's posture as B8.2's subject; then
B8.3 · Strategies as Deciders and B8.4 · Fan-Out and the
Scale-Out. Those modules and the Exchange.* objects this engine names are PROPOSED
design, not routes.
Three shapes, one wire
docs/trading/trading.mdA trading platform has four jobs that pull in different directions: sequence commands per instrument under a single writer; hold a latency budget in microseconds on the match path; stay durable and auditable — every fill a fold over facts; and fan out and follow up. The classic failure is answering all four with one primitive: a queue pressed into a log, a log into a bus, a bus carrying objects. The design rule is the opposite — three messaging shapes, each served by the primitive built for it. The engine fills the first seat and reads into the second.
| Shape | Carries | Served by (as-built unless marked PROPOSED) |
|---|---|---|
| Command | one ordered command stream per instrument, one writer | EchoCache.Ring ingress → Exchange.Book (PROPOSED) draining a pure Decider; sequence is branded mint order |
| Event | facts emitted once, read by many, replayable | the claim-check bus (Appendix G) for fan-out; the Journal (B4.4) then per-instrument stream lanes for the log |
| Work | retriable follow-ups: settlement, risk, reporting | EchoMQ.Jobs / Lanes / Consumer — fair per-venue lanes (B3.4) |
The seat — the ring, real and hardened
echo/apps/echo_cache/lib/echo_cache/ring.ex · B4.3 recordThe engine invents nothing under the hot path. The Disruptor seat is
EchoCache.Ring — real, shipped Elixir at
echo/apps/echo_cache/lib/echo_cache/ring.ex, whose surface is publish/2
(:ok, or :dropped with the drop counted when full), occupancy/1 (tail
minus head), stats/1 (the counter snapshot plus occupancy, max_batch, and
capacity), stop/1, and start_link/1. Its moduledoc states it in the
house's own words: "This is the Disruptor's shape translated to the BEAM — sequences, preallocated slots,
batched consumption — standing beside the bus's park-don't-poll: both replace discovery with arrival." The
Ring, the bus, and the cache are the convergence target of the rung-gated EchoMQ program
(/echomq, docs/echo_mq/emq.roadmap.md), and the trading platform is named
there as the program's downstream consumer — "the proposed Exchange.* suite standing on exactly
this tree; the program's named consumer." The Ring's committed behavior is on the B4.3 record, a
source-labelled slice quoted verbatim:
header: Valkey on 6390 | Elixir 1.14.0 OTP 25 | schedulers 1 G1 surface ok -- the ring's surface is whole -- publish, occupancy, stats, stop, a generic one-batch apply function -- and the declaration tells the truth: the broadcast table carries its ring name and capacity 512 in the directory, the :none table carries nil, and a fresh ring stands at occupancy 0 G4 full ok -- the bound held its shape: 64 accepted, 136 refused with :dropped and counted -- never blocked, never overwritten -- then the release drained all 64 and publish 201 landed and applied: a storm bends the lane's at-most-once contract no further than the contract already bends G3 occupancy ok -- mid-storm the gauge read 600 of 4096 and drained to exactly 0; priced, the ring moved 100000 items in 99 ms -- 1005116 items per second end to end on one scheduler, inside the derived band, largest batch 200, nothing dropped PASS 6/6
The full six-gate record is frozen in the dive that teaches the seat
(B8.1.1). The Ring's numbers are real; the trading
engine's are not yet — the match latency, the throughput, the fill counts of the
Exchange.* suite that drains this Ring do not exist, and so they appear nowhere on these pages.
The engine's first such number lands when its first rung's harness runs.
The Disruptor's provenance
docs/trading/trading.patterns.md · FowlerLMAX's published architecture centers a Business Logic Processor that runs in memory by event sourcing and handles "6 million orders per second on a single thread" (Fowler), surrounded by ring buffers where producers claim slots, a single writer applies in batches, and consumers chase a sequence. The figure is external and quoted with its attribution; the trading engine claims no such number, because it has run no rung yet. The engine takes the principles — the bounded buffer with an explicit overload answer, the single writer applying in batches, sequence as the coordination primitive, journaling beside the hot path — not the Java mechanics. What transfers and what the BEAM deliberately does not copy is the subject of dive 1.
The doors
the sibling coursesEchoMQ — the protocol, in depth
The bus the log and the work lanes ride, and the rung-gated program that hardens this substrate — with the trading platform as its named consumer: the keyspace, the Lua inventory, conformance.
/redis-patternsRedis Patterns Applied
The substrate under the engine: the bounded ring, sorted sets, atomic Lua, the single-writer move.
/elixirFunctional Programming in Elixir
The umbrella, and the functional core the Decider and the order book are written in.
References
sources · relatedSources
- Fowler — The LMAX Architecturethe Business Logic Processor, the single-writer case, the ring that feeds it — the prior art the engine takes onto the BEAM
- The LMAX Disruptor (technical paper)the bounded ring, sequences, batching, wait strategies — the pattern the as-built Ring fills as a Disruptor seat
- Chassaing — Functional Event Sourcing Deciderdecide / evolve / initial state — the pure core of the book, taught in dive 2
Related
- B8 — The Trading Systemthe chapter landing; the capstone's arc
- B4.3 — The Single Writer and the Ringthe as-built Disruptor seat, the ring quoted here
- B4 — EchoCachethe cache and ring the engine admits through
- B3 — The Busthe log and the work lanes
- B2 — The Elixir BCS Corethe functional core the Decider is written in
- EchoMQ — the coursethe bus protocol in rung-level depth
- Redis Patterns Appliedthe bounded-ring substrate
- Functional Programming in Elixirthe umbrella the runtimes live in