ReplyT route()

in mcrouter/routes/LatencyInjectionRoute.h [108:194]


  ReplyT<Request> route(const Request& req) const {
    auto& proxy = fiber_local<RouterInfo>::getSharedCtx()->proxy();
    const auto before_ms = getCurrentTimeInMs();
    SCOPE_EXIT {
      if (totalLatency_.count() > 0) {
        auto elapsed =
            std::chrono::milliseconds(getCurrentTimeInMs() - before_ms);

        // Pad latency out to total latency configured.
        if (totalLatency_ > elapsed) {
          proxy.stats().increment(mcrouter::total_latency_injected_stat);
          folly::fibers::Baton totalBaton;
          totalBaton.try_wait_for(totalLatency_ - elapsed);
        }
      }
    };

    // Fixed latency added before request is sent.
    if (beforeLatency_.count() > 0) {
      proxy.stats().increment(mcrouter::before_latency_injected_stat);
      folly::fibers::Baton beforeBaton;
      beforeBaton.try_wait_for(beforeLatency_);
    }

    std::chrono::microseconds beforeReqLatency{0};
    std::chrono::microseconds afterReqLatency{0};
    std::optional<Request> newReq;

    static folly::ThreadWheelTimekeeperHighRes timeKeeper;

    // Both beforeLatencyUs and afterLatencyUs fields have to be defined
    // for request specific latency injection to happen.
    if constexpr (
        HasBeforeLatencyUsTrait<Request>::value &&
        HasAfterLatencyUsTrait<Request>::value) {
      if (requestLatency_) {
        if (req.beforeLatencyUs_ref().has_value()) {
          beforeReqLatency =
              std::chrono::microseconds(*req.beforeLatencyUs_ref());
        }
        if (req.afterLatencyUs_ref().has_value()) {
          afterReqLatency =
              std::chrono::microseconds(*req.afterLatencyUs_ref());
        }
        // Reset request latencies to avoid downstream latency injection
        if (beforeReqLatency.count() > 0 || afterReqLatency.count() > 0) {
          newReq.emplace(req);
          newReq->afterLatencyUs_ref() = 0;
          newReq->beforeLatencyUs_ref() = 0;
        }
        // Inject per request latency if enabled
        if (beforeReqLatency.count() > 0 &&
            ((maxRequestLatency_.count() == 0) ||
             (beforeReqLatency.count() <= maxRequestLatency_.count()))) {
          proxy.stats().increment(
              mcrouter::before_request_latency_injected_stat);
          fiber_local<RouterInfo>::accumulateBeforeReqInjectedLatencyUs(
              beforeReqLatency.count());
          folly::futures::sleep(beforeReqLatency, &timeKeeper).get();
        }
      }
    }

    auto& reqToSend = newReq ? *newReq : req;
    auto reply = rh_->route(reqToSend);
    // Optimize out the logic that is related to request level latency injection
    // for protocols that does not support it
    if constexpr (HasAfterLatencyUsTrait<Request>::value) {
      if (afterReqLatency.count() > 0 &&
          ((maxRequestLatency_.count() == 0) ||
           (afterReqLatency.count() <= maxRequestLatency_.count()))) {
        proxy.stats().increment(mcrouter::after_request_latency_injected_stat);
        fiber_local<RouterInfo>::accumulateAfterReqInjectedLatencyUs(
            afterReqLatency.count());
        folly::futures::sleep(afterReqLatency, &timeKeeper).get();
      }
    }

    // Fixed latency added after reply is received.
    if (afterLatency_.count() > 0) {
      proxy.stats().increment(mcrouter::after_latency_injected_stat);
      folly::fibers::Baton afterBaton;
      afterBaton.try_wait_for(afterLatency_);
    }

    return reply;
  }