@@ -332,10 +332,6 @@ public boolean isEquivalentTo(RoundRobinPicker picker) {
332332 * The Static Stride Scheduler is an implementation of an earliest deadline first (EDF) scheduler
333333 * in which each object is chosen periodically with frequency proportional to its weight.
334334 * <p>
335- * Specifically, each backend is given a deadline equal to the multiplicative inverse of
336- * its weight. The place of each backend in its deadline is tracked, and each call to
337- * pick a backend returns the backend index with the least remaining time in its deadline.
338- * <p>
339335 * The way in which this is implemented is through a static stride scheduler.
340336 * The Static Stride Scheduler works by iterating through the list of subchannel weights
341337 * and using modular arithmetic to proportionally distribute picks, favoring entries
@@ -375,8 +371,7 @@ static final class StaticStrideScheduler {
375371
376372 double scalingFactor = K_MAX_WEIGHT / maxWeight ;
377373 if (numWeightedChannels > 0 ) {
378- int value = (int ) Math .round (scalingFactor * sumWeight / numWeightedChannels );
379- meanWeight = (short ) (value > 0x7FFF ? value - 0x10000 : value );
374+ meanWeight = (short ) Math .round (scalingFactor * sumWeight / numWeightedChannels );
380375 } else {
381376 meanWeight = 1 ;
382377 }
@@ -409,11 +404,32 @@ long getSequence() {
409404 /*
410405 * Selects index of next backend server.
411406 * <p>
412- * A 2D array is compactly represented where the row represents the generation and the column
413- * represents the backend index. The value of an element is a boolean value which indicates
414- * whether or not a backend should be picked now. An atomically incremented counter keeps track
415- * of our backend and generation through modular arithmetic within the pick() method.
416- * An offset is also included to minimize consecutive non-picks of a backend.
407+ * A 2D array is compactly represented as a function of W(backend), where the row
408+ * represents the generation and the column represents the backend index:
409+ * X(backend,generation) | generation ∈ [0,kMaxWeight).
410+ * Each element in the conceptual array is a boolean indicating whether the backend at
411+ * this index should be picked now. If false, the counter is incremented again,
412+ * and the new element is checked. An atomically incremented counter keeps track of our
413+ * backend and generation through modular arithmetic within the pick() method.
414+ * <p>
415+ * Modular arithmetic allows us to evenly distribute picks and skips between
416+ * generations based on W(backend).
417+ * X(backend,generation) = (W(backend) * generation) % kMaxWeight >= kMaxWeight - W(backend)
418+ * If we have the same three backends with weights:
419+ * W(backend) = {2,3,6} scaled to max(W(backend)) = 6, then X(backend,generation) is:
420+ * <p>
421+ * B0 B1 B2
422+ * T T T
423+ * F F T
424+ * F T T
425+ * T F T
426+ * F T T
427+ * F F T
428+ * The sequence of picked backend indices is given by
429+ * walking across and down: {0,1,2,2,1,2,0,2,1,2,2}.
430+ * <p>
431+ * To reduce the variance and spread the wasted work among different picks,
432+ * an offset that varies per backend index is also included to the calculation.
417433 */
418434 int pick () {
419435 while (true ) {
0 commit comments