package voldemort.utils;
import voldemort.annotations.concurrency.Threadsafe;
import java.util.concurrent.Callable;
import java.util.concurrent.atomic.AtomicReference;
@Threadsafe
public class CachedCallable<T> implements Callable<T> {
private final Callable<T> inner;
private final long ttlMs;
private final Time time;
private final AtomicReference<T> valueRef;
private volatile long lastCalledMs;
public CachedCallable(Callable<T> inner,
long ttlMs) {
this(inner, ttlMs, SystemTime.INSTANCE);
}
public CachedCallable(Callable<T> inner,
long ttlMs,
Time time) {
this.inner = inner;
this.ttlMs = ttlMs;
this.time = time;
valueRef = new AtomicReference<T>();
}
public T call() throws Exception {
T value = valueRef.get();
long now = time.getMilliseconds();
if(value == null || now - lastCalledMs > ttlMs) {
T newValue = inner.call();
if(valueRef.compareAndSet(value, newValue)) {
lastCalledMs = now;
return newValue;
}
}
return valueRef.get();
}
}