F4.09 · part 1 of 3 · the entity registry
Partition by namespace
The Portal keeps users, sessions, lessons, and pages in one in-memory registry. Rather than one
CHAMP holding every kind of key, the store is a tiny top-level map from a three-letter namespace
to a CHAMP per kind. A lookup reads the prefix it already has, picks the partition, and descends only that
sub-trie — so a USR key never shares a node with an LSN
key, and each partition stays shallow.
The registry, grouped. Select a namespace to see its partition and how many records it holds — counted from the same eight records.
Four partitions, one prefix away
The top-level map has one entry per namespace; its value is the partition for that kind. Selecting a namespace routes to its CHAMP and lists what it holds. The routing is a single map read on the three-character prefix.
Namespace · select one
partition: USR
records: 2
The store is a map of namespaces over CHAMPs. The prefix you already hold is the routing key, so finding the right partition costs one map read and never mixes one kind of record with another.
Advanced: why not one big map
You could put every record in a single CHAMP. Correctness would hold — the keys are unique — but three things get worse. The trie is deeper, because it holds every key at once. Keys of different kinds share nodes, so a hot path of session writes churns nodes that user reads also touch. And there is no seam to act on a single kind: you cannot snapshot only the lessons, evict only the sessions, or hand one kind to a different process. Partitioning by the prefix gives each kind its own shallow sub-trie and its own lifecycle, for the price of one extra map read.
The prefix is the natural partition key because it is already in the id and already means “what kind of thing this is.” The top-level map is tiny — one entry per namespace — so it stays in cache, and within a partition the keys are Snowflakes, which keeps that sub-trie time-ordered for the range scans of F4.08.
# the store routes on the prefix, then works one partition defp partition("USR" <> _), do: :users defp partition("SES" <> _), do: :sessions defp partition("LSN" <> _), do: :lessons def get(id), do: parts |> Map.fetch!(partition(id)) |> Champ.get(id) # one map read for the partition, then the CHAMP lookup within it
a branded id’s prefix
USR, SES, LSN, PGE — the kind, baked in.
a partition
One CHAMP per kind, each shallow and independently managed.
Next: structural sharing — inside a partition, how marking a lesson complete keeps every prior snapshot for free.
References
Primary sources for this lesson, and where it connects in the course.
Sources
- Steindorfer & Vinju, “Optimizing Hash-Array Mapped Tries” (OOPSLA 2015) — the CHAMP each partition is.
- Elixir — Map — the tiny top-level namespace map.
- Elixir — binary matching (
<>) — matching the prefix to route.
Related in this course
- F4.09 · Branded CHAMP maps & GenServer — the module hub.
- F4.07.3 · Branded ids — where the prefix comes from.
- F4 · Algorithms & Data Structures