in mcrouter/lib/fbi/WeightedFurcHash.cpp [117:184]
uint32_t weightedFurcHash(
folly::StringPiece key,
folly::Range<const double*> weights,
uint32_t maxRetries) {
uint32_t m = weights.size();
uint32_t num = m;
uint32_t a;
HashCache hash;
if (m <= 1) {
return 0;
}
uint32_t msb = folly::findLastSet(m - 1);
uint32_t d = msb;
uint32_t startIdx = 0;
a = d;
uint32_t old_ord = 0;
uint32_t furcAttempt = 0;
uint32_t overallAttempt = 0;
uint32_t next32bits = 0;
furcKickStartHash(key, hash);
while (overallAttempt < maxRetries) {
while (!furcGetBit(a, hash, old_ord)) {
if (--d == startIdx) {
num = 0;
break;
}
a = d;
}
a += kFurcShift; // We should make progress even in the case of num == 0
if (num != 0) { // It's not the all-zeros case where we set num = 0
num = 1;
for (uint32_t i = startIdx; i < d - 1; i++) {
num = (num << 1) | furcGetBit(a, hash, old_ord);
a += kFurcShift;
}
if (num >= m) {
if (++furcAttempt == kMaxFurcRetries) { // Last attempt, default to 0
num = 0;
} else {
num = m;
continue;
}
}
}
assert(0 <= weights[num] && weights[num] <= 1.0);
if (weights[num] == 1) {
return num;
}
uint64_t weightAsInt = weights[num] * std::numeric_limits<uint32_t>::max();
next32bits = furcGetNext32Bits(a, hash, old_ord);
if (next32bits < weightAsInt) {
return num;
}
furcAttempt = 0;
startIdx = a;
d = a + msb;
a = d;
num = m;
overallAttempt++;
}
// Give up; distribute the result using the last peeked 32 bits.
return next32bits % m;
}