void increment()

in mcrouter/routes/FailoverPolicy.h [404:483]


    void increment() {
      // No need to determine "next" index for passive iterators
      if (!active_) {
        ++id_;
        return;
      }
      uint32_t numAttempts = 0;
      const auto nChildren = policy_.children_.size();
      // arbitrarily set high number of max attempts so that finding the next
      // index does not get into infinite loop
      constexpr uint32_t maxAttempts = 100;
      // arbitrarily set percent of max attempts as failure domain threshold
      // so that we do not consider all the MSB as failed (Remember that we
      // do not have direct signal that a TKO is due to MSB failure, so if
      // the number failure domains are small and all the failure domains are
      // in the set, then we would be skipping all of them. This threshold is
      // to get out of skipping all the destinations due to this pathological
      // case
      constexpr uint32_t failureDomainThreshold = (3 * maxAttempts) / 4;
      if (index_ == 0) {
        // initialize usedIndexes_ here before it is used
        usedIndexes_.resize(nChildren);
        usedIndexes_.set(0);

        // Use normal_reply_index only if ignore flag is false
        if (!policy_.ignore_normal_reply_index_) {
          size_t normal_reply_index =
              mcrouter::fiber_local<RouterInfo>::getSelectedIndex();
          // Skip the destination selected by normal route by adding the
          // index of the normal route destination to usedIndexes.
          if ((normal_reply_index + 1) < usedIndexes_.size()) {
            usedIndexes_.set(normal_reply_index + 1);
          } else {
            LOG_FAILURE(
                "mcrouter",
                failure::Category::kInvalidConfig,
                "Normal Route and Failover route pool sizes seem to be different."
                " ignore_normal_reply_index config flag should be used.");
          }
        }
      }
      bool failedDomain = false;
      do {
        salt_++;
        if (funcType_ == Ch3HashFunc::type()) {
          Ch3HashFunc ch3Func(nChildren);
          index_ = HashSelector<Ch3HashFunc>(std::to_string(salt_), ch3Func)
                       .select(req_, nChildren);
        } else {
          WeightedCh3HashFunc wCh3Func{config_, nChildren};
          index_ =
              HashSelector<WeightedCh3HashFunc>(std::to_string(salt_), wCh3Func)
                  .select(req_, nChildren);
        }

        // Use failure domains only in case of non-const iterators
        if constexpr (!std::is_const<Policy>{}) {
          uint32_t nextFd = getFailureDomain(index_);
          failedDomain =
              (policy_.enableFailureDomains_ &&
               (failedDomains_.find(nextFd) != failedDomains_.end()));
        }
        // force ignore failure-domain if we have tried more than
        // failureDomainThreshold -- FAIL safe mechanism
        if (numAttempts > failureDomainThreshold) {
          failedDomain = false;
        }

        if (failedDomain) {
          num_failed_domain_collisions_++;
        } else {
          collisions_++;
        }

      } while ((usedIndexes_.test(index_) || failedDomain) &&
               (numAttempts++ < maxAttempts));
      collisions_--;
      usedIndexes_.set(index_);
      ++id_;
    }