AbfsBackoffMetrics.java

/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.hadoop.fs.azurebfs;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;

import static org.apache.hadoop.fs.azurebfs.constants.FileSystemConfigurations.HUNDRED;
import static org.apache.hadoop.fs.azurebfs.constants.FileSystemConfigurations.THOUSAND;

public class AbfsBackoffMetrics {

  private AtomicLong numberOfRequestsSucceeded;

  private AtomicLong minBackoff;

  private AtomicLong maxBackoff;

  private AtomicLong totalRequests;

  private AtomicLong totalBackoff;

  private String retryCount;

  private AtomicLong numberOfIOPSThrottledRequests;

  private AtomicLong numberOfBandwidthThrottledRequests;

  private AtomicLong numberOfOtherThrottledRequests;

  private AtomicLong numberOfNetworkFailedRequests;

  private AtomicLong maxRetryCount;

  private AtomicLong totalNumberOfRequests;

  private AtomicLong numberOfRequestsSucceededWithoutRetrying;

  private AtomicLong numberOfRequestsFailed;

  private final Map<String, AbfsBackoffMetrics> metricsMap
      = new ConcurrentHashMap<>();

  public AbfsBackoffMetrics() {
    initializeMap();
    this.numberOfIOPSThrottledRequests = new AtomicLong();
    this.numberOfBandwidthThrottledRequests = new AtomicLong();
    this.numberOfOtherThrottledRequests = new AtomicLong();
    this.totalNumberOfRequests = new AtomicLong();
    this.maxRetryCount = new AtomicLong();
    this.numberOfRequestsSucceededWithoutRetrying = new AtomicLong();
    this.numberOfRequestsFailed = new AtomicLong();
    this.numberOfNetworkFailedRequests = new AtomicLong();
  }

  public AbfsBackoffMetrics(String retryCount) {
    this.retryCount = retryCount;
    this.numberOfRequestsSucceeded = new AtomicLong();
    this.minBackoff = new AtomicLong(Long.MAX_VALUE);
    this.maxBackoff = new AtomicLong();
    this.totalRequests = new AtomicLong();
    this.totalBackoff = new AtomicLong();
  }

  private void initializeMap() {
    ArrayList<String> retryCountList = new ArrayList<String>(
        Arrays.asList("1", "2", "3", "4", "5_15", "15_25", "25AndAbove"));
    for (String s : retryCountList) {
      metricsMap.put(s, new AbfsBackoffMetrics(s));
    }
  }

  public long getNumberOfRequestsSucceeded() {
    return this.numberOfRequestsSucceeded.get();
  }

  public void setNumberOfRequestsSucceeded(long numberOfRequestsSucceeded) {
    this.numberOfRequestsSucceeded.set(numberOfRequestsSucceeded);
  }

  public void incrementNumberOfRequestsSucceeded() {
    this.numberOfRequestsSucceeded.getAndIncrement();
  }

  public long getMinBackoff() {
    return this.minBackoff.get();
  }

  public void setMinBackoff(long minBackoff) {
    this.minBackoff.set(minBackoff);
  }

  public long getMaxBackoff() {
    return this.maxBackoff.get();
  }

  public void setMaxBackoff(long maxBackoff) {
    this.maxBackoff.set(maxBackoff);
  }

  public long getTotalRequests() {
    return this.totalRequests.get();
  }

  public void incrementTotalRequests() {
    this.totalRequests.incrementAndGet();
  }

  public void setTotalRequests(long totalRequests) {
    this.totalRequests.set(totalRequests);
  }

  public long getTotalBackoff() {
    return this.totalBackoff.get();
  }

  public void setTotalBackoff(long totalBackoff) {
    this.totalBackoff.set(totalBackoff);
  }

  public String getRetryCount() {
    return this.retryCount;
  }

  public long getNumberOfIOPSThrottledRequests() {
    return this.numberOfIOPSThrottledRequests.get();
  }

  public void setNumberOfIOPSThrottledRequests(long numberOfIOPSThrottledRequests) {
    this.numberOfIOPSThrottledRequests.set(numberOfIOPSThrottledRequests);
  }

  public void incrementNumberOfIOPSThrottledRequests() {
    this.numberOfIOPSThrottledRequests.getAndIncrement();
  }

  public long getNumberOfBandwidthThrottledRequests() {
    return this.numberOfBandwidthThrottledRequests.get();
  }

  public void setNumberOfBandwidthThrottledRequests(long numberOfBandwidthThrottledRequests) {
    this.numberOfBandwidthThrottledRequests.set(numberOfBandwidthThrottledRequests);
  }

  public void incrementNumberOfBandwidthThrottledRequests() {
    this.numberOfBandwidthThrottledRequests.getAndIncrement();
  }

  public long getNumberOfOtherThrottledRequests() {
    return this.numberOfOtherThrottledRequests.get();
  }

  public void setNumberOfOtherThrottledRequests(long numberOfOtherThrottledRequests) {
    this.numberOfOtherThrottledRequests.set(numberOfOtherThrottledRequests);
  }

