B4.1 · dive 1 — declared, not discovered
A cache absent from the directory does not exist.
A cache comes into existence by declaring itself: name, kind, TTL, jitter, size bound,
sweep interval, and coherence mode, registered in the node's directory the moment the table starts
and removed the moment it stops or crashes — the directory monitors its tables, so the roster is true
even after a failure. The negative is gated too: an undeclared name answers :error, and a
wrong-kind id is refused at the door — zero loader runs, zero keys on the wire.
Source: content/bcs4.1.md, quoting bcs_rung_4_1_check.out; the modules
are committed at runtimes/elixir/lib/echo_store/echo_store.ex,
lib/echo_store/keyspace.ex, lib/echo_store/table.ex.
The transcript
bcs_rung_4_1_check.out · verbatim · this dive reads the header, E1, E2header: Valkey on 6390 | Elixir 1.14.0 OTP 25 | schedulers 1 E1 declared ok -- two caches enumerable with their full declarations -- kind, ttl, coherence -- an undeclared name answers :error, and a wrong-kind id is refused at the door: zero loader runs, zero keys on the wire E2 sources ok -- one name, three sources in order: a cold read fills (loader ran once), a warm read hits L1 without touching the owner, and an L1 drop falls back to L2 -- the loader still ran once; the L2 row carries the declared TTL (PTTL 300 ms of 300) … PASS 6/6
The elided middle holds the three derive lines and gates E3–E6 — the herd, the speed, the jitter, and the bound. Dive 2 and dive 3 read them, and the module hub freezes the record whole, header and derive lines included.
The declaration
content/bcs4.1.md · What · How · DecisionsA quote cache, declared — verbatim from the chapter's How:
{:ok, _} =
EchoStore.Table.start_link(
name: :quotes,
kind: "AST",
ttl_ms: 300,
jitter: 0.2,
sweep_ms: 100,
coherence: :none, # wired by Chapter 4.2
loader: &PriceFeed.load/1,
connector: [port: 6390]
)
The decision is "declared, not discovered": the directory is a monitored registry, not a
convention — a table registers its full specification at start, and a crash removes it. Enumeration is
the operator's right, and the negative is gated — an undeclared name answers :error. For
operators, EchoStore.tables/0 is "the law made callable": every cache on the node, with its
full declaration, and nothing else — a cache absent from the directory does not exist.
EchoStore.tables()
# [{:quotes, %{kind: "AST", ttl_ms: 300, jitter: 0.2, coherence: :none, ...}}, ...]
The declared coherence: :none is a socket, not a shrug:
B4.2 · Coherence by Mint Time wires it, and inherits invalidate/2 as
the hook its coherence messages will pull. The declaration's wire is the production connector, "reused
untouched" — the manuscript plans the connector's prose appendix.
Three sources of one answer
content/bcs4.1.md · What · WhereA read resolves from L1, L2, or the declared loader, in that order, and the record walks
one name through all three: a cold read fills (loader ran once), a warm read hits L1 without
touching the owner, and an L1 drop falls back to L2 -- the loader still ran once. The L2 row
carries the declared TTL on the server's own clock — PTTL 300 ms of 300 — written with
SET ... PX so the second layer expires itself even if every node forgets.
The surface is fetch/2 with source tags :hit | :l2 | :fill —
observability, not ceremony:
{:ok, quote, :hit} = EchoStore.Table.fetch(:quotes, "AST0NuE6bV7FoH")
The keyspace is its own — ecc:{<table>}:<id>, "a fresh prefix
beside emq:, never inside it", hashtagged on the table name for the clustered day.
Static record — the walk in the committed order: cold read → :fill
(loader ran once) · warm read → :hit (L1, without touching the owner) ·
L1 drop → :l2 (the loader still ran once; PTTL 300 ms of 300).
References
sources · relatedSources
- Erlang/OTP — etspublic read_concurrency tables: the L1's storage, read caller-side
- Valkey — SETthe PX option: the L2 row written with its expiry in one command
- Valkey — EXPIREexpiration semantics: the server expires the L2 row on its own clock
Related
- B4.1 — Cache-Aside at ETS Speedthe module hub; the full rung in context
- B4 — EchoStorethe chapter landing
- B2.2 — Property Storesthe stores being cached
- B3.2 — Jobs Are Entitiesthe neighbouring keyspace discipline under emq:
- Redis Patterns Appliedthe caching substrate patterns
- EchoMQ — the coursethe bus protocol in rung-level depth