1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.dialer.common.backoff; 18 19 import com.android.dialer.common.Assert; 20 21 /** 22 * Given an initial backoff delay, D, a base multiplier, B, and a total number of backoffs, N, this 23 * class returns values in the exponential sequence, D, D*B, D*B^2, ... D*B^(N-1), ... 24 * 25 * <p>Example usage: 26 * 27 * <pre> 28 * long initialDelayMillis = 1000; 29 * double multiplier = 1.2; 30 * int backoffs = 10; 31 * ExponentialBackoff backoff = new ExponentialBackoff(initialDelayMillis, multiplier, backoffs); 32 * while (backoff.isInRange()) { 33 * ... 34 * sleep(backoff.getNextBackoff()); 35 * } 36 * </pre> 37 * 38 * <p>Note: the base multiplier can be calculated using {@code ExponentialBaseCalculator} 39 */ 40 public final class ExponentialBackoff { 41 public final long initialDelayMillis; 42 public final double baseMultiplier; 43 public final int maximumBackoffs; 44 private double nextBackoff; 45 private int backoffCount; 46 47 /** 48 * Setup an exponential backoff with an initial delay, a base multiplier and a maximum number of 49 * backoff steps. 50 * 51 * @throws IllegalArgumentException for negative argument values 52 */ ExponentialBackoff(long initialDelayMillis, double baseMultiplier, int maximumBackoffs)53 public ExponentialBackoff(long initialDelayMillis, double baseMultiplier, int maximumBackoffs) { 54 Assert.checkArgument(initialDelayMillis > 0); 55 Assert.checkArgument(baseMultiplier > 0); 56 Assert.checkArgument(maximumBackoffs > 0); 57 this.initialDelayMillis = initialDelayMillis; 58 this.baseMultiplier = baseMultiplier; 59 this.maximumBackoffs = maximumBackoffs; 60 reset(); 61 } 62 63 /** 64 * @return the next backoff time in the exponential sequence. Specifically, if D is the initial 65 * delay, B is the base multiplier and N is the total number of backoffs, then the return 66 * values will be: D, D*B, D*B^2, ... D*B^(N-1), ... 67 */ getNextBackoff()68 public long getNextBackoff() { 69 long backoff = Math.round(nextBackoff); 70 backoffCount++; 71 nextBackoff *= baseMultiplier; 72 return backoff; 73 } 74 75 /** @return the number of times getNextBackoff() has been called */ getBackoffCount()76 public int getBackoffCount() { 77 return backoffCount; 78 } 79 80 /** 81 * @return {@code true} if getNextBackoff() has been called less than the maximumBackoffs value 82 * specified in the constructor. 83 */ isInRange()84 public boolean isInRange() { 85 return backoffCount < maximumBackoffs; 86 } 87 88 /** 89 * Reset the sequence of backoff values so the next call to getNextBackoff() will return the 90 * initial delay and getBackoffCount() will return 0 91 */ reset()92 public void reset() { 93 nextBackoff = initialDelayMillis; 94 backoffCount = 0; 95 } 96 } 97