v0.2.0
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.
That is 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. Forcing every pinned configuration through the new strategy reproduces 0.1.0 exactly, including 1000 backends at 655373 slots with a weight ratio of 10000.
Lopsided weights build faster
The fill walks every backend on every iteration and skips those not yet eligible to claim a slot. That is free when weights are equal, because every backend claims every time, but the iteration count grows with the ratio between the largest and smallest weight while the number of claims stays at the table size — so nearly every visit does nothing.
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. Neither strategy dominates, so the choice is made from the weights and both ship.
At 1000 backends and a 65537-slot table, each measurement in a fresh process:
| Weights | Scanning | Queue | Selected |
|---|---|---|---|
| all equal | 22.9 ms | 163.7 ms | scanning |
| spread over 1..10 | 22.1 ms | 98.0 ms | scanning |
| one at 100, rest at 1 | 155.5 ms | 132.5 ms | queue |
| one at 1000, rest at 1 | 664.4 ms | 103.0 ms | queue |
| one at 10000, rest at 1 | 1394.5 ms | 58.8 ms | queue |
Selection reads the weights once and costs single-digit microseconds against builds of tens of milliseconds, so the selected column is the chosen strategy's own cost.
Two limits are worth stating. The boundary is approximate: the curves cross near a weight ratio of 40 at 100 backends and 85 at 1000, and no single threshold fits both, because the queue's cost per claim grows faster than the log2(count) term it is weighed against. The threshold errs late, so near-equal weights are never moved onto the queue; the largest penalty measured from a wrong choice is about 1.7x, against gains of 5x to 20x where the queue wins.
And scanning allocates nothing while the queue allocates on the process heap. Measured in a fresh process the queue looks its best; called from a long-lived process holding a large heap it will do worse. The figures above are a best case for the queue, not a typical one.
Documentation
- 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. lookup_index/2applies no mixing, so a narrow or skewed hash leaves slots unreachable or unevenly loaded.- Consistent worker assignment, which is the more common use on the BEAM than packet routing.
:persistent_termrebuild frequency in minutes or hours rather than seconds, since the write triggers a global garbage collection scan that can cost more than the build.
See the CHANGELOG for the full list.