You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by sl...@apache.org on 2011/06/15 14:01:21 UTC
svn commit: r1136008 - in /cassandra/trunk: CHANGES.txt
src/java/org/apache/cassandra/dht/AbstractBounds.java
test/unit/org/apache/cassandra/dht/AbstractBoundsTest.java
Author: slebresne
Date: Wed Jun 15 12:01:21 2011
New Revision: 1136008
URL: http://svn.apache.org/viewvc?rev=1136008&view=rev
Log:
Make AbstractBounds.normalize de-overlapp overlapping ranges
patch by slebresne; reviewed by stuhood for CASSANDRA-2641
Added:
cassandra/trunk/test/unit/org/apache/cassandra/dht/AbstractBoundsTest.java
Modified:
cassandra/trunk/CHANGES.txt
cassandra/trunk/src/java/org/apache/cassandra/dht/AbstractBounds.java
Modified: cassandra/trunk/CHANGES.txt
URL: http://svn.apache.org/viewvc/cassandra/trunk/CHANGES.txt?rev=1136008&r1=1136007&r2=1136008&view=diff
==============================================================================
--- cassandra/trunk/CHANGES.txt (original)
+++ cassandra/trunk/CHANGES.txt Wed Jun 15 12:01:21 2011
@@ -2,6 +2,7 @@
* removed binarymemtable (CASSANDRA-2692)
* add commitlog_total_space_in_mb to prevent fragmented logs (CASSANDRA-2427)
* removed commitlog_rotation_threshold_in_mb configuration (CASSANDRA-2771)
+ * make AbstractBounds.normalize de-overlapp overlapping ranges (CASSANDRA-2641)
0.8.1
Modified: cassandra/trunk/src/java/org/apache/cassandra/dht/AbstractBounds.java
URL: http://svn.apache.org/viewvc/cassandra/trunk/src/java/org/apache/cassandra/dht/AbstractBounds.java?rev=1136008&r1=1136007&r2=1136008&view=diff
==============================================================================
--- cassandra/trunk/src/java/org/apache/cassandra/dht/AbstractBounds.java (original)
+++ cassandra/trunk/src/java/org/apache/cassandra/dht/AbstractBounds.java Wed Jun 15 12:01:21 2011
@@ -89,8 +89,8 @@ public abstract class AbstractBounds imp
public abstract List<AbstractBounds> unwrap();
/**
- * @return A copy of the given list of non-intersecting bounds with all bounds unwrapped, sorted by bound.left.
- * This method does not allow overlapping ranges as input.
+ * @return A copy of the given list of with all bounds unwrapped, sorted by bound.left and with overlapping bounds merged.
+ * This method does not allow allow to mix Range and Bound in the input list.
*/
public static List<AbstractBounds> normalize(Collection<? extends AbstractBounds> bounds)
{
@@ -107,6 +107,61 @@ public abstract class AbstractBounds imp
return b1.left.compareTo(b2.left);
}
});
+
+ // deoverlap
+ return deoverlap(output);
+ }
+
+ /**
+ * Given a list of unwrapped bounds sorted by left token, return a list a equivalent
+ * list of bounds but with no overlapping bounds.
+ */
+ private static List<AbstractBounds> deoverlap(List<AbstractBounds> bounds)
+ {
+ if (bounds.isEmpty())
+ return bounds;
+
+ List<AbstractBounds> output = new ArrayList<AbstractBounds>();
+
+ Iterator<AbstractBounds> iter = bounds.iterator();
+ AbstractBounds current = iter.next();
+ boolean isRange = current instanceof Range;
+
+ Token min = current.partitioner.getMinimumToken();
+ while (iter.hasNext())
+ {
+ if (current.right.equals(min))
+ {
+ // If one of the bound is the full range, we return only that
+ if (current.left.equals(min))
+ return Collections.<AbstractBounds>singletonList(current);
+
+ output.add(current.createFrom(min));
+ return output;
+ }
+
+ AbstractBounds next = iter.next();
+ assert isRange ? next instanceof Range : next instanceof Bounds;
+
+ // For Ranges, if next left is equal to current right, we do not intersect per se, but replacing (A, B] and (B, C] by (A, C] is
+ // legit, and since this actually avoid special casing and will result in more "optimal" ranges, we do this transformation
+ if (next.left.compareTo(current.right) <= 0)
+ {
+ // We do overlap
+ // (we've handler current.right.equals(min) already)
+ Token newRight = next.right.equals(min) || current.right.compareTo(next.right) < 0 ? next.right : current.right;
+ current = current.createFrom(newRight);
+ if (current == null)
+ // current is the full ring, can only happen for Range
+ return Collections.<AbstractBounds>singletonList(new Range(min, min));
+ }
+ else
+ {
+ output.add(current);
+ current = next;
+ }
+ }
+ output.add(current);
return output;
}
Added: cassandra/trunk/test/unit/org/apache/cassandra/dht/AbstractBoundsTest.java
URL: http://svn.apache.org/viewvc/cassandra/trunk/test/unit/org/apache/cassandra/dht/AbstractBoundsTest.java?rev=1136008&view=auto
==============================================================================
--- cassandra/trunk/test/unit/org/apache/cassandra/dht/AbstractBoundsTest.java (added)
+++ cassandra/trunk/test/unit/org/apache/cassandra/dht/AbstractBoundsTest.java Wed Jun 15 12:01:21 2011
@@ -0,0 +1,135 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cassandra.dht;
+
+import java.util.List;
+import static java.util.Arrays.asList;
+
+import org.junit.Test;
+
+import static org.apache.cassandra.Util.range;
+import static org.apache.cassandra.Util.bounds;
+
+public class AbstractBoundsTest
+{
+ private void assertNormalize(List<? extends AbstractBounds> input, List<? extends AbstractBounds> expected)
+ {
+ List<AbstractBounds> result = AbstractBounds.normalize(input);
+ assert result.equals(expected) : "Expecting " + expected + " but got " + result;
+ }
+
+ @Test
+ public void testNormalizeNoop()
+ {
+ List<? extends AbstractBounds> l;
+
+ l = asList(range("1", "3"), range("4", "5"));
+ assert AbstractBounds.normalize(l).equals(l);
+
+ l = asList(bounds("1", "3"), bounds("4", "5"));
+ assertNormalize(l, l);
+ }
+
+ @Test
+ public void testNormalizeSimpleOverlap()
+ {
+ List<? extends AbstractBounds> input, expected;
+
+ input = asList(range("1", "4"), range("3", "5"));
+ expected = asList(range("1", "5"));
+ assertNormalize(input, expected);
+
+ input = asList(range("1", "4"), range("1", "4"));
+ expected = asList(range("1", "4"));
+ assertNormalize(input, expected);
+
+ input = asList(bounds("1", "4"), bounds("3", "5"));
+ expected = asList(bounds("1", "5"));
+ assertNormalize(input, expected);
+
+ input = asList(bounds("1", "4"), bounds("1", "4"));
+ expected = asList(bounds("1", "4"));
+ assertNormalize(input, expected);
+
+ input = asList(bounds("1", "1"), bounds("1", "1"));
+ expected = asList(bounds("1", "1"));
+ assertNormalize(input, expected);
+ }
+
+ @Test
+ public void testNormalizeSort()
+ {
+ List<? extends AbstractBounds> input, expected;
+
+ input = asList(range("4", "5"), range("1", "3"));
+ expected = asList(range("1", "3"), range("4", "5"));
+ assertNormalize(input, expected);
+
+ input = asList(bounds("4", "5"), bounds("1", "3"));
+ expected = asList(bounds("1", "3"), bounds("4", "5"));
+ assertNormalize(input, expected);
+ }
+
+ @Test
+ public void testNormalizeUnwrap()
+ {
+ List<? extends AbstractBounds> input, expected;
+
+ input = asList(range("9", "2"));
+ expected = asList(range("", "2"), range("9", ""));
+ assertNormalize(input, expected);
+
+ // Bounds cannot wrap
+ }
+
+ @Test
+ public void testNormalizeComplex()
+ {
+ List<? extends AbstractBounds> input, expected;
+
+ input = asList(range("8", "2"), range("7", "9"), range("4", "5"));
+ expected = asList(range("", "2"), range("4", "5"), range("7", ""));
+ assertNormalize(input, expected);
+
+ input = asList(range("5", "9"), range("2", "5"));
+ expected = asList(range("2", "9"));
+ assertNormalize(input, expected);
+
+ input = asList(range ("", "1"), range("9", "2"), range("4", "5"), range("", ""));
+ expected = asList(range("", ""));
+ assertNormalize(input, expected);
+
+ input = asList(range ("", "1"), range("1", "4"), range("4", "5"), range("5", ""));
+ expected = asList(range("", ""));
+ assertNormalize(input, expected);
+
+ // bounds
+ input = asList(bounds("5", "9"), bounds("2", "5"));
+ expected = asList(bounds("2", "9"));
+ assertNormalize(input, expected);
+
+ input = asList(bounds ("", "1"), bounds("", "9"), bounds("4", "5"), bounds("", ""));
+ expected = asList(bounds("", ""));
+ assertNormalize(input, expected);
+
+ input = asList(bounds ("", "1"), bounds("1", "4"), bounds("4", "5"), bounds("5", ""));
+ expected = asList(bounds("", ""));
+ assertNormalize(input, expected);
+ }
+}