[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