alluxio.time.ExponentialTimer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of alluxio-core-common Show documentation
Show all versions of alluxio-core-common Show documentation
Common utilities shared in Alluxio core modules
/*
* 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.time;
import alluxio.retry.ExponentialBackoffRetry;
import alluxio.retry.RetryPolicy;
/**
* The {@link ExponentialTimer} can be used for generating a sequence of events that are
* exponentially distributed in time.
*
* The intended usage is to associate the timer with an operation that should to be re-attempted
* if it fails using exponential back-off. For instance, an event loop iterates over scheduled
* operations each of which is associated with a timer and the event loop can use the timer to check
* if the operation is ready to be attempted and whether it should be re-attempted again in the
* future in case it fails.
*
*
* while (true) {
* Operation op = operations.pop();
* switch (op.getTimer().tick()) {
* case EXPIRED:
* // operation will not be re-attempted
* break;
* case NOT_READY:
* // operation is not ready to be re-attempted
* operations.push(op);
* break;
* case READY:
* boolean success = op.run();
* if (!success) {
* operations.push(op);
* }
* }
* Thread.sleep(10);
* }
*
*
* Note that in the above scenario, the {@link ExponentialBackoffRetry} policy cannot be used
* because the {@link RetryPolicy#attemptRetry()} is blocking.
*/
public class ExponentialTimer {
/**
* Represents the result of {@link #tick()}.
*/
public enum Result {
EXPIRED,
NOT_READY,
READY,
}
/** The maximum interval time between events (in milliseconds). */
private final long mMaxIntervalMs;
/** The last event horizon (in milliseconds). */
private final long mLastEventHorizonMs;
/** The number of generated events. */
private long mNumEvents;
/** The time of the next event. */
private long mNextEventMs;
/** The current interval between events (in milliseconds). */
private long mIntervalMs;
/**
* Creates a new instance of {@link ExponentialTimer}.
*
* @param initialIntervalMs the initial interval between events (in milliseconds)
* @param maxIntervalMs the maximum interval between events (in milliseconds)
* @param initialWaitTimeMs the initial wait time before first event (in milliseconds)
* @param maxTotalWaitTimeMs the maximum total wait time (in milliseconds)
*/
public ExponentialTimer(long initialIntervalMs, long maxIntervalMs, long initialWaitTimeMs,
long maxTotalWaitTimeMs) {
mMaxIntervalMs = maxIntervalMs;
mLastEventHorizonMs = System.currentTimeMillis() + maxTotalWaitTimeMs;
mNextEventMs = System.currentTimeMillis() + initialWaitTimeMs;
mIntervalMs = Math.min(initialIntervalMs, maxIntervalMs);
mNumEvents = 0;
}
/**
* @return the number of generated events so far
*/
public long getNumEvents() {
return mNumEvents;
}
/**
* Attempts to perform a timer tick. One of three scenarios can be encountered:
*
* 1. the timer has expired
* 2. the next event is not ready
* 3. the next event is generated
*
* The last option has the side-effect of updating the internal state of the timer to reflect
* the generation of the event.
*
* @return the {@link Result} that indicates which scenario was encountered
*/
public Result tick() {
if (System.currentTimeMillis() >= mLastEventHorizonMs) {
return Result.EXPIRED;
}
if (System.currentTimeMillis() < mNextEventMs) {
return Result.NOT_READY;
}
mNextEventMs = System.currentTimeMillis() + mIntervalMs;
long next = Math.min(mIntervalMs * 2, mMaxIntervalMs);
// Account for overflow.
if (next < mIntervalMs) {
next = Integer.MAX_VALUE;
}
mIntervalMs = next;
mNumEvents++;
return Result.READY;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy