[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