package net.spy.memcached; import java.util.Arrays; import java.util.Collection; import java.util.Iterator; import java.util.List; /** * NodeLocator implementation for dealing with simple array lookups using a * modulus of the hash code and node list length. */ public final class ArrayModNodeLocator implements NodeLocator { final MemcachedNode[] nodes; private final HashAlgorithm hashAlg; /** * Construct an ArraymodNodeLocator over the given array of nodes and * using the given hash algorithm. * * @param n the array of nodes * @param alg the hash algorithm */ public ArrayModNodeLocator(List<MemcachedNode> n, HashAlgorithm alg) { super(); nodes=n.toArray(new MemcachedNode[n.size()]); hashAlg=alg; } public Collection<MemcachedNode> getAll() { return Arrays.asList(nodes); } public MemcachedNode getPrimary(String k) { return nodes[getServerForKey(k)]; } public Iterator<MemcachedNode> getSequence(String k) { return new NodeIterator(getServerForKey(k)); } private int getServerForKey(String key) { int rv=(int)(hashAlg.hash(key) % nodes.length); assert rv >= 0 : "Returned negative key for key " + key; assert rv < nodes.length : "Invalid server number " + rv + " for key " + key; return rv; } class NodeIterator implements Iterator<MemcachedNode> { private final int start; private int next=0; public NodeIterator(int keyStart) { start=keyStart; next=start; computeNext(); assert next >= 0 || nodes.length == 1 : "Starting sequence at " + start + " of " + nodes.length + " next is " + next; } public boolean hasNext() { return next >= 0; } private void computeNext() { if(++next >= nodes.length) { next=0; } if(next == start) { next=-1; } } public MemcachedNode next() { try { return nodes[next]; } finally { computeNext(); } } public void remove() { throw new UnsupportedOperationException("Can't remove a node"); } } }