diff --git a/CHANGES.txt b/CHANGES.txt index 38d4e38ebb..c41839e3b3 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -30,6 +30,8 @@ provide latency information to dynamic snitch (CASSANDRA-1873) * enable keepalive on intra-cluster sockets (CASSANDRA-1766) * count timeouts towards dynamicsnitch latencies (CASSANDRA-1905) + * change RandomPartitioner min token to -1 to avoid collision w/ + tokens on actual nodes (CASSANDRA-1901) * examine the right nibble when validating TimeUUID (CASSANDRA-1910) diff --git a/src/java/org/apache/cassandra/dht/RandomPartitioner.java b/src/java/org/apache/cassandra/dht/RandomPartitioner.java index b8d6691c07..73129e92d0 100644 --- a/src/java/org/apache/cassandra/dht/RandomPartitioner.java +++ b/src/java/org/apache/cassandra/dht/RandomPartitioner.java @@ -35,9 +35,8 @@ import org.apache.cassandra.utils.Pair; */ public class RandomPartitioner implements IPartitioner { - public static final BigInteger TWO = new BigInteger("2"); - - public static final BigIntegerToken MINIMUM = new BigIntegerToken("0"); + public static final BigInteger ZERO = new BigInteger("0"); + public static final BigIntegerToken MINIMUM = new BigIntegerToken("-1"); private static final String DELIMITER = ":"; @@ -62,7 +61,10 @@ public class RandomPartitioner implements IPartitioner public BigIntegerToken midpoint(BigIntegerToken ltoken, BigIntegerToken rtoken) { - Pair midpair = FBUtilities.midpoint(ltoken.token, rtoken.token, 127); + // the symbolic MINIMUM token should act as ZERO: the empty bit array + BigInteger left = ltoken.equals(MINIMUM) ? ZERO : ltoken.token; + BigInteger right = rtoken.equals(MINIMUM) ? ZERO : rtoken.token; + Pair midpair = FBUtilities.midpoint(left, right, 127); // discard the remainder return new BigIntegerToken(midpair.left); } diff --git a/test/unit/org/apache/cassandra/utils/MerkleTreeTest.java b/test/unit/org/apache/cassandra/utils/MerkleTreeTest.java index 6f32fe0b66..7f9f7e6a2d 100644 --- a/test/unit/org/apache/cassandra/utils/MerkleTreeTest.java +++ b/test/unit/org/apache/cassandra/utils/MerkleTreeTest.java @@ -70,11 +70,13 @@ public class MerkleTreeTest /** * The value returned by this method is affected by TOKEN_SCALE: setting TOKEN_SCALE - * to 8 means that passing 0 through 8 for this method will return values mapped - * between 0 and Token.MAX_VALUE. + * to 8 means that passing -1 through 8 for this method will return values mapped + * between -1 and Token.MAX_VALUE. */ public static BigIntegerToken tok(int i) { + if (i == -1) + return new BigIntegerToken(new BigInteger("-1")); BigInteger md5_max = new BigInteger("2").pow(127); BigInteger bint = md5_max.divide(TOKEN_SCALE).multiply(new BigInteger(""+i)); return new BigIntegerToken(bint); @@ -90,9 +92,9 @@ public class MerkleTreeTest mt.split(tok(7)); assertEquals(4, mt.size()); - assertEquals(new Range(tok(7), tok(0)), mt.get(tok(0))); - assertEquals(new Range(tok(0), tok(4)), mt.get(tok(3))); - assertEquals(new Range(tok(0), tok(4)), mt.get(tok(4))); + assertEquals(new Range(tok(7), tok(-1)), mt.get(tok(-1))); + assertEquals(new Range(tok(-1), tok(4)), mt.get(tok(3))); + assertEquals(new Range(tok(-1), tok(4)), mt.get(tok(4))); assertEquals(new Range(tok(4), tok(6)), mt.get(tok(6))); assertEquals(new Range(tok(6), tok(7)), mt.get(tok(7))); @@ -100,7 +102,7 @@ public class MerkleTreeTest assertEquals((byte)1, mt.get(tok(4)).depth); assertEquals((byte)2, mt.get(tok(6)).depth); assertEquals((byte)3, mt.get(tok(7)).depth); - assertEquals((byte)3, mt.get(tok(0)).depth); + assertEquals((byte)3, mt.get(tok(-1)).depth); try { @@ -125,8 +127,8 @@ public class MerkleTreeTest // should fail to split below hashdepth assertFalse(mt.split(tok(1))); assertEquals(3, mt.size()); - assertEquals(new Range(tok(4), tok(0)), mt.get(tok(0))); - assertEquals(new Range(tok(0), tok(2)), mt.get(tok(2))); + assertEquals(new Range(tok(4), tok(-1)), mt.get(tok(-1))); + assertEquals(new Range(tok(-1), tok(2)), mt.get(tok(2))); assertEquals(new Range(tok(2), tok(4)), mt.get(tok(4))); } @@ -141,8 +143,8 @@ public class MerkleTreeTest // should fail to split above maxsize assertFalse(mt.split(tok(2))); assertEquals(2, mt.size()); - assertEquals(new Range(tok(4), tok(0)), mt.get(tok(0))); - assertEquals(new Range(tok(0), tok(4)), mt.get(tok(4))); + assertEquals(new Range(tok(4), tok(-1)), mt.get(tok(-1))); + assertEquals(new Range(tok(-1), tok(4)), mt.get(tok(4))); } @Test @@ -161,46 +163,46 @@ public class MerkleTreeTest mt.compact(tok(1)); mt.compact(tok(5)); assertEquals(6, mt.size()); - assertEquals(new Range(tok(0), tok(2)), mt.get(tok(2))); + assertEquals(new Range(tok(-1), tok(2)), mt.get(tok(2))); assertEquals(new Range(tok(2), tok(3)), mt.get(tok(3))); assertEquals(new Range(tok(3), tok(4)), mt.get(tok(4))); assertEquals(new Range(tok(4), tok(6)), mt.get(tok(5))); assertEquals(new Range(tok(6), tok(7)), mt.get(tok(7))); - assertEquals(new Range(tok(7), tok(0)), mt.get(tok(0))); + assertEquals(new Range(tok(7), tok(-1)), mt.get(tok(-1))); // compacted ranges should be at depth 2, and the rest at 3 for (int i : new int[]{2,6}){ assertEquals((byte)2, mt.get(tok(i)).depth); } - for (int i : new int[]{3,4,7,0}){ assertEquals((byte)3, mt.get(tok(i)).depth); } + for (int i : new int[]{3,4,7,-1}){ assertEquals((byte)3, mt.get(tok(i)).depth); } // compact (two,four] and then (six,zero] mt.compact(tok(3)); mt.compact(tok(7)); assertEquals(4, mt.size()); - assertEquals(new Range(tok(0), tok(2)), mt.get(tok(2))); + assertEquals(new Range(tok(-1), tok(2)), mt.get(tok(2))); assertEquals(new Range(tok(2), tok(4)), mt.get(tok(4))); assertEquals(new Range(tok(4), tok(6)), mt.get(tok(5))); - assertEquals(new Range(tok(6), tok(0)), mt.get(tok(0))); - for (int i : new int[]{2,4,5,0}){ assertEquals((byte)2, mt.get(tok(i)).depth); } + assertEquals(new Range(tok(6), tok(-1)), mt.get(tok(-1))); + for (int i : new int[]{2,4,5,-1}){ assertEquals((byte)2, mt.get(tok(i)).depth); } // compact (zero,four] mt.compact(tok(2)); assertEquals(3, mt.size()); - assertEquals(new Range(tok(0), tok(4)), mt.get(tok(2))); + assertEquals(new Range(tok(-1), tok(4)), mt.get(tok(2))); assertEquals(new Range(tok(4), tok(6)), mt.get(tok(6))); - assertEquals(new Range(tok(6), tok(0)), mt.get(tok(0))); + assertEquals(new Range(tok(6), tok(-1)), mt.get(tok(-1))); // compact (four, zero] mt.compact(tok(6)); assertEquals(2, mt.size()); - assertEquals(new Range(tok(0), tok(4)), mt.get(tok(2))); - assertEquals(new Range(tok(4), tok(0)), mt.get(tok(6))); + assertEquals(new Range(tok(-1), tok(4)), mt.get(tok(2))); + assertEquals(new Range(tok(4), tok(-1)), mt.get(tok(6))); assertEquals((byte)1, mt.get(tok(2)).depth); assertEquals((byte)1, mt.get(tok(6)).depth); // compact (zero, zero] (the root) mt.compact(tok(4)); assertEquals(1, mt.size()); - assertEquals(new Range(tok(0), tok(0)), mt.get(tok(0))); - assertEquals((byte)0, mt.get(tok(0)).depth); + assertEquals(new Range(tok(-1), tok(-1)), mt.get(tok(-1))); + assertEquals((byte)0, mt.get(tok(-1)).depth); } @Test @@ -214,11 +216,11 @@ public class MerkleTreeTest // validate both ranges mt.get(tok(4)).hash(val); - mt.get(tok(0)).hash(val); + mt.get(tok(-1)).hash(val); // compact (zero, eight] mt.compact(tok(4)); - assertHashEquals(valXval, mt.get(tok(0)).hash()); + assertHashEquals(valXval, mt.get(tok(-1)).hash()); } @Test @@ -227,8 +229,8 @@ public class MerkleTreeTest Iterator ranges; // (zero, zero] - ranges = mt.invalids(new Range(tok(0), tok(0))); - assertEquals(new Range(tok(0), tok(0)), ranges.next()); + ranges = mt.invalids(new Range(tok(-1), tok(-1))); + assertEquals(new Range(tok(-1), tok(-1)), ranges.next()); assertFalse(ranges.hasNext()); // all invalid @@ -237,33 +239,33 @@ public class MerkleTreeTest mt.split(tok(6)); mt.split(tok(3)); mt.split(tok(5)); - ranges = mt.invalids(new Range(tok(0), tok(0))); - assertEquals(new Range(tok(0), tok(2)), ranges.next()); + ranges = mt.invalids(new Range(tok(-1), tok(-1))); + assertEquals(new Range(tok(-1), tok(2)), ranges.next()); assertEquals(new Range(tok(2), tok(3)), ranges.next()); assertEquals(new Range(tok(3), tok(4)), ranges.next()); assertEquals(new Range(tok(4), tok(5)), ranges.next()); assertEquals(new Range(tok(5), tok(6)), ranges.next()); - assertEquals(new Range(tok(6), tok(0)), ranges.next()); + assertEquals(new Range(tok(6), tok(-1)), ranges.next()); assertFalse(ranges.hasNext()); // some invalid mt.get(tok(2)).hash("non-null!".getBytes()); mt.get(tok(4)).hash("non-null!".getBytes()); mt.get(tok(5)).hash("non-null!".getBytes()); - mt.get(tok(0)).hash("non-null!".getBytes()); - ranges = mt.invalids(new Range(tok(0), tok(0))); + mt.get(tok(-1)).hash("non-null!".getBytes()); + ranges = mt.invalids(new Range(tok(-1), tok(-1))); assertEquals(new Range(tok(2), tok(3)), ranges.next()); assertEquals(new Range(tok(5), tok(6)), ranges.next()); assertFalse(ranges.hasNext()); // some invalid in left subrange - ranges = mt.invalids(new Range(tok(0), tok(6))); + ranges = mt.invalids(new Range(tok(-1), tok(6))); assertEquals(new Range(tok(2), tok(3)), ranges.next()); assertEquals(new Range(tok(5), tok(6)), ranges.next()); assertFalse(ranges.hasNext()); // some invalid in right subrange - ranges = mt.invalids(new Range(tok(2), tok(0))); + ranges = mt.invalids(new Range(tok(2), tok(-1))); assertEquals(new Range(tok(2), tok(3)), ranges.next()); assertEquals(new Range(tok(5), tok(6)), ranges.next()); assertFalse(ranges.hasNext()); @@ -273,13 +275,13 @@ public class MerkleTreeTest public void testHashFull() { byte[] val = DUMMY; - Range range = new Range(tok(0), tok(0)); + Range range = new Range(tok(-1), tok(-1)); // (zero, zero] assertNull(mt.hash(range)); // validate the range - mt.get(tok(0)).hash(val); + mt.get(tok(-1)).hash(val); assertHashEquals(val, mt.hash(range)); } @@ -290,9 +292,9 @@ public class MerkleTreeTest byte[] val = DUMMY; byte[] leftval = hashed(val, 1, 1); byte[] partialval = hashed(val, 1); - Range left = new Range(tok(0), tok(4)); + Range left = new Range(tok(-1), tok(4)); Range partial = new Range(tok(2), tok(4)); - Range right = new Range(tok(4), tok(0)); + Range right = new Range(tok(4), tok(-1)); Range linvalid = new Range(tok(1), tok(4)); Range rinvalid = new Range(tok(4), tok(6)); @@ -308,7 +310,7 @@ public class MerkleTreeTest // validate the range mt.get(tok(2)).hash(val); mt.get(tok(4)).hash(val); - mt.get(tok(0)).hash(val); + mt.get(tok(-1)).hash(val); assertHashEquals(leftval, mt.hash(left)); assertHashEquals(partialval, mt.hash(partial)); @@ -324,10 +326,10 @@ public class MerkleTreeTest byte[] lchildval = hashed(val, 3, 3, 2); byte[] rchildval = hashed(val, 2, 2); byte[] fullval = hashed(val, 3, 3, 2, 2, 2); - Range full = new Range(tok(0), tok(0)); - Range lchild = new Range(tok(0), tok(4)); - Range rchild = new Range(tok(4), tok(0)); - Range invalid = new Range(tok(1), tok(0)); + Range full = new Range(tok(-1), tok(-1)); + Range lchild = new Range(tok(-1), tok(4)); + Range rchild = new Range(tok(4), tok(-1)); + Range invalid = new Range(tok(1), tok(-1)); // (zero,one] (one, two] (two,four] (four, six] (six, zero] mt.split(tok(4)); @@ -344,7 +346,7 @@ public class MerkleTreeTest mt.get(tok(2)).hash(val); mt.get(tok(4)).hash(val); mt.get(tok(6)).hash(val); - mt.get(tok(0)).hash(val); + mt.get(tok(-1)).hash(val); assertHashEquals(fullval, mt.hash(full)); assertHashEquals(lchildval, mt.hash(lchild)); @@ -360,9 +362,9 @@ public class MerkleTreeTest byte[] val = DUMMY; byte[] childfullval = hashed(val, 5, 5, 4); byte[] fullval = hashed(val, 5, 5, 4, 3, 2, 1); - Range childfull = new Range(tok(0), tok(4)); - Range full = new Range(tok(0), tok(0)); - Range invalid = new Range(tok(4), tok(0)); + Range childfull = new Range(tok(-1), tok(4)); + Range full = new Range(tok(-1), tok(-1)); + Range invalid = new Range(tok(4), tok(-1)); mt = new MerkleTree(partitioner, RECOMMENDED_DEPTH, Integer.MAX_VALUE); mt.split(tok(16)); @@ -380,7 +382,7 @@ public class MerkleTreeTest mt.get(tok(4)).hash(val); mt.get(tok(8)).hash(val); mt.get(tok(16)).hash(val); - mt.get(tok(0)).hash(val); + mt.get(tok(-1)).hash(val); assertHashEquals(fullval, mt.hash(full)); assertHashEquals(childfullval, mt.hash(childfull)); @@ -402,11 +404,11 @@ public class MerkleTreeTest } // validate the tree - TreeRangeIterator ranges = mt.invalids(new Range(tok(0), tok(0))); + TreeRangeIterator ranges = mt.invalids(new Range(tok(-1), tok(-1))); for (TreeRange range : ranges) range.addHash(new RowHash(range.right, new byte[0])); - assert null != mt.hash(new Range(tok(0), tok(0))) : + assert null != mt.hash(new Range(tok(-1), tok(-1))) : "Could not hash tree " + mt; } @@ -421,7 +423,7 @@ public class MerkleTreeTest { TOKEN_SCALE = new BigInteger("16"); // this test needs slightly more resolution - Range full = new Range(tok(0), tok(0)); + Range full = new Range(tok(-1), tok(-1)); Iterator ranges; MerkleTree mt2 = new MerkleTree(partitioner, RECOMMENDED_DEPTH, Integer.MAX_VALUE); @@ -432,12 +434,12 @@ public class MerkleTreeTest mt.split(tok(10)); ranges = mt.invalids(full); - ranges.next().addAll(new HIterator(2, 4)); // (0,4]: depth 2 + ranges.next().addAll(new HIterator(2, 4)); // (-1,4]: depth 2 ranges.next().addAll(new HIterator(6)); // (4,6] ranges.next().addAll(new HIterator(8)); // (6,8] ranges.next().addAll(new HIterator(/*empty*/ new int[0])); // (8,10] ranges.next().addAll(new HIterator(12)); // (10,12] - ranges.next().addAll(new HIterator(14, 0)); // (12,0]: depth 2 + ranges.next().addAll(new HIterator(14, -1)); // (12,-1]: depth 2 mt2.split(tok(8)); @@ -449,14 +451,14 @@ public class MerkleTreeTest mt2.split(tok(11)); ranges = mt2.invalids(full); - ranges.next().addAll(new HIterator(2)); // (0,2] + ranges.next().addAll(new HIterator(2)); // (-1,2] ranges.next().addAll(new HIterator(4)); // (2,4] ranges.next().addAll(new HIterator(6, 8)); // (4,8]: depth 2 ranges.next().addAll(new HIterator(/*empty*/ new int[0])); // (8,9] ranges.next().addAll(new HIterator(/*empty*/ new int[0])); // (9,10] ranges.next().addAll(new HIterator(/*empty*/ new int[0])); // (10,11]: depth 4 ranges.next().addAll(new HIterator(12)); // (11,12]: depth 4 - ranges.next().addAll(new HIterator(14, 0)); // (12,0]: depth 2 + ranges.next().addAll(new HIterator(14, -1)); // (12,-1]: depth 2 byte[] mthash = mt.hash(full); byte[] mt2hash = mt2.hash(full); @@ -466,7 +468,7 @@ public class MerkleTreeTest @Test public void testSerialization() throws Exception { - Range full = new Range(tok(0), tok(0)); + Range full = new Range(tok(-1), tok(-1)); ByteArrayOutputStream bout = new ByteArrayOutputStream(); ObjectOutputStream oout = new ObjectOutputStream(bout); @@ -493,7 +495,7 @@ public class MerkleTreeTest @Test public void testDifference() { - Range full = new Range(tok(0), tok(0)); + Range full = new Range(tok(-1), tok(-1)); int maxsize = 16; mt.maxsize(maxsize); MerkleTree mt2 = new MerkleTree(partitioner, RECOMMENDED_DEPTH, maxsize);