package cassandra.routing; import cassandra.cql.AbstractStatement; import cassandra.metadata.Metadata; import cassandra.metadata.PeerMetadata; import java.net.InetAddress; import java.util.Iterator; import java.util.concurrent.ConcurrentMap; import static io.netty.util.internal.PlatformDependent.newConcurrentHashMap; public class DCAwareRoundRobinPolicy implements RoutingPolicy { private final String datacenter; private final ConcurrentMap<String, RoundRobinPolicy> dc2Policy; private Metadata metadata; public DCAwareRoundRobinPolicy(String datacenter) { if (datacenter == null) { throw new NullPointerException("datacenter"); } if (datacenter.isEmpty()) { throw new IllegalArgumentException("empty datacenter"); } this.datacenter = datacenter; dc2Policy = newConcurrentHashMap(); dc2Policy.put(datacenter, new RoundRobinPolicy()); } public String datacenter() { return datacenter; } public void init(Metadata metadata) { this.metadata = metadata; } @Override public boolean isLocal(InetAddress endpoint) { if (metadata == null) { return false; } PeerMetadata peer = metadata.getPeer(endpoint); return peer != null && peer.hasDatacenter() && peer.getDatacenter().equals(datacenter); } @Override public Iterator<InetAddress> activeEndpoints(final AbstractStatement<?> statement) { if (metadata == null) { metadata = statement.getSession().metadata(); for (PeerMetadata peer : metadata.getPeers()) { add(peer); } } return new Iterator<InetAddress>() { private final Iterator<InetAddress> local = dc2Policy.get(datacenter).activeEndpoints(statement); private final Iterator<String> remotedc = dc2Policy.keySet().iterator(); private Iterator<InetAddress> current = local; @Override public boolean hasNext() { for (;;) { if (current.hasNext()) { return true; } if (!remotedc.hasNext()) { return false; } while (remotedc.hasNext()) { String nextdc = remotedc.next(); if (!nextdc.equals(datacenter)) { current = dc2Policy.get(nextdc).activeEndpoints(statement); break; } } } } @Override public InetAddress next() { return current.next(); } @Override public void remove() { throw new UnsupportedOperationException(); } }; } @Override public void addEndpoint(InetAddress endpoint) { if (metadata != null) { add(metadata.getPeer(endpoint)); } } @Override public void removeEndpoint(InetAddress endpoint) { for (RoutingPolicy policy : dc2Policy.values()) { policy.removeEndpoint(endpoint); } } private void add(PeerMetadata peer) { if (metadata != null) { if (peer != null && peer.hasDatacenter()) { String dc = peer.getDatacenter(); RoundRobinPolicy policy = dc2Policy.get(dc); if (policy == null) { RoundRobinPolicy newPolicy = new RoundRobinPolicy(); policy = dc2Policy.putIfAbsent(dc, newPolicy); if (policy == null) { policy = newPolicy; } } policy.addEndpoint(peer.getAddress()); } } } }