Repository: cassandra Updated Branches: refs/heads/cassandra-2.1 e3d5b98e4 -> b407ebc89
Tolerate min/max cell names of different lengths Patch and review by Jonathan Ellis and Tyler Hobbs for CASSANDRA-7651 Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/46326737 Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/46326737 Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/46326737 Branch: refs/heads/cassandra-2.1 Commit: 46326737288ae1d4d05a80d7074126e0502465e8 Parents: abe8590 Author: Tyler Hobbs <ty...@datastax.com> Authored: Thu Jul 31 17:31:10 2014 -0500 Committer: Tyler Hobbs <ty...@datastax.com> Committed: Thu Jul 31 17:31:10 2014 -0500 ---------------------------------------------------------------------- CHANGES.txt | 1 + .../apache/cassandra/db/filter/ColumnSlice.java | 21 ++++++- .../cassandra/db/filter/SliceQueryFilter.java | 1 - .../cassandra/db/filter/ColumnSliceTest.java | 66 ++++++++++++++++++++ 4 files changed, 85 insertions(+), 4 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cassandra/blob/46326737/CHANGES.txt ---------------------------------------------------------------------- diff --git a/CHANGES.txt b/CHANGES.txt index 378e812..fcccccd 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,4 +1,5 @@ 2.1.0-final + * Tolerate min/max cell names of different lengths (CASSANDRA-7651) * Filter cached results correctly (CASSANDRA-7636) * Fix tracing on the new SEPExecutor (CASSANDRA-7644) * Remove shuffle and taketoken (CASSANDRA-7601) http://git-wip-us.apache.org/repos/asf/cassandra/blob/46326737/src/java/org/apache/cassandra/db/filter/ColumnSlice.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/db/filter/ColumnSlice.java b/src/java/org/apache/cassandra/db/filter/ColumnSlice.java index bca4743..b9b248d 100644 --- a/src/java/org/apache/cassandra/db/filter/ColumnSlice.java +++ b/src/java/org/apache/cassandra/db/filter/ColumnSlice.java @@ -65,8 +65,6 @@ public class ColumnSlice public boolean intersects(List<ByteBuffer> minCellNames, List<ByteBuffer> maxCellNames, CellNameType comparator, boolean reversed) { - assert minCellNames.size() == maxCellNames.size(); - Composite sStart = reversed ? finish : start; Composite sEnd = reversed ? start : finish; @@ -76,7 +74,7 @@ public class ColumnSlice // We could safely return true here, but there's a minor optimization: if the first component is restricted // to a single value, we can check that the second component falls within the min/max for that component // (and repeat for all components). - for (int i = 0; i < minCellNames.size(); i++) + for (int i = 0; i < minCellNames.size() && i < maxCellNames.size(); i++) { AbstractType<?> t = comparator.subtype(i); ByteBuffer s = i < sStart.size() ? sStart.get(i) : ByteBufferUtil.EMPTY_BYTE_BUFFER; @@ -101,12 +99,29 @@ public class ColumnSlice for (int i = 0; i < sstableBounds.size(); i++) { if (i >= sliceBounds.size()) + { + // When isSliceStart is true, we're comparing the end of the slice against the min cell name for the sstable, + // so the slice is something like [(1, 0), (1, 0)], and the sstable max is something like (1, 0, 1). + // We want to return -1 (slice start is smaller than max column name) so that we say the slice intersects. + // The opposite is true when dealing with the end slice. For example, with the same slice and a min + // cell name of (1, 0, 1), we want to return 1 (slice end is bigger than min column name). return isSliceStart ? -1 : 1; + } int comparison = comparator.subtype(i).compare(sliceBounds.get(i), sstableBounds.get(i)); if (comparison != 0) return comparison; } + + // the slice bound and sstable bound have been equal in all components so far + if (sliceBounds.size() > sstableBounds.size()) + { + // We have the opposite situation from the one described above. With a slice of [(1, 0), (1, 0)], + // and a min/max cell name of (1), we want to say the slice start is smaller than the max and the slice + // end is larger than the min. + return isSliceStart ? -1 : 1; + } + return 0; } http://git-wip-us.apache.org/repos/asf/cassandra/blob/46326737/src/java/org/apache/cassandra/db/filter/SliceQueryFilter.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/db/filter/SliceQueryFilter.java b/src/java/org/apache/cassandra/db/filter/SliceQueryFilter.java index e24f68b..13c0bd0 100644 --- a/src/java/org/apache/cassandra/db/filter/SliceQueryFilter.java +++ b/src/java/org/apache/cassandra/db/filter/SliceQueryFilter.java @@ -344,7 +344,6 @@ public class SliceQueryFilter implements IDiskAtomFilter { List<ByteBuffer> minColumnNames = sstable.getSSTableMetadata().minColumnNames; List<ByteBuffer> maxColumnNames = sstable.getSSTableMetadata().maxColumnNames; - assert minColumnNames.size() == maxColumnNames.size(); CellNameType comparator = sstable.metadata.comparator; if (minColumnNames.isEmpty() || maxColumnNames.isEmpty()) http://git-wip-us.apache.org/repos/asf/cassandra/blob/46326737/test/unit/org/apache/cassandra/db/filter/ColumnSliceTest.java ---------------------------------------------------------------------- diff --git a/test/unit/org/apache/cassandra/db/filter/ColumnSliceTest.java b/test/unit/org/apache/cassandra/db/filter/ColumnSliceTest.java index 2dc3744..25fb942 100644 --- a/test/unit/org/apache/cassandra/db/filter/ColumnSliceTest.java +++ b/test/unit/org/apache/cassandra/db/filter/ColumnSliceTest.java @@ -267,6 +267,33 @@ public class ColumnSliceTest slice = new ColumnSlice(composite(1, 1, 2), composite(1, 1, 3)); assertFalse(slice.intersects(columnNames(1, 1, 0), columnNames(2, 2, 1), nameType, false)); + // empty min/max column names + slice = new ColumnSlice(composite(), composite()); + assertTrue(slice.intersects(columnNames(), columnNames(), nameType, false)); + + slice = new ColumnSlice(composite(1), composite()); + assertTrue(slice.intersects(columnNames(), columnNames(), nameType, false)); + + slice = new ColumnSlice(composite(), composite(1)); + assertTrue(slice.intersects(columnNames(), columnNames(), nameType, false)); + + slice = new ColumnSlice(composite(1), composite(1)); + assertTrue(slice.intersects(columnNames(), columnNames(), nameType, false)); + + slice = new ColumnSlice(composite(), composite()); + assertTrue(slice.intersects(columnNames(), columnNames(1), nameType, false)); + + slice = new ColumnSlice(composite(), composite(1)); + assertTrue(slice.intersects(columnNames(), columnNames(1), nameType, false)); + + slice = new ColumnSlice(composite(), composite(1)); + assertTrue(slice.intersects(columnNames(), columnNames(2), nameType, false)); + + slice = new ColumnSlice(composite(), composite(2)); + assertTrue(slice.intersects(columnNames(), columnNames(1), nameType, false)); + + slice = new ColumnSlice(composite(2), composite(3)); + assertFalse(slice.intersects(columnNames(), columnNames(1), nameType, false)); // basic check on reversed slices slice = new ColumnSlice(composite(1, 0, 0), composite(0, 0, 0)); @@ -280,6 +307,45 @@ public class ColumnSliceTest } @Test + public void testDifferentMinMaxLengths() + { + List<AbstractType<?>> types = new ArrayList<>(); + types.add(Int32Type.instance); + types.add(Int32Type.instance); + types.add(Int32Type.instance); + CompoundDenseCellNameType nameType = new CompoundDenseCellNameType(types); + + // slice does intersect + ColumnSlice slice = new ColumnSlice(composite(), composite()); + assertTrue(slice.intersects(columnNames(), columnNames(1), nameType, false)); + + slice = new ColumnSlice(composite(), composite()); + assertTrue(slice.intersects(columnNames(1), columnNames(1, 2), nameType, false)); + + slice = new ColumnSlice(composite(), composite(1)); + assertTrue(slice.intersects(columnNames(), columnNames(1), nameType, false)); + + slice = new ColumnSlice(composite(1), composite()); + assertTrue(slice.intersects(columnNames(), columnNames(1), nameType, false)); + + slice = new ColumnSlice(composite(1), composite(1)); + assertTrue(slice.intersects(columnNames(), columnNames(1), nameType, false)); + + slice = new ColumnSlice(composite(0), composite(1, 2, 3)); + assertTrue(slice.intersects(columnNames(), columnNames(1), nameType, false)); + + slice = new ColumnSlice(composite(1, 2, 3), composite(2)); + assertTrue(slice.intersects(columnNames(), columnNames(1), nameType, false)); + + // slice does not intersect + slice = new ColumnSlice(composite(2), composite(3, 4, 5)); + assertFalse(slice.intersects(columnNames(), columnNames(1), nameType, false)); + + slice = new ColumnSlice(composite(0), composite(0, 1, 2)); + assertFalse(slice.intersects(columnNames(1), columnNames(1, 2), nameType, false)); + } + + @Test public void testDeoverlapSlices() { ColumnSlice[] slices;