  public void incrementNumberOfOtherThrottledRequests() {
    this.numberOfOtherThrottledRequests.getAndIncrement();
  }

  public long getMaxRetryCount() {
    return this.maxRetryCount.get();
  }

  public void setMaxRetryCount(long maxRetryCount) {
    this.maxRetryCount.set(maxRetryCount);
  }

  public void incrementMaxRetryCount() {
    this.maxRetryCount.getAndIncrement();
  }

  public long getTotalNumberOfRequests() {
    return this.totalNumberOfRequests.get();
  }

  public void setTotalNumberOfRequests(long totalNumberOfRequests) {
    this.totalNumberOfRequests.set(totalNumberOfRequests);
  }

  public void incrementTotalNumberOfRequests() {
    this.totalNumberOfRequests.getAndIncrement();
  }

  public Map<String, AbfsBackoffMetrics> getMetricsMap() {
    return metricsMap;
  }

  public long getNumberOfRequestsSucceededWithoutRetrying() {
    return this.numberOfRequestsSucceededWithoutRetrying.get();
  }

  public void setNumberOfRequestsSucceededWithoutRetrying(long numberOfRequestsSucceededWithoutRetrying) {
    this.numberOfRequestsSucceededWithoutRetrying.set(numberOfRequestsSucceededWithoutRetrying);
  }

  public void incrementNumberOfRequestsSucceededWithoutRetrying() {
    this.numberOfRequestsSucceededWithoutRetrying.getAndIncrement();
  }

  public long getNumberOfRequestsFailed() {
    return this.numberOfRequestsFailed.get();
  }

  public void setNumberOfRequestsFailed(long numberOfRequestsFailed) {
    this.numberOfRequestsFailed.set(numberOfRequestsFailed);
  }

  public void incrementNumberOfRequestsFailed() {
    this.numberOfRequestsFailed.getAndIncrement();
  }

  public long getNumberOfNetworkFailedRequests() {
    return this.numberOfNetworkFailedRequests.get();
  }

  public void setNumberOfNetworkFailedRequests(long numberOfNetworkFailedRequests) {
    this.numberOfNetworkFailedRequests.set(numberOfNetworkFailedRequests);
  }

  public void incrementNumberOfNetworkFailedRequests() {
    this.numberOfNetworkFailedRequests.getAndIncrement();
  }

  /*
          Acronyms :-
          1.RCTSI :- Request count that succeeded in x retries
          2.MMA :- Min Max Average (This refers to the backoff or sleep time between 2 requests)
          3.s :- seconds
          4.BWT :- Number of Bandwidth throttled requests
          5.IT :- Number of IOPS throttled requests
          6.OT :- Number of Other throttled requests
          7.NFR :- Number of requests which failed due to network errors
          8.%RT :- Percentage of requests that are throttled
          9.TRNR :- Total number of requests which succeeded without retrying
          10.TRF :- Total number of requests which failed
          11.TR :- Total number of requests which were made
          12.MRC :- Max retry count across all requests
           */
  @Override
  public String toString() {
    StringBuilder metricString = new StringBuilder();
    long totalRequestsThrottled = getNumberOfBandwidthThrottledRequests()
        + getNumberOfIOPSThrottledRequests()
        + getNumberOfOtherThrottledRequests();
    double percentageOfRequestsThrottled =
        ((double) totalRequestsThrottled / getTotalNumberOfRequests()) * HUNDRED;
    for (Map.Entry<String, AbfsBackoffMetrics> entry : metricsMap.entrySet()) {
      metricString.append("$RCTSI$_").append(entry.getKey())
          .append("R_").append("=")
          .append(entry.getValue().getNumberOfRequestsSucceeded());
      long totalRequests = entry.getValue().getTotalRequests();
      if (totalRequests > 0) {
        metricString.append("$MMA$_").append(entry.getKey())
            .append("R_").append("=")
            .append(String.format("%.3f",
                (double) entry.getValue().getMinBackoff() / THOUSAND))
            .append("s")
            .append(String.format("%.3f",
                (double) entry.getValue().getMaxBackoff() / THOUSAND))
            .append("s")
            .append(String.format("%.3f",
                ((double) entry.getValue().getTotalBackoff() / totalRequests)
                    / THOUSAND))
            .append("s");
      } else {
        metricString.append("$MMA$_").append(entry.getKey())
            .append("R_").append("=0s");
      }
    }
    metricString.append("$BWT=")
        .append(getNumberOfBandwidthThrottledRequests())
        .append("$IT=")
        .append(getNumberOfIOPSThrottledRequests())
        .append("$OT=")
        .append(getNumberOfOtherThrottledRequests())
        .append("$RT=")
        .append(String.format("%.3f", percentageOfRequestsThrottled))
        .append("$NFR=")
        .append(getNumberOfNetworkFailedRequests())
        .append("$TRNR=")
        .append(getNumberOfRequestsSucceededWithoutRetrying())
        .append("$TRF=")
        .append(getNumberOfRequestsFailed())
        .append("$TR=")
        .append(getTotalNumberOfRequests())
        .append("$MRC=")
        .append(getMaxRetryCount());

    return metricString + "";
  }
}