[infinispan-commits] Infinispan SVN: r962 - in trunk/core/src: test/java/org/infinispan/distribution and 1 other directory.

infinispan-commits at lists.jboss.org infinispan-commits at lists.jboss.org
Fri Oct 16 07:26:40 EDT 2009


Author: manik.surtani at jboss.com
Date: 2009-10-16 07:26:40 -0400 (Fri, 16 Oct 2009)
New Revision: 962

Added:
   trunk/core/src/main/java/org/infinispan/distribution/DefaultConsistentHash.java
Removed:
   trunk/core/src/main/java/org/infinispan/distribution/DefaultConsistentHash.java
Modified:
   trunk/core/src/test/java/org/infinispan/distribution/BaseDistFunctionalTest.java
   trunk/core/src/test/java/org/infinispan/distribution/DefaultConsistentHashTest.java
   trunk/core/src/test/java/org/infinispan/distribution/DistSyncFuncTest.java
Log:
Updated the default CH and added more tests

Deleted: trunk/core/src/main/java/org/infinispan/distribution/DefaultConsistentHash.java
===================================================================
--- trunk/core/src/main/java/org/infinispan/distribution/DefaultConsistentHash.java	2009-10-16 11:25:23 UTC (rev 961)
+++ trunk/core/src/main/java/org/infinispan/distribution/DefaultConsistentHash.java	2009-10-16 11:26:40 UTC (rev 962)
@@ -1,144 +0,0 @@
-package org.infinispan.distribution;
-
-import org.infinispan.marshall.Ids;
-import org.infinispan.marshall.Marshallable;
-import org.infinispan.remoting.transport.Address;
-
-import java.io.IOException;
-import java.io.ObjectInput;
-import java.io.ObjectOutput;
-import static java.lang.Math.min;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.SortedMap;
-import java.util.TreeMap;
-
- at Marshallable(externalizer = DefaultConsistentHash.Externalizer.class, id = Ids.DEFAULT_CONSISTENT_HASH)
-public class DefaultConsistentHash extends AbstractConsistentHash {
-
-   // make sure all threads see the current list
-   ArrayList<Address> addresses;
-   SortedMap<Integer, Address> positions;
-
-   final static int HASH_SPACE = 10240; // no more than 10k nodes?
-
-
-   public void setCaches(List<Address> caches) {
-
-      addresses = new ArrayList<Address>(caches);
-
-      // this list won't grow.
-      addresses.trimToSize();
-
-      positions = new TreeMap<Integer, Address>();
-
-      for (Address a : addresses) {
-         int positionIndex = Math.abs(a.hashCode()) % 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);
-      }
-
-      addresses.clear();
-      for (Address a : positions.values()) addresses.add(a);
-   }
-
-   public List<Address> getCaches() {
-      return addresses;
-   }
-
-   public List<Address> locate(Object key, int replCount) {
-      int keyHashCode = key.hashCode();
-      if (keyHashCode == Integer.MIN_VALUE) keyHashCode += 1;
-      int hash = Math.abs(keyHashCode);
-      int clusterSize = addresses.size();
-      int numCopiesToFind = min(replCount, clusterSize);
-
-      List<Address> owners = new ArrayList<Address>(numCopiesToFind);
-
-      SortedMap<Integer, Address> candidates = positions.tailMap(hash % HASH_SPACE);
-
-      for (Address a : candidates.values()) {
-         if (owners.size() < numCopiesToFind)
-            owners.add(a);
-         else
-            break;
-      }
-
-      if (owners.size() < numCopiesToFind) {
-         for (Address a : positions.values()) {
-            if (owners.size() < numCopiesToFind)
-               owners.add(a);
-            else
-               break;
-         }
-      }
-
-      return owners;
-   }
-
-   public int getDistance(Address a1, Address a2) {
-      if (a1 == null || a2 == null) throw new NullPointerException("Cannot deal with nulls as parameters!");
-
-      int p1 = addresses.indexOf(a1);
-      if (p1 < 0)
-         throw new IllegalArgumentException("Address " + a1 + " not in the addresses list of this consistent hash impl!");
-
-      int p2 = addresses.indexOf(a2);
-      if (p2 < 0)
-         throw new IllegalArgumentException("Address " + a2 + " not in the addresses list of this consistent hash impl!");
-
-      if (p1 <= p2)
-         return p2 - p1;
-      else
-         return addresses.size() - (p1 - p2);
-   }
-
-   public boolean isAdjacent(Address a1, Address a2) {
-      int distance = getDistance(a1, a2);
-      return distance == 1 || distance == addresses.size() - 1;
-   }
-
-   @Override
-   public boolean equals(Object o) {
-      if (this == o) return true;
-      if (o == null || getClass() != o.getClass()) return false;
-
-      DefaultConsistentHash that = (DefaultConsistentHash) o;
-
-      if (addresses != null ? !addresses.equals(that.addresses) : that.addresses != null) return false;
-      if (positions != null ? !positions.equals(that.positions) : that.positions != null) return false;
-
-      return true;
-   }
-
-   @Override
-   public int hashCode() {
-      int result = addresses != null ? addresses.hashCode() : 0;
-      result = 31 * result + (positions != null ? positions.hashCode() : 0);
-      return result;
-   }
-
-   public static class Externalizer implements org.infinispan.marshall.Externalizer {
-      public void writeObject(ObjectOutput output, Object subject) throws IOException {
-         DefaultConsistentHash dch = (DefaultConsistentHash) subject;
-         output.writeObject(dch.addresses);
-         output.writeObject(dch.positions);
-      }
-
-      @SuppressWarnings("unchecked")
-      public Object readObject(ObjectInput unmarshaller) throws IOException, ClassNotFoundException {
-         DefaultConsistentHash dch = new DefaultConsistentHash();
-         dch.addresses = (ArrayList<Address>) unmarshaller.readObject();
-         dch.positions = (SortedMap<Integer, Address>) unmarshaller.readObject();
-         return dch;
-      }
-   }
-
-   @Override
-   public String toString() {
-      return "DefaultConsistentHash{" +
-            "addresses (in order of hash space position)=" + positions.values() +
-            '}';
-   }
-}

