Merge branch 'cassandra-3.11' into trunk
Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/de60cf07 Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/de60cf07 Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/de60cf07 Branch: refs/heads/trunk Commit: de60cf0759e9721ddd1aab725c511a8f910cf415 Parents: 2842716 99196cb Author: Jeff Jirsa <jji...@apple.com> Authored: Mon Jul 31 15:30:10 2017 -0700 Committer: Jeff Jirsa <jji...@apple.com> Committed: Mon Jul 31 15:30:54 2017 -0700 ---------------------------------------------------------------------- CHANGES.txt | 1 + .../cql3/selection/ResultSetBuilder.java | 6 ++++ .../cql3/validation/entities/TimestampTest.java | 30 ++++++++++++++++++++ .../cql3/validation/operations/SelectTest.java | 29 +++++++++++++++++++ 4 files changed, 66 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cassandra/blob/de60cf07/CHANGES.txt ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cassandra/blob/de60cf07/src/java/org/apache/cassandra/cql3/selection/ResultSetBuilder.java ---------------------------------------------------------------------- diff --cc src/java/org/apache/cassandra/cql3/selection/ResultSetBuilder.java index d179f93,0000000..9b7abe1 mode 100644,000000..100644 --- a/src/java/org/apache/cassandra/cql3/selection/ResultSetBuilder.java +++ b/src/java/org/apache/cassandra/cql3/selection/ResultSetBuilder.java @@@ -1,165 -1,0 +1,171 @@@ +/* + * 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.selection; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.apache.cassandra.cql3.ResultSet; +import org.apache.cassandra.cql3.ResultSet.ResultMetadata; +import org.apache.cassandra.cql3.selection.Selection.Selectors; +import org.apache.cassandra.db.Clustering; +import org.apache.cassandra.db.DecoratedKey; +import org.apache.cassandra.db.aggregation.GroupMaker; +import org.apache.cassandra.db.context.CounterContext; +import org.apache.cassandra.db.rows.Cell; +import org.apache.cassandra.utils.ByteBufferUtil; + +public final class ResultSetBuilder +{ + private final ResultSet resultSet; + + /** + * As multiple thread can access a <code>Selection</code> instance each <code>ResultSetBuilder</code> will use + * its own <code>Selectors</code> instance. + */ + private final Selectors selectors; + + /** + * The <code>GroupMaker</code> used to build the aggregates. + */ + private final GroupMaker groupMaker; + + /* + * We'll build CQL3 row one by one. + * The currentRow is the values for the (CQL3) columns we've fetched. + * We also collect timestamps and ttls for the case where the writetime and + * ttl functions are used. Note that we might collect timestamp and/or ttls + * we don't care about, but since the array below are allocated just once, + * it doesn't matter performance wise. + */ + List<ByteBuffer> current; + final long[] timestamps; + final int[] ttls; + + public ResultSetBuilder(ResultMetadata metadata, Selectors selectors) + { + this(metadata, selectors, null); + } + + public ResultSetBuilder(ResultMetadata metadata, Selectors selectors, GroupMaker groupMaker) + { + this.resultSet = new ResultSet(metadata.copy(), new ArrayList<List<ByteBuffer>>()); + this.selectors = selectors; + this.groupMaker = groupMaker; + this.timestamps = selectors.collectTimestamps() ? new long[selectors.numberOfFetchedColumns()] : null; + this.ttls = selectors.collectTTLs() ? new int[selectors.numberOfFetchedColumns()] : null; + + // We use MIN_VALUE to indicate no timestamp and -1 for no ttl + if (timestamps != null) + Arrays.fill(timestamps, Long.MIN_VALUE); + if (ttls != null) + Arrays.fill(ttls, -1); + } + + public void add(ByteBuffer v) + { + current.add(v); + } + + public void add(Cell c, int nowInSec) + { + if (c == null) + { + current.add(null); + return; + } + + current.add(value(c)); + + if (timestamps != null) + timestamps[current.size() - 1] = c.timestamp(); + + if (ttls != null) + ttls[current.size() - 1] = remainingTTL(c, nowInSec); + } + + private int remainingTTL(Cell c, int nowInSec) + { + if (!c.isExpiring()) + return -1; + + int remaining = c.localDeletionTime() - nowInSec; + return remaining >= 0 ? remaining : -1; + } + + private ByteBuffer value(Cell c) + { + return c.isCounterCell() + ? ByteBufferUtil.bytes(CounterContext.instance().total(c.value())) + : c.value(); + } + + /** + * Notifies this <code>Builder</code> that a new row is being processed. + * + * @param partitionKey the partition key of the new row + * @param clustering the clustering of the new row + */ + public void newRow(DecoratedKey partitionKey, Clustering clustering) + { + // The groupMaker needs to be called for each row + boolean isNewAggregate = groupMaker == null || groupMaker.isNewGroup(partitionKey, clustering); + if (current != null) + { + selectors.addInputRow(this); + if (isNewAggregate) + { + resultSet.addRow(getOutputRow()); + selectors.reset(); + } + } + current = new ArrayList<>(selectors.numberOfFetchedColumns()); ++ ++ // Timestamps and TTLs are arrays per row, we must null them out between rows ++ if (timestamps != null) ++ Arrays.fill(timestamps, Long.MIN_VALUE); ++ if (ttls != null) ++ Arrays.fill(ttls, -1); + } + + /** + * Builds the <code>ResultSet</code> + */ + public ResultSet build() + { + if (current != null) + { + selectors.addInputRow(this); + resultSet.addRow(getOutputRow()); + selectors.reset(); + current = null; + } + + // For aggregates we need to return a row even it no records have been found + if (resultSet.isEmpty() && groupMaker != null && groupMaker.returnAtLeastOneRow()) + resultSet.addRow(getOutputRow()); + return resultSet; + } + + private List<ByteBuffer> getOutputRow() + { + return selectors.getOutputRow(); + } +} http://git-wip-us.apache.org/repos/asf/cassandra/blob/de60cf07/test/unit/org/apache/cassandra/cql3/validation/entities/TimestampTest.java ---------------------------------------------------------------------- diff --cc test/unit/org/apache/cassandra/cql3/validation/entities/TimestampTest.java index 3e70cd0,b41163c..985a5e0 --- a/test/unit/org/apache/cassandra/cql3/validation/entities/TimestampTest.java +++ b/test/unit/org/apache/cassandra/cql3/validation/entities/TimestampTest.java @@@ -152,4 -152,33 +152,34 @@@ public class TimestampTest extends CQLT execute("INSERT INTO %s (k, i) VALUES (1, 1) USING TIMESTAMP ?", unset()); // treat as 'now' } + @Test + public void testTimestampsOnUnsetColumns() throws Throwable + { + createTable("CREATE TABLE %s (k int PRIMARY KEY, i int)"); + execute("INSERT INTO %s (k, i) VALUES (1, 1) USING TIMESTAMP 1;"); + execute("INSERT INTO %s (k) VALUES (2) USING TIMESTAMP 2;"); + execute("INSERT INTO %s (k, i) VALUES (3, 3) USING TIMESTAMP 1;"); + assertRows(execute("SELECT k, i, writetime(i) FROM %s "), + row(1, 1, 1L), + row(2, null, null), + row(3, 3, 1L)); + } + + @Test + public void testTimestampsOnUnsetColumnsWide() throws Throwable + { + createTable("CREATE TABLE %s (k int , c int, i int, PRIMARY KEY (k, c))"); + execute("INSERT INTO %s (k, c, i) VALUES (1, 1, 1) USING TIMESTAMP 1;"); + execute("INSERT INTO %s (k, c) VALUES (1, 2) USING TIMESTAMP 1;"); + execute("INSERT INTO %s (k, c, i) VALUES (1, 3, 1) USING TIMESTAMP 1;"); + execute("INSERT INTO %s (k, c) VALUES (2, 2) USING TIMESTAMP 2;"); + execute("INSERT INTO %s (k, c, i) VALUES (3, 3, 3) USING TIMESTAMP 1;"); + assertRows(execute("SELECT k, c, i, writetime(i) FROM %s "), + row(1, 1, 1, 1L), + row(1, 2, null, null), + row(1, 3, 1, 1L), + row(2, 2, null, null), + row(3, 3, 3, 1L)); + } ++ } http://git-wip-us.apache.org/repos/asf/cassandra/blob/de60cf07/test/unit/org/apache/cassandra/cql3/validation/operations/SelectTest.java ---------------------------------------------------------------------- diff --cc test/unit/org/apache/cassandra/cql3/validation/operations/SelectTest.java index c0a8a9c,7c6c589..54f11ff --- a/test/unit/org/apache/cassandra/cql3/validation/operations/SelectTest.java +++ b/test/unit/org/apache/cassandra/cql3/validation/operations/SelectTest.java @@@ -4747,4 -4738,32 +4747,33 @@@ public class SelectTest extends CQLTest assertRows(execute("SELECT k, v FROM %s WHERE k = 0 AND m CONTAINS KEY 'c' ALLOW FILTERING"), row(0, 2)); }); } + + @Test + public void testMixedTTLOnColumns() throws Throwable + { + createTable("CREATE TABLE %s (k int PRIMARY KEY, i int)"); + execute("INSERT INTO %s (k) VALUES (2);"); + execute("INSERT INTO %s (k, i) VALUES (1, 1) USING TTL 100;"); + execute("INSERT INTO %s (k, i) VALUES (3, 3) USING TTL 100;"); + assertRows(execute("SELECT k, i, TTL(i) FROM %s "), + row(1, 1, 100), row(2, null, null), row(3, 3, 100)); + } + + @Test + public void testMixedTTLOnColumnsWide() throws Throwable + { + createTable("CREATE TABLE %s (k int, c int, i int, PRIMARY KEY (k, c))"); + execute("INSERT INTO %s (k, c) VALUES (2, 2);"); + execute("INSERT INTO %s (k, c, i) VALUES (1, 1, 1) USING TTL 100;"); + execute("INSERT INTO %s (k, c) VALUES (1, 2) ;"); + execute("INSERT INTO %s (k, c, i) VALUES (1, 3, 3) USING TTL 100;"); + execute("INSERT INTO %s (k, c, i) VALUES (3, 3, 3) USING TTL 100;"); + assertRows(execute("SELECT k, c, i, TTL(i) FROM %s "), + row(1, 1, 1, 100), + row(1, 2, null, null), + row(1, 3, 3, 100), + row(2, 2, null, null), + row(3, 3, 3, 100)); + } ++ } --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@cassandra.apache.org For additional commands, e-mail: commits-h...@cassandra.apache.org