Merge branch cassandra-3.0 into trunk

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

Branch: refs/heads/trunk
Commit: b0448e66b567bb8dc80acb1cb9c66bbf8b5f461c
Parents: ebd6c23 1aa97e3
Author: Benjamin Lerer <b.le...@gmail.com>
Authored: Thu Feb 11 10:44:30 2016 +0100
Committer: Benjamin Lerer <b.le...@gmail.com>
Committed: Thu Feb 11 10:48:28 2016 +0100

----------------------------------------------------------------------
 CHANGES.txt                                     |    1 +
 .../cql3/restrictions/AbstractRestriction.java  |   14 +
 .../ForwardingPrimaryKeyRestrictions.java       |    3 +-
 .../restrictions/MultiColumnRestriction.java    |   76 +-
 .../restrictions/PrimaryKeyRestrictionSet.java  |   34 +-
 .../cql3/restrictions/Restriction.java          |    4 +-
 .../cql3/restrictions/RestrictionSet.java       |    4 +-
 .../restrictions/SingleColumnRestriction.java   |    9 +-
 .../cql3/restrictions/TokenRestriction.java     |    2 +-
 .../org/apache/cassandra/db/MultiCBuilder.java  |   90 +-
 .../PrimaryKeyRestrictionSetTest.java           | 1174 +++++++++++++++---
 .../SelectMultiColumnRelationTest.java          |  859 ++++++++++++-
 12 files changed, 2059 insertions(+), 211 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cassandra/blob/b0448e66/CHANGES.txt
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/cassandra/blob/b0448e66/src/java/org/apache/cassandra/cql3/restrictions/AbstractRestriction.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/cassandra/blob/b0448e66/src/java/org/apache/cassandra/cql3/restrictions/ForwardingPrimaryKeyRestrictions.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/cassandra/blob/b0448e66/src/java/org/apache/cassandra/cql3/restrictions/PrimaryKeyRestrictionSet.java
----------------------------------------------------------------------
diff --cc 
src/java/org/apache/cassandra/cql3/restrictions/PrimaryKeyRestrictionSet.java
index d24799a,8121858..978ebbc
--- 
a/src/java/org/apache/cassandra/cql3/restrictions/PrimaryKeyRestrictionSet.java
+++ 
b/src/java/org/apache/cassandra/cql3/restrictions/PrimaryKeyRestrictionSet.java
@@@ -163,20 -175,6 +163,30 @@@ final class PrimaryKeyRestrictionSet ex
          return new PrimaryKeyRestrictionSet(this, restriction);
      }
  
 +    // Whether any of the underlying restriction is an IN
 +    private boolean hasIN()
 +    {
 +        if (isIN())
 +            return true;
 +
 +        for (Restriction restriction : restrictions)
 +        {
 +            if (restriction.isIN())
 +                return true;
 +        }
 +        return false;
 +    }
 +
++    private boolean hasMultiColumnSlice()
++    {
++        for (Restriction restriction : restrictions)
++        {
++            if (restriction.isMultiColumn() && restriction.isSlice())
++                return true;
++        }
++        return false;
++    }
++
      @Override
      public NavigableSet<Clustering> valuesAsClustering(QueryOptions options) 
