Skip to content

Commit

Permalink
Support more than one hashing algorithm.
Browse files Browse the repository at this point in the history
	Tested the crc32 hash algorithm against values returned from the perl
client's implementation.
  • Loading branch information
dustin committed Mar 31, 2007
1 parent 9731db1 commit e906d23
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 1 deletion.
40 changes: 40 additions & 0 deletions src/java/net/spy/memcached/HashAlgorithm.java
@@ -0,0 +1,40 @@
package net.spy.memcached;

import java.util.zip.CRC32;

/**
* Known hashing algorithms for locating a server for a key.
*/
public enum HashAlgorithm {
/**
* Native hash (String.hashCode()).
*/
NATIVE_HASH,
/**
* CRC32_HASH as used by the perl API. This will be more consistent
* both across multiple API users as well as java versions.
*/
CRC32_HASH;

/**
* Compute the hash for the given key.
* @return a positive integer hash
*/
public int hash(String k) {
int rv=0;
switch(this) {
case NATIVE_HASH:
rv=k.hashCode();
break;
case CRC32_HASH:
// return (crc32(shift) >> 16) & 0x7fff;
CRC32 crc32=new CRC32();
crc32.update(k.getBytes());
rv=(int)(crc32.getValue() & 0xffffffff);
rv=(rv >> 16) & 0x7fff;
break;
default: assert false;
}
return Math.abs(rv);
}
}
17 changes: 16 additions & 1 deletion src/java/net/spy/memcached/MemcachedClient.java
Expand Up @@ -75,6 +75,7 @@ public class MemcachedClient extends SpyThread {

private volatile boolean running=true;
private MemcachedConnection conn=null;
private HashAlgorithm hashAlg=HashAlgorithm.NATIVE_HASH;
Transcoder transcoder=null;

/**
Expand All @@ -98,6 +99,20 @@ public MemcachedClient(InetSocketAddress... ia) throws IOException {
start();
}

/**
* Set the hash algorithm.
*/
public HashAlgorithm getHashAlgorithm() {
return hashAlg;
}

public void setHashAlgorithm(HashAlgorithm to) {
if(to == null) {
throw new NullPointerException("Null hash algorithm not allowed");
}
hashAlg=to;
}

/**
* Set the transcoder for managing the cache representations of objects
* going in and out of the cache.
Expand Down Expand Up @@ -509,7 +524,7 @@ private int getServerForKey(String key) {
throw new IllegalArgumentException(
"Key contains invalid characters: " + key);
}
int rv=Math.abs(key.hashCode()) % conn.getNumConnections();
int rv=hashAlg.hash(key) % conn.getNumConnections();
assert rv >= 0 : "Returned negative key for key " + key;
assert rv < conn.getNumConnections()
: "Invalid server number " + rv + " for key " + key;
Expand Down
41 changes: 41 additions & 0 deletions src/test/net/spy/memcached/HashAlgorithmTest.java
@@ -0,0 +1,41 @@
package net.spy.memcached;

import java.util.HashMap;
import java.util.Map;

import junit.framework.TestCase;

/**
* Test the hash algorithms.
*/
public class HashAlgorithmTest extends TestCase {

private void assertHash(HashAlgorithm ha, String key, int exp) {
assertTrue(exp >= 0);
assertEquals("Invalid " + ha + " for key " + key, exp, ha.hash(key));
// System.out.println(ha + "(" + key + ") = " + exp);
}

// I don't hardcode any values here because they're subject to change
private void assertNativeHash(String key) {
assertHash(HashAlgorithm.NATIVE_HASH, key, Math.abs(key.hashCode()));
}

public void testNativeHash() {
for(String k : new String[]{"Test1", "Test2", "Test3", "Test4"}) {
assertNativeHash(k);
}
}

public void testCrc32Hash() {
Map<String, Integer> exp=new HashMap<String, Integer>();
exp.put("Test1", 19315);
exp.put("Test2", 21114);
exp.put("Test3", 9597);
exp.put("Test4", 15129);

for(Map.Entry<String, Integer> me : exp.entrySet()) {
assertHash(HashAlgorithm.CRC32_HASH, me.getKey(), me.getValue());
}
}
}

0 comments on commit e906d23

Please sign in to comment.