Added: trunk/core/src/main/java/org/infinispan/distribution/DefaultConsistentHash.java
===================================================================
--- trunk/core/src/main/java/org/infinispan/distribution/DefaultConsistentHash.java	                        (rev 0)
+++ trunk/core/src/main/java/org/infinispan/distribution/DefaultConsistentHash.java	2009-10-16 11:26:40 UTC (rev 962)
@@ -0,0 +1,145 @@
+package org.infinispan.distribution;
+
+import org.infinispan.marshall.Ids;
+import org.infinispan.marshall.Marshallable;
+import org.infinispan.remoting.transport.Address;
+
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import static java.lang.Math.min;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+ at Marshallable(externalizer = DefaultConsistentHash.Externalizer.class, id = Ids.DEFAULT_CONSISTENT_HASH)
+public class DefaultConsistentHash extends AbstractConsistentHash {
+
+   // make sure all threads see the current list
+   ArrayList<Address> addresses;
+   SortedMap<Integer, Address> positions;
+
+   final static int HASH_SPACE = 10240; // no more than 10k nodes?
+
+
+   public void setCaches(List<Address> caches) {
+
+      addresses = new ArrayList<Address>(caches);
+
+      // this list won't grow.
+      addresses.trimToSize();
+
+      positions = new TreeMap<Integer, Address>();
+
+      for (Address a : addresses) {
+         int positionIndex = Math.abs(a.hashCode()) % 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);
+      }
+
+      addresses.clear();
+      // reorder addresses as per the positions.
+      for (Address a : positions.values()) addresses.add(a);
+   }
+
+   public List<Address> getCaches() {
+      return addresses;
+   }
+
+   public List<Address> locate(Object key, int replCount) {
+      int keyHashCode = key.hashCode();
+      if (keyHashCode == Integer.MIN_VALUE) keyHashCode += 1;
+      int hash = Math.abs(keyHashCode);
+      int clusterSize = addresses.size();
+      int numCopiesToFind = min(replCount, clusterSize);
+
+      List<Address> owners = new ArrayList<Address>(numCopiesToFind);
+
+      SortedMap<Integer, Address> candidates = positions.tailMap(hash % HASH_SPACE);
+
+      for (Address a : candidates.values()) {
+         if (owners.size() < numCopiesToFind)
+            owners.add(a);
+         else
+            break;
+      }
+
+      if (owners.size() < numCopiesToFind) {
+         for (Address a : positions.values()) {
+            if (owners.size() < numCopiesToFind)
+               owners.add(a);
+            else
+               break;
+         }
+      }
+
+      return owners;
+   }
+
+   public int getDistance(Address a1, Address a2) {
+      if (a1 == null || a2 == null) throw new NullPointerException("Cannot deal with nulls as parameters!");
+
+      int p1 = addresses.indexOf(a1);
+      if (p1 < 0)
+         throw new IllegalArgumentException("Address " + a1 + " not in the addresses list of this consistent hash impl!");
+
+      int p2 = addresses.indexOf(a2);
+      if (p2 < 0)
+         throw new IllegalArgumentException("Address " + a2 + " not in the addresses list of this consistent hash impl!");
+
+      if (p1 <= p2)
+         return p2 - p1;
+      else
+         return addresses.size() - (p1 - p2);
+   }
+
+   public boolean isAdjacent(Address a1, Address a2) {
+      int distance = getDistance(a1, a2);
+      return distance == 1 || distance == addresses.size() - 1;
+   }
+
+   @Override
+   public boolean equals(Object o) {
+      if (this == o) return true;
+      if (o == null || getClass() != o.getClass()) return false;
+
+      DefaultConsistentHash that = (DefaultConsistentHash) o;
+
+      if (addresses != null ? !addresses.equals(that.addresses) : that.addresses != null) return false;
+      if (positions != null ? !positions.equals(that.positions) : that.positions != null) return false;
+
+      return true;
+   }
+
+   @Override
+   public int hashCode() {
+      int result = addresses != null ? addresses.hashCode() : 0;
+      result = 31 * result + (positions != null ? positions.hashCode() : 0);
+      return result;
+   }
+
+   public static class Externalizer implements org.infinispan.marshall.Externalizer {
+      public void writeObject(ObjectOutput output, Object subject) throws IOException {
+         DefaultConsistentHash dch = (DefaultConsistentHash) subject;
+         output.writeObject(dch.addresses);
+         output.writeObject(dch.positions);
+      }
+
+      @SuppressWarnings("unchecked")
+      public Object readObject(ObjectInput unmarshaller) throws IOException, ClassNotFoundException {
+         DefaultConsistentHash dch = new DefaultConsistentHash();
+         dch.addresses = (ArrayList<Address>) unmarshaller.readObject();
+         dch.positions = (SortedMap<Integer, Address>) unmarshaller.readObject();
+         return dch;
+      }
+   }
+
+   @Override
+   public String toString() {
+      return "DefaultConsistentHash{" +
+            "addresses (in order of hash space position)=" + positions.values() +
+            '}';
+   }
+}
\ No newline at end of file


