package cassandra;
import io.netty.channel.Channel;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
import static io.netty.util.internal.PlatformDependent.newConcurrentHashMap;
public class CassandraFutureMap implements Iterable<CassandraFuture> {
private static final Throwable REQUEST_TIMEOUT = new TimeoutException();
private final ConcurrentMap<Long, CassandraFuture> futures;
private final AtomicInteger nextStreamId;
public CassandraFutureMap() {
futures = newConcurrentHashMap();
nextStreamId = new AtomicInteger();
}
public CassandraFuture addFuture(CassandraFuture future) {
int channelId = future.connection().hashCode();
long streamId = encodeStreamId(channelId, nextStreamId());
while (futures.putIfAbsent(streamId, future) != null) {
streamId = encodeStreamId(channelId, nextStreamId());
}
future.request().setStreamId((int)streamId);
return future;
}
public CassandraFuture removeFuture(Channel channel, int streamId) {
return futures.remove(encodeStreamId(channel.hashCode(), streamId));
}
public List<CassandraFuture> clearExpiredFutures() {
List<CassandraFuture> futureList = null;
long now = System.currentTimeMillis();
Iterator<CassandraFuture> iterator = iterator();
while (iterator.hasNext()) {
CassandraFuture future = iterator.next();
if (future.isExpired(now)) {
if (futureList == null) {
futureList = new ArrayList<CassandraFuture>();
}
future.setFailure(REQUEST_TIMEOUT);
iterator.remove();
futureList.add(future);
}
}
if (futureList == null) {
return Collections.emptyList();
} else {
return futureList;
}
}
public List<CassandraFuture> fail(Channel channel, Throwable cause) {
List<CassandraFuture> futureList = null;
Iterator<CassandraFuture> iterator = iterator();
while (iterator.hasNext()) {
CassandraFuture future = iterator.next();
if (future.connection().hashCode() == channel.hashCode()) {
if (futureList == null) {
futureList = new ArrayList<CassandraFuture>();
}
future.setFailure(cause);
iterator.remove();
futureList.add(future);
}
}
if (futureList == null) {
return Collections.emptyList();
} else {
return futureList;
}
}
public int nextStreamId() {
return nextStreamId.getAndIncrement() & 0x7F;
}
@Override
public Iterator<CassandraFuture> iterator() {
return futures.values().iterator();
}
public static long encodeStreamId(int channelId, int streamId) {
return ((long)channelId << 32) | (streamId & 0xFFFFFFFFL);
}
}