Fix full ring range subtraction

Patch by Aleksandr Sorokoumov; reviewed by Alex Petrov for CASSANDRA-14869


Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/c6f822c2
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/c6f822c2
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/c6f822c2

Branch: refs/heads/cassandra-3.11
Commit: c6f822c2a07e0e7c8e4af72523fe62d181c71e56
Parents: 60a8cfe
Author: Aleksandr Sorokoumov <aleksandr.sorokou...@gmail.com>
Authored: Tue Nov 6 21:47:03 2018 +0100
Committer: Alex Petrov <oleksandr.pet...@gmail.com>
Committed: Mon Nov 19 08:51:56 2018 +0100

----------------------------------------------------------------------
 src/java/org/apache/cassandra/dht/Range.java    | 27 +++++++++++--
 .../org/apache/cassandra/dht/RangeTest.java     | 40 ++++++++++++++++++++
 2 files changed, 63 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cassandra/blob/c6f822c2/src/java/org/apache/cassandra/dht/Range.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/dht/Range.java 
b/src/java/org/apache/cassandra/dht/Range.java
index ba6854e..3cf292a 100644
--- a/src/java/org/apache/cassandra/dht/Range.java
+++ b/src/java/org/apache/cassandra/dht/Range.java
@@ -256,6 +256,14 @@ public class Range<T extends RingPosition<T>> extends 
AbstractBounds<T> implemen
     }
 
     /**
+     * Tells if the given range covers the entire ring
+     */
+    private static <T extends RingPosition<T>> boolean isFull(T left, T right)
+    {
+        return left.equals(right);
+    }
+
+    /**
      * Note: this class has a natural ordering that is inconsistent with equals
      */
     public int compareTo(Range<T> rhs)
@@ -274,13 +282,24 @@ public class Range<T extends RingPosition<T>> extends 
AbstractBounds<T> implemen
      * Subtracts a portion of this range.
      * @param contained The range to subtract from this. It must be totally
      * contained by this range.
-     * @return An ArrayList of the Ranges left after subtracting contained
+     * @return A List of the Ranges left after subtracting contained
      * from this.
      */
-    private ArrayList<Range<T>> subtractContained(Range<T> contained)
+    private List<Range<T>> subtractContained(Range<T> contained)
     {
-        ArrayList<Range<T>> difference = new ArrayList<Range<T>>(2);
+        // both ranges cover the entire ring, their difference is an empty set
+        if(isFull(left, right) && isFull(contained.left, contained.right))
+        {
+            return Collections.emptyList();
+        }
+
+        // a range is subtracted from another range that covers the entire ring
+        if(isFull(left, right))
+        {
+            return Collections.singletonList(new Range<>(contained.right, 
contained.left));
+        }
 
+        List<Range<T>> difference = new ArrayList<>(2);
         if (!left.equals(contained.left))
             difference.add(new Range<T>(left, contained.left));
         if (!right.equals(contained.right))
@@ -346,7 +365,7 @@ public class Range<T extends RingPosition<T>> extends 
AbstractBounds<T> implemen
                 // intersections.length must be 2
                 Range<T> first = intersections[0];
                 Range<T> second = intersections[1];
-                ArrayList<Range<T>> temp = rhs.subtractContained(first);
+                List<Range<T>> temp = rhs.subtractContained(first);
 
                 // Because there are two intersections, subtracting only one 
of them
                 // will yield a single Range.

http://git-wip-us.apache.org/repos/asf/cassandra/blob/c6f822c2/test/unit/org/apache/cassandra/dht/RangeTest.java
----------------------------------------------------------------------
diff --git a/test/unit/org/apache/cassandra/dht/RangeTest.java 
b/test/unit/org/apache/cassandra/dht/RangeTest.java
index 5cd94e2..627253d 100644
--- a/test/unit/org/apache/cassandra/dht/RangeTest.java
+++ b/test/unit/org/apache/cassandra/dht/RangeTest.java
@@ -362,6 +362,8 @@ public class RangeTest
         assertRanges(range.subtractAll(collection), 10L, 54L, 60L, 90L);
         collection.add(makeRange(80L, 95L));
         assertRanges(range.subtractAll(collection), 10L, 54L, 60L, 80L);
+
+        assertEquals(Collections.emptySet(), 
range.subtractAll(Collections.singleton(range)));
     }
 
     @Test
@@ -380,6 +382,44 @@ public class RangeTest
         assertRanges(range.subtractAll(collection), 100L, 200L, 500L, 0L);
         collection.add(makeRange(1000L, 0));
         assertRanges(range.subtractAll(collection), 100L, 200L, 500L, 1000L);
+
+        assertEquals(Collections.emptySet(), 
range.subtractAll(Collections.singleton(range)));
+    }
+
+    @Test
+    public void testSubtractAllFromFullRingRange()
+    {
+        Range<Token> ring1 = makeRange(50L, 50L);
+        Range<Token> ring2 = makeRange(0L, 0L);
+
+        Set<Range<Token>> contained1 = Collections.singleton(makeRange(10L, 
100L));
+        Set<Range<Token>> contained2 = Collections.singleton(makeRange(100L, 
10L));
+
+        assertEquals(contained2, ring1.subtractAll(contained1));
+        assertEquals(contained2, ring2.subtractAll(contained1));
+        assertEquals(contained1, ring1.subtractAll(contained2));
+        assertEquals(contained1, ring2.subtractAll(contained2));
+        assertEquals(Collections.emptySet(), 
ring1.subtractAll(Collections.singleton(ring1)));
+        assertEquals(Collections.emptySet(), 
ring2.subtractAll(Collections.singleton(ring2)));
+        assertEquals(Collections.emptySet(), 
ring1.subtractAll(Collections.singleton(ring2)));
+    }
+
+    @Test
+    public void testSubtractFromFullRingRange()
+    {
+        Range<Token> ring1 = makeRange(50L, 50L);
+        Range<Token> ring2 = makeRange(0L, 0L);
+
+        Range<Token> contained1 = makeRange(10L, 100L);
+        Range<Token> contained2 = makeRange(100L, 10L);
+
+        assertEquals(Collections.singleton(contained2), 
ring1.subtract(contained1));
+        assertEquals(Collections.singleton(contained2), 
ring2.subtract(contained1));
+        assertEquals(Collections.singleton(contained1), 
ring1.subtract(contained2));
+        assertEquals(Collections.singleton(contained1), 
ring2.subtract(contained2));
+        assertEquals(Collections.emptySet(), ring1.subtract(ring1));
+        assertEquals(Collections.emptySet(), ring2.subtract(ring2));
+        assertEquals(Collections.emptySet(), ring1.subtract(ring2));
     }
     
     private Range<Token> makeRange(String token1, String token2)


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@cassandra.apache.org
For additional commands, e-mail: commits-h...@cassandra.apache.org

Reply via email to