package cassandra.routing; import cassandra.cql.AbstractStatement; import cassandra.cql.RoutingKey; import cassandra.metadata.Metadata; import cassandra.metadata.Partitioner; import cassandra.metadata.ReplicationStrategy; import java.net.InetAddress; import java.util.Iterator; import java.util.List; public class TokenAwareRoutingPolicy extends RoutingPolicy.Wrapper { public TokenAwareRoutingPolicy(RoutingPolicy routingPolicy) { super(routingPolicy); } @Override public boolean isLocal(InetAddress endpoint) { return routingPolicy.isLocal(endpoint); } @Override public Iterator<InetAddress> activeEndpoints(final AbstractStatement<?> statement) { String keyspace = statement.getKeyspace(); RoutingKey routingKey = statement.getRoutingKey(); if (keyspace != null && routingKey != null) { Metadata metadata = statement.getSession().metadata(); Partitioner partitioner = metadata.getPartitioner(); Partitioner.Token token = partitioner.getToken(routingKey.asByteBuffer()); ReplicationStrategy replicationStrategy = metadata.getKeyspace(keyspace).getReplicationStrategy(); final List<InetAddress> replicas = replicationStrategy.calculateNaturalEndpoints(token); if (!replicas.isEmpty()) { return new Iterator<InetAddress>() { private final Iterator<InetAddress> parent = replicas.iterator(); private Iterator<InetAddress> child; private InetAddress next; @Override public boolean hasNext() { if (parent.hasNext()) { InetAddress endpoint = parent.next(); if (isLocal(endpoint)) { next = endpoint; return true; } } if (child == null) { child = routingPolicy.activeEndpoints(statement); } while (child.hasNext()) { InetAddress endpoint = child.next(); if (!replicas.contains(endpoint) && !isLocal(endpoint)) { next = endpoint; return true; } } return false; } @Override public InetAddress next() { InetAddress endpoint = null; if (next != null) { endpoint = next; next = null; } return endpoint; } @Override public void remove() { throw new UnsupportedOperationException(); } }; } } return routingPolicy.activeEndpoints(statement); } @Override public void addEndpoint(InetAddress endpoint) { routingPolicy.addEndpoint(endpoint); } @Override public void removeEndpoint(InetAddress endpoint) { routingPolicy.removeEndpoint(endpoint); } }