content: /*
   * The Alluxio Open Foundation licenses this work under the Apache License, version 2.0
   * (the "License"). You may not use this work except in compliance with the License, which is
   * available at www.apache.org/licenses/LICENSE-2.0
   *
   * This software is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
   * either express or implied, as more fully set forth in the License.
   *
   * See the NOTICE file distributed with this work for information regarding copyright ownership.
   */
  
  package alluxio.retry;
  
  import alluxio.time.Sleeper;
  import alluxio.time.TimeContext;
  
  import java.time.Clock;
  import java.time.Duration;
  import java.time.Instant;
  
  /**
   * Retry mechanism which performs retries until a certain period of time has elapsed. Subclasses
   * determine the interval between retries.
   */
  public abstract class TimeBoundedRetry implements RetryPolicy {
    private final Clock mClock;
    private final Sleeper mSleeper;
    protected final Duration mMaxDuration;
    private final Instant mStartTime;
    private final Instant mEndTime;
  
    private int mAttemptCount = 0;
  
    /**
     * @param timeCtx the time context to use for time-based operations
     * @param maxDuration the maximum duration
     */
    public TimeBoundedRetry(TimeContext timeCtx, Duration maxDuration) {
      mClock = timeCtx.getClock();
      mSleeper = timeCtx.getSleeper();
      mMaxDuration = maxDuration;
      mStartTime = mClock.instant();
      mEndTime = mStartTime.plus(mMaxDuration);
    }
  
    @Override
    public int getAttemptCount() {
      return mAttemptCount;
    }
  
    @Override
    public boolean attempt() {
      if (mAttemptCount == 0) {
        mAttemptCount++;
        return true;
      }
      Instant now = mClock.instant();
      if (now.isAfter(mEndTime) || now.equals(mEndTime)) {
        return false;
      }
      Duration nextWaitTime = computeNextWaitTime();
      if (now.plus(nextWaitTime).isAfter(mEndTime)) {
        nextWaitTime = Duration.between(now, mEndTime);
      }
      if (nextWaitTime.getNano() > 0) {
        try {
          mSleeper.sleep(nextWaitTime);
        } catch (InterruptedException e) {
          Thread.currentThread().interrupt();
          return false;
        }
      }
      mAttemptCount++;
      return true;
    }
  
    /**
     * @return how long to wait before the next retry
     */
    protected abstract Duration computeNextWaitTime();
  }
  