All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.spy.memcached.KetamaNodeLocator Maven / Gradle / Ivy

The newest version!
package net.spy.memcached;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;

import net.spy.memcached.compat.SpyObject;
import net.spy.memcached.util.DefaultKetamaNodeLocatorConfiguration;
import net.spy.memcached.util.KetamaNodeLocatorConfiguration;

/**
 * This is an implementation of the Ketama consistent hash strategy from
 * last.fm.  This implementation may not be compatible with libketama as
 * hashing is considered separate from node location.
 *
 * Note that this implementation does not currently supported weighted nodes.
 *
 * @see RJ's blog post
 */
public final class KetamaNodeLocator extends SpyObject implements NodeLocator {


	private volatile TreeMap ketamaNodes;
	final Collection allNodes;

	final HashAlgorithm hashAlg;
	final KetamaNodeLocatorConfiguration config;


	/**
	 * Create a new KetamaNodeLocator using specified nodes and the specifed hash algorithm.
	 *
	 * @param nodes The List of nodes to use in the Ketama consistent hash continuum
	 * @param alg The hash algorithm to use when choosing a node in the Ketama consistent hash continuum
	 */
	public KetamaNodeLocator(List nodes, HashAlgorithm alg) {
        this(nodes, alg, new DefaultKetamaNodeLocatorConfiguration());
	}

	/**
	 * Create a new KetamaNodeLocator using specified nodes and the specifed hash algorithm and configuration.
	 *
	 * @param nodes The List of nodes to use in the Ketama consistent hash continuum
	 * @param alg The hash algorithm to use when choosing a node in the Ketama consistent hash continuum
	 * @param conf
	 */
	public KetamaNodeLocator(List nodes, HashAlgorithm alg, KetamaNodeLocatorConfiguration conf) {
		super();
		allNodes = nodes;
		hashAlg = alg;
		config = conf;

		setKetamaNodes(nodes);

    }

	private KetamaNodeLocator(TreeMap smn,
			Collection an, HashAlgorithm alg, KetamaNodeLocatorConfiguration conf) {
		super();
		ketamaNodes=smn;
		allNodes=an;
		hashAlg=alg;
        config=conf;
	}

	public Collection getAll() {
		return allNodes;
	}

	public MemcachedNode getPrimary(final String k) {
		MemcachedNode rv=getNodeForKey(hashAlg.hash(k));
		assert rv != null : "Found no node for key " + k;
		return rv;
	}

	long getMaxKey() {
		return getKetamaNodes().lastKey();
	}

	MemcachedNode getNodeForKey(long hash) {
		final MemcachedNode rv;
		if(!ketamaNodes.containsKey(hash)) {
			// Java 1.6 adds a ceilingKey method, but I'm still stuck in 1.5
			// in a lot of places, so I'm doing this myself.
			SortedMap tailMap=getKetamaNodes().tailMap(hash);
			if(tailMap.isEmpty()) {
				hash=getKetamaNodes().firstKey();
			} else {
				hash=tailMap.firstKey();
			}
		}
		rv=getKetamaNodes().get(hash);
		return rv;
	}

	public Iterator getSequence(String k) {
		// Seven searches gives us a 1 in 2^7 chance of hitting the
		// same dead node all of the time.
		return new KetamaIterator(k, 7, getKetamaNodes(), hashAlg);
	}

	public NodeLocator getReadonlyCopy() {
		TreeMap smn=new TreeMap(
			getKetamaNodes());
		Collection an=
			new ArrayList(allNodes.size());

		// Rewrite the values a copy of the map.
		for(Map.Entry me : smn.entrySet()) {
			me.setValue(new MemcachedNodeROImpl(me.getValue()));
		}
		// Copy the allNodes collection.
		for(MemcachedNode n : allNodes) {
			an.add(new MemcachedNodeROImpl(n));
		}

		return new KetamaNodeLocator(smn, an, hashAlg, config);
	}

    /**
     * @return the ketamaNodes
     */
    protected TreeMap getKetamaNodes() {
	return ketamaNodes;
    }

    /**
     * Setup the KetamaNodeLocator with the list of nodes it should use.
     *
     * @param nodes a List of MemcachedNodes for this KetamaNodeLocator to use in its continuum
     */
    protected void setKetamaNodes(List nodes) {
	TreeMap newNodeMap = new TreeMap();
	int numReps= config.getNodeRepetitions();
	for(MemcachedNode node : nodes) {
		// Ketama does some special work with md5 where it reuses chunks.
		if(hashAlg == HashAlgorithm.KETAMA_HASH) {
			for(int i=0; i




© 2015 - 2025 Weber Informatics LLC | Privacy Policy