private void evaluatePerformanceAndUpdateMetrics() {
    RestRequestMetricsTracker restRequestMetricsTracker = request.getMetricsTracker();
    long roundTripTimeInMs = restRequestMetricsTracker.getRoundTripTimeInMs();
    long timeToFirstBytesInMs = restRequestMetricsTracker.getTimeToFirstByteInMs();
    long totalOutboundBytes = totalBytesReceived.get();
    long totalInboundBytes = request.getBytesReceived();
    RestMethod method = request.getRestMethod();
    Map<PerformanceIndex, Long> requestPerfToCheck = new HashMap<>();
    if (errorResponseStatus != null) {
      responseStatus = errorResponseStatus;
    }
    restRequestMetricsTracker.setResponseStatus(responseStatus);
    boolean shouldSkipCheck = false;
    switch (method) {
      case GET:
        if (responseStatus.isSuccess()) {
          requestPerfToCheck.put(PerformanceIndex.TimeToFirstByte, timeToFirstBytesInMs);
          requestPerfToCheck.put(PerformanceIndex.AverageBandwidth,
              roundTripTimeInMs == 0L ? Long.MAX_VALUE : totalOutboundBytes * 1000L / roundTripTimeInMs);
          restRequestMetricsTracker.setBytesTransferred(totalOutboundBytes);
        } else if (responseStatus.isClientError() || responseStatus.isRedirection()) {
          requestPerfToCheck.put(PerformanceIndex.RoundTripTime, roundTripTimeInMs);
        }
        break;
      case POST:
        if (responseStatus.isSuccess()) {
          requestPerfToCheck.put(PerformanceIndex.AverageBandwidth,
              roundTripTimeInMs == 0L ? Long.MAX_VALUE : totalInboundBytes * 1000L / roundTripTimeInMs);
        } else if (responseStatus.isClientError() || responseStatus.isRedirection()) {
          requestPerfToCheck.put(PerformanceIndex.RoundTripTime, roundTripTimeInMs);
        }
        break;
      case PUT:
      case HEAD:
      case DELETE:
        if (!responseStatus.isServerError()) {
          requestPerfToCheck.put(PerformanceIndex.RoundTripTime, roundTripTimeInMs);
        }
        break;
      default:
        shouldSkipCheck = true;
        logger.debug("Temporarily no evaluation criteria for {} request. Mark as satisfied directly", method);
    }
    EnumMap<RestMethod, Thresholds> thresholdsByMethod =
        responseStatus.isSuccess() ? perfConfig.successRequestThresholds : perfConfig.nonSuccessRequestThresholds;
    if (!shouldSkipCheck && (responseStatus.isServerError() || !thresholdsByMethod.get(method)
        .checkThresholds(requestPerfToCheck))) {
      // this means either response is 5xx or request missed one of thresholds, the request should be unsatisfied
      restRequestMetricsTracker.markUnsatisfied();
      logUnsatisfiedRequest(requestPerfToCheck);
    }
    restRequestMetricsTracker.recordMetrics();
  }
Evaluate performance of the request based on its associated {@link PerformanceIndex} and then update the metrics accordingly.
ambry-rest/src/main/java/com/github/ambry/rest/NettyResponseChannel.java