Clarify ClusteringPrefix hierarchy Patch by Branimir Lambov; reviewed by Sylvain Lebresne for CASSANDRA-11213
Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/2cc26eba Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/2cc26eba Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/2cc26eba Branch: refs/heads/trunk Commit: 2cc26eba7a742eb23e95b027bc611c924c233e1e Parents: 94ca769 Author: Branimir Lambov <[email protected]> Authored: Wed Apr 6 11:47:23 2016 +0300 Committer: Sylvain Lebresne <[email protected]> Committed: Thu Apr 28 14:32:36 2016 +0200 ---------------------------------------------------------------------- CHANGES.txt | 1 + .../ClusteringColumnRestrictions.java | 2 +- .../restrictions/StatementRestrictions.java | 2 +- .../cql3/statements/ModificationStatement.java | 10 +- .../cql3/statements/SelectStatement.java | 16 +- .../db/AbstractReadCommandBuilder.java | 16 +- src/java/org/apache/cassandra/db/CBuilder.java | 30 +- .../apache/cassandra/db/ClusteringBound.java | 151 ++++++++++ .../cassandra/db/ClusteringBoundOrBoundary.java | 163 +++++++++++ .../apache/cassandra/db/ClusteringBoundary.java | 45 +++ .../apache/cassandra/db/ClusteringPrefix.java | 30 +- .../org/apache/cassandra/db/LegacyLayout.java | 42 +-- .../org/apache/cassandra/db/MultiCBuilder.java | 37 ++- .../cassandra/db/MutableDeletionInfo.java | 4 +- .../org/apache/cassandra/db/RangeTombstone.java | 142 ---------- .../apache/cassandra/db/RangeTombstoneList.java | 56 ++-- .../org/apache/cassandra/db/ReadCommand.java | 10 +- .../org/apache/cassandra/db/Serializers.java | 8 +- src/java/org/apache/cassandra/db/Slice.java | 278 ++----------------- src/java/org/apache/cassandra/db/Slices.java | 10 +- .../cassandra/db/UnfilteredDeserializer.java | 8 +- .../columniterator/AbstractSSTableIterator.java | 6 +- .../db/columniterator/SSTableIterator.java | 8 +- .../columniterator/SSTableReversedIterator.java | 6 +- .../db/partitions/AbstractBTreePartition.java | 4 +- .../db/rows/AbstractRangeTombstoneMarker.java | 12 +- .../db/rows/RangeTombstoneBoundMarker.java | 22 +- .../db/rows/RangeTombstoneBoundaryMarker.java | 20 +- .../cassandra/db/rows/RangeTombstoneMarker.java | 9 +- .../db/rows/RowAndDeletionMergeIterator.java | 4 +- .../UnfilteredRowIteratorWithLowerBound.java | 15 +- .../cassandra/db/rows/UnfilteredSerializer.java | 14 +- .../index/internal/CassandraIndexSearcher.java | 10 +- .../apache/cassandra/service/DataResolver.java | 6 +- .../cassandra/thrift/CassandraServer.java | 10 +- .../apache/cassandra/tools/JsonTransformer.java | 8 +- .../cql3/TombstonesWithIndexedSSTableTest.java | 1 - .../ClusteringColumnRestrictionsTest.java | 64 ++--- .../org/apache/cassandra/db/KeyspaceTest.java | 12 +- .../cassandra/db/RangeTombstoneListTest.java | 16 +- .../apache/cassandra/db/RangeTombstoneTest.java | 4 +- test/unit/org/apache/cassandra/db/RowTest.java | 10 +- .../db/SinglePartitionSliceCommandTest.java | 2 +- .../apache/cassandra/db/filter/SliceTest.java | 4 +- .../partition/PartitionImplementationTest.java | 3 +- .../rows/RowAndDeletionMergeIteratorTest.java | 39 ++- .../rows/UnfilteredRowIteratorsMergeTest.java | 18 +- 47 files changed, 680 insertions(+), 708 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cassandra/blob/2cc26eba/CHANGES.txt ---------------------------------------------------------------------- diff --git a/CHANGES.txt b/CHANGES.txt index f78ea90..78518b6 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,4 +1,5 @@ 3.6 + * Clarify ClusteringPrefix hierarchy (CASSANDRA-11213) * Always perform collision check before joining ring (CASSANDRA-10134) * SSTableWriter output discrepancy (CASSANDRA-11646) * Fix potential timeout in NativeTransportService.testConcurrentDestroys (CASSANDRA-10756) http://git-wip-us.apache.org/repos/asf/cassandra/blob/2cc26eba/src/java/org/apache/cassandra/cql3/restrictions/ClusteringColumnRestrictions.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/restrictions/ClusteringColumnRestrictions.java b/src/java/org/apache/cassandra/cql3/restrictions/ClusteringColumnRestrictions.java index ab16ebc..837ee13 100644 --- a/src/java/org/apache/cassandra/cql3/restrictions/ClusteringColumnRestrictions.java +++ b/src/java/org/apache/cassandra/cql3/restrictions/ClusteringColumnRestrictions.java @@ -113,7 +113,7 @@ final class ClusteringColumnRestrictions extends RestrictionSetWrapper return builder.build(); } - public NavigableSet<Slice.Bound> boundsAsClustering(Bound bound, QueryOptions options) throws InvalidRequestException + public NavigableSet<ClusteringBound> boundsAsClustering(Bound bound, QueryOptions options) throws InvalidRequestException { MultiCBuilder builder = MultiCBuilder.create(comparator, hasIN() || hasMultiColumnSlice()); int keyPosition = 0; http://git-wip-us.apache.org/repos/asf/cassandra/blob/2cc26eba/src/java/org/apache/cassandra/cql3/restrictions/StatementRestrictions.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/restrictions/StatementRestrictions.java b/src/java/org/apache/cassandra/cql3/restrictions/StatementRestrictions.java index c4d7622..43a912d 100644 --- a/src/java/org/apache/cassandra/cql3/restrictions/StatementRestrictions.java +++ b/src/java/org/apache/cassandra/cql3/restrictions/StatementRestrictions.java @@ -721,7 +721,7 @@ public final class StatementRestrictions * @param options the query options * @return the bounds (start or end) of the clustering columns */ - public NavigableSet<Slice.Bound> getClusteringColumnsBounds(Bound b, QueryOptions options) + public NavigableSet<ClusteringBound> getClusteringColumnsBounds(Bound b, QueryOptions options) { return clusteringColumnsRestrictions.boundsAsClustering(b, options); } http://git-wip-us.apache.org/repos/asf/cassandra/blob/2cc26eba/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java b/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java index 7243daa..6224457 100644 --- a/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java +++ b/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java @@ -674,8 +674,8 @@ public abstract class ModificationStatement implements CQLStatement private Slices createSlice(QueryOptions options) { - SortedSet<Slice.Bound> startBounds = restrictions.getClusteringColumnsBounds(Bound.START, options); - SortedSet<Slice.Bound> endBounds = restrictions.getClusteringColumnsBounds(Bound.END, options); + SortedSet<ClusteringBound> startBounds = restrictions.getClusteringColumnsBounds(Bound.START, options); + SortedSet<ClusteringBound> endBounds = restrictions.getClusteringColumnsBounds(Bound.END, options); return toSlices(startBounds, endBounds); } @@ -714,14 +714,14 @@ public abstract class ModificationStatement implements CQLStatement return new UpdateParameters(cfm, updatedColumns(), options, getTimestamp(now, options), getTimeToLive(options), lists); } - private Slices toSlices(SortedSet<Slice.Bound> startBounds, SortedSet<Slice.Bound> endBounds) + private Slices toSlices(SortedSet<ClusteringBound> startBounds, SortedSet<ClusteringBound> endBounds) { assert startBounds.size() == endBounds.size(); Slices.Builder builder = new Slices.Builder(cfm.comparator); - Iterator<Slice.Bound> starts = startBounds.iterator(); - Iterator<Slice.Bound> ends = endBounds.iterator(); + Iterator<ClusteringBound> starts = startBounds.iterator(); + Iterator<ClusteringBound> ends = endBounds.iterator(); while (starts.hasNext()) { http://git-wip-us.apache.org/repos/asf/cassandra/blob/2cc26eba/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java b/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java index e46cb06..3f72bd8 100644 --- a/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java +++ b/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java @@ -553,27 +553,27 @@ public class SelectStatement implements CQLStatement private Slices makeSlices(QueryOptions options) throws InvalidRequestException { - SortedSet<Slice.Bound> startBounds = restrictions.getClusteringColumnsBounds(Bound.START, options); - SortedSet<Slice.Bound> endBounds = restrictions.getClusteringColumnsBounds(Bound.END, options); + SortedSet<ClusteringBound> startBounds = restrictions.getClusteringColumnsBounds(Bound.START, options); + SortedSet<ClusteringBound> endBounds = restrictions.getClusteringColumnsBounds(Bound.END, options); assert startBounds.size() == endBounds.size(); // The case where startBounds == 1 is common enough that it's worth optimizing if (startBounds.size() == 1) { - Slice.Bound start = startBounds.first(); - Slice.Bound end = endBounds.first(); + ClusteringBound start = startBounds.first(); + ClusteringBound end = endBounds.first(); return cfm.comparator.compare(start, end) > 0 ? Slices.NONE : Slices.with(cfm.comparator, Slice.make(start, end)); } Slices.Builder builder = new Slices.Builder(cfm.comparator, startBounds.size()); - Iterator<Slice.Bound> startIter = startBounds.iterator(); - Iterator<Slice.Bound> endIter = endBounds.iterator(); + Iterator<ClusteringBound> startIter = startBounds.iterator(); + Iterator<ClusteringBound> endIter = endBounds.iterator(); while (startIter.hasNext() && endIter.hasNext()) { - Slice.Bound start = startIter.next(); - Slice.Bound end = endIter.next(); + ClusteringBound start = startIter.next(); + ClusteringBound end = endIter.next(); // Ignore slices that are nonsensical if (cfm.comparator.compare(start, end) > 0) http://git-wip-us.apache.org/repos/asf/cassandra/blob/2cc26eba/src/java/org/apache/cassandra/db/AbstractReadCommandBuilder.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/db/AbstractReadCommandBuilder.java b/src/java/org/apache/cassandra/db/AbstractReadCommandBuilder.java index dab22c7..849e684 100644 --- a/src/java/org/apache/cassandra/db/AbstractReadCommandBuilder.java +++ b/src/java/org/apache/cassandra/db/AbstractReadCommandBuilder.java @@ -43,8 +43,8 @@ public abstract class AbstractReadCommandBuilder protected Set<ColumnIdentifier> columns; protected final RowFilter filter = RowFilter.create(); - private Slice.Bound lowerClusteringBound; - private Slice.Bound upperClusteringBound; + private ClusteringBound lowerClusteringBound; + private ClusteringBound upperClusteringBound; private NavigableSet<Clustering> clusterings; @@ -64,28 +64,28 @@ public abstract class AbstractReadCommandBuilder public AbstractReadCommandBuilder fromIncl(Object... values) { assert lowerClusteringBound == null && clusterings == null; - this.lowerClusteringBound = Slice.Bound.create(cfs.metadata.comparator, true, true, values); + this.lowerClusteringBound = ClusteringBound.create(cfs.metadata.comparator, true, true, values); return this; } public AbstractReadCommandBuilder fromExcl(Object... values) { assert lowerClusteringBound == null && clusterings == null; - this.lowerClusteringBound = Slice.Bound.create(cfs.metadata.comparator, true, false, values); + this.lowerClusteringBound = ClusteringBound.create(cfs.metadata.comparator, true, false, values); return this; } public AbstractReadCommandBuilder toIncl(Object... values) { assert upperClusteringBound == null && clusterings == null; - this.upperClusteringBound = Slice.Bound.create(cfs.metadata.comparator, false, true, values); + this.upperClusteringBound = ClusteringBound.create(cfs.metadata.comparator, false, true, values); return this; } public AbstractReadCommandBuilder toExcl(Object... values) { assert upperClusteringBound == null && clusterings == null; - this.upperClusteringBound = Slice.Bound.create(cfs.metadata.comparator, false, false, values); + this.upperClusteringBound = ClusteringBound.create(cfs.metadata.comparator, false, false, values); return this; } @@ -195,8 +195,8 @@ public abstract class AbstractReadCommandBuilder } else { - Slice slice = Slice.make(lowerClusteringBound == null ? Slice.Bound.BOTTOM : lowerClusteringBound, - upperClusteringBound == null ? Slice.Bound.TOP : upperClusteringBound); + Slice slice = Slice.make(lowerClusteringBound == null ? ClusteringBound.BOTTOM : lowerClusteringBound, + upperClusteringBound == null ? ClusteringBound.TOP : upperClusteringBound); return new ClusteringIndexSliceFilter(Slices.with(cfs.metadata.comparator, slice), reversed); } } http://git-wip-us.apache.org/repos/asf/cassandra/blob/2cc26eba/src/java/org/apache/cassandra/db/CBuilder.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/db/CBuilder.java b/src/java/org/apache/cassandra/db/CBuilder.java index 73b575f..be56394 100644 --- a/src/java/org/apache/cassandra/db/CBuilder.java +++ b/src/java/org/apache/cassandra/db/CBuilder.java @@ -24,7 +24,7 @@ import java.util.List; import org.apache.cassandra.db.marshal.AbstractType; /** - * Allows to build ClusteringPrefixes, either Clustering or Slice.Bound. + * Allows to build ClusteringPrefixes, either Clustering or ClusteringBound. */ public abstract class CBuilder { @@ -60,7 +60,7 @@ public abstract class CBuilder return Clustering.STATIC_CLUSTERING; } - public Slice.Bound buildBound(boolean isStart, boolean isInclusive) + public ClusteringBound buildBound(boolean isStart, boolean isInclusive) { throw new UnsupportedOperationException(); } @@ -80,12 +80,12 @@ public abstract class CBuilder throw new UnsupportedOperationException(); } - public Slice.Bound buildBoundWith(ByteBuffer value, boolean isStart, boolean isInclusive) + public ClusteringBound buildBoundWith(ByteBuffer value, boolean isStart, boolean isInclusive) { throw new UnsupportedOperationException(); } - public Slice.Bound buildBoundWith(List<ByteBuffer> newValues, boolean isStart, boolean isInclusive) + public ClusteringBound buildBoundWith(List<ByteBuffer> newValues, boolean isStart, boolean isInclusive) { throw new UnsupportedOperationException(); } @@ -102,12 +102,12 @@ public abstract class CBuilder public abstract CBuilder add(ByteBuffer value); public abstract CBuilder add(Object value); public abstract Clustering build(); - public abstract Slice.Bound buildBound(boolean isStart, boolean isInclusive); + public abstract ClusteringBound buildBound(boolean isStart, boolean isInclusive); public abstract Slice buildSlice(); public abstract Clustering buildWith(ByteBuffer value); public abstract Clustering buildWith(List<ByteBuffer> newValues); - public abstract Slice.Bound buildBoundWith(ByteBuffer value, boolean isStart, boolean isInclusive); - public abstract Slice.Bound buildBoundWith(List<ByteBuffer> newValues, boolean isStart, boolean isInclusive); + public abstract ClusteringBound buildBoundWith(ByteBuffer value, boolean isStart, boolean isInclusive); + public abstract ClusteringBound buildBoundWith(List<ByteBuffer> newValues, boolean isStart, boolean isInclusive); private static class ArrayBackedBuilder extends CBuilder { @@ -165,17 +165,17 @@ public abstract class CBuilder return size == 0 ? Clustering.EMPTY : Clustering.make(values); } - public Slice.Bound buildBound(boolean isStart, boolean isInclusive) + public ClusteringBound buildBound(boolean isStart, boolean isInclusive) { // We don't allow to add more element to a builder that has been built so // that we don't have to copy values (even though we have to do it in most cases). built = true; if (size == 0) - return isStart ? Slice.Bound.BOTTOM : Slice.Bound.TOP; + return isStart ? ClusteringBound.BOTTOM : ClusteringBound.TOP; - return Slice.Bound.create(Slice.Bound.boundKind(isStart, isInclusive), - size == values.length ? values : Arrays.copyOfRange(values, 0, size)); + return ClusteringBound.create(ClusteringBound.boundKind(isStart, isInclusive), + size == values.length ? values : Arrays.copyOfRange(values, 0, size)); } public Slice buildSlice() @@ -210,21 +210,21 @@ public abstract class CBuilder return Clustering.make(buffers); } - public Slice.Bound buildBoundWith(ByteBuffer value, boolean isStart, boolean isInclusive) + public ClusteringBound buildBoundWith(ByteBuffer value, boolean isStart, boolean isInclusive) { ByteBuffer[] newValues = Arrays.copyOf(values, size+1); newValues[size] = value; - return Slice.Bound.create(Slice.Bound.boundKind(isStart, isInclusive), newValues); + return ClusteringBound.create(ClusteringBound.boundKind(isStart, isInclusive), newValues); } - public Slice.Bound buildBoundWith(List<ByteBuffer> newValues, boolean isStart, boolean isInclusive) + public ClusteringBound buildBoundWith(List<ByteBuffer> newValues, boolean isStart, boolean isInclusive) { ByteBuffer[] buffers = Arrays.copyOf(values, size + newValues.size()); int newSize = size; for (ByteBuffer value : newValues) buffers[newSize++] = value; - return Slice.Bound.create(Slice.Bound.boundKind(isStart, isInclusive), buffers); + return ClusteringBound.create(ClusteringBound.boundKind(isStart, isInclusive), buffers); } } } http://git-wip-us.apache.org/repos/asf/cassandra/blob/2cc26eba/src/java/org/apache/cassandra/db/ClusteringBound.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/db/ClusteringBound.java b/src/java/org/apache/cassandra/db/ClusteringBound.java new file mode 100644 index 0000000..6366a37 --- /dev/null +++ b/src/java/org/apache/cassandra/db/ClusteringBound.java @@ -0,0 +1,151 @@ +package org.apache.cassandra.db; + +import java.nio.ByteBuffer; +import java.util.List; + +import org.apache.cassandra.utils.memory.AbstractAllocator; + +/** + * The start or end of a range of clusterings, either inclusive or exclusive. + */ +public class ClusteringBound extends ClusteringBoundOrBoundary +{ + /** The smallest start bound, i.e. the one that starts before any row. */ + public static final ClusteringBound BOTTOM = new ClusteringBound(Kind.INCL_START_BOUND, EMPTY_VALUES_ARRAY); + /** The biggest end bound, i.e. the one that ends after any row. */ + public static final ClusteringBound TOP = new ClusteringBound(Kind.INCL_END_BOUND, EMPTY_VALUES_ARRAY); + + protected ClusteringBound(Kind kind, ByteBuffer[] values) + { + super(kind, values); + } + + public static ClusteringBound create(Kind kind, ByteBuffer[] values) + { + assert !kind.isBoundary(); + return new ClusteringBound(kind, values); + } + + public static Kind boundKind(boolean isStart, boolean isInclusive) + { + return isStart + ? (isInclusive ? Kind.INCL_START_BOUND : Kind.EXCL_START_BOUND) + : (isInclusive ? Kind.INCL_END_BOUND : Kind.EXCL_END_BOUND); + } + + public static ClusteringBound inclusiveStartOf(ByteBuffer... values) + { + return create(Kind.INCL_START_BOUND, values); + } + + public static ClusteringBound inclusiveEndOf(ByteBuffer... values) + { + return create(Kind.INCL_END_BOUND, values); + } + + public static ClusteringBound exclusiveStartOf(ByteBuffer... values) + { + return create(Kind.EXCL_START_BOUND, values); + } + + public static ClusteringBound exclusiveEndOf(ByteBuffer... values) + { + return create(Kind.EXCL_END_BOUND, values); + } + + public static ClusteringBound inclusiveStartOf(ClusteringPrefix prefix) + { + ByteBuffer[] values = new ByteBuffer[prefix.size()]; + for (int i = 0; i < prefix.size(); i++) + values[i] = prefix.get(i); + return inclusiveStartOf(values); + } + + public static ClusteringBound exclusiveStartOf(ClusteringPrefix prefix) + { + ByteBuffer[] values = new ByteBuffer[prefix.size()]; + for (int i = 0; i < prefix.size(); i++) + values[i] = prefix.get(i); + return exclusiveStartOf(values); + } + + public static ClusteringBound inclusiveEndOf(ClusteringPrefix prefix) + { + ByteBuffer[] values = new ByteBuffer[prefix.size()]; + for (int i = 0; i < prefix.size(); i++) + values[i] = prefix.get(i); + return inclusiveEndOf(values); + } + + public static ClusteringBound create(ClusteringComparator comparator, boolean isStart, boolean isInclusive, Object... values) + { + CBuilder builder = CBuilder.create(comparator); + for (Object val : values) + { + if (val instanceof ByteBuffer) + builder.add((ByteBuffer) val); + else + builder.add(val); + } + return builder.buildBound(isStart, isInclusive); + } + + @Override + public ClusteringBound invert() + { + return create(kind().invert(), values); + } + + public ClusteringBound copy(AbstractAllocator allocator) + { + return (ClusteringBound) super.copy(allocator); + } + + public boolean isStart() + { + return kind().isStart(); + } + + public boolean isEnd() + { + return !isStart(); + } + + public boolean isInclusive() + { + return kind == Kind.INCL_START_BOUND || kind == Kind.INCL_END_BOUND; + } + + public boolean isExclusive() + { + return kind == Kind.EXCL_START_BOUND || kind == Kind.EXCL_END_BOUND; + } + + // For use by intersects, it's called with the sstable bound opposite to the slice bound + // (so if the slice bound is a start, it's call with the max sstable bound) + int compareTo(ClusteringComparator comparator, List<ByteBuffer> sstableBound) + { + for (int i = 0; i < sstableBound.size(); i++) + { + // Say the slice bound is a start. It means we're in the case where the max + // sstable bound is say (1:5) while the slice start is (1). So the start + // does start before the sstable end bound (and intersect it). It's the exact + // inverse with a end slice bound. + if (i >= size()) + return isStart() ? -1 : 1; + + int cmp = comparator.compareComponent(i, get(i), sstableBound.get(i)); + if (cmp != 0) + return cmp; + } + + // Say the slice bound is a start. I means we're in the case where the max + // sstable bound is say (1), while the slice start is (1:5). This again means + // that the slice start before the end bound. + if (size() > sstableBound.size()) + return isStart() ? -1 : 1; + + // The slice bound is equal to the sstable bound. Results depends on whether the slice is inclusive or not + return isInclusive() ? 0 : (isStart() ? 1 : -1); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/cassandra/blob/2cc26eba/src/java/org/apache/cassandra/db/ClusteringBoundOrBoundary.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/db/ClusteringBoundOrBoundary.java b/src/java/org/apache/cassandra/db/ClusteringBoundOrBoundary.java new file mode 100644 index 0000000..0c965e9 --- /dev/null +++ b/src/java/org/apache/cassandra/db/ClusteringBoundOrBoundary.java @@ -0,0 +1,163 @@ +package org.apache.cassandra.db; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.List; + +import org.apache.cassandra.config.CFMetaData; +import org.apache.cassandra.db.marshal.AbstractType; +import org.apache.cassandra.io.util.DataInputPlus; +import org.apache.cassandra.io.util.DataOutputPlus; +import org.apache.cassandra.utils.memory.AbstractAllocator; + +/** + * This class defines a threshold between ranges of clusterings. It can either be a start or end bound of a range, or + * the boundary between two different defined ranges. + * <p> + * The latter is used for range tombstones for 2 main reasons: + * 1) When merging multiple iterators having range tombstones (that are represented by their start and end markers), + * we need to know when a range is close on an iterator, if it is reopened right away. Otherwise, we cannot + * easily produce the markers on the merged iterators within risking to fail the sorting guarantees of an + * iterator. See this comment for more details: https://goo.gl/yyB5mR. + * 2) This saves some storage space. + */ +public abstract class ClusteringBoundOrBoundary extends AbstractBufferClusteringPrefix +{ + public static final ClusteringBoundOrBoundary.Serializer serializer = new Serializer(); + + protected ClusteringBoundOrBoundary(Kind kind, ByteBuffer[] values) + { + super(kind, values); + assert values.length > 0 || !kind.isBoundary(); + } + + public static ClusteringBoundOrBoundary create(Kind kind, ByteBuffer[] values) + { + return kind.isBoundary() + ? new ClusteringBoundary(kind, values) + : new ClusteringBound(kind, values); + } + + public boolean isBoundary() + { + return kind.isBoundary(); + } + + public boolean isOpen(boolean reversed) + { + return kind.isOpen(reversed); + } + + public boolean isClose(boolean reversed) + { + return kind.isClose(reversed); + } + + public static ClusteringBound inclusiveOpen(boolean reversed, ByteBuffer[] boundValues) + { + return new ClusteringBound(reversed ? Kind.INCL_END_BOUND : Kind.INCL_START_BOUND, boundValues); + } + + public static ClusteringBound exclusiveOpen(boolean reversed, ByteBuffer[] boundValues) + { + return new ClusteringBound(reversed ? Kind.EXCL_END_BOUND : Kind.EXCL_START_BOUND, boundValues); + } + + public static ClusteringBound inclusiveClose(boolean reversed, ByteBuffer[] boundValues) + { + return new ClusteringBound(reversed ? Kind.INCL_START_BOUND : Kind.INCL_END_BOUND, boundValues); + } + + public static ClusteringBound exclusiveClose(boolean reversed, ByteBuffer[] boundValues) + { + return new ClusteringBound(reversed ? Kind.EXCL_START_BOUND : Kind.EXCL_END_BOUND, boundValues); + } + + public static ClusteringBoundary inclusiveCloseExclusiveOpen(boolean reversed, ByteBuffer[] boundValues) + { + return new ClusteringBoundary(reversed ? Kind.EXCL_END_INCL_START_BOUNDARY : Kind.INCL_END_EXCL_START_BOUNDARY, boundValues); + } + + public static ClusteringBoundary exclusiveCloseInclusiveOpen(boolean reversed, ByteBuffer[] boundValues) + { + return new ClusteringBoundary(reversed ? Kind.INCL_END_EXCL_START_BOUNDARY : Kind.EXCL_END_INCL_START_BOUNDARY, boundValues); + } + + public ClusteringBoundOrBoundary copy(AbstractAllocator allocator) + { + ByteBuffer[] newValues = new ByteBuffer[size()]; + for (int i = 0; i < size(); i++) + newValues[i] = allocator.clone(get(i)); + return create(kind(), newValues); + } + + public String toString(CFMetaData metadata) + { + return toString(metadata.comparator); + } + + public String toString(ClusteringComparator comparator) + { + StringBuilder sb = new StringBuilder(); + sb.append(kind()).append('('); + for (int i = 0; i < size(); i++) + { + if (i > 0) + sb.append(", "); + sb.append(comparator.subtype(i).getString(get(i))); + } + return sb.append(')').toString(); + } + + /** + * Returns the inverse of the current bound. + * <p> + * This invert both start into end (and vice-versa) and inclusive into exclusive (and vice-versa). + * + * @return the invert of this bound. For instance, if this bound is an exlusive start, this return + * an inclusive end with the same values. + */ + public abstract ClusteringBoundOrBoundary invert(); + + public static class Serializer + { + public void serialize(ClusteringBoundOrBoundary bound, DataOutputPlus out, int version, List<AbstractType<?>> types) throws IOException + { + out.writeByte(bound.kind().ordinal()); + out.writeShort(bound.size()); + ClusteringPrefix.serializer.serializeValuesWithoutSize(bound, out, version, types); + } + + public long serializedSize(ClusteringBoundOrBoundary bound, int version, List<AbstractType<?>> types) + { + return 1 // kind ordinal + + TypeSizes.sizeof((short)bound.size()) + + ClusteringPrefix.serializer.valuesWithoutSizeSerializedSize(bound, version, types); + } + + public ClusteringBoundOrBoundary deserialize(DataInputPlus in, int version, List<AbstractType<?>> types) throws IOException + { + Kind kind = Kind.values()[in.readByte()]; + return deserializeValues(in, kind, version, types); + } + + public void skipValues(DataInputPlus in, Kind kind, int version, List<AbstractType<?>> types) throws IOException + { + int size = in.readUnsignedShort(); + if (size == 0) + return; + + ClusteringPrefix.serializer.skipValuesWithoutSize(in, size, version, types); + } + + public ClusteringBoundOrBoundary deserializeValues(DataInputPlus in, Kind kind, int version, List<AbstractType<?>> types) throws IOException + { + int size = in.readUnsignedShort(); + if (size == 0) + return kind.isStart() ? ClusteringBound.BOTTOM : ClusteringBound.TOP; + + ByteBuffer[] values = ClusteringPrefix.serializer.deserializeValuesWithoutSize(in, size, version, types); + return create(kind, values); + } + } +} http://git-wip-us.apache.org/repos/asf/cassandra/blob/2cc26eba/src/java/org/apache/cassandra/db/ClusteringBoundary.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/db/ClusteringBoundary.java b/src/java/org/apache/cassandra/db/ClusteringBoundary.java new file mode 100644 index 0000000..503eaad --- /dev/null +++ b/src/java/org/apache/cassandra/db/ClusteringBoundary.java @@ -0,0 +1,45 @@ +package org.apache.cassandra.db; + +import java.nio.ByteBuffer; + +import org.apache.cassandra.utils.memory.AbstractAllocator; + +/** + * The threshold between two different ranges, i.e. a shortcut for the combination of two ClusteringBounds -- one + * specifying the end of one of the ranges, and its (implicit) complement specifying the beginning of the other. + */ +public class ClusteringBoundary extends ClusteringBoundOrBoundary +{ + protected ClusteringBoundary(Kind kind, ByteBuffer[] values) + { + super(kind, values); + } + + public static ClusteringBoundary create(Kind kind, ByteBuffer[] values) + { + assert kind.isBoundary(); + return new ClusteringBoundary(kind, values); + } + + @Override + public ClusteringBoundary invert() + { + return create(kind().invert(), values); + } + + @Override + public ClusteringBoundary copy(AbstractAllocator allocator) + { + return (ClusteringBoundary) super.copy(allocator); + } + + public ClusteringBound openBound(boolean reversed) + { + return ClusteringBound.create(kind.openBoundOfBoundary(reversed), values); + } + + public ClusteringBound closeBound(boolean reversed) + { + return ClusteringBound.create(kind.closeBoundOfBoundary(reversed), values); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/cassandra/blob/2cc26eba/src/java/org/apache/cassandra/db/ClusteringPrefix.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/db/ClusteringPrefix.java b/src/java/org/apache/cassandra/db/ClusteringPrefix.java index df0befc..d6aa484 100644 --- a/src/java/org/apache/cassandra/db/ClusteringPrefix.java +++ b/src/java/org/apache/cassandra/db/ClusteringPrefix.java @@ -37,10 +37,10 @@ import org.apache.cassandra.utils.ByteBufferUtil; * a "kind" that allows us to implement slices with inclusive and exclusive bounds. * <p> * In practice, {@code ClusteringPrefix} is just the common parts to its 3 main subtype: {@link Clustering} and - * {@link Slice.Bound}/{@link RangeTombstone.Bound}, where: + * {@link ClusteringBound}/{@link ClusteringBoundary}, where: * 1) {@code Clustering} represents the clustering values for a row, i.e. the values for it's clustering columns. - * 2) {@code Slice.Bound} represents a bound (start or end) of a slice (of rows). - * 3) {@code RangeTombstoneBoundMarker.Bound} represents a range tombstone marker "bound". + * 2) {@code ClusteringBound} represents a bound (start or end) of a slice (of rows) or a range tombstone. + * 3) {@code ClusteringBoundary} represents the threshold between two adjacent range tombstones. * See those classes for more details. */ public interface ClusteringPrefix extends IMeasurableMemory, Clusterable @@ -51,7 +51,7 @@ public interface ClusteringPrefix extends IMeasurableMemory, Clusterable * The kind of clustering prefix this actually is. * * The kind {@code STATIC_CLUSTERING} is only implemented by {@link Clustering#STATIC_CLUSTERING} and {@code CLUSTERING} is - * implemented by the {@link Clustering} class. The rest is used by {@link Slice.Bound} and {@link RangeTombstone.Bound}. + * implemented by the {@link Clustering} class. The rest is used by {@link ClusteringBound} and {@link ClusteringBoundary}. */ public enum Kind { @@ -122,8 +122,9 @@ public interface ClusteringPrefix extends IMeasurableMemory, Clusterable case EXCL_START_BOUND: case EXCL_END_BOUND: return true; + default: + return false; } - return false; } public boolean isBoundary() @@ -133,8 +134,9 @@ public interface ClusteringPrefix extends IMeasurableMemory, Clusterable case INCL_END_EXCL_START_BOUNDARY: case EXCL_END_INCL_START_BOUNDARY: return true; + default: + return false; } - return false; } public boolean isStart() @@ -259,7 +261,7 @@ public interface ClusteringPrefix extends IMeasurableMemory, Clusterable } else { - RangeTombstone.Bound.serializer.serialize((RangeTombstone.Bound)clustering, out, version, types); + ClusteringBoundOrBoundary.serializer.serialize((ClusteringBoundOrBoundary)clustering, out, version, types); } } @@ -271,7 +273,7 @@ public interface ClusteringPrefix extends IMeasurableMemory, Clusterable if (kind == Kind.CLUSTERING) Clustering.serializer.skip(in, version, types); else - RangeTombstone.Bound.serializer.skipValues(in, kind, version, types); + ClusteringBoundOrBoundary.serializer.skipValues(in, kind, version, types); } public ClusteringPrefix deserialize(DataInputPlus in, int version, List<AbstractType<?>> types) throws IOException @@ -282,7 +284,7 @@ public interface ClusteringPrefix extends IMeasurableMemory, Clusterable if (kind == Kind.CLUSTERING) return Clustering.serializer.deserialize(in, version, types); else - return RangeTombstone.Bound.serializer.deserializeValues(in, kind, version, types); + return ClusteringBoundOrBoundary.serializer.deserializeValues(in, kind, version, types); } public long serializedSize(ClusteringPrefix clustering, int version, List<AbstractType<?>> types) @@ -292,7 +294,7 @@ public interface ClusteringPrefix extends IMeasurableMemory, Clusterable if (clustering.kind() == Kind.CLUSTERING) return 1 + Clustering.serializer.serializedSize((Clustering)clustering, version, types); else - return RangeTombstone.Bound.serializer.serializedSize((RangeTombstone.Bound)clustering, version, types); + return ClusteringBoundOrBoundary.serializer.serializedSize((ClusteringBoundOrBoundary)clustering, version, types); } void serializeValuesWithoutSize(ClusteringPrefix clustering, DataOutputPlus out, int version, List<AbstractType<?>> types) throws IOException @@ -462,9 +464,9 @@ public interface ClusteringPrefix extends IMeasurableMemory, Clusterable this.nextValues = new ByteBuffer[nextSize]; } - public int compareNextTo(Slice.Bound bound) throws IOException + public int compareNextTo(ClusteringBoundOrBoundary bound) throws IOException { - if (bound == Slice.Bound.TOP) + if (bound == ClusteringBound.TOP) return -1; for (int i = 0; i < bound.size(); i++) @@ -516,11 +518,11 @@ public interface ClusteringPrefix extends IMeasurableMemory, Clusterable continue; } - public RangeTombstone.Bound deserializeNextBound() throws IOException + public ClusteringBoundOrBoundary deserializeNextBound() throws IOException { assert !nextIsRow; deserializeAll(); - RangeTombstone.Bound bound = new RangeTombstone.Bound(nextKind, nextValues); + ClusteringBoundOrBoundary bound = ClusteringBoundOrBoundary.create(nextKind, nextValues); nextValues = null; return bound; } http://git-wip-us.apache.org/repos/asf/cassandra/blob/2cc26eba/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 92ecbf5..1c80128 100644 --- a/src/java/org/apache/cassandra/db/LegacyLayout.java +++ b/src/java/org/apache/cassandra/db/LegacyLayout.java @@ -193,26 +193,26 @@ public abstract class LegacyLayout List<CompositeType.CompositeComponent> prefix = components.size() <= metadata.comparator.size() ? components : components.subList(0, metadata.comparator.size()); - Slice.Bound.Kind boundKind; + ClusteringPrefix.Kind boundKind; if (isStart) { if (components.get(components.size() - 1).eoc > 0) - boundKind = Slice.Bound.Kind.EXCL_START_BOUND; + boundKind = ClusteringPrefix.Kind.EXCL_START_BOUND; else - boundKind = Slice.Bound.Kind.INCL_START_BOUND; + boundKind = ClusteringPrefix.Kind.INCL_START_BOUND; } else { if (components.get(components.size() - 1).eoc < 0) - boundKind = Slice.Bound.Kind.EXCL_END_BOUND; + boundKind = ClusteringPrefix.Kind.EXCL_END_BOUND; else - boundKind = Slice.Bound.Kind.INCL_END_BOUND; + boundKind = ClusteringPrefix.Kind.INCL_END_BOUND; } 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); + ClusteringBound sb = ClusteringBound.create(boundKind, prefixValues); ColumnDefinition collectionName = components.size() == metadata.comparator.size() + 1 ? metadata.getColumnDefinition(components.get(metadata.comparator.size()).value) @@ -220,9 +220,9 @@ public abstract class LegacyLayout return new LegacyBound(sb, metadata.isCompound() && CompositeType.isStaticName(bound), collectionName); } - public static ByteBuffer encodeBound(CFMetaData metadata, Slice.Bound bound, boolean isStart) + public static ByteBuffer encodeBound(CFMetaData metadata, ClusteringBound bound, boolean isStart) { - if (bound == Slice.Bound.BOTTOM || bound == Slice.Bound.TOP || metadata.comparator.size() == 0) + if (bound == ClusteringBound.BOTTOM || bound == ClusteringBound.TOP || metadata.comparator.size() == 0) return ByteBufferUtil.EMPTY_BYTE_BUFFER; ClusteringPrefix clustering = bound.clustering(); @@ -722,8 +722,8 @@ public abstract class LegacyLayout if (!row.deletion().isLive()) { Clustering clustering = row.clustering(); - Slice.Bound startBound = Slice.Bound.inclusiveStartOf(clustering); - Slice.Bound endBound = Slice.Bound.inclusiveEndOf(clustering); + ClusteringBound startBound = ClusteringBound.inclusiveStartOf(clustering); + ClusteringBound endBound = ClusteringBound.inclusiveEndOf(clustering); LegacyBound start = new LegacyLayout.LegacyBound(startBound, false, null); LegacyBound end = new LegacyLayout.LegacyBound(endBound, false, null); @@ -742,8 +742,8 @@ public abstract class LegacyLayout { Clustering clustering = row.clustering(); - Slice.Bound startBound = Slice.Bound.inclusiveStartOf(clustering); - Slice.Bound endBound = Slice.Bound.inclusiveEndOf(clustering); + ClusteringBound startBound = ClusteringBound.inclusiveStartOf(clustering); + ClusteringBound endBound = ClusteringBound.inclusiveEndOf(clustering); LegacyLayout.LegacyBound start = new LegacyLayout.LegacyBound(startBound, col.isStatic(), col); LegacyLayout.LegacyBound end = new LegacyLayout.LegacyBound(endBound, col.isStatic(), col); @@ -918,9 +918,9 @@ public abstract class LegacyLayout // we can have collection deletion and we want those to sort properly just before the column they // delete, not before the whole row. // We also want to special case static so they sort before any non-static. Note in particular that - // this special casing is important in the case of one of the Atom being Slice.Bound.BOTTOM: we want + // this special casing is important in the case of one of the Atom being Bound.BOTTOM: we want // it to sort after the static as we deal with static first in toUnfilteredAtomIterator and having - // Slice.Bound.BOTTOM first would mess that up (note that static deletion is handled through a specific + // Bound.BOTTOM first would mess that up (note that static deletion is handled through a specific // static tombstone, see LegacyDeletionInfo.add()). if (o1.isStatic() != o2.isStatic()) return o1.isStatic() ? -1 : 1; @@ -1328,14 +1328,14 @@ public abstract class LegacyLayout public static class LegacyBound { - public static final LegacyBound BOTTOM = new LegacyBound(Slice.Bound.BOTTOM, false, null); - public static final LegacyBound TOP = new LegacyBound(Slice.Bound.TOP, false, null); + public static final LegacyBound BOTTOM = new LegacyBound(ClusteringBound.BOTTOM, false, null); + public static final LegacyBound TOP = new LegacyBound(ClusteringBound.TOP, false, null); - public final Slice.Bound bound; + public final ClusteringBound bound; public final boolean isStatic; public final ColumnDefinition collectionName; - public LegacyBound(Slice.Bound bound, boolean isStatic, ColumnDefinition collectionName) + public LegacyBound(ClusteringBound bound, boolean isStatic, ColumnDefinition collectionName) { this.bound = bound; this.isStatic = isStatic; @@ -1640,7 +1640,7 @@ public abstract class LegacyLayout deletionInfo.add(topLevel); } - private static Slice.Bound staticBound(CFMetaData metadata, boolean isStart) + private static ClusteringBound staticBound(CFMetaData metadata, boolean isStart) { // In pre-3.0 nodes, static row started by a clustering with all empty values so we // preserve that here. Note that in practice, it doesn't really matter since the rest @@ -1649,8 +1649,8 @@ public abstract class LegacyLayout for (int i = 0; i < values.length; i++) values[i] = ByteBufferUtil.EMPTY_BYTE_BUFFER; return isStart - ? Slice.Bound.inclusiveStartOf(values) - : Slice.Bound.inclusiveEndOf(values); + ? ClusteringBound.inclusiveStartOf(values) + : ClusteringBound.inclusiveEndOf(values); } public void add(CFMetaData metadata, LegacyRangeTombstone tombstone) http://git-wip-us.apache.org/repos/asf/cassandra/blob/2cc26eba/src/java/org/apache/cassandra/db/MultiCBuilder.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/db/MultiCBuilder.java b/src/java/org/apache/cassandra/db/MultiCBuilder.java index f03e674..ae8c26c 100644 --- a/src/java/org/apache/cassandra/db/MultiCBuilder.java +++ b/src/java/org/apache/cassandra/db/MultiCBuilder.java @@ -24,12 +24,11 @@ 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; /** - * Builder that allow to build multiple Clustering/Slice.Bound at the same time. + * Builder that allow to build multiple Clustering/ClusteringBound at the same time. */ public abstract class MultiCBuilder { @@ -167,27 +166,27 @@ public abstract class MultiCBuilder public abstract NavigableSet<Clustering> build(); /** - * Builds the <code>Slice.Bound</code>s for slice restrictions. + * Builds the <code>ClusteringBound</code>s for slice restrictions. * * @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 + * @return the <code>ClusteringBound</code>s */ - public abstract NavigableSet<Slice.Bound> buildBoundForSlice(boolean isStart, + public abstract NavigableSet<ClusteringBound> buildBoundForSlice(boolean isStart, boolean isInclusive, boolean isOtherBoundInclusive, List<ColumnDefinition> columnDefs); /** - * Builds the <code>Slice.Bound</code>s + * Builds the <code>ClusteringBound</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 + * @return the <code>ClusteringBound</code>s */ - public abstract NavigableSet<Slice.Bound> buildBound(boolean isStart, boolean isInclusive); + public abstract NavigableSet<ClusteringBound> buildBound(boolean isStart, boolean isInclusive); /** * Checks if some elements can still be added to the clusterings. @@ -264,15 +263,15 @@ public abstract class MultiCBuilder } @Override - public NavigableSet<Bound> buildBoundForSlice(boolean isStart, - boolean isInclusive, - boolean isOtherBoundInclusive, - List<ColumnDefinition> columnDefs) + public NavigableSet<ClusteringBound> buildBoundForSlice(boolean isStart, + boolean isInclusive, + boolean isOtherBoundInclusive, + List<ColumnDefinition> columnDefs) { return buildBound(isStart, columnDefs.get(0).isReversedType() ? isOtherBoundInclusive : isInclusive); } - public NavigableSet<Slice.Bound> buildBound(boolean isStart, boolean isInclusive) + public NavigableSet<ClusteringBound> buildBound(boolean isStart, boolean isInclusive) { built = true; @@ -280,13 +279,13 @@ public abstract class MultiCBuilder return BTreeSet.empty(comparator); if (size == 0) - return BTreeSet.of(comparator, isStart ? Slice.Bound.BOTTOM : Slice.Bound.TOP); + return BTreeSet.of(comparator, isStart ? ClusteringBound.BOTTOM : ClusteringBound.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 BTreeSet.of(comparator, ClusteringBound.create(ClusteringBound.boundKind(isStart, isInclusive), newValues)); } } @@ -419,7 +418,7 @@ public abstract class MultiCBuilder return set.build(); } - public NavigableSet<Slice.Bound> buildBoundForSlice(boolean isStart, + public NavigableSet<ClusteringBound> buildBoundForSlice(boolean isStart, boolean isInclusive, boolean isOtherBoundInclusive, List<ColumnDefinition> columnDefs) @@ -435,7 +434,7 @@ public abstract class MultiCBuilder return BTreeSet.of(comparator, builder.buildBound(isStart, isInclusive)); // Use a TreeSet to sort and eliminate duplicates - BTreeSet.Builder<Slice.Bound> set = BTreeSet.builder(comparator); + BTreeSet.Builder<ClusteringBound> 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(); @@ -470,7 +469,7 @@ public abstract class MultiCBuilder return set.build(); } - public NavigableSet<Slice.Bound> buildBound(boolean isStart, boolean isInclusive) + public NavigableSet<ClusteringBound> buildBound(boolean isStart, boolean isInclusive) { built = true; @@ -483,7 +482,7 @@ public abstract class MultiCBuilder return BTreeSet.of(comparator, builder.buildBound(isStart, isInclusive)); // Use a TreeSet to sort and eliminate duplicates - BTreeSet.Builder<Slice.Bound> set = BTreeSet.builder(comparator); + BTreeSet.Builder<ClusteringBound> set = BTreeSet.builder(comparator); for (int i = 0, m = elementsList.size(); i < m; i++) { http://git-wip-us.apache.org/repos/asf/cassandra/blob/2cc26eba/src/java/org/apache/cassandra/db/MutableDeletionInfo.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/db/MutableDeletionInfo.java b/src/java/org/apache/cassandra/db/MutableDeletionInfo.java index d01b1d1..1ba77bb 100644 --- a/src/java/org/apache/cassandra/db/MutableDeletionInfo.java +++ b/src/java/org/apache/cassandra/db/MutableDeletionInfo.java @@ -290,8 +290,8 @@ public class MutableDeletionInfo implements DeletionInfo DeletionTime openDeletion = openMarker.openDeletionTime(reversed); assert marker.closeDeletionTime(reversed).equals(openDeletion); - Slice.Bound open = openMarker.openBound(reversed); - Slice.Bound close = marker.closeBound(reversed); + ClusteringBound open = openMarker.openBound(reversed); + ClusteringBound close = marker.closeBound(reversed); Slice slice = reversed ? Slice.make(close, open) : Slice.make(open, close); deletion.add(new RangeTombstone(slice, openDeletion), comparator); http://git-wip-us.apache.org/repos/asf/cassandra/blob/2cc26eba/src/java/org/apache/cassandra/db/RangeTombstone.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/db/RangeTombstone.java b/src/java/org/apache/cassandra/db/RangeTombstone.java index 29feb46..8e01b8e 100644 --- a/src/java/org/apache/cassandra/db/RangeTombstone.java +++ b/src/java/org/apache/cassandra/db/RangeTombstone.java @@ -17,16 +17,9 @@ */ package org.apache.cassandra.db; -import java.io.IOException; -import java.nio.ByteBuffer; -import java.util.List; import java.util.Objects; -import org.apache.cassandra.db.marshal.AbstractType; import org.apache.cassandra.db.rows.RangeTombstoneMarker; -import org.apache.cassandra.io.util.DataInputPlus; -import org.apache.cassandra.io.util.DataOutputPlus; -import org.apache.cassandra.utils.memory.AbstractAllocator; /** @@ -89,139 +82,4 @@ public class RangeTombstone { return Objects.hash(deletedSlice(), deletionTime()); } - - /** - * The bound of a range tombstone. - * <p> - * This is the same than for a slice but it includes "boundaries" between ranges. A boundary simply condensed - * a close and an opening "bound" into a single object. There is 2 main reasons for these "shortcut" boundaries: - * 1) When merging multiple iterators having range tombstones (that are represented by their start and end markers), - * we need to know when a range is close on an iterator, if it is reopened right away. Otherwise, we cannot - * easily produce the markers on the merged iterators within risking to fail the sorting guarantees of an - * iterator. See this comment for more details: https://goo.gl/yyB5mR. - * 2) This saves some storage space. - */ - public static class Bound extends Slice.Bound - { - public static final Serializer serializer = new Serializer(); - - /** The smallest start bound, i.e. the one that starts before any row. */ - public static final Bound BOTTOM = new Bound(Kind.INCL_START_BOUND, EMPTY_VALUES_ARRAY); - /** The biggest end bound, i.e. the one that ends after any row. */ - public static final Bound TOP = new Bound(Kind.INCL_END_BOUND, EMPTY_VALUES_ARRAY); - - public Bound(Kind kind, ByteBuffer[] values) - { - super(kind, values); - assert values.length > 0 || !kind.isBoundary(); - } - - public boolean isBoundary() - { - return kind.isBoundary(); - } - - public boolean isOpen(boolean reversed) - { - return kind.isOpen(reversed); - } - - public boolean isClose(boolean reversed) - { - return kind.isClose(reversed); - } - - public static RangeTombstone.Bound inclusiveOpen(boolean reversed, ByteBuffer[] boundValues) - { - return new Bound(reversed ? Kind.INCL_END_BOUND : Kind.INCL_START_BOUND, boundValues); - } - - public static RangeTombstone.Bound exclusiveOpen(boolean reversed, ByteBuffer[] boundValues) - { - return new Bound(reversed ? Kind.EXCL_END_BOUND : Kind.EXCL_START_BOUND, boundValues); - } - - public static RangeTombstone.Bound inclusiveClose(boolean reversed, ByteBuffer[] boundValues) - { - return new Bound(reversed ? Kind.INCL_START_BOUND : Kind.INCL_END_BOUND, boundValues); - } - - public static RangeTombstone.Bound exclusiveClose(boolean reversed, ByteBuffer[] boundValues) - { - return new Bound(reversed ? Kind.EXCL_START_BOUND : Kind.EXCL_END_BOUND, boundValues); - } - - public static RangeTombstone.Bound inclusiveCloseExclusiveOpen(boolean reversed, ByteBuffer[] boundValues) - { - return new Bound(reversed ? Kind.EXCL_END_INCL_START_BOUNDARY : Kind.INCL_END_EXCL_START_BOUNDARY, boundValues); - } - - public static RangeTombstone.Bound exclusiveCloseInclusiveOpen(boolean reversed, ByteBuffer[] boundValues) - { - return new Bound(reversed ? Kind.INCL_END_EXCL_START_BOUNDARY : Kind.EXCL_END_INCL_START_BOUNDARY, boundValues); - } - - public static RangeTombstone.Bound fromSliceBound(Slice.Bound sliceBound) - { - return new RangeTombstone.Bound(sliceBound.kind(), sliceBound.getRawValues()); - } - - public RangeTombstone.Bound copy(AbstractAllocator allocator) - { - ByteBuffer[] newValues = new ByteBuffer[size()]; - for (int i = 0; i < size(); i++) - newValues[i] = allocator.clone(get(i)); - return new Bound(kind(), newValues); - } - - @Override - public Bound withNewKind(Kind kind) - { - return new Bound(kind, values); - } - - public static class Serializer - { - public void serialize(RangeTombstone.Bound bound, DataOutputPlus out, int version, List<AbstractType<?>> types) throws IOException - { - out.writeByte(bound.kind().ordinal()); - out.writeShort(bound.size()); - ClusteringPrefix.serializer.serializeValuesWithoutSize(bound, out, version, types); - } - - public long serializedSize(RangeTombstone.Bound bound, int version, List<AbstractType<?>> types) - { - return 1 // kind ordinal - + TypeSizes.sizeof((short)bound.size()) - + ClusteringPrefix.serializer.valuesWithoutSizeSerializedSize(bound, version, types); - } - - public RangeTombstone.Bound deserialize(DataInputPlus in, int version, List<AbstractType<?>> types) throws IOException - { - Kind kind = Kind.values()[in.readByte()]; - return deserializeValues(in, kind, version, types); - } - - public void skipValues(DataInputPlus in, Kind kind, int version, - List<AbstractType<?>> types) throws IOException - { - int size = in.readUnsignedShort(); - if (size == 0) - return; - - ClusteringPrefix.serializer.skipValuesWithoutSize(in, size, version, types); - } - - public RangeTombstone.Bound deserializeValues(DataInputPlus in, Kind kind, int version, - List<AbstractType<?>> types) throws IOException - { - int size = in.readUnsignedShort(); - if (size == 0) - return kind.isStart() ? BOTTOM : TOP; - - ByteBuffer[] values = ClusteringPrefix.serializer.deserializeValuesWithoutSize(in, size, version, types); - return new RangeTombstone.Bound(kind, values); - } - } - } } http://git-wip-us.apache.org/repos/asf/cassandra/blob/2cc26eba/src/java/org/apache/cassandra/db/RangeTombstoneList.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/db/RangeTombstoneList.java b/src/java/org/apache/cassandra/db/RangeTombstoneList.java index baeb227..c60b774 100644 --- a/src/java/org/apache/cassandra/db/RangeTombstoneList.java +++ b/src/java/org/apache/cassandra/db/RangeTombstoneList.java @@ -54,15 +54,15 @@ public class RangeTombstoneList implements Iterable<RangeTombstone>, IMeasurable // Note: we don't want to use a List for the markedAts and delTimes to avoid boxing. We could // use a List for starts and ends, but having arrays everywhere is almost simpler. - private Slice.Bound[] starts; - private Slice.Bound[] ends; + private ClusteringBound[] starts; + private ClusteringBound[] ends; private long[] markedAts; private int[] delTimes; private long boundaryHeapSize; private int size; - private RangeTombstoneList(ClusteringComparator comparator, Slice.Bound[] starts, Slice.Bound[] ends, long[] markedAts, int[] delTimes, long boundaryHeapSize, int size) + private RangeTombstoneList(ClusteringComparator comparator, ClusteringBound[] starts, ClusteringBound[] ends, long[] markedAts, int[] delTimes, long boundaryHeapSize, int size) { assert starts.length == ends.length && starts.length == markedAts.length && starts.length == delTimes.length; this.comparator = comparator; @@ -76,7 +76,7 @@ public class RangeTombstoneList implements Iterable<RangeTombstone>, IMeasurable public RangeTombstoneList(ClusteringComparator comparator, int capacity) { - this(comparator, new Slice.Bound[capacity], new Slice.Bound[capacity], new long[capacity], new int[capacity], 0, 0); + this(comparator, new ClusteringBound[capacity], new ClusteringBound[capacity], new long[capacity], new int[capacity], 0, 0); } public boolean isEmpty() @@ -107,8 +107,8 @@ public class RangeTombstoneList implements Iterable<RangeTombstone>, IMeasurable public RangeTombstoneList copy(AbstractAllocator allocator) { RangeTombstoneList copy = new RangeTombstoneList(comparator, - new Slice.Bound[size], - new Slice.Bound[size], + new ClusteringBound[size], + new ClusteringBound[size], Arrays.copyOf(markedAts, size), Arrays.copyOf(delTimes, size), boundaryHeapSize, size); @@ -123,12 +123,12 @@ public class RangeTombstoneList implements Iterable<RangeTombstone>, IMeasurable return copy; } - private static Slice.Bound clone(Slice.Bound bound, AbstractAllocator allocator) + private static ClusteringBound clone(ClusteringBound bound, AbstractAllocator allocator) { ByteBuffer[] values = new ByteBuffer[bound.size()]; for (int i = 0; i < values.length; i++) values[i] = allocator.clone(bound.get(i)); - return new Slice.Bound(bound.kind(), values); + return new ClusteringBound(bound.kind(), values); } public void add(RangeTombstone tombstone) @@ -145,7 +145,7 @@ public class RangeTombstoneList implements Iterable<RangeTombstone>, IMeasurable * This method will be faster if the new tombstone sort after all the currently existing ones (this is a common use case), * but it doesn't assume it. */ - public void add(Slice.Bound start, Slice.Bound end, long markedAt, int delTime) + public void add(ClusteringBound start, ClusteringBound end, long markedAt, int delTime) { if (isEmpty()) { @@ -324,17 +324,17 @@ public class RangeTombstoneList implements Iterable<RangeTombstone>, IMeasurable return new RangeTombstone(Slice.make(starts[idx], ends[idx]), new DeletionTime(markedAts[idx], delTimes[idx])); } - private RangeTombstone rangeTombstoneWithNewStart(int idx, Slice.Bound newStart) + private RangeTombstone rangeTombstoneWithNewStart(int idx, ClusteringBound newStart) { return new RangeTombstone(Slice.make(newStart, ends[idx]), new DeletionTime(markedAts[idx], delTimes[idx])); } - private RangeTombstone rangeTombstoneWithNewEnd(int idx, Slice.Bound newEnd) + private RangeTombstone rangeTombstoneWithNewEnd(int idx, ClusteringBound newEnd) { return new RangeTombstone(Slice.make(starts[idx], newEnd), new DeletionTime(markedAts[idx], delTimes[idx])); } - private RangeTombstone rangeTombstoneWithNewBounds(int idx, Slice.Bound newStart, Slice.Bound newEnd) + private RangeTombstone rangeTombstoneWithNewBounds(int idx, ClusteringBound newStart, ClusteringBound newEnd) { return new RangeTombstone(Slice.make(newStart, newEnd), new DeletionTime(markedAts[idx], delTimes[idx])); } @@ -380,13 +380,13 @@ public class RangeTombstoneList implements Iterable<RangeTombstone>, IMeasurable private Iterator<RangeTombstone> forwardIterator(final Slice slice) { - int startIdx = slice.start() == Slice.Bound.BOTTOM ? 0 : searchInternal(slice.start(), 0, size); + int startIdx = slice.start() == ClusteringBound.BOTTOM ? 0 : searchInternal(slice.start(), 0, size); final int start = startIdx < 0 ? -startIdx-1 : startIdx; if (start >= size) return Collections.emptyIterator(); - int finishIdx = slice.end() == Slice.Bound.TOP ? size - 1 : searchInternal(slice.end(), start, size); + int finishIdx = slice.end() == ClusteringBound.TOP ? size - 1 : searchInternal(slice.end(), start, size); // if stopIdx is the first range after 'slice.end()' we care only until the previous range final int finish = finishIdx < 0 ? -finishIdx-2 : finishIdx; @@ -397,8 +397,8 @@ public class RangeTombstoneList implements Iterable<RangeTombstone>, IMeasurable { // We want to make sure the range are stricly included within the queried slice as this // make it easier to combine things when iterating over successive slices. - Slice.Bound s = comparator.compare(starts[start], slice.start()) < 0 ? slice.start() : starts[start]; - Slice.Bound e = comparator.compare(slice.end(), ends[start]) < 0 ? slice.end() : ends[start]; + ClusteringBound s = comparator.compare(starts[start], slice.start()) < 0 ? slice.start() : starts[start]; + ClusteringBound e = comparator.compare(slice.end(), ends[start]) < 0 ? slice.end() : ends[start]; return Iterators.<RangeTombstone>singletonIterator(rangeTombstoneWithNewBounds(start, s, e)); } @@ -425,14 +425,14 @@ public class RangeTombstoneList implements Iterable<RangeTombstone>, IMeasurable private Iterator<RangeTombstone> reverseIterator(final Slice slice) { - int startIdx = slice.end() == Slice.Bound.TOP ? size - 1 : searchInternal(slice.end(), 0, size); + int startIdx = slice.end() == ClusteringBound.TOP ? size - 1 : searchInternal(slice.end(), 0, size); // if startIdx is the first range after 'slice.end()' we care only until the previous range final int start = startIdx < 0 ? -startIdx-2 : startIdx; if (start < 0) return Collections.emptyIterator(); - int finishIdx = slice.start() == Slice.Bound.BOTTOM ? 0 : searchInternal(slice.start(), 0, start + 1); // include same as finish + int finishIdx = slice.start() == ClusteringBound.BOTTOM ? 0 : searchInternal(slice.start(), 0, start + 1); // include same as finish // if stopIdx is the first range after 'slice.end()' we care only until the previous range final int finish = finishIdx < 0 ? -finishIdx-1 : finishIdx; @@ -443,8 +443,8 @@ public class RangeTombstoneList implements Iterable<RangeTombstone>, IMeasurable { // We want to make sure the range are stricly included within the queried slice as this // make it easier to combine things when iterator over successive slices. - Slice.Bound s = comparator.compare(starts[start], slice.start()) < 0 ? slice.start() : starts[start]; - Slice.Bound e = comparator.compare(slice.end(), ends[start]) < 0 ? slice.end() : ends[start]; + ClusteringBound s = comparator.compare(starts[start], slice.start()) < 0 ? slice.start() : starts[start]; + ClusteringBound e = comparator.compare(slice.end(), ends[start]) < 0 ? slice.end() : ends[start]; return Iterators.<RangeTombstone>singletonIterator(rangeTombstoneWithNewBounds(start, s, e)); } @@ -527,7 +527,7 @@ public class RangeTombstoneList implements Iterable<RangeTombstone>, IMeasurable * - e_i <= s_i+1 * Basically, range are non overlapping and in order. */ - private void insertFrom(int i, Slice.Bound start, Slice.Bound end, long markedAt, int delTime) + private void insertFrom(int i, ClusteringBound start, ClusteringBound end, long markedAt, int delTime) { while (i < size) { @@ -546,7 +546,7 @@ public class RangeTombstoneList implements Iterable<RangeTombstone>, IMeasurable // First deal with what might come before the newly added one. if (comparator.compare(starts[i], start) < 0) { - Slice.Bound newEnd = start.invert(); + ClusteringBound newEnd = start.invert(); if (!Slice.isEmpty(comparator, starts[i], newEnd)) { addInternal(i, starts[i], start.invert(), markedAts[i], delTimes[i]); @@ -594,7 +594,7 @@ public class RangeTombstoneList implements Iterable<RangeTombstone>, IMeasurable // one to reflect the not overwritten parts. We're then done. addInternal(i, start, end, markedAt, delTime); i++; - Slice.Bound newStart = end.invert(); + ClusteringBound newStart = end.invert(); if (!Slice.isEmpty(comparator, newStart, ends[i])) { setInternal(i, newStart, ends[i], markedAts[i], delTimes[i]); @@ -616,7 +616,7 @@ public class RangeTombstoneList implements Iterable<RangeTombstone>, IMeasurable addInternal(i, start, end, markedAt, delTime); return; } - Slice.Bound newEnd = starts[i].invert(); + ClusteringBound newEnd = starts[i].invert(); if (!Slice.isEmpty(comparator, start, newEnd)) { addInternal(i, start, newEnd, markedAt, delTime); @@ -648,7 +648,7 @@ public class RangeTombstoneList implements Iterable<RangeTombstone>, IMeasurable /* * Adds the new tombstone at index i, growing and/or moving elements to make room for it. */ - private void addInternal(int i, Slice.Bound start, Slice.Bound end, long markedAt, int delTime) + private void addInternal(int i, ClusteringBound start, ClusteringBound end, long markedAt, int delTime) { assert i >= 0; @@ -687,12 +687,12 @@ public class RangeTombstoneList implements Iterable<RangeTombstone>, IMeasurable delTimes = grow(delTimes, size, newLength, i); } - private static Slice.Bound[] grow(Slice.Bound[] a, int size, int newLength, int i) + private static ClusteringBound[] grow(ClusteringBound[] a, int size, int newLength, int i) { if (i < 0 || i >= size) return Arrays.copyOf(a, newLength); - Slice.Bound[] newA = new Slice.Bound[newLength]; + ClusteringBound[] newA = new ClusteringBound[newLength]; System.arraycopy(a, 0, newA, 0, i); System.arraycopy(a, i, newA, i+1, size - i); return newA; @@ -737,7 +737,7 @@ public class RangeTombstoneList implements Iterable<RangeTombstone>, IMeasurable starts[i] = null; } - private void setInternal(int i, Slice.Bound start, Slice.Bound end, long markedAt, int delTime) + private void setInternal(int i, ClusteringBound start, ClusteringBound end, long markedAt, int delTime) { if (starts[i] != null) boundaryHeapSize -= starts[i].unsharedHeapSize() + ends[i].unsharedHeapSize(); http://git-wip-us.apache.org/repos/asf/cassandra/blob/2cc26eba/src/java/org/apache/cassandra/db/ReadCommand.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/db/ReadCommand.java b/src/java/org/apache/cassandra/db/ReadCommand.java index 387e062..c842814 100644 --- a/src/java/org/apache/cassandra/db/ReadCommand.java +++ b/src/java/org/apache/cassandra/db/ReadCommand.java @@ -1074,7 +1074,7 @@ public abstract class ReadCommand extends MonitorableImpl implements ReadQuery // slice filter's stop. DataRange.Paging pagingRange = (DataRange.Paging) rangeCommand.dataRange(); Clustering lastReturned = pagingRange.getLastReturned(); - Slice.Bound newStart = Slice.Bound.exclusiveStartOf(lastReturned); + ClusteringBound newStart = ClusteringBound.exclusiveStartOf(lastReturned); Slice lastSlice = filter.requestedSlices().get(filter.requestedSlices().size() - 1); ByteBufferUtil.writeWithShortLength(LegacyLayout.encodeBound(metadata, newStart, true), out); ByteBufferUtil.writeWithShortLength(LegacyLayout.encodeClustering(metadata, lastSlice.end().clustering()), out); @@ -1542,7 +1542,7 @@ public abstract class ReadCommand extends MonitorableImpl implements ReadQuery static long serializedStaticSliceSize(CFMetaData metadata) { // unlike serializeStaticSlice(), but we don't care about reversal for size calculations - ByteBuffer sliceStart = LegacyLayout.encodeBound(metadata, Slice.Bound.BOTTOM, false); + ByteBuffer sliceStart = LegacyLayout.encodeBound(metadata, ClusteringBound.BOTTOM, false); long size = ByteBufferUtil.serializedSizeWithShortLength(sliceStart); size += TypeSizes.sizeof((short) (metadata.comparator.size() * 3 + 2)); @@ -1570,7 +1570,7 @@ public abstract class ReadCommand extends MonitorableImpl implements ReadQuery // slice finish after we've written the static slice start if (!isReversed) { - ByteBuffer sliceStart = LegacyLayout.encodeBound(metadata, Slice.Bound.BOTTOM, false); + ByteBuffer sliceStart = LegacyLayout.encodeBound(metadata, ClusteringBound.BOTTOM, false); ByteBufferUtil.writeWithShortLength(sliceStart, out); } @@ -1586,7 +1586,7 @@ public abstract class ReadCommand extends MonitorableImpl implements ReadQuery if (isReversed) { - ByteBuffer sliceStart = LegacyLayout.encodeBound(metadata, Slice.Bound.BOTTOM, false); + ByteBuffer sliceStart = LegacyLayout.encodeBound(metadata, ClusteringBound.BOTTOM, false); ByteBufferUtil.writeWithShortLength(sliceStart, out); } } @@ -1708,7 +1708,7 @@ public abstract class ReadCommand extends MonitorableImpl implements ReadQuery { Slices.Builder slicesBuilder = new Slices.Builder(metadata.comparator); for (Clustering clustering : requestedRows) - slicesBuilder.add(Slice.Bound.inclusiveStartOf(clustering), Slice.Bound.inclusiveEndOf(clustering)); + slicesBuilder.add(ClusteringBound.inclusiveStartOf(clustering), ClusteringBound.inclusiveEndOf(clustering)); slices = slicesBuilder.build(); } http://git-wip-us.apache.org/repos/asf/cassandra/blob/2cc26eba/src/java/org/apache/cassandra/db/Serializers.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/db/Serializers.java b/src/java/org/apache/cassandra/db/Serializers.java index a0503e0..d6aac64 100644 --- a/src/java/org/apache/cassandra/db/Serializers.java +++ b/src/java/org/apache/cassandra/db/Serializers.java @@ -132,11 +132,11 @@ public class Serializers { // It's a range tombstone bound. It is a start since that's the only part we've ever included // in the index entries. - Slice.Bound.Kind boundKind = eoc > 0 - ? Slice.Bound.Kind.EXCL_START_BOUND - : Slice.Bound.Kind.INCL_START_BOUND; + ClusteringPrefix.Kind boundKind = eoc > 0 + ? ClusteringPrefix.Kind.EXCL_START_BOUND + : ClusteringPrefix.Kind.INCL_START_BOUND; - return Slice.Bound.create(boundKind, components.toArray(new ByteBuffer[components.size()])); + return ClusteringBound.create(boundKind, components.toArray(new ByteBuffer[components.size()])); } }
