ketama - a consistent hashing algo for memcache clients
Dustin Sallings
dustin at spy.net
Wed Apr 11 00:52:44 UTC 2007
Do you have a license for this? Seems like something I could use as
a decent hash provider.
On Apr 10, 2007, at 16:20 , Pierre Demartines wrote:
> FYI, we found the Fowler-Noll-Vo hashes to be very quick to
> compute, and
> yet having beautiful properties in terms of dispersion.
>
> FWIW, here is a simple Java implementation that computes a 64-bit
> hashcode for a class that extends CharSequence:
>
> package com.yourco.util;
>
> /**
> * Enables a CharSequence with the capability to produce a
> Fowler-Noll-Vo (FNV) 64-bit hashcode.<p>
> *
> * FNV hashes are designed to be fast while maintaining a low
> collision
> rate.
> * The FNV speed allows one to quickly hash lots of data while
> maintaining a
> * reasonable collision rate. The high dispersion of the FNV hashes
> makes them
> * well suited for hashing nearly identical strings such as URLs,
> hostnames,
> * filenames, text, IP addresses, etc.
> *
> * Usage: add "extends CharSequenceHash64" to a class that implements
> CharSequence,
> * and that class will have hashCode64().<p>
> *
> * You can daisy-chain several hashCode calculations like this:<p>
> * <pre>long hashOfSeveral =
> a.hashCode64(b.hashCode64(c.hashCode64()));</pre><p>
> * or, alternatively, like that:
> * <pre>
> * long hashOfSeveral = CharSequenceHash64.FNV1_64_INIT;
> * for (MyCharSequence x : collectionOfMyCharSequences) {
> * hashOfSeveral = x.hashCode64(hashOfSeveral);
> * }</pre><p>
>
> * @see http://www.isthe.com/chongo/tech/comp/fnv/ and
> * @see http://en.wikipedia.org/wiki/Fowler_Noll_Vo_hash<p>
> *
> * @author pdemartines at quantcast.com
> */
> public abstract class CharSequenceHash64 implements CharSequence {
> public static final long FNV1_64_INIT = 0xcbf29ce484222325L;
> private static final long FNV_64_PRIME = 0x100000001b3L;
> /**
> * @param initialValue -- optional: initial value
> * @return a 64-bit FNV hash called fnv164
> */
> public long hashCode64(long initialValue) {
> long hval = initialValue;
> int len = length();
> for (int i=0; i<len; i++) {
> hval *= FNV_64_PRIME;
> hval ^= (long)charAt(i);
> }
>
> return hval;
> }
>
> public long hashCode64() {
> return hashCode64(FNV1_64_INIT);
> }
> }
>
>
> Here is a junit test for it, that shows how it can be used:
>
> package com.yourco.util;
>
> import java.util.HashMap;
>
> import junit.framework.TestCase;
>
> public class CharSequenceHash64_T extends TestCase {
>
> public class MyCharSeq extends CharSequenceHash64 implements
> CharSequence {
> private char[] buffer = null;
> private MyCharSeq() {}
> private MyCharSeq(int length) {
> buffer = new char[length];
> }
> public MyCharSeq(String s) {
> buffer = s.toCharArray();
> }
> public int length() {
> return (buffer == null ? 0 : buffer.length);
> }
> public char charAt(int index) {
> if (index < length()) {
> return buffer[index];
> } else {
> throw new IndexOutOfBoundsException();
> }
> }
> public String toString() {
> if (buffer == null) return "";
> return new String(buffer);
> }
> public CharSequence subSequence(int start, int end) {
> if (buffer == null) throw new IndexOutOfBoundsException();
> int length = end-start;
> MyCharSeq sub = new MyCharSeq(length);
> System.arraycopy(buffer, start, sub.buffer, 0, end-start);
> return sub;
> }
> }
>
> // FNV's hashCode64
> // Compare this function's value against known values (calculated
> using bona-fide implementations of FNV164)
> public void testHashCode64() {
> HashMap<String,Long> value = new HashMap<String,Long>();
> value.put("", new Long(0xcbf29ce484222325L));
> value.put(" ", new Long(0xaf63bd4c8601b7ffL));
> value.put("hello world!", new Long(0x58735284b97b86bcL));
> value.put("Lorem ipsum dolor sit amet, consectetuer adipiscing
> elit.", new Long(0x536c9cdee87c054aL));
> value.put("wd:com.google", new Long(0xcf4e7986071b08f8L));
> value.put("wd:com.google ", new Long(0x5d6176be12f03d48L));
> for (String s:value.keySet()) {
> long h64 = value.get(s);
> assertEquals("\""+s+"\".hashCode64()", h64, new
> MyCharSeq(s).hashCode64());
> }
> }
> }
>
>
> Enjoy,
>
> ~Pierre
>
>
> On Tue, 2007-04-10 at 23:01 +0100, Richard Jones wrote:
>>> This is a very interesting idea, and I'd like to add a consistent
>>> hash driver to my java interface, but there's a bit of gap between
>>> your writeup and what the implementation.
>>
>> Check the init() method - that builds up the appropriate data
>> structure (a
>> TreeMap called buckets iirc). You can use any hashing mechanism
>> you want
>> instead of the md5 thing, that just seemed a convenient way to
>> generate a
>> bunch of hashes. If you change it you won't be compatible with other
>> implementations - not a problem if you are exclusively using java
>> tho.
>>
>> Once you've build the data structure using the servers list, that
>> is pretty
>> much it in java, just check how keys are mapped to servers in
>> findPointFor().
>>
>> RJ
>>
>>
>>>
>>> In the java interface, all I see is that you've added a new hash
>>> type that's based off an MD5. Is that actually an important detail?
>>> It seems like you should be able to use any hash that produces an
>>> even 32-bits.
>>>
>>> Is it OK if I use your C implementation as a specification?
>>
>
--
Dustin Sallings
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.danga.com/pipermail/memcached/attachments/20070410/93cf08f6/attachment.html
More information about the memcached
mailing list