package com.lambdaworks.redis;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
/**
* Utility to {@link #awaitAll(long, TimeUnit, Future[])} futures until they are done and to synchronize future execution using
* {@link #awaitOrCancel(RedisFuture, long, TimeUnit)}.
*
* @author Mark Paluch
* @since 3.0
*/
public class LettuceFutures {
private LettuceFutures() {
}
/**
* Wait until futures are complete or the supplied timeout is reached. Commands are not canceled (in contrast to
* {@link #awaitOrCancel(RedisFuture, long, TimeUnit)}) when the timeout expires.
*
* @param timeout Maximum time to wait for futures to complete.
* @param unit Unit of time for the timeout.
* @param futures Futures to wait for.
* @return {@literal true} if all futures complete in time, otherwise {@literal false}
*/
public static boolean awaitAll(long timeout, TimeUnit unit, Future<?>... futures) {
boolean complete;
try {
long nanos = unit.toNanos(timeout);
long time = System.nanoTime();
for (Future<?> f : futures) {
if (nanos < 0) {
return false;
}
f.get(nanos, TimeUnit.NANOSECONDS);
long now = System.nanoTime();
nanos -= now - time;
time = now;
}
complete = true;
} catch (TimeoutException e) {
complete = false;
} catch (ExecutionException e) {
if (e.getCause() instanceof RedisCommandExecutionException) {
throw new RedisCommandExecutionException(e.getCause().getMessage(), e.getCause());
}
throw new RedisException(e.getCause());
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RedisCommandInterruptedException(e);
} catch (Exception e) {
throw new RedisCommandExecutionException(e);
}
return complete;
}
/**
* Wait until futures are complete or the supplied timeout is reached. Commands are canceled if the timeout is reached but
* the command is not finished.
*
* @param cmd Command to wait for
* @param timeout Maximum time to wait for futures to complete
* @param unit Unit of time for the timeout
* @param <T> Result type
*
* @return Result of the command.
*/
public static <T> T awaitOrCancel(RedisFuture<T> cmd, long timeout, TimeUnit unit) {
return await(timeout, unit, cmd);
}
/**
* Wait until futures are complete or the supplied timeout is reached. Commands are canceled if the timeout is reached but
* the command is not finished.
*
* @param cmd Command to wait for
* @param timeout Maximum time to wait for futures to complete
* @param unit Unit of time for the timeout
* @param <T> Result type
* @deprecated The method name does not reflect what the method is doing, therefore it is deprecated. Use
* {@link #awaitOrCancel(RedisFuture, long, TimeUnit)} instead. The semantics did not change and
* {@link #awaitOrCancel(RedisFuture, long, TimeUnit)} simply calls this method.
* @return True if all futures complete in time.
*/
@Deprecated
public static <T> T await(long timeout, TimeUnit unit, RedisFuture<T> cmd) {
try {
if (!cmd.await(timeout, unit)) {
cmd.cancel(true);
throw new RedisCommandTimeoutException();
}
return cmd.get();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RedisCommandInterruptedException(e);
} catch (ExecutionException e) {
if (e.getCause() instanceof RedisCommandExecutionException) {
throw new RedisCommandExecutionException(e.getCause().getMessage(), e.getCause());
}
throw new RedisException(e.getCause());
}
}
}