Skip to content

v0.2.0

Choose a tag to compare

@thatsme thatsme released this 06 Aug 12:48
· 4 commits to main since this release

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 h1 and h2 without defining them, while Maglev.slots/1 was 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/2 applies 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_term rebuild 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.