Property changes on: trunk/core/src/main/java/org/infinispan/distribution/DefaultConsistentHash.java
___________________________________________________________________
Name: svn:keywords
   + Id Revision
Name: svn:eol-style
   + LF

Modified: trunk/core/src/test/java/org/infinispan/distribution/BaseDistFunctionalTest.java
===================================================================
--- trunk/core/src/test/java/org/infinispan/distribution/BaseDistFunctionalTest.java	2009-10-16 11:25:23 UTC (rev 961)
+++ trunk/core/src/test/java/org/infinispan/distribution/BaseDistFunctionalTest.java	2009-10-16 11:26:40 UTC (rev 962)
@@ -97,7 +97,8 @@
       DefaultConsistentHash ch = getDefaultConsistentHash(seed, SECONDS.toMillis(480));
       List<Cache<Object, String>> reordered = new ArrayList<Cache<Object, String>>();
 
-      for (Address a : ch.positions.values()) {
+      
+      for (Address a : ch.getCaches()) {
          for (Cache<Object, String> c : caches) {
             if (a.equals(c.getCacheManager().getAddress())) {
                reordered.add(c);
@@ -322,7 +323,7 @@
          Random r = new Random();
          for (; ;) {
             // create a dummy object with this hashcode
-            final int hc = r.nextInt(DefaultConsistentHash.HASH_SPACE);
+            final int hc = r.nextInt();
             Object dummy = new Object() {
                @Override
                public int hashCode() {

Modified: trunk/core/src/test/java/org/infinispan/distribution/DefaultConsistentHashTest.java
===================================================================
--- trunk/core/src/test/java/org/infinispan/distribution/DefaultConsistentHashTest.java	2009-10-16 11:25:23 UTC (rev 961)
+++ trunk/core/src/test/java/org/infinispan/distribution/DefaultConsistentHashTest.java	2009-10-16 11:26:40 UTC (rev 962)
@@ -11,8 +11,9 @@
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.Random;
 
- at Test(groups = "unit", testName = "distribution.DefaultConsistentHashTest", enabled = false)
+ at Test(groups = "unit", testName = "distribution.DefaultConsistentHashTest", enabled = true)
 public class DefaultConsistentHashTest extends AbstractInfinispanTest {
 
    List<Address> servers;
@@ -77,14 +78,21 @@
    }
 
    public void testDistances() {
-      Address a1 = new TestAddress(1);
-      Address a2 = new TestAddress(2);
-      Address a3 = new TestAddress(3);
-      Address a4 = new TestAddress(4);
+      Address a1 = new TestAddress(1000);
+      Address a2 = new TestAddress(2000);
+      Address a3 = new TestAddress(3000);
+      Address a4 = new TestAddress(4000);
 
       ConsistentHash ch = new DefaultConsistentHash();
       ch.setCaches(Arrays.asList(a1, a2, a3, a4));
 
+      // the CH may reorder the addresses.  Get the new order.
+      List<Address> adds = ch.getCaches();
+      a1 = adds.get(0);
+      a2 = adds.get(1);
+      a3 = adds.get(2);
+      a4 = adds.get(3);
+
       assert ch.getDistance(a1, a1) == 0;
       assert ch.getDistance(a1, a4) == 3;
       assert ch.getDistance(a1, a3) == 2;
@@ -96,6 +104,26 @@
       assert !ch.isAdjacent(a1, a3);
       assert ch.isAdjacent(a1, a4);
    }
+
+   public void testNumHashedNodes() {
+      Address a1 = new TestAddress(1000);
+      Address a2 = new TestAddress(2000);
+      Address a3 = new TestAddress(3000);
+      Address a4 = new TestAddress(4000);
+
+      ConsistentHash ch = new DefaultConsistentHash();
+      ch.setCaches(Arrays.asList(a1, a2, a3, a4));
+
+      String[] keys = new String[10000];
+      Random r = new Random();
+      for (int i=0; i<10000; i++) keys[i] = Integer.toHexString(r.nextInt());
+
+      for (String key: keys) {
+         List<Address> l = ch.locate(key, 2);
+         assert l.size() == 2: "Did NOT find 2 owners for key ["+key+"] as expected!  Found " + l;
+         assert ch.isAdjacent(l.get(0), l.get(1)) : "Nodes " + l + " should be adjacent!";
+      }
+   }
 }
 
 class TestAddress implements Address {
@@ -130,6 +158,11 @@
       return addressNum;
    }
 
+   @Override
+   public String toString() {
+      return "TestAddress#"+addressNum;
+   }
+
    public int compareTo(Object o) {
       return this.addressNum - ((TestAddress) o).addressNum;
    }

Modified: trunk/core/src/test/java/org/infinispan/distribution/DistSyncFuncTest.java
===================================================================
--- trunk/core/src/test/java/org/infinispan/distribution/DistSyncFuncTest.java	2009-10-16 11:25:23 UTC (rev 961)
+++ trunk/core/src/test/java/org/infinispan/distribution/DistSyncFuncTest.java	2009-10-16 11:26:40 UTC (rev 962)
@@ -5,12 +5,16 @@
 import org.infinispan.commands.write.PutKeyValueCommand;
 import org.infinispan.commands.write.RemoveCommand;
 import org.infinispan.commands.write.ReplaceCommand;
+import org.infinispan.remoting.transport.Address;
 import org.infinispan.test.TestingUtil;
 import org.infinispan.util.ObjectDuplicator;
 import org.testng.annotations.Test;
 
+import java.util.ArrayList;
 import java.util.Collection;
+import java.util.List;
 import java.util.Map;
+import java.util.Random;
 import java.util.Set;
 
 @Test(groups = "functional", testName = "distribution.DistSyncFuncTest")
@@ -22,6 +26,39 @@
       testRetVals = true;
    }
 
+   public void testLocationConsensus() {
+      String[] keys = new String[100];
+      Random r = new Random();
+      for (int i = 0; i < 100; i++) keys[i] = Integer.toHexString(r.nextInt());
+
+      // always expect key to be mapped to adjacent nodes!
+      for (String key : keys) {
+
+         List<Address> owners = new ArrayList<Address>();
+         for (Cache<Object, String> c : caches) {
+            boolean isOwner = isOwner(c, key);
+            if (isOwner) owners.add(addressOf(c));
+            boolean secondCheck = getDefaultConsistentHash(c).locate(key, 2).contains(addressOf(c));
+            assert isOwner == secondCheck : "Second check failed for key " + key + " on cache " + addressOf(c) + " isO = " + isOwner + " sC = " + secondCheck;
+         }
+         // check consensus
+         assertOwnershipConsensus(key);
+         assert owners.size() == 2 : "Expected 2 owners for key " + key + " but was " + owners;
+      }
+   }
+
+   private void assertOwnershipConsensus(String key) {
+      List l1 = getDefaultConsistentHash(c1).locate(key, 2);
+      List l2 = getDefaultConsistentHash(c2).locate(key, 2);
+      List l3 = getDefaultConsistentHash(c3).locate(key, 2);
+      List l4 = getDefaultConsistentHash(c4).locate(key, 2);
+
+      assert l1.equals(l2) : "L1 "+l1+" and L2 "+l2+" don't agree.";
+      assert l2.equals(l3): "L2 "+l2+" and L3 "+l3+" don't agree.";
+      assert l3.equals(l4): "L3 "+l3+" and L4 "+l4+" don't agree.";
+
+   }
+
    public void testBasicDistribution() {
       for (Cache<Object, String> c : caches) assert c.isEmpty();
 



More information about the infinispan-commits mailing list