throws InvalidRequestException
      {
@@@ -204,7 -202,7 +214,7 @@@
      @Override
      public NavigableSet<Slice.Bound> boundsAsClustering(Bound bound, 
QueryOptions options) throws InvalidRequestException
      {
-         MultiCBuilder builder = MultiCBuilder.create(comparator, hasIN());
 -        MultiCBuilder builder = MultiCBuilder.create(comparator);
++        MultiCBuilder builder = MultiCBuilder.create(comparator, hasIN() || 
hasMultiColumnSlice());
          int keyPosition = 0;
          for (Restriction r : restrictions)
          {

http://git-wip-us.apache.org/repos/asf/cassandra/blob/b0448e66/src/java/org/apache/cassandra/cql3/restrictions/Restriction.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/cassandra/blob/b0448e66/src/java/org/apache/cassandra/cql3/restrictions/RestrictionSet.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/cassandra/blob/b0448e66/src/java/org/apache/cassandra/cql3/restrictions/SingleColumnRestriction.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/cassandra/blob/b0448e66/src/java/org/apache/cassandra/db/MultiCBuilder.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/db/MultiCBuilder.java
index 7a4eef0,7c77ab0..f03e674
--- a/src/java/org/apache/cassandra/db/MultiCBuilder.java
+++ b/src/java/org/apache/cassandra/db/MultiCBuilder.java
@@@ -18,8 -18,11 +18,13 @@@
  package org.apache.cassandra.db;
  
  import java.nio.ByteBuffer;
- import java.util.*;
+ import java.util.ArrayList;
++import java.util.Arrays;
+ import java.util.List;
+ import java.util.NavigableSet;
  
+ import org.apache.cassandra.config.ColumnDefinition;
++import org.apache.cassandra.db.Slice.Bound;
  import org.apache.cassandra.utils.ByteBufferUtil;
  import org.apache.cassandra.utils.btree.BTreeSet;
  
@@@ -159,260 -257,123 +164,333 @@@ public abstract class MultiCBuilde
       *
       * @return the clusterings
       */
 -    public NavigableSet<Clustering> build()
 -    {
 -        built = true;
 -
 -        if (hasMissingElements)
 -            return BTreeSet.empty(comparator);
 -
 -        CBuilder builder = CBuilder.create(comparator);
 -
 -        if (elementsList.isEmpty())
 -            return BTreeSet.of(builder.comparator(), builder.build());
 -
 -        BTreeSet.Builder<Clustering> set = 
BTreeSet.builder(builder.comparator());
 -        for (int i = 0, m = elementsList.size(); i < m; i++)
 -        {
 -            List<ByteBuffer> elements = elementsList.get(i);
 -            set.add(builder.buildWith(elements));
 -        }
 -        return set.build();
 -    }
 +    public abstract NavigableSet<Clustering> build();
  
      /**
-      * Builds the <code>clusterings</code> with the specified EOC.
+      * Builds the <code>Slice.Bound</code>s for slice restrictions.
       *
-      * @return the clusterings
+      * @param isStart specify if the bound is a start one
+      * @param isInclusive specify if the bound is inclusive or not
+      * @param isOtherBoundInclusive specify if the other bound is inclusive 
or not
+      * @param columnDefs the columns of the slice restriction
+      * @return the <code>Slice.Bound</code>s
+      */
 -    public NavigableSet<Slice.Bound> buildBoundForSlice(boolean isStart,
 -                                                        boolean isInclusive,
 -                                                        boolean 
isOtherBoundInclusive,
 -                                                        
List<ColumnDefinition> columnDefs)
++    public abstract NavigableSet<Slice.Bound> buildBoundForSlice(boolean 
isStart,
++                                                                 boolean 
isInclusive,
++                                                                 boolean 
isOtherBoundInclusive,
++                                                                 
List<ColumnDefinition> columnDefs);
++
++    /**
++     * Builds the <code>Slice.Bound</code>s
++     *
++     * @param isStart specify if the bound is a start one
++     * @param isInclusive specify if the bound is inclusive or not
++     * @return the <code>Slice.Bound</code>s
 +     */
 +    public abstract NavigableSet<Slice.Bound> buildBound(boolean isStart, 
boolean isInclusive);
 +
 +    /**
 +     * Checks if some elements can still be added to the clusterings.
 +     *
 +     * @return <code>true</code> if it is possible to add more elements to 
the clusterings, <code>false</code> otherwise.
 +     */
 +    public boolean hasRemaining()
      {
 -        built = true;
 +        return remainingCount() > 0;
 +    }
  
 -        if (hasMissingElements)
 -            return BTreeSet.empty(comparator);
 +    /**
 +     * Specialization of MultiCBuilder when we know only one clustering/bound 
is created.
 +     */
 +    private static class OneClusteringBuilder extends MultiCBuilder
 +    {
 +        /**
 +         * The elements of the clusterings
 +         */
 +        private final ByteBuffer[] elements;
  
 -        CBuilder builder = CBuilder.create(comparator);
 +        public OneClusteringBuilder(ClusteringComparator comparator)
 +        {
 +            super(comparator);
 +            this.elements = new ByteBuffer[comparator.size()];
 +        }
  
 -        if (elementsList.isEmpty())
 -            return BTreeSet.of(comparator, builder.buildBound(isStart, 
isInclusive));
 +        public MultiCBuilder addElementToAll(ByteBuffer value)
 +        {
 +            checkUpdateable();
  
 -        // Use a TreeSet to sort and eliminate duplicates
 -        BTreeSet.Builder<Slice.Bound> set = BTreeSet.builder(comparator);
 +            if (value == null)
 +                containsNull = true;
 +            if (value == ByteBufferUtil.UNSET_BYTE_BUFFER)
 +                containsUnset = true;
  
 -        // The first column of the slice might not be the first clustering 
column (e.g. clustering_0 = ? AND (clustering_1, clustering_2) >= (?, ?)
 -        int offset = columnDefs.get(0).position();
 +            elements[size++] = value;
 +            return this;
 +        }
  
 -        for (int i = 0, m = elementsList.size(); i < m; i++)
 +        public MultiCBuilder addEachElementToAll(List<ByteBuffer> values)
          {
 -            List<ByteBuffer> elements = elementsList.get(i);
 -
 -            // Handle the no bound case
 -            if (elements.size() == offset)
 +            if (values.isEmpty())
              {
 -                set.add(builder.buildBoundWith(elements, isStart, true));
 -                continue;
 +                hasMissingElements = true;
 +                return this;
              }
  
 -            // In the case of mixed order columns, we will have some extra 
slices where the columns change directions.
 -            // For example: if we have clustering_0 DESC and clustering_1 ASC 
a slice like (clustering_0, clustering_1) > (1, 2)
 -            // will produce 2 slices: [BOTTOM, 1) and (1.2, 1]
 -            // So, the END bound will return 2 bounds with the same values 1
 -            ColumnDefinition lastColumn = columnDefs.get(columnDefs.size() - 
1);
 -            if (elements.size() <= lastColumn.position() && i < m - 1 && 
elements.equals(elementsList.get(i + 1)))
 +            assert values.size() == 1;
 +
 +            return addElementToAll(values.get(0));
 +        }
 +
 +        public MultiCBuilder addAllElementsToAll(List<List<ByteBuffer>> 
values)
 +        {
 +            if (values.isEmpty())
              {
 -                set.add(builder.buildBoundWith(elements, isStart, false));
 -                set.add(builder.buildBoundWith(elementsList.get(i++), 
isStart, true));
 -                continue;
 +                hasMissingElements = true;
 +                return this;
              }
  
 -            // Handle the normal bounds
 -            ColumnDefinition column = columnDefs.get(elements.size() - 1 - 
offset);
 -            set.add(builder.buildBoundWith(elements, isStart, 
column.isReversedType() ? isOtherBoundInclusive : isInclusive));
 +            assert values.size() == 1;
 +            return addEachElementToAll(values.get(0));
          }
 -        return set.build();
 -    }
  
 -    public NavigableSet<Slice.Bound> buildBound(boolean isStart, boolean 
isInclusive)
 -    {
 -        built = true;
 -
 -        if (hasMissingElements)
 -            return BTreeSet.empty(comparator);
 +        public NavigableSet<Clustering> build()
 +        {
 +            built = true;
  
 -        CBuilder builder = CBuilder.create(comparator);
 +            if (hasMissingElements)
 +                return BTreeSet.empty(comparator);
  
 -        if (elementsList.isEmpty())
 -            return BTreeSet.of(comparator, builder.buildBound(isStart, 
isInclusive));
 +            return BTreeSet.of(comparator, size == 0 ? Clustering.EMPTY : 
Clustering.make(elements));
 +        }
  
 -        // Use a TreeSet to sort and eliminate duplicates
 -        BTreeSet.Builder<Slice.Bound> set = BTreeSet.builder(comparator);
++        @Override
++        public NavigableSet<Bound> buildBoundForSlice(boolean isStart,
++                                                      boolean isInclusive,
++                                                      boolean 
isOtherBoundInclusive,
++                                                      List<ColumnDefinition> 
columnDefs)
++        {
++            return buildBound(isStart, columnDefs.get(0).isReversedType() ? 
isOtherBoundInclusive : isInclusive);
++        }
+ 
 -        for (int i = 0, m = elementsList.size(); i < m; i++)
 +        public NavigableSet<Slice.Bound> buildBound(boolean isStart, boolean 
isInclusive)
          {
 -            List<ByteBuffer> elements = elementsList.get(i);
 -            set.add(builder.buildBoundWith(elements, isStart, isInclusive));
 +            built = true;
 +
 +            if (hasMissingElements)
 +                return BTreeSet.empty(comparator);
 +
 +            if (size == 0)
 +                return BTreeSet.of(comparator, isStart ? Slice.Bound.BOTTOM : 
Slice.Bound.TOP);
 +
 +            ByteBuffer[] newValues = size == elements.length
 +                                   ? elements
 +                                   : Arrays.copyOf(elements, size);
 +
 +            return BTreeSet.of(comparator, 
Slice.Bound.create(Slice.Bound.boundKind(isStart, isInclusive), newValues));
          }
 -        return set.build();
      }
  
      /**
 -     * Checks if some elements can still be added to the clusterings.
 -     *
 -     * @return <code>true</code> if it is possible to add more elements to 
the clusterings, <code>false</code> otherwise.
 +     * MultiCBuilder implementation actually supporting the creation of 
multiple clustering/bound.
       */
 -    public boolean hasRemaining()
 +    private static class MultiClusteringBuilder extends MultiCBuilder
      {
 -        return remainingCount() > 0;
 -    }
 +        /**
 +         * The elements of the clusterings
 +         */
 +        private final List<List<ByteBuffer>> elementsList = new ArrayList<>();
  
 -    private void checkUpdateable()
 -    {
 -        if (!hasRemaining() || built)
 -            throw new IllegalStateException("this builder cannot be updated 
anymore");
 +        public MultiClusteringBuilder(ClusteringComparator comparator)
 +        {
 +            super(comparator);
 +        }
 +
 +        public MultiCBuilder addElementToAll(ByteBuffer value)
 +        {
 +            checkUpdateable();
 +
 +            if (elementsList.isEmpty())
 +                elementsList.add(new ArrayList<ByteBuffer>());
 +
 +            if (value == null)
 +                containsNull = true;
 +            else if (value == ByteBufferUtil.UNSET_BYTE_BUFFER)
 +                containsUnset = true;
 +
 +            for (int i = 0, m = elementsList.size(); i < m; i++)
 +                elementsList.get(i).add(value);
 +
 +            size++;
 +            return this;
 +        }
 +
 +        public MultiCBuilder addEachElementToAll(List<ByteBuffer> values)
 +        {
 +            checkUpdateable();
 +
 +            if (elementsList.isEmpty())
 +                elementsList.add(new ArrayList<ByteBuffer>());
 +
 +            if (values.isEmpty())
 +            {
 +                hasMissingElements = true;
 +            }
 +            else
 +            {
 +                for (int i = 0, m = elementsList.size(); i < m; i++)
 +                {
 +                    List<ByteBuffer> oldComposite = elementsList.remove(0);
 +
 +                    for (int j = 0, n = values.size(); j < n; j++)
 +                    {
 +                        List<ByteBuffer> newComposite = new 
ArrayList<>(oldComposite);
 +                        elementsList.add(newComposite);
 +
 +                        ByteBuffer value = values.get(j);
 +
 +                        if (value == null)
 +                            containsNull = true;
 +                        if (value == ByteBufferUtil.UNSET_BYTE_BUFFER)
 +                            containsUnset = true;
 +
 +                        newComposite.add(values.get(j));
 +                    }
 +                }
 +            }
 +            size++;
 +            return this;
 +        }
 +
 +        public MultiCBuilder addAllElementsToAll(List<List<ByteBuffer>> 
values)
 +        {
 +            checkUpdateable();
 +
 +            if (elementsList.isEmpty())
 +                elementsList.add(new ArrayList<ByteBuffer>());
 +
 +            if (values.isEmpty())
 +            {
 +                hasMissingElements = true;
 +            }
 +            else
 +            {
 +                for (int i = 0, m = elementsList.size(); i < m; i++)
 +                {
 +                    List<ByteBuffer> oldComposite = elementsList.remove(0);
 +
 +                    for (int j = 0, n = values.size(); j < n; j++)
 +                    {
 +                        List<ByteBuffer> newComposite = new 
ArrayList<>(oldComposite);
 +                        elementsList.add(newComposite);
 +
 +                        List<ByteBuffer> value = values.get(j);
 +
-                         if (value.isEmpty())
-                             hasMissingElements = true;
- 
 +                        if (value.contains(null))
 +                            containsNull = true;
 +                        if (value.contains(ByteBufferUtil.UNSET_BYTE_BUFFER))
 +                            containsUnset = true;
 +
 +                        newComposite.addAll(value);
 +                    }
 +                }
 +                size += values.get(0).size();
 +            }
 +            return this;
 +        }
 +
 +        public NavigableSet<Clustering> build()
 +        {
 +            built = true;
 +
 +            if (hasMissingElements)
 +                return BTreeSet.empty(comparator);
 +
 +            CBuilder builder = CBuilder.create(comparator);
 +
 +            if (elementsList.isEmpty())
 +                return BTreeSet.of(builder.comparator(), builder.build());
 +
 +            BTreeSet.Builder<Clustering> set = 
BTreeSet.builder(builder.comparator());
 +            for (int i = 0, m = elementsList.size(); i < m; i++)
 +            {
 +                List<ByteBuffer> elements = elementsList.get(i);
 +                set.add(builder.buildWith(elements));
 +            }
 +            return set.build();
 +        }
 +
++        public NavigableSet<Slice.Bound> buildBoundForSlice(boolean isStart,
++                                                            boolean 
isInclusive,
++                                                            boolean 
isOtherBoundInclusive,
++                                                            
List<ColumnDefinition> columnDefs)
++        {
++            built = true;
++
++            if (hasMissingElements)
++                return BTreeSet.empty(comparator);
++
++            CBuilder builder = CBuilder.create(comparator);
++
++            if (elementsList.isEmpty())
++                return BTreeSet.of(comparator, builder.buildBound(isStart, 
isInclusive));
++
++            // Use a TreeSet to sort and eliminate duplicates
++            BTreeSet.Builder<Slice.Bound> set = BTreeSet.builder(comparator);
++
++            // The first column of the slice might not be the first 
clustering column (e.g. clustering_0 = ? AND (clustering_1, clustering_2) >= 
(?, ?)
++            int offset = columnDefs.get(0).position();
++
++            for (int i = 0, m = elementsList.size(); i < m; i++)
++            {
++                List<ByteBuffer> elements = elementsList.get(i);
++
++                // Handle the no bound case
++                if (elements.size() == offset)
++                {
++                    set.add(builder.buildBoundWith(elements, isStart, true));
++                    continue;
++                }
++
++                // In the case of mixed order columns, we will have some 
extra slices where the columns change directions.
++                // For example: if we have clustering_0 DESC and clustering_1 
ASC a slice like (clustering_0, clustering_1) > (1, 2)
++                // will produce 2 slices: [BOTTOM, 1) and (1.2, 1]
++                // So, the END bound will return 2 bounds with the same 
values 1
++                ColumnDefinition lastColumn = 
columnDefs.get(columnDefs.size() - 1);
++                if (elements.size() <= lastColumn.position() && i < m - 1 && 
elements.equals(elementsList.get(i + 1)))
++                {
++                    set.add(builder.buildBoundWith(elements, isStart, false));
++                    set.add(builder.buildBoundWith(elementsList.get(i++), 
isStart, true));
++                    continue;
++                }
++
++                // Handle the normal bounds
++                ColumnDefinition column = columnDefs.get(elements.size() - 1 
- offset);
++                set.add(builder.buildBoundWith(elements, isStart, 
column.isReversedType() ? isOtherBoundInclusive : isInclusive));
++            }
++            return set.build();
++        }
++
 +        public NavigableSet<Slice.Bound> buildBound(boolean isStart, boolean 
isInclusive)
 +        {
 +            built = true;
 +
 +            if (hasMissingElements)
 +                return BTreeSet.empty(comparator);
 +
 +            CBuilder builder = CBuilder.create(comparator);
 +
 +            if (elementsList.isEmpty())
 +                return BTreeSet.of(comparator, builder.buildBound(isStart, 
isInclusive));
 +
 +            // Use a TreeSet to sort and eliminate duplicates
 +            BTreeSet.Builder<Slice.Bound> set = BTreeSet.builder(comparator);
 +
 +            for (int i = 0, m = elementsList.size(); i < m; i++)
 +            {
 +                List<ByteBuffer> elements = elementsList.get(i);
 +                set.add(builder.buildBoundWith(elements, isStart, 
isInclusive));
 +            }
 +            return set.build();
 +        }
      }
  }

Reply via email to