public static <RETURN, THROWABLE extends Throwable> RETURN attempt(
      CheckedSupplier<RETURN, THROWABLE> supplier,
      RetryPolicy<RETURN> policy,
      Supplier<?> name,
      Logger log)
      throws THROWABLE, InterruptedException {
    Objects.requireNonNull(supplier, "supplier == null");
    for (int attempt = 0; ; attempt++) {
      try {
        final RETURN ret = supplier.get();
        // if we should retry and the total attempt doesn't reach max allowed attempts
        if (policy.shouldRetry(ret) && policy.shoudAttempt(attempt)) {
          TimeDuration waitTime = policy.getWaitTime(attempt);
          if (log != null && log.isDebugEnabled()) {
            log.debug(
                "Failed {}, attempt #{}, sleep {} and then retry", name.get(), attempt, waitTime);
          }
          waitTime.sleep();
          continue;
        }
        return ret;
      } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
        if (log != null && log.isWarnEnabled()) {
          log.warn("{}: interrupted when waiting for retry", name.get());
        }
        throw e;
      }
    }
  }
* Attempt the given operation {@param supplier}. May retry several times according to the given
retry policy {@param policy}

@param name the operation's name.
@param log the logger to print messages.
@throws InterruptedException if the sleep is interrupted.
@throws THROWABLE if the operation throws a pre-defined error.
@return the result of given operation if it executes successfully
iotdb-core/consensus/src/main/java/org/apache/iotdb/consensus/ratis/utils/Retriable.java