[infinispan-commits] Infinispan SVN: r1754 - in trunk/core/src: main/java/org/infinispan/util/hash and 2 other directories.
infinispan-commits at lists.jboss.org
infinispan-commits at lists.jboss.org
Fri May 7 05:54:03 EDT 2010
Author: manik.surtani at jboss.com
Date: 2010-05-07 05:54:03 -0400 (Fri, 07 May 2010)
New Revision: 1754
Added:
trunk/core/src/test/java/org/infinispan/util/MurmurHash2Test.java
Modified:
trunk/core/src/main/java/org/infinispan/distribution/DefaultConsistentHash.java
trunk/core/src/main/java/org/infinispan/util/hash/MurmurHash2.java
trunk/core/src/test/java/org/infinispan/distribution/HashFunctionComparisonTest.java
Log:
[ISPN-423] ( Implement MurmurHash2 for hashing addresses and keys in the DefaultConsistentHash impl)
Modified: trunk/core/src/main/java/org/infinispan/distribution/DefaultConsistentHash.java
===================================================================
--- trunk/core/src/main/java/org/infinispan/distribution/DefaultConsistentHash.java 2010-05-07 09:24:19 UTC (rev 1753)
+++ trunk/core/src/main/java/org/infinispan/distribution/DefaultConsistentHash.java 2010-05-07 09:54:03 UTC (rev 1754)
@@ -3,6 +3,7 @@
import org.infinispan.marshall.Ids;
import org.infinispan.marshall.Marshallable;
import org.infinispan.remoting.transport.Address;
+import org.infinispan.util.hash.MurmurHash2;
import org.infinispan.util.logging.Log;
import org.infinispan.util.logging.LogFactory;
@@ -13,10 +14,12 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Random;
import java.util.SortedMap;
import java.util.TreeMap;
import static java.lang.Math.min;
+import static org.infinispan.util.hash.MurmurHash2.hash;
@Marshallable(externalizer = DefaultConsistentHash.Externalizer.class, id = Ids.DEFAULT_CONSISTENT_HASH)
public class DefaultConsistentHash extends AbstractConsistentHash {
@@ -29,18 +32,6 @@
final static int HASH_SPACE = 10240; // no more than 10k nodes?
- private int hash(Object o) {
- // Borrowed from Sun's JDK, a bit spreader to help normalize distribution.
- // Uses a variant of single-word Wang/Jenkins hash.
- int h = o.hashCode();
- h += (h << 15) ^ 0xffffcd7d;
- h ^= (h >>> 10);
- h += (h << 3);
- h ^= (h >>> 6);
- h += (h << 2) + (h << 14);
- return h ^ (h >>> 16);
- }
-
public void setCaches(List<Address> caches) {
addresses = new ArrayList<Address>(caches);
@@ -52,7 +43,7 @@
addressToHashIds = new HashMap<Address, Integer>();
for (Address a : addresses) {
- int positionIndex = Math.abs(hash(a.hashCode())) % HASH_SPACE;
+ int positionIndex = Math.abs(hash(a)) % HASH_SPACE;
// this is deterministic since the address list is ordered and the order is consistent across the grid
while (positions.containsKey(positionIndex)) positionIndex = positionIndex + 1 % HASH_SPACE;
positions.put(positionIndex, a);
@@ -72,7 +63,7 @@
}
public List<Address> locate(Object key, int replCount) {
- int keyHashCode = hash(key.hashCode());
+ int keyHashCode = hash(key);
if (keyHashCode == Integer.MIN_VALUE) keyHashCode += 1;
int hash = Math.abs(keyHashCode);
int numCopiesToFind = min(replCount, addresses.size());
@@ -109,7 +100,7 @@
@Override
public boolean isKeyLocalToAddress(Address target, Object key, int replCount) {
// more efficient impl
- int keyHashCode = hash(key.hashCode());
+ int keyHashCode = hash(key);
if (keyHashCode == Integer.MIN_VALUE) keyHashCode += 1;
int hash = Math.abs(keyHashCode);
int numCopiesToFind = min(replCount, addresses.size());
@@ -216,8 +207,8 @@
@Override
public String toString() {
return "DefaultConsistentHash{" +
- "addresses =" + positions +
- ", hash space =" + HASH_SPACE +
- '}';
+ "addresses =" + positions +
+ ", hash space =" + HASH_SPACE +
+ '}';
}
}
\ No newline at end of file
Modified: trunk/core/src/main/java/org/infinispan/util/hash/MurmurHash2.java
===================================================================
--- trunk/core/src/main/java/org/infinispan/util/hash/MurmurHash2.java 2010-05-07 09:24:19 UTC (rev 1753)
+++ trunk/core/src/main/java/org/infinispan/util/hash/MurmurHash2.java 2010-05-07 09:54:03 UTC (rev 1754)
@@ -3,18 +3,30 @@
import java.util.Random;
/**
- * TODO: Document this
- *
+ * An implementation of Austin Appleby's MurmurHash2.0 algorithm, as documented on <a href="http://sites.google.com/site/murmurhash/">his website</a>.
+ * <p />
+ * This implementation is based on the slower, endian-neutral version of the algorithm as documented on the site,
+ * ported from Austin Appleby's original C++ version <a href="http://sites.google.com/site/murmurhash/MurmurHashNeutral2.cpp">MurmurHashNeutral2.cpp</a>.
+ * <p />
+ * Other implementations are documented on Wikipedia's <a href="http://en.wikipedia.org/wiki/MurmurHash">MurmurHash</a> page.
+ * <p />
+ * @see {@link http://en.wikipedia.org/wiki/MurmurHash}
+ * @see {@link http://sites.google.com/site/murmurhash/}
* @author Manik Surtani
* @version 4.1
*/
public class MurmurHash2 {
-
+ private static final int M = 0x5bd1e995;
+ private static final int R = 24;
+ private static final int H = -1;
+
+ /**
+ * Hashes a byte array efficiently.
+ * @param payload a byte array to hash
+ * @return a hash code for the byte array
+ */
public static final int hash(byte[] payload) {
- int m = 0x5bd1e995;
- int r = 24;
- int h = new Random().nextInt() ^ 1024;
-
+ int h = H;
int len = payload.length;
int offset = 0;
while (len >= 4) {
@@ -23,10 +35,10 @@
k |= payload[offset + 2] << 16;
k |= payload[offset + 3] << 24;
- k *= m;
- k ^= k >> r;
- k *= m;
- h *= m;
+ k *= M;
+ k ^= k >> R;
+ k *= M;
+ h *= M;
h ^= k;
len -= 4;
@@ -40,16 +52,22 @@
h ^= payload[offset + 1] << 8;
case 1:
h ^= payload[offset];
- h *= m;
+ h *= M;
}
h ^= h >> 13;
- h *= m;
+ h *= M;
h ^= h >> 15;
return h;
}
+ /**
+ * An incremental version of the hash function, that spreads a pre-calculated hash code, such as one derived from
+ * {@link Object#hashCode()}.
+ * @param hashcode an object's hashcode
+ * @return a spread and hashed version of the hashcode
+ */
public static final int hash(int hashcode) {
byte[] b = new byte[4];
b[0] = (byte) hashcode;
@@ -59,6 +77,12 @@
return hash(b);
}
+ /**
+ * A helper that calculates the hashcode of an object, choosing the optimal mechanism of hash calculation after
+ * considering the type of the object (byte array, String or Object).
+ * @param o object to hash
+ * @return a hashcode
+ */
public static final int hash(Object o) {
if (o instanceof byte[])
return hash((byte[]) o);
@@ -67,6 +91,4 @@
else
return hash(o.hashCode());
}
-
-
}
Modified: trunk/core/src/test/java/org/infinispan/distribution/HashFunctionComparisonTest.java
===================================================================
--- trunk/core/src/test/java/org/infinispan/distribution/HashFunctionComparisonTest.java 2010-05-07 09:24:19 UTC (rev 1753)
+++ trunk/core/src/test/java/org/infinispan/distribution/HashFunctionComparisonTest.java 2010-05-07 09:54:03 UTC (rev 1754)
@@ -4,6 +4,7 @@
import org.infinispan.profiling.testinternals.Generator;
import org.infinispan.remoting.transport.Address;
import org.infinispan.util.Util;
+import org.infinispan.util.hash.MurmurHash2;
import org.testng.annotations.Test;
import java.text.NumberFormat;
@@ -281,49 +282,12 @@
class MurmurHash extends HashFunction {
- int m = 0x5bd1e995;
- int r = 24;
- int h = new Random().nextInt() ^ 1024;
-
-
public String functionName() {
return "MurmurHash2 (neutral)";
}
@Override
public int hash(byte[] payload) {
- int len = payload.length;
- int offset = 0;
- while (len >= 4) {
- int k = payload[offset];
- k |= payload[offset + 1] << 8;
- k |= payload[offset + 2] << 16;
- k |= payload[offset + 3] << 24;
-
- k *= m;
- k ^= k >> r;
- k *= m;
- h *= m;
- h ^= k;
-
- len -= 4;
- offset += 4;
- }
-
- switch (len) {
- case 3:
- h ^= payload[offset + 2] << 16;
- case 2:
- h ^= payload[offset + 1] << 8;
- case 1:
- h ^= payload[offset];
- h *= m;
- }
-
- h ^= h >> 13;
- h *= m;
- h ^= h >> 15;
-
- return h;
+ return MurmurHash2.hash(payload);
}
}
Added: trunk/core/src/test/java/org/infinispan/util/MurmurHash2Test.java
===================================================================
--- trunk/core/src/test/java/org/infinispan/util/MurmurHash2Test.java (rev 0)
+++ trunk/core/src/test/java/org/infinispan/util/MurmurHash2Test.java 2010-05-07 09:54:03 UTC (rev 1754)
@@ -0,0 +1,27 @@
+package org.infinispan.util;
+
+import org.infinispan.test.AbstractInfinispanTest;
+import org.infinispan.util.hash.MurmurHash2;
+import org.testng.annotations.Test;
+
+/**
+ * TODO: Document this
+ *
+ * @author Manik Surtani
+ * @version 4.1
+ */
+ at Test(testName = "util.MurmurHash2Test", groups = "unit")
+public class MurmurHash2Test extends AbstractInfinispanTest {
+
+ public void testHashConsistency() {
+ Object o = new Object();
+ int i1 = MurmurHash2.hash(o);
+ int i2 = MurmurHash2.hash(o);
+ int i3 = MurmurHash2.hash(o);
+
+ assert i1 == i2: "i1 and i2 are not the same: " + i1 + ", " + i2;
+ assert i3 == i2: "i3 and i2 are not the same: " + i2 + ", " + i3;
+ assert i1 == i3: "i1 and i3 are not the same: " + i1 + ", " + i3;
+ }
+
+}
Property changes on: trunk/core/src/test/java/org/infinispan/util/MurmurHash2Test.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
More information about the infinispan-commits
mailing list