You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by bl...@apache.org on 2016/07/04 12:45:13 UTC
[4/6] cassandra git commit: Merge branch cassandra-3.0 into
cassandra-3.9
Merge branch cassandra-3.0 into cassandra-3.9
Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/118f1a0d
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/118f1a0d
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/118f1a0d
Branch: refs/heads/trunk
Commit: 118f1a0d698eddedd70bcd72193bf3796219b9a7
Parents: c86b3e1 9244531
Author: Benjamin Lerer <b....@gmail.com>
Authored: Mon Jul 4 14:33:20 2016 +0200
Committer: Benjamin Lerer <b....@gmail.com>
Committed: Mon Jul 4 14:34:32 2016 +0200
----------------------------------------------------------------------
CHANGES.txt | 1 +
.../ClusteringColumnRestrictions.java | 20 ++------
.../restrictions/MultiColumnRestriction.java | 2 +-
.../SelectMultiColumnRelationTest.java | 27 ++++++++++
.../cql3/validation/operations/SelectTest.java | 54 ++++++++++++++++++++
5 files changed, 86 insertions(+), 18 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/118f1a0d/CHANGES.txt
----------------------------------------------------------------------
diff --cc CHANGES.txt
index 475365f,2df77e1..1a03b89
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@@ -5,34 -4,11 +5,35 @@@ Merged from 3.0
Merged from 2.2:
* MemoryUtil.getShort() should return an unsigned short also for architectures not supporting unaligned memory accesses (CASSANDRA-11973)
Merged from 2.1:
+ * Fix filtering on clustering columns when 2i is used (CASSANDRA-11907)
+ * Avoid stalling paxos when the paxos state expires (CASSANDRA-12043)
+ * Remove finished incoming streaming connections from MessagingService (CASSANDRA-11854)
-3.0.8
- * Fix potential race in schema during new table creation (CASSANDRA-12083)
+3.8
+ * Improve details in compaction log message (CASSANDRA-12080)
+ * Allow unset values in CQLSSTableWriter (CASSANDRA-11911)
+ * Chunk cache to request compressor-compatible buffers if pool space is exhausted (CASSANDRA-11993)
+ * Remove DatabaseDescriptor dependencies from SequentialWriter (CASSANDRA-11579)
+ * Move skip_stop_words filter before stemming (CASSANDRA-12078)
+ * Support seek() in EncryptedFileSegmentInputStream (CASSANDRA-11957)
+ * SSTable tools mishandling LocalPartitioner (CASSANDRA-12002)
+ * When SEPWorker assigned work, set thread name to match pool (CASSANDRA-11966)
+ * Add cross-DC latency metrics (CASSANDRA-11596)
+ * Allow terms in selection clause (CASSANDRA-10783)
+ * Add bind variables to trace (CASSANDRA-11719)
+ * Switch counter shards' clock to timestamps (CASSANDRA-9811)
+ * Introduce HdrHistogram and response/service/wait separation to stress tool (CASSANDRA-11853)
+ * entry-weighers in QueryProcessor should respect partitionKeyBindIndexes field (CASSANDRA-11718)
+ * Support older ant versions (CASSANDRA-11807)
+ * Estimate compressed on disk size when deciding if sstable size limit reached (CASSANDRA-11623)
+ * cassandra-stress profiles should support case sensitive schemas (CASSANDRA-11546)
+ * Remove DatabaseDescriptor dependency from FileUtils (CASSANDRA-11578)
+ * Faster streaming (CASSANDRA-9766)
+ * Add prepared query parameter to trace for "Execute CQL3 prepared query" session (CASSANDRA-11425)
+ * Add repaired percentage metric (CASSANDRA-11503)
+ * Add Change-Data-Capture (CASSANDRA-8844)
+Merged from 3.0:
* cqlsh: fix error handling in rare COPY FROM failure scenario (CASSANDRA-12070)
* Disable autocompaction during drain (CASSANDRA-11878)
* Add a metrics timer to MemtablePool and use it to track time spent blocked on memory in MemtableAllocator (CASSANDRA-11327)
http://git-wip-us.apache.org/repos/asf/cassandra/blob/118f1a0d/src/java/org/apache/cassandra/cql3/restrictions/ClusteringColumnRestrictions.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/restrictions/ClusteringColumnRestrictions.java
index 837ee13,0000000..dc349d9
mode 100644,000000..100644
--- a/src/java/org/apache/cassandra/cql3/restrictions/ClusteringColumnRestrictions.java
+++ b/src/java/org/apache/cassandra/cql3/restrictions/ClusteringColumnRestrictions.java
@@@ -1,229 -1,0 +1,215 @@@
+/*
+ * 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.cql3.restrictions;
+
+import java.util.*;
+
+import org.apache.cassandra.config.CFMetaData;
+import org.apache.cassandra.config.ColumnDefinition;
+import org.apache.cassandra.cql3.QueryOptions;
+import org.apache.cassandra.cql3.statements.Bound;
+import org.apache.cassandra.db.*;
+import org.apache.cassandra.db.filter.RowFilter;
+import org.apache.cassandra.exceptions.InvalidRequestException;
+import org.apache.cassandra.index.SecondaryIndexManager;
+import org.apache.cassandra.utils.btree.BTreeSet;
+
+import static org.apache.cassandra.cql3.statements.RequestValidations.checkFalse;
+import static org.apache.cassandra.cql3.statements.RequestValidations.invalidRequest;
+
+/**
+ * A set of restrictions on the clustering key.
+ */
+final class ClusteringColumnRestrictions extends RestrictionSetWrapper
+{
+ /**
+ * The composite type.
+ */
+ protected final ClusteringComparator comparator;
+
+ /**
+ * <code>true</code> if filtering is allowed for this restriction, <code>false</code> otherwise
+ */
+ private final boolean allowFiltering;
+
+ public ClusteringColumnRestrictions(CFMetaData cfm)
+ {
+ this(cfm, false);
+ }
+
+ public ClusteringColumnRestrictions(CFMetaData cfm, boolean allowFiltering)
+ {
+ this(cfm.comparator, new RestrictionSet(), allowFiltering);
+ }
+
+ private ClusteringColumnRestrictions(ClusteringComparator comparator,
+ RestrictionSet restrictionSet,
+ boolean allowFiltering)
+ {
+ super(restrictionSet);
+ this.comparator = comparator;
+ this.allowFiltering = allowFiltering;
+ }
+
+ public ClusteringColumnRestrictions mergeWith(Restriction restriction) throws InvalidRequestException
+ {
+ SingleRestriction newRestriction = (SingleRestriction) restriction;
+ RestrictionSet newRestrictionSet = restrictions.addRestriction(newRestriction);
+
+ if (!isEmpty() && !allowFiltering)
+ {
+ SingleRestriction lastRestriction = restrictions.lastRestriction();
+ ColumnDefinition lastRestrictionStart = lastRestriction.getFirstColumn();
+ ColumnDefinition newRestrictionStart = restriction.getFirstColumn();
+
+ checkFalse(lastRestriction.isSlice() && newRestrictionStart.position() > lastRestrictionStart.position(),
+ "Clustering column \"%s\" cannot be restricted (preceding column \"%s\" is restricted by a non-EQ relation)",
+ newRestrictionStart.name,
+ lastRestrictionStart.name);
+
+ if (newRestrictionStart.position() < lastRestrictionStart.position() && newRestriction.isSlice())
+ throw invalidRequest("PRIMARY KEY column \"%s\" cannot be restricted (preceding column \"%s\" is restricted by a non-EQ relation)",
+ restrictions.nextColumn(newRestrictionStart).name,
+ newRestrictionStart.name);
+ }
+
+ return new ClusteringColumnRestrictions(this.comparator, newRestrictionSet, allowFiltering);
+ }
+
+ private boolean hasMultiColumnSlice()
+ {
+ for (SingleRestriction restriction : restrictions)
+ {
+ if (restriction.isMultiColumn() && restriction.isSlice())
+ return true;
+ }
+ return false;
+ }
+
+ public NavigableSet<Clustering> valuesAsClustering(QueryOptions options) throws InvalidRequestException
+ {
+ MultiCBuilder builder = MultiCBuilder.create(comparator, hasIN());
+ for (SingleRestriction r : restrictions)
+ {
+ r.appendTo(builder, options);
+ if (builder.hasMissingElements())
+ break;
+ }
+ return builder.build();
+ }
+
+ public NavigableSet<ClusteringBound> boundsAsClustering(Bound bound, QueryOptions options) throws InvalidRequestException
+ {
+ MultiCBuilder builder = MultiCBuilder.create(comparator, hasIN() || hasMultiColumnSlice());
+ int keyPosition = 0;
+
+ for (SingleRestriction r : restrictions)
+ {
+ if (handleInFilter(r, keyPosition))
+ break;
+
+ if (r.isSlice())
+ {
+ r.appendBoundTo(builder, bound, options);
+ return builder.buildBoundForSlice(bound.isStart(),
+ r.isInclusive(bound),
+ r.isInclusive(bound.reverse()),
+ r.getColumnDefs());
+ }
+
+ r.appendBoundTo(builder, bound, options);
+
+ if (builder.hasMissingElements())
+ return BTreeSet.empty(comparator);
+
+ keyPosition = r.getLastColumn().position() + 1;
+ }
+
+ // Everything was an equal (or there was nothing)
+ return builder.buildBound(bound.isStart(), true);
+ }
+
+ /**
+ * Checks if any of the underlying restriction is a CONTAINS or CONTAINS KEY.
+ *
+ * @return <code>true</code> if any of the underlying restriction is a CONTAINS or CONTAINS KEY,
+ * <code>false</code> otherwise
+ */
+ public final boolean hasContains()
+ {
+ return restrictions.stream().anyMatch(SingleRestriction::isContains);
+ }
+
+ /**
+ * Checks if any of the underlying restriction is a slice restrictions.
+ *
+ * @return <code>true</code> if any of the underlying restriction is a slice restrictions,
+ * <code>false</code> otherwise
+ */
+ public final boolean hasSlice()
+ {
+ return restrictions.stream().anyMatch(SingleRestriction::isSlice);
+ }
+
+ /**
+ * Checks if underlying restrictions would require filtering
+ *
+ * @return <code>true</code> if any underlying restrictions require filtering, <code>false</code>
+ * otherwise
+ */
+ public final boolean needFiltering()
+ {
+ int position = 0;
- SingleRestriction slice = null;
++
+ for (SingleRestriction restriction : restrictions)
+ {
+ if (handleInFilter(restriction, position))
+ return true;
+
- if (slice != null && !slice.getFirstColumn().equals(restriction.getFirstColumn()))
- return true;
-
- if (slice == null && restriction.isSlice())
- slice = restriction;
- else
++ if (!restriction.isSlice())
+ position = restriction.getLastColumn().position() + 1;
+ }
+ return hasContains();
+ }
+
+ @Override
+ public void addRowFilterTo(RowFilter filter,
+ SecondaryIndexManager indexManager,
+ QueryOptions options) throws InvalidRequestException
+ {
+ int position = 0;
+
- SingleRestriction slice = null;
+ for (SingleRestriction restriction : restrictions)
+ {
+ // We ignore all the clustering columns that can be handled by slices.
+ if (handleInFilter(restriction, position) || restriction.hasSupportingIndex(indexManager))
+ {
+ restriction.addRowFilterTo(filter, indexManager, options);
+ continue;
+ }
+
- if (slice != null && !slice.getFirstColumn().equals(restriction.getFirstColumn()))
- {
- restriction.addRowFilterTo(filter, indexManager, options);
- continue;
- }
-
- if (slice == null && restriction.isSlice())
- slice = restriction;
- else
++ if (!restriction.isSlice())
+ position = restriction.getLastColumn().position() + 1;
+ }
+ }
+
+ private boolean handleInFilter(SingleRestriction restriction, int index) {
+ return restriction.isContains() || restriction.isLIKE() || index != restriction.getFirstColumn().position();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/118f1a0d/src/java/org/apache/cassandra/cql3/restrictions/MultiColumnRestriction.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/restrictions/MultiColumnRestriction.java
index 012b319,9d33bb1..e5e3bc8
--- a/src/java/org/apache/cassandra/cql3/restrictions/MultiColumnRestriction.java
+++ b/src/java/org/apache/cassandra/cql3/restrictions/MultiColumnRestriction.java
@@@ -474,9 -475,9 +474,9 @@@ public abstract class MultiColumnRestri
@Override
public final void addRowFilterTo(RowFilter filter,
SecondaryIndexManager indexManager,
- QueryOptions options) throws InvalidRequestException
+ QueryOptions options)
{
- throw invalidRequest("Slice restrictions are not supported on indexed columns");
+ throw invalidRequest("Multi-column slice restrictions cannot be used for filtering.");
}
@Override
http://git-wip-us.apache.org/repos/asf/cassandra/blob/118f1a0d/test/unit/org/apache/cassandra/cql3/validation/operations/SelectMultiColumnRelationTest.java
----------------------------------------------------------------------
diff --cc test/unit/org/apache/cassandra/cql3/validation/operations/SelectMultiColumnRelationTest.java
index 1239b7a,ce74fe2..7f43c6b
--- a/test/unit/org/apache/cassandra/cql3/validation/operations/SelectMultiColumnRelationTest.java
+++ b/test/unit/org/apache/cassandra/cql3/validation/operations/SelectMultiColumnRelationTest.java
@@@ -885,19 -885,46 +885,46 @@@ public class SelectMultiColumnRelationT
}
@Test
+ public void testMultipleClusteringWithIndexAndValueOver64K() throws Throwable
+ {
+ createTable("CREATE TABLE %s (a int, b blob, c int, d int, PRIMARY KEY (a, b, c))");
+ createIndex("CREATE INDEX ON %s (b)");
+
+ execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, ByteBufferUtil.bytes(1), 0, 0);
+ execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, ByteBufferUtil.bytes(2), 1, 0);
+
+ assertInvalidMessage("Index expression values may not be larger than 64K",
+ "SELECT * FROM %s WHERE (b, c) = (?, ?) AND d = ? ALLOW FILTERING", TOO_BIG, 1, 2);
+ }
+
+ @Test
+ public void testMultiColumnRestrictionsWithIndex() throws Throwable
+ {
+ createTable("CREATE TABLE %s (a int, b int, c int, d int, e int, v int, PRIMARY KEY (a, b, c, d, e))");
+ createIndex("CREATE INDEX ON %s (v)");
+ for (int i = 1; i <= 5; i++)
+ {
+ execute("INSERT INTO %s (a,b,c,d,e,v) VALUES (?,?,?,?,?,?)", 0, i, 0, 0, 0, 0);
+ execute("INSERT INTO %s (a,b,c,d,e,v) VALUES (?,?,?,?,?,?)", 0, i, i, 0, 0, 0);
+ execute("INSERT INTO %s (a,b,c,d,e,v) VALUES (?,?,?,?,?,?)", 0, i, i, i, 0, 0);
+ execute("INSERT INTO %s (a,b,c,d,e,v) VALUES (?,?,?,?,?,?)", 0, i, i, i, i, 0);
+ execute("INSERT INTO %s (a,b,c,d,e,v) VALUES (?,?,?,?,?,?)", 0, i, i, i, i, i);
+ }
+
+ String errorMsg = "Multi-column slice restrictions cannot be used for filtering.";
+ assertInvalidMessage(errorMsg,
+ "SELECT * FROM %s WHERE a = 0 AND (c,d) < (2,2) AND v = 0 ALLOW FILTERING");
+ assertInvalidMessage(errorMsg,
+ "SELECT * FROM %s WHERE a = 0 AND (d,e) < (2,2) AND b = 1 AND v = 0 ALLOW FILTERING");
+ assertInvalidMessage(errorMsg,
+ "SELECT * FROM %s WHERE a = 0 AND b = 1 AND (d,e) < (2,2) AND v = 0 ALLOW FILTERING");
+ assertInvalidMessage(errorMsg,
+ "SELECT * FROM %s WHERE a = 0 AND b > 1 AND (d,e) < (2,2) AND v = 0 ALLOW FILTERING");
+ assertInvalidMessage(errorMsg,
+ "SELECT * FROM %s WHERE a = 0 AND (b,c) > (1,0) AND (d,e) < (2,2) AND v = 0 ALLOW FILTERING");
+ }
+
+ @Test
- public void testMultipleClusteringWithIndexAndValueOver64K() throws Throwable
- {
- createTable("CREATE TABLE %s (a int, b blob, c int, d int, PRIMARY KEY (a, b, c))");
- createIndex("CREATE INDEX ON %s (b)");
-
- execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, ByteBufferUtil.bytes(1), 0, 0);
- execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, ByteBufferUtil.bytes(2), 1, 0);
-
- assertInvalidMessage("Index expression values may not be larger than 64K",
- "SELECT * FROM %s WHERE (b, c) = (?, ?) AND d = ? ALLOW FILTERING", TOO_BIG, 1, 2);
- }
-
- @Test
public void testMultiplePartitionKeyAndMultiClusteringWithIndex() throws Throwable
{
createTable("CREATE TABLE %s (a int, b int, c int, d int, e int, f int, PRIMARY KEY ((a, b), c, d, e))");
http://git-wip-us.apache.org/repos/asf/cassandra/blob/118f1a0d/test/unit/org/apache/cassandra/cql3/validation/operations/SelectTest.java
----------------------------------------------------------------------
diff --cc test/unit/org/apache/cassandra/cql3/validation/operations/SelectTest.java
index dde87d8,1b6fe9b..9a1493b
--- a/test/unit/org/apache/cassandra/cql3/validation/operations/SelectTest.java
+++ b/test/unit/org/apache/cassandra/cql3/validation/operations/SelectTest.java
@@@ -2937,4 -2533,47 +2937,58 @@@ public class SelectTest extends CQLTest
row("a", 3, 5));
}
}
+
+ @Test
+ public void testFilteringWithSecondaryIndex() throws Throwable
+ {
+ createTable("CREATE TABLE %s (pk int, " +
+ "c1 int, " +
+ "c2 int, " +
+ "c3 int, " +
+ "v int, " +
+ "PRIMARY KEY (pk, c1, c2, c3))");
+ createIndex("CREATE INDEX v_idx_1 ON %s (v);");
+
+ for (int i = 1; i <= 5; i++)
+ {
+ execute("INSERT INTO %s (pk, c1, c2, c3, v) VALUES (?, ?, ?, ?, ?)", 1, 1, 1, 1, i);
+ execute("INSERT INTO %s (pk, c1, c2, c3, v) VALUES (?, ?, ?, ?, ?)", 1, 1, 1, i, i);
+ execute("INSERT INTO %s (pk, c1, c2, c3, v) VALUES (?, ?, ?, ?, ?)", 1, 1, i, i, i);
+ execute("INSERT INTO %s (pk, c1, c2, c3, v) VALUES (?, ?, ?, ?, ?)", 1, i, i, i, i);
+ }
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = 1 AND c1 > 0 AND c1 < 5 AND c2 = 1 AND v = 3 ALLOW FILTERING;"),
+ row(1, 1, 1, 3, 3));
+
+ assertEmpty(execute("SELECT * FROM %s WHERE pk = 1 AND c1 > 1 AND c1 < 5 AND c2 = 1 AND v = 3 ALLOW FILTERING;"));
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = 1 AND c1 > 1 AND c2 > 2 AND c3 > 2 AND v = 3 ALLOW FILTERING;"),
+ row(1, 3, 3, 3, 3));
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = 1 AND c1 > 1 AND c2 > 2 AND c3 = 3 AND v = 3 ALLOW FILTERING;"),
+ row(1, 3, 3, 3, 3));
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = 1 AND c1 IN(0,1,2) AND c2 = 1 AND v = 3 ALLOW FILTERING;"),
+ row(1, 1, 1, 3, 3));
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = 1 AND c1 IN(0,1,2) AND c2 = 1 AND v = 3"),
+ row(1, 1, 1, 3, 3));
++ }
+
- assertInvalidMessage("Clustering column \"c2\" cannot be restricted (preceding column \"c1\" is restricted by a non-EQ relation)",
- "SELECT * FROM %s WHERE pk = 1 AND c1 > 0 AND c1 < 5 AND c2 = 1 ALLOW FILTERING;");
++ @Test
++ public void testIndexQueryWithCompositePartitionKey() throws Throwable
++ {
++ createTable("CREATE TABLE %s (p1 int, p2 int, v int, PRIMARY KEY ((p1, p2)))");
++ assertInvalidMessage("Partition key parts: p2 must be restricted as other parts are",
++ "SELECT * FROM %s WHERE p1 = 1 AND v = 3 ALLOW FILTERING");
++ createIndex("CREATE INDEX ON %s(v)");
+
- assertInvalidMessage("PRIMARY KEY column \"c2\" cannot be restricted as preceding column \"c1\" is not restricted",
- "SELECT * FROM %s WHERE pk = 1 AND c2 = 1 ALLOW FILTERING;");
++ execute("INSERT INTO %s(p1, p2, v) values (?, ?, ?)", 1, 1, 3);
++ execute("INSERT INTO %s(p1, p2, v) values (?, ?, ?)", 1, 2, 3);
++ execute("INSERT INTO %s(p1, p2, v) values (?, ?, ?)", 2, 1, 3);
++
++ assertRows(execute("SELECT * FROM %s WHERE p1 = 1 AND v = 3 ALLOW FILTERING"),
++ row(1, 2, 3),
++ row(1, 1, 3));
+ }
}