All notable changes to this project are documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
0.2.1 - 2026-08-06
No behaviour change. Slot assignment is identical to 0.2.0 and 0.1.0.
Fixed
- The golden fixture is now declared as an
@external_resource, so regenerating it recompiles the tests that read it. Without that, a regenerated fixture left the previous digests compiled in and the suite passed while checking nothing.
Documentation
- Tables are compared with
Maglev.slots/1rather than with==. A table records how it was built as well as what it decided, so two tables that route every key identically can compare unequal across a release that changes which fill strategy a weight distribution selects.
0.2.0 - 2026-08-06
Tagged but never published to Hex; its contents are included in 0.2.1.
Lookup tables are unchanged by this release: the same backends and weights
produce the same slot assignment as 0.1.0, so upgrading moves no traffic. This
is now checked rather than argued — test/fixtures/golden_0_1_0.txt records
slot tables produced by the 0.1.0 package as published, and the suite rebuilds
them on every run.
Changed
Lopsided weights build faster. The existing fill walks every backend on every iteration and skips those not yet eligible to claim a slot, which is free at equal weights and wasteful as the weight ratio widens. A second strategy holds the turn order in a priority queue keyed on each backend's next eligible iteration, so ineligible backends are never visited. The strategy is chosen from the weights. At 1000 backends and a 65537-slot table, one backend weighted 10000 against the rest at 1 builds in 59 ms rather than 1395 ms, while evenly weighted sets keep their previous cost.
The boundary between the two is approximate, and the threshold errs towards scanning so that near-equal weights are never moved onto the queue. Selecting the slower strategy near the boundary costs about 1.7x at most. The queue also allocates where scanning does not, so its advantage narrows when a build runs in a process already holding a large heap.
Added
- A golden fixture pinning slot assignment to the 0.1.0 package as published. The equivalence properties establish that the fill strategies agree with the reference implementation, which is a definition that lives in this repository and could itself move; the fixture depends on no such reasoning. Forcing every pinned configuration through the priority queue reproduces 0.1.0 exactly, including 1000 backends at 655373 slots with a weight ratio of 10000, which is well beyond the range the properties generate.
Documentation
- State which hash functions are used. The construction referred to
h1andh2without defining them, whileMaglev.slots/1was described as the form to hand to an external datapath — together implying an interoperability that does not exist. Tables built here match no other Maglev implementation, because the offset and skip hashes and the lookup hash both differ. - Document that
Maglev.lookup_index/2applies no mixing, so a narrow or skewed hash leaves slots unreachable or unevenly loaded. - Describe consistent worker assignment, which is the more common use on the BEAM than packet routing.
- Give
:persistent_termrebuild guidance in minutes or hours rather than seconds, since the write triggers a global garbage collection scan that can cost more than the build. - Record that weights are reduced by their greatest common divisor, and that this does not reduce build cost, which tracks the ratio rather than the magnitude.
0.1.0 - 2026-08-06
First release.
Added
Maglev.new/2builds a lookup table over a set of backends, with a configurable prime table size and backend key encoding.Maglev.lookup/2andMaglev.lookup_index/2select a backend, the latter for callers that have already hashed the key.Maglev.slots/1,Maglev.backends/1,Maglev.entry_counts/1andMaglev.size/1expose the built table for inspection, monitoring and export to an external datapath.Maglev.table_sizes/0lists prime table sizes.- Weighted backends via the
:weightsoption, taking a map or a one-argument function, withMaglev.weights/1reporting what a table was built with.
Notes
- Backends are sorted by encoded key before construction. The algorithm as published fills slots in backend index order, which would otherwise make the table depend on the order the backend list arrives in.
- Backends that encode to the same key are rejected, since the algorithm cannot distinguish them.
- Weights are positive integers rather than floats, so that the arithmetic deciding slot assignment is exact and cannot diverge between nodes.
- Every backend receives at least one slot, which takes precedence over the requested weight ratio when a table is too small to express it.