Handle composite prefixes with final EOC=0 as in 2.x and refactor 
LegacyLayout.decodeBound

patch by Stefania Alborghetti and Sylvain Lebresne; reviewed by Tyler Hobbs and
Sylvain Lebresne for CASSANDRA-12423


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

Branch: refs/heads/cassandra-3.9
Commit: d600f51ee1a3eb7b30ce3c409129567b70c22012
Parents: 932f3eb
Author: Stefania Alborghetti <stefania.alborghe...@datastax.com>
Authored: Tue Aug 30 16:08:09 2016 +0800
Committer: Stefania Alborghetti <stefania.alborghe...@datastax.com>
Committed: Mon Sep 12 16:56:30 2016 +0800

----------------------------------------------------------------------
 CHANGES.txt                                     |  1 +
 .../org/apache/cassandra/db/LegacyLayout.java   | 64 +++++++++++---------
 .../cassandra/db/marshal/CompositeType.java     | 26 --------
 3 files changed, 37 insertions(+), 54 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cassandra/blob/d600f51e/CHANGES.txt
----------------------------------------------------------------------
diff --git a/CHANGES.txt b/CHANGES.txt
index 459d591..f0ec3e3 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,5 @@
 3.0.9
+ * Handle composite prefixes with final EOC=0 as in 2.x and refactor 
LegacyLayout.decodeBound (CASSANDRA-12423)
  * Fix paging for 2.x to 3.x upgrades (CASSANDRA-11195)
  * select_distinct_with_deletions_test failing on non-vnode environments 
(CASSANDRA-11126)
  * Stack Overflow returned to queries while upgrading (CASSANDRA-12527)

http://git-wip-us.apache.org/repos/asf/cassandra/blob/d600f51e/src/java/org/apache/cassandra/db/LegacyLayout.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/LegacyLayout.java 
b/src/java/org/apache/cassandra/db/LegacyLayout.java
index 65f9d3f..c8e7536 100644
--- a/src/java/org/apache/cassandra/db/LegacyLayout.java
+++ b/src/java/org/apache/cassandra/db/LegacyLayout.java
@@ -186,41 +186,49 @@ public abstract class LegacyLayout
         if (!bound.hasRemaining())
             return isStart ? LegacyBound.BOTTOM : LegacyBound.TOP;
 
-        List<CompositeType.CompositeComponent> components = 
metadata.isCompound()
-                                                          ? 
CompositeType.deconstruct(bound)
-                                                          : 
Collections.singletonList(new CompositeType.CompositeComponent(bound, (byte) 
0));
-
-        // Either it's a prefix of the clustering, or it's the bound of a 
collection range tombstone (and thus has
-        // the collection column name)
-        assert components.size() <= metadata.comparator.size() || 
(!metadata.isCompactTable() && components.size() == metadata.comparator.size() 
+ 1);
-
-        List<CompositeType.CompositeComponent> prefix = components.size() <= 
metadata.comparator.size()
-                                                      ? components
-                                                      : components.subList(0, 
metadata.comparator.size());
-        Slice.Bound.Kind boundKind;
+        if (!metadata.isCompound())
+        {
+            // The non compound case is a lot easier, in that there is no EOC 
nor collection to worry about, so dealing
+            // with that first.
+            return new LegacyBound(isStart ? 
Slice.Bound.inclusiveStartOf(bound) : Slice.Bound.inclusiveEndOf(bound), false, 
null);
+        }
+
+        int clusteringSize = metadata.comparator.size();
+
+        List<ByteBuffer> components = CompositeType.splitName(bound);
+        byte eoc = CompositeType.lastEOC(bound);
+
+        // There can be  more components than the clustering size only in the 
case this is the bound of a collection
+        // range tombstone. In which case, there is exactly one more 
component, and that component is the name of the
+        // collection being selected/deleted.
+        assert components.size() <= clusteringSize || 
(!metadata.isCompactTable() && components.size() == clusteringSize + 1);
+
+        ColumnDefinition collectionName = null;
+        if (components.size() > clusteringSize)
+            collectionName = 
metadata.getColumnDefinition(components.remove(clusteringSize));
+
+        boolean isInclusive;
         if (isStart)
         {
-            if (components.get(components.size() - 1).eoc > 0)
-                boundKind = Slice.Bound.Kind.EXCL_START_BOUND;
-            else
-                boundKind = Slice.Bound.Kind.INCL_START_BOUND;
+            isInclusive = eoc <= 0;
         }
         else
         {
-            if (components.get(components.size() - 1).eoc < 0)
-                boundKind = Slice.Bound.Kind.EXCL_END_BOUND;
-            else
-                boundKind = Slice.Bound.Kind.INCL_END_BOUND;
-        }
+            isInclusive = eoc >= 0;
 
-        ByteBuffer[] prefixValues = new ByteBuffer[prefix.size()];
-        for (int i = 0; i < prefix.size(); i++)
-            prefixValues[i] = prefix.get(i).value;
-        Slice.Bound sb = Slice.Bound.create(boundKind, prefixValues);
+            // for an end bound, if we only have a prefix of all the 
components and the final EOC is zero,
+            // then it should only match up to the prefix but no further, that 
is, it is an inclusive bound
+            // of the exact prefix but an exclusive bound of anything beyond 
it, so adding an empty
+            // composite value ensures this behavior, see CASSANDRA-12423 for 
more details
+            if (eoc == 0 && components.size() < clusteringSize)
+            {
+                components.add(ByteBufferUtil.EMPTY_BYTE_BUFFER);
+                isInclusive = false;
+            }
+        }
 
-        ColumnDefinition collectionName = components.size() == 
metadata.comparator.size() + 1
-                                        ? 
metadata.getColumnDefinition(components.get(metadata.comparator.size()).value)
-                                        : null;
+        Slice.Bound.Kind boundKind = Slice.Bound.boundKind(isStart, 
isInclusive);
+        Slice.Bound sb = Slice.Bound.create(boundKind, components.toArray(new 
ByteBuffer[components.size()]));
         return new LegacyBound(sb, metadata.isCompound() && 
CompositeType.isStaticName(bound), collectionName);
     }
 

http://git-wip-us.apache.org/repos/asf/cassandra/blob/d600f51e/src/java/org/apache/cassandra/db/marshal/CompositeType.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/marshal/CompositeType.java 
b/src/java/org/apache/cassandra/db/marshal/CompositeType.java
index d005fd7..52d6d39 100644
--- a/src/java/org/apache/cassandra/db/marshal/CompositeType.java
+++ b/src/java/org/apache/cassandra/db/marshal/CompositeType.java
@@ -227,32 +227,6 @@ public class CompositeType extends AbstractCompositeType
         return null;
     }
 
-    public static class CompositeComponent
-    {
-        public ByteBuffer value;
-        public byte eoc;
-
-        public CompositeComponent(ByteBuffer value, byte eoc)
-        {
-            this.value = value;
-            this.eoc = eoc;
-        }
-    }
-
-    public static List<CompositeComponent> deconstruct(ByteBuffer bytes)
-    {
-        List<CompositeComponent> list = new ArrayList<>();
-        ByteBuffer bb = bytes.duplicate();
-        readStatic(bb);
-        while (bb.remaining() > 0)
-        {
-            ByteBuffer value = ByteBufferUtil.readBytesWithShortLength(bb);
-            byte eoc = bb.get();
-            list.add(new CompositeComponent(value, eoc));
-        }
-        return list;
-    }
-
     // Extract CQL3 column name from the full column name.
     public ByteBuffer extractLastComponent(ByteBuffer bb)
     {

Reply via email to