From ccab496d2d37c86341d364dea6c27513fda27331 Mon Sep 17 00:00:00 2001 From: Blake Eggleston Date: Tue, 15 Oct 2019 13:04:26 -0700 Subject: [PATCH] Add byte array backed cells Patch by Blake Eggleston; reviewed by Caleb Rackliffe and Marcus Eriksson for CASSANDRA-15393 --- CHANGES.txt | 1 + .../cassandra/cache/CounterCacheKey.java | 21 +- .../org/apache/cassandra/cql3/CQL3Type.java | 17 +- src/java/org/apache/cassandra/cql3/Lists.java | 7 +- src/java/org/apache/cassandra/cql3/Maps.java | 2 +- src/java/org/apache/cassandra/cql3/Sets.java | 2 +- .../org/apache/cassandra/cql3/Tuples.java | 2 +- .../cassandra/cql3/UntypedResultSet.java | 8 +- .../cassandra/cql3/UpdateParameters.java | 14 +- .../cql3/conditions/ColumnCondition.java | 58 +-- .../cql3/conditions/ColumnConditions.java | 2 +- .../cassandra/cql3/conditions/Conditions.java | 2 +- .../cql3/conditions/IfExistsCondition.java | 2 +- .../cql3/conditions/IfNotExistsCondition.java | 2 +- .../ClusteringColumnRestrictions.java | 4 +- .../restrictions/StatementRestrictions.java | 4 +- .../cql3/selection/ResultSetBuilder.java | 12 +- .../cql3/statements/BatchStatement.java | 2 +- .../cql3/statements/CQL3CasRequest.java | 30 +- .../cql3/statements/DeleteStatement.java | 2 +- .../statements/ModificationStatement.java | 45 +- .../cql3/statements/SelectStatement.java | 24 +- .../cql3/statements/UpdateStatement.java | 2 +- .../db/AbstractArrayClusteringPrefix.java | 53 +++ .../db/AbstractBufferClusteringPrefix.java | 46 +- .../db/AbstractClusteringPrefix.java | 77 ---- .../db/AbstractOnHeapClusteringPrefix.java | 67 +++ .../db/AbstractReadCommandBuilder.java | 41 +- .../apache/cassandra/db/ArrayClustering.java | 46 ++ .../cassandra/db/ArrayClusteringBound.java | 58 +++ .../db/ArrayClusteringBoundOrBoundary.java | 37 ++ .../cassandra/db/ArrayClusteringBoundary.java | 60 +++ .../apache/cassandra/db/BufferClustering.java | 23 +- .../cassandra/db/BufferClusteringBound.java | 79 ++++ .../db/BufferClusteringBoundOrBoundary.java | 33 ++ .../db/BufferClusteringBoundary.java | 70 +++ .../org/apache/cassandra/db/CBuilder.java | 94 ++-- .../org/apache/cassandra/db/Clusterable.java | 4 +- .../org/apache/cassandra/db/Clustering.java | 36 +- .../apache/cassandra/db/ClusteringBound.java | 154 +++---- .../db/ClusteringBoundOrBoundary.java | 87 +--- .../cassandra/db/ClusteringBoundary.java | 45 +- .../cassandra/db/ClusteringComparator.java | 40 +- .../apache/cassandra/db/ClusteringPrefix.java | 184 ++++++-- .../cassandra/db/ColumnFamilyStore.java | 4 +- .../org/apache/cassandra/db/ColumnIndex.java | 4 +- .../apache/cassandra/db/CounterMutation.java | 11 +- .../org/apache/cassandra/db/DataRange.java | 11 +- .../org/apache/cassandra/db/DeletionInfo.java | 2 +- .../org/apache/cassandra/db/DeletionTime.java | 2 +- src/java/org/apache/cassandra/db/Digest.java | 25 +- .../apache/cassandra/db/MultiCBuilder.java | 46 +- .../cassandra/db/MutableDeletionInfo.java | 6 +- .../apache/cassandra/db/NativeClustering.java | 38 +- .../cassandra/db/PartitionRangeReadQuery.java | 2 +- .../cassandra/db/RangeTombstoneList.java | 66 +-- .../org/apache/cassandra/db/ReadCommand.java | 4 +- .../org/apache/cassandra/db/ReadQuery.java | 4 +- .../apache/cassandra/db/RowIndexEntry.java | 6 +- .../apache/cassandra/db/SimpleBuilders.java | 14 +- .../db/SinglePartitionReadCommand.java | 20 +- .../db/SinglePartitionReadQuery.java | 6 +- src/java/org/apache/cassandra/db/Slice.java | 64 ++- src/java/org/apache/cassandra/db/Slices.java | 44 +- .../org/apache/cassandra/db/TypeSizes.java | 32 +- .../cassandra/db/UnfilteredDeserializer.java | 5 +- .../VirtualTableSinglePartitionReadQuery.java | 2 +- .../cassandra/db/aggregation/GroupMaker.java | 8 +- .../db/aggregation/GroupingState.java | 9 +- .../AbstractSSTableIterator.java | 8 +- .../db/columniterator/SSTableIterator.java | 8 +- .../SSTableReversedIterator.java | 8 +- .../cassandra/db/compaction/Scrubber.java | 8 +- .../cassandra/db/context/CounterContext.java | 71 +-- .../db/filter/ClusteringIndexFilter.java | 4 +- .../db/filter/ClusteringIndexNamesFilter.java | 36 +- .../db/filter/ClusteringIndexSliceFilter.java | 4 +- .../cassandra/db/filter/ColumnFilter.java | 2 +- .../apache/cassandra/db/filter/RowFilter.java | 22 +- .../TombstoneOverwhelmingException.java | 6 +- .../db/marshal/AbstractCompositeType.java | 139 +++--- .../cassandra/db/marshal/AbstractType.java | 148 ++++--- .../cassandra/db/marshal/BooleanType.java | 14 +- .../db/marshal/ByteArrayAccessor.java | 294 ++++++++++++ .../db/marshal/ByteArrayObjectFactory.java | 82 ++++ .../db/marshal/ByteBufferAccessor.java | 292 ++++++++++++ .../db/marshal/ByteBufferObjectFactory.java | 86 ++++ .../apache/cassandra/db/marshal/ByteType.java | 4 +- .../cassandra/db/marshal/CollectionType.java | 16 +- .../cassandra/db/marshal/CompositeType.java | 96 ++-- .../db/marshal/CounterColumnType.java | 13 +- .../cassandra/db/marshal/DecimalType.java | 7 +- .../cassandra/db/marshal/DoubleType.java | 7 +- .../db/marshal/DynamicCompositeType.java | 68 ++- .../cassandra/db/marshal/EmptyType.java | 13 +- .../cassandra/db/marshal/FloatType.java | 7 +- .../cassandra/db/marshal/FrozenType.java | 2 +- .../cassandra/db/marshal/Int32Type.java | 10 +- .../cassandra/db/marshal/IntegerType.java | 30 +- .../cassandra/db/marshal/LexicalUUIDType.java | 10 +- .../apache/cassandra/db/marshal/ListType.java | 46 +- .../apache/cassandra/db/marshal/LongType.java | 14 +- .../apache/cassandra/db/marshal/MapType.java | 63 +-- .../db/marshal/PartitionerDefinedOrder.java | 13 +- .../cassandra/db/marshal/ReversedType.java | 12 +- .../apache/cassandra/db/marshal/SetType.java | 13 +- .../cassandra/db/marshal/ShortType.java | 7 +- .../cassandra/db/marshal/TimeUUIDType.java | 21 +- .../cassandra/db/marshal/TimestampType.java | 4 +- .../cassandra/db/marshal/TupleType.java | 97 ++-- .../apache/cassandra/db/marshal/UTF8Type.java | 1 - .../apache/cassandra/db/marshal/UUIDType.java | 20 +- .../apache/cassandra/db/marshal/UserType.java | 16 +- .../cassandra/db/marshal/ValueAccessor.java | 418 ++++++++++++++++++ .../db/marshal/ValueComparators.java | 43 ++ .../db/partitions/AbstractBTreePartition.java | 12 +- .../db/partitions/AtomicBTreePartition.java | 6 +- .../db/partitions/CachedBTreePartition.java | 2 +- .../cassandra/db/partitions/Partition.java | 4 +- .../PartitionStatisticsCollector.java | 2 +- .../db/partitions/PartitionUpdate.java | 16 +- .../cassandra/db/rows/AbstractCell.java | 57 +-- .../db/rows/AbstractRangeTombstoneMarker.java | 8 +- .../apache/cassandra/db/rows/AbstractRow.java | 27 +- .../apache/cassandra/db/rows/ArrayCell.java | 111 +++++ .../apache/cassandra/db/rows/BTreeRow.java | 82 ++-- .../apache/cassandra/db/rows/BufferCell.java | 17 +- .../org/apache/cassandra/db/rows/Cell.java | 64 +-- .../org/apache/cassandra/db/rows/Cells.java | 73 ++- .../cassandra/db/rows/ComplexColumnData.java | 41 +- .../cassandra/db/rows/CounterCells.java | 4 +- .../db/rows/DeserializationHelper.java | 13 +- .../cassandra/db/rows/EncodingStats.java | 2 +- .../apache/cassandra/db/rows/NativeCell.java | 21 +- .../db/rows/RangeTombstoneBoundMarker.java | 46 +- .../db/rows/RangeTombstoneBoundaryMarker.java | 58 ++- .../db/rows/RangeTombstoneMarker.java | 22 +- .../org/apache/cassandra/db/rows/Row.java | 40 +- .../db/rows/RowAndDeletionMergeIterator.java | 4 +- .../cassandra/db/rows/RowDiffListener.java | 8 +- .../org/apache/cassandra/db/rows/Rows.java | 36 +- .../db/rows/ThrottledUnfilteredIterator.java | 5 +- .../apache/cassandra/db/rows/Unfiltered.java | 10 +- .../UnfilteredRowIteratorWithLowerBound.java | 22 +- .../db/rows/UnfilteredSerializer.java | 25 +- .../db/transform/DuplicateRowChecker.java | 2 +- .../cassandra/db/transform/RTBoundCloser.java | 4 +- .../apache/cassandra/db/view/TableViews.java | 6 +- .../db/view/ViewUpdateGenerator.java | 41 +- .../cassandra/db/virtual/SimpleDataSet.java | 13 +- .../apache/cassandra/gms/TokenSerializer.java | 4 +- .../hadoop/cql3/CqlRecordWriter.java | 3 +- .../index/SecondaryIndexManager.java | 23 +- .../index/internal/CassandraIndex.java | 52 +-- .../internal/CassandraIndexSearcher.java | 18 +- .../cassandra/index/internal/IndexEntry.java | 8 +- .../composites/ClusteringColumnIndex.java | 22 +- .../composites/CollectionEntryIndex.java | 9 +- .../composites/CollectionKeyIndex.java | 4 +- .../composites/CollectionKeyIndexBase.java | 16 +- .../composites/CollectionValueIndex.java | 22 +- .../composites/CompositesSearcher.java | 8 +- .../composites/PartitionKeyIndex.java | 16 +- .../composites/RegularColumnIndex.java | 33 +- .../index/internal/keys/KeysIndex.java | 20 +- .../index/internal/keys/KeysSearcher.java | 2 +- .../index/sasi/conf/ColumnIndex.java | 6 +- .../io/sstable/CQLSSTableWriter.java | 4 +- .../cassandra/io/sstable/IndexInfo.java | 13 +- .../sstable/metadata/CompactionMetadata.java | 3 +- .../sstable/metadata/MetadataCollector.java | 12 +- .../cassandra/schema/ColumnMetadata.java | 12 +- .../serializers/AbstractTextSerializer.java | 16 +- .../serializers/AsciiSerializer.java | 9 +- .../serializers/BooleanSerializer.java | 22 +- .../cassandra/serializers/ByteSerializer.java | 17 +- .../serializers/BytesSerializer.java | 13 +- .../serializers/CollectionSerializer.java | 83 ++-- .../serializers/DecimalSerializer.java | 21 +- .../serializers/DoubleSerializer.java | 19 +- .../serializers/DurationSerializer.java | 21 +- .../serializers/EmptySerializer.java | 15 +- .../serializers/FloatSerializer.java | 19 +- .../serializers/InetAddressSerializer.java | 17 +- .../serializers/Int32Serializer.java | 17 +- .../serializers/IntegerSerializer.java | 9 +- .../cassandra/serializers/ListSerializer.java | 67 +-- .../cassandra/serializers/LongSerializer.java | 17 +- .../cassandra/serializers/MapSerializer.java | 84 ++-- .../cassandra/serializers/SetSerializer.java | 72 +-- .../serializers/ShortSerializer.java | 17 +- .../serializers/SimpleDateSerializer.java | 13 +- .../cassandra/serializers/TimeSerializer.java | 13 +- .../serializers/TimeUUIDSerializer.java | 14 +- .../serializers/TimestampSerializer.java | 17 +- .../serializers/TupleSerializer.java | 25 +- .../cassandra/serializers/TypeSerializer.java | 36 +- .../cassandra/serializers/UTF8Serializer.java | 17 +- .../cassandra/serializers/UUIDSerializer.java | 14 +- .../serializers/UserTypeSerializer.java | 26 +- .../cassandra/service/CacheService.java | 5 +- .../service/pager/AbstractQueryPager.java | 2 +- .../service/pager/AggregationQueryPager.java | 6 +- .../cassandra/service/pager/PagingState.java | 24 +- .../service/pager/SinglePartitionPager.java | 2 +- .../reads/ReplicaFilteringProtection.java | 4 +- .../reads/ShortReadRowsProtection.java | 4 +- .../repair/RowIteratorMergeListener.java | 20 +- .../cassandra/tools/JsonTransformer.java | 14 +- .../tools/SSTableMetadataViewer.java | 2 +- .../apache/cassandra/utils/ByteArrayUtil.java | 285 +++++++----- .../cassandra/utils/ByteBufferUtil.java | 17 +- .../cassandra/utils/FastByteOperations.java | 42 ++ .../utils/NativeSSTableLoaderClient.java | 2 - .../utils/memory/AbstractAllocator.java | 29 +- .../cassandra/utils/memory/EnsureOnHeap.java | 10 +- .../utils/memory/NativeAllocator.java | 4 +- .../apache/cassandra/distributed/Cluster.java | 1 - .../db/commitlog/CommitLogStressTest.java | 6 +- .../hints/HintsWriteThenReadTest.java | 2 +- test/unit/org/apache/cassandra/Util.java | 22 +- .../cassandra/cql3/CQL3TypeLiteralTest.java | 20 +- .../org/apache/cassandra/cql3/ListsTest.java | 6 +- .../TombstonesWithIndexedSSTableTest.java | 4 +- .../apache/cassandra/cql3/UDHelperTest.java | 5 +- .../ClusteringColumnRestrictionsTest.java | 64 +-- .../entities/SecondaryIndexTest.java | 8 +- .../validation/entities/VirtualTableTest.java | 2 +- .../org/apache/cassandra/db/CellTest.java | 54 +-- .../cassandra/db/ClusteringBoundTest.java | 43 ++ .../cassandra/db/ColumnFamilyStoreTest.java | 4 +- .../apache/cassandra/db/CounterCacheTest.java | 12 +- .../apache/cassandra/db/CounterCellTest.java | 65 +-- .../cassandra/db/CounterMutationTest.java | 20 +- .../org/apache/cassandra/db/KeyspaceTest.java | 40 +- .../org/apache/cassandra/db/NameSortTest.java | 2 +- .../apache/cassandra/db/NativeCellTest.java | 4 +- .../cassandra/db/PartitionRangeReadTest.java | 20 +- .../apache/cassandra/db/PartitionTest.java | 2 +- .../cassandra/db/RangeTombstoneListTest.java | 16 +- .../cassandra/db/RangeTombstoneTest.java | 2 +- .../apache/cassandra/db/ReadCommandTest.java | 8 +- .../cassandra/db/RecoveryManagerTest.java | 2 +- .../cassandra/db/RepairedDataInfoTest.java | 6 +- .../db/RepairedDataTombstonesTest.java | 4 +- .../org/apache/cassandra/db/RowCacheTest.java | 25 +- .../cassandra/db/RowIndexEntryTest.java | 20 +- .../unit/org/apache/cassandra/db/RowTest.java | 18 +- .../cassandra/db/SecondaryIndexTest.java | 2 +- .../cassandra/db/SerializationHeaderTest.java | 10 +- .../db/SinglePartitionSliceCommandTest.java | 17 +- .../apache/cassandra/db/TransformerTest.java | 4 +- .../db/aggregation/GroupMakerTest.java | 2 +- .../db/commitlog/CommitLogReaderTest.java | 2 +- .../db/commitlog/CommitLogUpgradeTest.java | 6 +- .../db/compaction/CompactionsCQLTest.java | 2 +- .../db/compaction/CompactionsTest.java | 13 +- .../db/compaction/NeverPurgeTest.java | 2 +- .../cassandra/db/composites/CTypeTest.java | 17 +- .../db/context/CounterContextTest.java | 35 +- .../apache/cassandra/db/filter/SliceTest.java | 4 +- .../db/marshal/ByteBufferAccessorTest.java | 85 ++++ .../db/marshal/CollectionTypesTest.java | 124 ++++++ .../marshal/CompositeAndTupleTypesTest.java | 138 ++++++ .../db/marshal/CompositeTypeTest.java | 6 +- .../db/marshal/DynamicCompositeTypeTest.java | 4 +- .../cassandra/db/marshal/EmptyTypeTest.java | 4 +- .../db/marshal/ValueAccessorTest.java | 132 ++++++ .../cassandra/db/marshal/ValueAccessors.java | 62 +++ .../cassandra/db/marshal/ValueGenerator.java | 95 ++++ .../PartitionImplementationTest.java | 49 +- .../db/partitions/PurgeFunctionTest.java | 4 +- .../rows/RowAndDeletionMergeIteratorTest.java | 36 +- .../apache/cassandra/db/rows/RowBuilder.java | 10 +- .../apache/cassandra/db/rows/RowsTest.java | 88 ++-- .../rows/ThrottledUnfilteredIteratorTest.java | 22 +- .../rows/UnfilteredRowIteratorsMergeTest.java | 24 +- .../db/rows/UnfilteredRowIteratorsTest.java | 6 +- .../db/rows/UnfilteredRowsGenerator.java | 20 +- .../db/transform/RTTransformationsTest.java | 4 +- .../cassandra/hints/HintsBufferTest.java | 7 +- .../cassandra/hints/HintsReaderTest.java | 7 +- .../cassandra/index/CustomIndexTest.java | 2 +- .../index/internal/CustomCassandraIndex.java | 54 +-- .../cassandra/index/sasi/SASIIndexTest.java | 22 +- .../index/sasi/plan/OperationTest.java | 14 +- .../io/sstable/IndexSummaryManagerTest.java | 4 +- .../io/sstable/SSTableLoaderTest.java | 4 +- .../io/sstable/SSTableMetadataTest.java | 3 +- .../io/sstable/SSTableReaderTest.java | 2 +- .../format/SSTableFlushObserverTest.java | 8 +- .../cassandra/io/util/DataOutputTest.java | 17 +- .../cassandra/service/PaxosStateTest.java | 2 +- .../cassandra/service/QueryPagerTest.java | 8 +- .../reads/AbstractReadResponseTest.java | 12 +- .../service/reads/DataResolverTest.java | 24 +- .../reads/repair/AbstractReadRepairTest.java | 18 +- .../service/reads/repair/ReadRepairTest.java | 12 +- .../streaming/StreamingTransferTest.java | 4 +- .../triggers/TriggerExecutorTest.java | 2 +- .../cassandra/utils/ByteArrayUtilTest.java | 18 +- .../cassandra/utils/CassandraGenerators.java | 3 +- .../io/sstable/StressCQLSSTableWriter.java | 4 +- 303 files changed, 5720 insertions(+), 2820 deletions(-) create mode 100644 src/java/org/apache/cassandra/db/AbstractArrayClusteringPrefix.java delete mode 100644 src/java/org/apache/cassandra/db/AbstractClusteringPrefix.java create mode 100644 src/java/org/apache/cassandra/db/AbstractOnHeapClusteringPrefix.java create mode 100644 src/java/org/apache/cassandra/db/ArrayClustering.java create mode 100644 src/java/org/apache/cassandra/db/ArrayClusteringBound.java create mode 100644 src/java/org/apache/cassandra/db/ArrayClusteringBoundOrBoundary.java create mode 100644 src/java/org/apache/cassandra/db/ArrayClusteringBoundary.java create mode 100644 src/java/org/apache/cassandra/db/BufferClusteringBound.java create mode 100644 src/java/org/apache/cassandra/db/BufferClusteringBoundOrBoundary.java create mode 100644 src/java/org/apache/cassandra/db/BufferClusteringBoundary.java create mode 100644 src/java/org/apache/cassandra/db/marshal/ByteArrayAccessor.java create mode 100644 src/java/org/apache/cassandra/db/marshal/ByteArrayObjectFactory.java create mode 100644 src/java/org/apache/cassandra/db/marshal/ByteBufferAccessor.java create mode 100644 src/java/org/apache/cassandra/db/marshal/ByteBufferObjectFactory.java create mode 100644 src/java/org/apache/cassandra/db/marshal/ValueAccessor.java create mode 100644 src/java/org/apache/cassandra/db/marshal/ValueComparators.java create mode 100644 src/java/org/apache/cassandra/db/rows/ArrayCell.java create mode 100644 test/unit/org/apache/cassandra/db/ClusteringBoundTest.java create mode 100644 test/unit/org/apache/cassandra/db/marshal/ByteBufferAccessorTest.java create mode 100644 test/unit/org/apache/cassandra/db/marshal/CollectionTypesTest.java create mode 100644 test/unit/org/apache/cassandra/db/marshal/CompositeAndTupleTypesTest.java create mode 100644 test/unit/org/apache/cassandra/db/marshal/ValueAccessorTest.java create mode 100644 test/unit/org/apache/cassandra/db/marshal/ValueAccessors.java create mode 100644 test/unit/org/apache/cassandra/db/marshal/ValueGenerator.java diff --git a/CHANGES.txt b/CHANGES.txt index 90238ef73a..fa281012d6 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,4 +1,5 @@ 4.0-beta3 + * Add byte array backed cells (CASSANDRA-15393) * Correctly handle pending ranges with adjacent range movements (CASSANDRA-14801) * Avoid adding locahost when streaming trivial ranges (CASSANDRA-16099) * Add nodetool getfullquerylog (CASSANDRA-15988) diff --git a/src/java/org/apache/cassandra/cache/CounterCacheKey.java b/src/java/org/apache/cassandra/cache/CounterCacheKey.java index dc3ce4ebc7..1f8526340a 100644 --- a/src/java/org/apache/cassandra/cache/CounterCacheKey.java +++ b/src/java/org/apache/cassandra/cache/CounterCacheKey.java @@ -27,6 +27,7 @@ import org.apache.cassandra.db.*; import org.apache.cassandra.db.filter.ClusteringIndexFilter; import org.apache.cassandra.db.filter.ClusteringIndexNamesFilter; import org.apache.cassandra.db.filter.ColumnFilter; +import org.apache.cassandra.db.marshal.ByteBufferAccessor; import org.apache.cassandra.db.marshal.CompositeType; import org.apache.cassandra.db.marshal.UTF8Type; import org.apache.cassandra.db.rows.CellPath; @@ -61,22 +62,22 @@ public final class CounterCacheKey extends CacheKey this(tableMetadata, ByteBufferUtil.getArray(partitionKey), ByteBufferUtil.getArray(cellName)); } - public static CounterCacheKey create(TableMetadata tableMetadata, ByteBuffer partitionKey, Clustering clustering, ColumnMetadata c, CellPath path) + public static CounterCacheKey create(TableMetadata tableMetadata, ByteBuffer partitionKey, Clustering clustering, ColumnMetadata c, CellPath path) { return new CounterCacheKey(tableMetadata, partitionKey, makeCellName(clustering, c, path)); } - private static ByteBuffer makeCellName(Clustering clustering, ColumnMetadata c, CellPath path) + private static ByteBuffer makeCellName(Clustering clustering, ColumnMetadata c, CellPath path) { int cs = clustering.size(); ByteBuffer[] values = new ByteBuffer[cs + 1 + (path == null ? 0 : path.size())]; for (int i = 0; i < cs; i++) - values[i] = clustering.get(i); + values[i] = clustering.bufferAt(i); values[cs] = c.name.bytes; if (path != null) for (int i = 0; i < path.size(); i++) values[cs + 1 + i] = path.get(i); - return CompositeType.build(values); + return CompositeType.build(ByteBufferAccessor.instance, values); } public ByteBuffer partitionKey() @@ -99,10 +100,10 @@ public final class CounterCacheKey extends CacheKey DecoratedKey key = cfs.decorateKey(partitionKey()); int clusteringSize = metadata.comparator.size(); - List buffers = CompositeType.splitName(ByteBuffer.wrap(cellName)); + List buffers = CompositeType.splitName(ByteBuffer.wrap(cellName), ByteBufferAccessor.instance); assert buffers.size() >= clusteringSize + 1; // See makeCellName above - Clustering clustering = Clustering.make(buffers.subList(0, clusteringSize).toArray(new ByteBuffer[clusteringSize])); + Clustering clustering = Clustering.make(buffers.subList(0, clusteringSize).toArray(new ByteBuffer[clusteringSize])); ColumnMetadata column = metadata.getColumn(buffers.get(clusteringSize)); // This can theoretically happen if a column is dropped after the cache is saved and we // try to load it. Not point if failing in any case, just skip the value. @@ -125,9 +126,9 @@ public final class CounterCacheKey extends CacheKey { ByteBuffer value = null; if (column.isStatic()) - value = iter.staticRow().getCell(column).value(); + value = iter.staticRow().getCell(column).buffer(); else if (iter.hasNext()) - value = iter.next().getCell(column).value(); + value = iter.next().getCell(column).buffer(); return value; } @@ -136,8 +137,8 @@ public final class CounterCacheKey extends CacheKey public void write(DataOutputPlus out) throws IOException { - ByteBufferUtil.writeWithLength(partitionKey, out); - ByteBufferUtil.writeWithLength(cellName, out); + ByteArrayUtil.writeWithLength(partitionKey, out); + ByteArrayUtil.writeWithLength(cellName, out); } public static CounterCacheKey read(TableMetadata tableMetadata, DataInputPlus in) diff --git a/src/java/org/apache/cassandra/cql3/CQL3Type.java b/src/java/org/apache/cassandra/cql3/CQL3Type.java index 84aab07787..5059104446 100644 --- a/src/java/org/apache/cassandra/cql3/CQL3Type.java +++ b/src/java/org/apache/cassandra/cql3/CQL3Type.java @@ -24,6 +24,7 @@ import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.apache.cassandra.db.TypeSizes; import org.apache.cassandra.schema.Schema; import org.apache.cassandra.db.marshal.*; import org.apache.cassandra.db.marshal.CollectionType.Kind; @@ -57,11 +58,11 @@ public interface CQL3Type /** * Generates CQL literal from a binary value of this type. - * @param buffer the value to convert to a CQL literal. This value must be + * @param bytes the value to convert to a CQL literal. This value must be * serialized with {@code version} of the native protocol. * @param version the native protocol version in which {@code buffer} is encoded. */ - public String toCQLLiteral(ByteBuffer buffer, ProtocolVersion version); + String toCQLLiteral(ByteBuffer bytes, ProtocolVersion version); public enum Native implements CQL3Type { @@ -196,6 +197,7 @@ public interface CQL3Type StringBuilder target = new StringBuilder(); buffer = buffer.duplicate(); int size = CollectionSerializer.readCollectionSize(buffer, version); + buffer.position(buffer.position() + CollectionSerializer.sizeOfCollectionSize(size, version)); switch (type.kind) { @@ -224,25 +226,30 @@ public interface CQL3Type { CQL3Type keys = ((MapType) type).getKeysType().asCQL3Type(); CQL3Type values = ((MapType) type).getValuesType().asCQL3Type(); + int offset = 0; for (int i = 0; i < size; i++) { if (i > 0) target.append(", "); - ByteBuffer element = CollectionSerializer.readValue(buffer, version); + ByteBuffer element = CollectionSerializer.readValue(buffer, ByteBufferAccessor.instance, offset, version); + offset += CollectionSerializer.sizeOfValue(element, ByteBufferAccessor.instance, version); target.append(keys.toCQLLiteral(element, version)); target.append(": "); - element = CollectionSerializer.readValue(buffer, version); + element = CollectionSerializer.readValue(buffer, ByteBufferAccessor.instance, offset, version); + offset += CollectionSerializer.sizeOfValue(element, ByteBufferAccessor.instance, version); target.append(values.toCQLLiteral(element, version)); } } private static void generateSetOrListCQLLiteral(ByteBuffer buffer, ProtocolVersion version, StringBuilder target, int size, CQL3Type elements) { + int offset = 0; for (int i = 0; i < size; i++) { if (i > 0) target.append(", "); - ByteBuffer element = CollectionSerializer.readValue(buffer, version); + ByteBuffer element = CollectionSerializer.readValue(buffer, ByteBufferAccessor.instance, offset, version); + offset += CollectionSerializer.sizeOfValue(element, ByteBufferAccessor.instance, version); target.append(elements.toCQLLiteral(element, version)); } } diff --git a/src/java/org/apache/cassandra/cql3/Lists.java b/src/java/org/apache/cassandra/cql3/Lists.java index 14961c9cb7..1d94d697a5 100644 --- a/src/java/org/apache/cassandra/cql3/Lists.java +++ b/src/java/org/apache/cassandra/cql3/Lists.java @@ -28,6 +28,7 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; import java.util.stream.StreamSupport; +import org.apache.cassandra.db.marshal.ByteBufferAccessor; import org.apache.cassandra.schema.ColumnMetadata; import com.google.common.annotations.VisibleForTesting; import org.apache.cassandra.cql3.functions.Function; @@ -210,7 +211,7 @@ public abstract class Lists { // Collections have this small hack that validate cannot be called on a serialized object, // but compose does the validation (so we're fine). - List l = type.getSerializer().deserializeForNativeProtocol(value, version); + List l = type.getSerializer().deserializeForNativeProtocol(value, ByteBufferAccessor.instance, version); List elements = new ArrayList<>(l.size()); for (Object element : l) // elements can be null in lists that represent a set of IN values @@ -576,9 +577,9 @@ public abstract class Lists // the read-before-write this operation requires limits its usefulness on big lists, so in practice // toDiscard will be small and keeping a list will be more efficient. List toDiscard = ((Value)value).elements; - for (Cell cell : complexData) + for (Cell cell : complexData) { - if (toDiscard.contains(cell.value())) + if (toDiscard.contains(cell.buffer())) params.addTombstone(column, cell.path()); } } diff --git a/src/java/org/apache/cassandra/cql3/Maps.java b/src/java/org/apache/cassandra/cql3/Maps.java index 4ae98f56e8..6e7e07b576 100644 --- a/src/java/org/apache/cassandra/cql3/Maps.java +++ b/src/java/org/apache/cassandra/cql3/Maps.java @@ -228,7 +228,7 @@ public abstract class Maps { // Collections have this small hack that validate cannot be called on a serialized object, // but compose does the validation (so we're fine). - Map m = type.getSerializer().deserializeForNativeProtocol(value, version); + Map m = type.getSerializer().deserializeForNativeProtocol(value, ByteBufferAccessor.instance, version); Map map = new LinkedHashMap<>(m.size()); for (Map.Entry entry : m.entrySet()) map.put(type.getKeysType().decompose(entry.getKey()), type.getValuesType().decompose(entry.getValue())); diff --git a/src/java/org/apache/cassandra/cql3/Sets.java b/src/java/org/apache/cassandra/cql3/Sets.java index 7084477b20..aab4192587 100644 --- a/src/java/org/apache/cassandra/cql3/Sets.java +++ b/src/java/org/apache/cassandra/cql3/Sets.java @@ -214,7 +214,7 @@ public abstract class Sets { // Collections have this small hack that validate cannot be called on a serialized object, // but compose does the validation (so we're fine). - Set s = type.getSerializer().deserializeForNativeProtocol(value, version); + Set s = type.getSerializer().deserializeForNativeProtocol(value, ByteBufferAccessor.instance, version); SortedSet elements = new TreeSet<>(type.getElementsType()); for (Object element : s) elements.add(type.getElementsType().decompose(element)); diff --git a/src/java/org/apache/cassandra/cql3/Tuples.java b/src/java/org/apache/cassandra/cql3/Tuples.java index 317e192065..b8acd5954a 100644 --- a/src/java/org/apache/cassandra/cql3/Tuples.java +++ b/src/java/org/apache/cassandra/cql3/Tuples.java @@ -264,7 +264,7 @@ public class Tuples { // Collections have this small hack that validate cannot be called on a serialized object, // but the deserialization does the validation (so we're fine). - List l = type.getSerializer().deserializeForNativeProtocol(value, options.getProtocolVersion()); + List l = type.getSerializer().deserializeForNativeProtocol(value, ByteBufferAccessor.instance, options.getProtocolVersion()); assert type.getElementsType() instanceof TupleType; TupleType tupleType = Tuples.getTupleType(type.getElementsType()); diff --git a/src/java/org/apache/cassandra/cql3/UntypedResultSet.java b/src/java/org/apache/cassandra/cql3/UntypedResultSet.java index 5de4eaee73..f4ac99fdc4 100644 --- a/src/java/org/apache/cassandra/cql3/UntypedResultSet.java +++ b/src/java/org/apache/cassandra/cql3/UntypedResultSet.java @@ -310,17 +310,17 @@ public abstract class UntypedResultSet implements Iterable for (ColumnMetadata def : metadata.partitionKeyColumns()) data.put(def.name.toString(), keyComponents[def.position()]); - Clustering clustering = row.clustering(); + Clustering clustering = row.clustering(); for (ColumnMetadata def : metadata.clusteringColumns()) - data.put(def.name.toString(), clustering.get(def.position())); + data.put(def.name.toString(), clustering.bufferAt(def.position())); for (ColumnMetadata def : metadata.regularAndStaticColumns()) { if (def.isSimple()) { - Cell cell = row.getCell(def); + Cell cell = row.getCell(def); if (cell != null) - data.put(def.name.toString(), cell.value()); + data.put(def.name.toString(), cell.buffer()); } else { diff --git a/src/java/org/apache/cassandra/cql3/UpdateParameters.java b/src/java/org/apache/cassandra/cql3/UpdateParameters.java index 5579e103b1..f90958bb98 100644 --- a/src/java/org/apache/cassandra/cql3/UpdateParameters.java +++ b/src/java/org/apache/cassandra/cql3/UpdateParameters.java @@ -80,7 +80,7 @@ public class UpdateParameters throw new InvalidRequestException(String.format("Out of bound timestamp, must be in [%d, %d]", Long.MIN_VALUE + 1, Long.MAX_VALUE)); } - public void newRow(Clustering clustering) throws InvalidRequestException + public void newRow(Clustering clustering) throws InvalidRequestException { if (clustering == Clustering.STATIC_CLUSTERING) { @@ -98,7 +98,7 @@ public class UpdateParameters builder.newRow(clustering); } - public Clustering currentClustering() + public Clustering currentClustering() { return builder.clustering(); } @@ -130,9 +130,9 @@ public class UpdateParameters public void addCell(ColumnMetadata column, CellPath path, ByteBuffer value) throws InvalidRequestException { - Cell cell = ttl == LivenessInfo.NO_TTL - ? BufferCell.live(column, timestamp, value, path) - : BufferCell.expiring(column, timestamp, ttl, nowInSec, value, path); + Cell cell = ttl == LivenessInfo.NO_TTL + ? BufferCell.live(column, timestamp, value, path) + : BufferCell.expiring(column, timestamp, ttl, nowInSec, value, path); builder.addCell(cell); } @@ -177,7 +177,7 @@ public class UpdateParameters return deletionTime; } - public RangeTombstone makeRangeTombstone(ClusteringComparator comparator, Clustering clustering) + public RangeTombstone makeRangeTombstone(ClusteringComparator comparator, Clustering clustering) { return makeRangeTombstone(Slice.make(comparator, clustering)); } @@ -197,7 +197,7 @@ public class UpdateParameters * @param clustering the row clustering * @return the prefetched row with the already performed modifications */ - public Row getPrefetchedRow(DecoratedKey key, Clustering clustering) + public Row getPrefetchedRow(DecoratedKey key, Clustering clustering) { if (prefetchedRows == null) return null; diff --git a/src/java/org/apache/cassandra/cql3/conditions/ColumnCondition.java b/src/java/org/apache/cassandra/cql3/conditions/ColumnCondition.java index aa5c10d8d9..93ed6ae941 100644 --- a/src/java/org/apache/cassandra/cql3/conditions/ColumnCondition.java +++ b/src/java/org/apache/cassandra/cql3/conditions/ColumnCondition.java @@ -259,29 +259,29 @@ public abstract class ColumnCondition } } - protected static final Cell getCell(Row row, ColumnMetadata column) + protected static final Cell getCell(Row row, ColumnMetadata column) { // If we're asking for a given cell, and we didn't got any row from our read, it's // the same as not having said cell. return row == null ? null : row.getCell(column); } - protected static final Cell getCell(Row row, ColumnMetadata column, CellPath path) + protected static final Cell getCell(Row row, ColumnMetadata column, CellPath path) { // If we're asking for a given cell, and we didn't got any row from our read, it's // the same as not having said cell. return row == null ? null : row.getCell(column, path); } - protected static final Iterator getCells(Row row, ColumnMetadata column) + protected static final Iterator> getCells(Row row, ColumnMetadata column) { // If we're asking for a complex cells, and we didn't got any row from our read, it's // the same as not having any cells for that column. if (row == null) - return Collections.emptyIterator(); + return Collections.emptyIterator(); ComplexColumnData complexData = row.getComplexColumnData(column); - return complexData == null ? Collections.emptyIterator() : complexData.iterator(); + return complexData == null ? Collections.>emptyIterator() : complexData.iterator(); } protected static final boolean evaluateComparisonWithOperator(int comparison, Operator operator) @@ -328,8 +328,8 @@ public abstract class ColumnCondition private ByteBuffer rowValue(Row row) { - Cell c = getCell(row, column); - return c == null ? null : c.value(); + Cell c = getCell(row, column); + return c == null ? null : c.buffer(); } private boolean isSatisfiedBy(ByteBuffer rowValue) @@ -393,14 +393,14 @@ public abstract class ColumnCondition { if (column.type.isMultiCell()) { - Cell cell = getCell(row, column, CellPath.create(collectionElement)); - return cell == null ? null : cell.value(); + Cell cell = getCell(row, column, CellPath.create(collectionElement)); + return cell == null ? null : cell.buffer(); } - Cell cell = getCell(row, column); + Cell cell = getCell(row, column); return cell == null ? null - : type.getSerializer().getSerializedValue(cell.value(), collectionElement, type.getKeysType()); + : type.getSerializer().getSerializedValue(cell.buffer(), collectionElement, type.getKeysType()); } private ByteBuffer rowListValue(ListType type, Row row) @@ -408,17 +408,17 @@ public abstract class ColumnCondition if (column.type.isMultiCell()) return cellValueAtIndex(getCells(row, column), getListIndex(collectionElement)); - Cell cell = getCell(row, column); + Cell cell = getCell(row, column); return cell == null ? null - : type.getSerializer().getElement(cell.value(), getListIndex(collectionElement)); + : type.getSerializer().getElement(cell.buffer(), getListIndex(collectionElement)); } - private static ByteBuffer cellValueAtIndex(Iterator iter, int index) + private static ByteBuffer cellValueAtIndex(Iterator> iter, int index) { int adv = Iterators.advance(iter, index); if (adv == index && iter.hasNext()) - return iter.next().value(); + return iter.next().buffer(); return null; } @@ -468,7 +468,7 @@ public abstract class ColumnCondition // copy iterator contents so that we can properly reuse them for each comparison with an IN value for (Term.Terminal value : values) { - Iterator iter = getCells(row, column); + Iterator> iter = getCells(row, column); if (value == null) { if (comparisonOperator == Operator.EQ) @@ -490,7 +490,7 @@ public abstract class ColumnCondition return false; } - private static boolean valueAppliesTo(CollectionType type, Iterator iter, Term.Terminal value, Operator operator) + private static boolean valueAppliesTo(CollectionType type, Iterator> iter, Term.Terminal value, Operator operator) { if (value == null) return !iter.hasNext(); @@ -510,7 +510,7 @@ public abstract class ColumnCondition throw new AssertionError(); } - private static boolean setOrListAppliesTo(AbstractType type, Iterator iter, Iterator conditionIter, Operator operator, boolean isSet) + private static boolean setOrListAppliesTo(AbstractType type, Iterator> iter, Iterator conditionIter, Operator operator, boolean isSet) { while(iter.hasNext()) { @@ -518,7 +518,7 @@ public abstract class ColumnCondition return (operator == Operator.GT) || (operator == Operator.GTE) || (operator == Operator.NEQ); // for lists we use the cell value; for sets we use the cell name - ByteBuffer cellValue = isSet ? iter.next().path().get(0) : iter.next().value(); + ByteBuffer cellValue = isSet ? iter.next().path().get(0) : iter.next().buffer(); int comparison = type.compare(cellValue, conditionIter.next()); if (comparison != 0) return evaluateComparisonWithOperator(comparison, operator); @@ -531,19 +531,19 @@ public abstract class ColumnCondition return operator == Operator.EQ || operator == Operator.LTE || operator == Operator.GTE; } - private static boolean listAppliesTo(ListType type, Iterator iter, List elements, Operator operator) + private static boolean listAppliesTo(ListType type, Iterator> iter, List elements, Operator operator) { return setOrListAppliesTo(type.getElementsType(), iter, elements.iterator(), operator, false); } - private static boolean setAppliesTo(SetType type, Iterator iter, Set elements, Operator operator) + private static boolean setAppliesTo(SetType type, Iterator> iter, Set elements, Operator operator) { ArrayList sortedElements = new ArrayList<>(elements); Collections.sort(sortedElements, type.getElementsType()); return setOrListAppliesTo(type.getElementsType(), iter, sortedElements.iterator(), operator, true); } - private static boolean mapAppliesTo(MapType type, Iterator iter, Map elements, Operator operator) + private static boolean mapAppliesTo(MapType type, Iterator> iter, Map elements, Operator operator) { Iterator> conditionIter = elements.entrySet().iterator(); while(iter.hasNext()) @@ -552,7 +552,7 @@ public abstract class ColumnCondition return (operator == Operator.GT) || (operator == Operator.GTE) || (operator == Operator.NEQ); Map.Entry conditionEntry = conditionIter.next(); - Cell c = iter.next(); + Cell c = iter.next(); // compare the keys int comparison = type.getKeysType().compare(c.path().get(0), conditionEntry.getKey()); @@ -560,7 +560,7 @@ public abstract class ColumnCondition return evaluateComparisonWithOperator(comparison, operator); // compare the values - comparison = type.getValuesType().compare(c.value(), conditionEntry.getValue()); + comparison = type.getValuesType().compare(c.buffer(), conditionEntry.getValue()); if (comparison != 0) return evaluateComparisonWithOperator(comparison, operator); } @@ -608,14 +608,14 @@ public abstract class ColumnCondition if (column.type.isMultiCell()) { - Cell cell = getCell(row, column, userType.cellPathForField(field)); - return cell == null ? null : cell.value(); + Cell cell = getCell(row, column, userType.cellPathForField(field)); + return cell == null ? null : cell.buffer(); } - Cell cell = getCell(row, column); + Cell cell = getCell(row, column); return cell == null ? null - : userType.split(cell.value())[userType.fieldPosition(field)]; + : userType.split(cell.buffer())[userType.fieldPosition(field)]; } private boolean isSatisfiedBy(ByteBuffer rowValue) @@ -670,7 +670,7 @@ public abstract class ColumnCondition private final ByteBuffer rowValue(Row row) { UserType userType = (UserType) column.type; - Iterator iter = getCells(row, column); + Iterator> iter = getCells(row, column); return iter.hasNext() ? userType.serializeForNativeProtocol(iter, protocolVersion) : null; } diff --git a/src/java/org/apache/cassandra/cql3/conditions/ColumnConditions.java b/src/java/org/apache/cassandra/cql3/conditions/ColumnConditions.java index ba82643c4d..35d4a9570f 100644 --- a/src/java/org/apache/cassandra/cql3/conditions/ColumnConditions.java +++ b/src/java/org/apache/cassandra/cql3/conditions/ColumnConditions.java @@ -91,7 +91,7 @@ public final class ColumnConditions extends AbstractConditions * @param options the query options */ public void addConditionsTo(CQL3CasRequest request, - Clustering clustering, + Clustering clustering, QueryOptions options) { if (!columnConditions.isEmpty()) diff --git a/src/java/org/apache/cassandra/cql3/conditions/Conditions.java b/src/java/org/apache/cassandra/cql3/conditions/Conditions.java index 1622be0327..1a202dff0d 100644 --- a/src/java/org/apache/cassandra/cql3/conditions/Conditions.java +++ b/src/java/org/apache/cassandra/cql3/conditions/Conditions.java @@ -98,6 +98,6 @@ public interface Conditions * @param options the query options */ public void addConditionsTo(CQL3CasRequest request, - Clustering clustering, + Clustering clustering, QueryOptions options); } diff --git a/src/java/org/apache/cassandra/cql3/conditions/IfExistsCondition.java b/src/java/org/apache/cassandra/cql3/conditions/IfExistsCondition.java index fa8822dcce..51e8dd005b 100644 --- a/src/java/org/apache/cassandra/cql3/conditions/IfExistsCondition.java +++ b/src/java/org/apache/cassandra/cql3/conditions/IfExistsCondition.java @@ -24,7 +24,7 @@ import org.apache.cassandra.db.Clustering; final class IfExistsCondition extends AbstractConditions { @Override - public void addConditionsTo(CQL3CasRequest request, Clustering clustering, QueryOptions options) + public void addConditionsTo(CQL3CasRequest request, Clustering clustering, QueryOptions options) { request.addExist(clustering); } diff --git a/src/java/org/apache/cassandra/cql3/conditions/IfNotExistsCondition.java b/src/java/org/apache/cassandra/cql3/conditions/IfNotExistsCondition.java index ede9119097..ccbe3865a9 100644 --- a/src/java/org/apache/cassandra/cql3/conditions/IfNotExistsCondition.java +++ b/src/java/org/apache/cassandra/cql3/conditions/IfNotExistsCondition.java @@ -24,7 +24,7 @@ import org.apache.cassandra.db.Clustering; final class IfNotExistsCondition extends AbstractConditions { @Override - public void addConditionsTo(CQL3CasRequest request, Clustering clustering, QueryOptions options) + public void addConditionsTo(CQL3CasRequest request, Clustering clustering, QueryOptions options) { request.addNotExist(clustering); } diff --git a/src/java/org/apache/cassandra/cql3/restrictions/ClusteringColumnRestrictions.java b/src/java/org/apache/cassandra/cql3/restrictions/ClusteringColumnRestrictions.java index 265d3540db..0a252ff557 100644 --- a/src/java/org/apache/cassandra/cql3/restrictions/ClusteringColumnRestrictions.java +++ b/src/java/org/apache/cassandra/cql3/restrictions/ClusteringColumnRestrictions.java @@ -101,7 +101,7 @@ final class ClusteringColumnRestrictions extends RestrictionSetWrapper return false; } - public NavigableSet valuesAsClustering(QueryOptions options) throws InvalidRequestException + public NavigableSet> valuesAsClustering(QueryOptions options) throws InvalidRequestException { MultiCBuilder builder = MultiCBuilder.create(comparator, hasIN()); for (SingleRestriction r : restrictions) @@ -113,7 +113,7 @@ final class ClusteringColumnRestrictions extends RestrictionSetWrapper return builder.build(); } - public NavigableSet boundsAsClustering(Bound bound, QueryOptions options) throws InvalidRequestException + public NavigableSet> boundsAsClustering(Bound bound, QueryOptions options) throws InvalidRequestException { MultiCBuilder builder = MultiCBuilder.create(comparator, hasIN() || hasMultiColumnSlice()); int keyPosition = 0; diff --git a/src/java/org/apache/cassandra/cql3/restrictions/StatementRestrictions.java b/src/java/org/apache/cassandra/cql3/restrictions/StatementRestrictions.java index a9005d1491..328e0a9f5d 100644 --- a/src/java/org/apache/cassandra/cql3/restrictions/StatementRestrictions.java +++ b/src/java/org/apache/cassandra/cql3/restrictions/StatementRestrictions.java @@ -743,7 +743,7 @@ public final class StatementRestrictions * @param options the query options * @return the requested clustering columns */ - public NavigableSet getClusteringColumns(QueryOptions options) + public NavigableSet> getClusteringColumns(QueryOptions options) { return clusteringColumnsRestrictions.valuesAsClustering(options); } @@ -755,7 +755,7 @@ public final class StatementRestrictions * @param options the query options * @return the bounds (start or end) of the clustering columns */ - public NavigableSet getClusteringColumnsBounds(Bound b, QueryOptions options) + public NavigableSet> getClusteringColumnsBounds(Bound b, QueryOptions options) { return clusteringColumnsRestrictions.boundsAsClustering(b, options); } diff --git a/src/java/org/apache/cassandra/cql3/selection/ResultSetBuilder.java b/src/java/org/apache/cassandra/cql3/selection/ResultSetBuilder.java index 9b7abe1e72..84e1e84589 100644 --- a/src/java/org/apache/cassandra/cql3/selection/ResultSetBuilder.java +++ b/src/java/org/apache/cassandra/cql3/selection/ResultSetBuilder.java @@ -84,7 +84,7 @@ public final class ResultSetBuilder current.add(v); } - public void add(Cell c, int nowInSec) + public void add(Cell c, int nowInSec) { if (c == null) { @@ -101,7 +101,7 @@ public final class ResultSetBuilder ttls[current.size() - 1] = remainingTTL(c, nowInSec); } - private int remainingTTL(Cell c, int nowInSec) + private int remainingTTL(Cell c, int nowInSec) { if (!c.isExpiring()) return -1; @@ -110,11 +110,11 @@ public final class ResultSetBuilder return remaining >= 0 ? remaining : -1; } - private ByteBuffer value(Cell c) + private ByteBuffer value(Cell c) { return c.isCounterCell() - ? ByteBufferUtil.bytes(CounterContext.instance().total(c.value())) - : c.value(); + ? ByteBufferUtil.bytes(CounterContext.instance().total(c.value(), c.accessor())) + : c.buffer(); } /** @@ -123,7 +123,7 @@ public final class ResultSetBuilder * @param partitionKey the partition key of the new row * @param clustering the clustering of the new row */ - public void newRow(DecoratedKey partitionKey, Clustering clustering) + public void newRow(DecoratedKey partitionKey, Clustering clustering) { // The groupMaker needs to be called for each row boolean isNewAggregate = groupMaker == null || groupMaker.isNewGroup(partitionKey, clustering); diff --git a/src/java/org/apache/cassandra/cql3/statements/BatchStatement.java b/src/java/org/apache/cassandra/cql3/statements/BatchStatement.java index c165969728..2cf2660253 100644 --- a/src/java/org/apache/cassandra/cql3/statements/BatchStatement.java +++ b/src/java/org/apache/cassandra/cql3/statements/BatchStatement.java @@ -503,7 +503,7 @@ public class BatchStatement implements CQLStatement } else { - Clustering clustering = Iterables.getOnlyElement(statement.createClustering(statementOptions)); + Clustering clustering = Iterables.getOnlyElement(statement.createClustering(statementOptions)); if (statement.hasConditions()) { statement.addConditions(clustering, casRequest, statementOptions); diff --git a/src/java/org/apache/cassandra/cql3/statements/CQL3CasRequest.java b/src/java/org/apache/cassandra/cql3/statements/CQL3CasRequest.java index ed985dbd75..d61381d0aa 100644 --- a/src/java/org/apache/cassandra/cql3/statements/CQL3CasRequest.java +++ b/src/java/org/apache/cassandra/cql3/statements/CQL3CasRequest.java @@ -56,7 +56,7 @@ public class CQL3CasRequest implements CASRequest // We index RowCondition by the clustering of the row they applied to for 2 reasons: // 1) this allows to keep things sorted to build the read command below // 2) this allows to detect when contradictory conditions are set (not exists with some other conditions on the same row) - private final TreeMap conditions; + private final TreeMap, RowCondition> conditions; private final List updates = new ArrayList<>(); private final List rangeDeletions = new ArrayList<>(); @@ -75,7 +75,7 @@ public class CQL3CasRequest implements CASRequest this.updatesStaticRow = updatesStaticRow; } - void addRowUpdate(Clustering clustering, ModificationStatement stmt, QueryOptions options, long timestamp, int nowInSeconds) + void addRowUpdate(Clustering clustering, ModificationStatement stmt, QueryOptions options, long timestamp, int nowInSeconds) { updates.add(new RowUpdate(clustering, stmt, options, timestamp, nowInSeconds)); } @@ -85,17 +85,17 @@ public class CQL3CasRequest implements CASRequest rangeDeletions.add(new RangeDeletion(slice, stmt, options, timestamp, nowInSeconds)); } - public void addNotExist(Clustering clustering) throws InvalidRequestException + public void addNotExist(Clustering clustering) throws InvalidRequestException { addExistsCondition(clustering, new NotExistCondition(clustering), true); } - public void addExist(Clustering clustering) throws InvalidRequestException + public void addExist(Clustering clustering) throws InvalidRequestException { addExistsCondition(clustering, new ExistCondition(clustering), false); } - private void addExistsCondition(Clustering clustering, RowCondition condition, boolean isNotExist) + private void addExistsCondition(Clustering clustering, RowCondition condition, boolean isNotExist) { assert condition instanceof ExistCondition || condition instanceof NotExistCondition; RowCondition previous = getConditionsForRow(clustering); @@ -128,7 +128,7 @@ public class CQL3CasRequest implements CASRequest hasExists = true; } - public void addConditions(Clustering clustering, Collection conds, QueryOptions options) throws InvalidRequestException + public void addConditions(Clustering clustering, Collection conds, QueryOptions options) throws InvalidRequestException { RowCondition condition = getConditionsForRow(clustering); if (condition == null) @@ -143,12 +143,12 @@ public class CQL3CasRequest implements CASRequest ((ColumnsConditions)condition).addConditions(conds, options); } - private RowCondition getConditionsForRow(Clustering clustering) + private RowCondition getConditionsForRow(Clustering clustering) { return clustering == Clustering.STATIC_CLUSTERING ? staticConditions : conditions.get(clustering); } - private void setConditionsForRow(Clustering clustering, RowCondition condition) + private void setConditionsForRow(Clustering clustering, RowCondition condition) { if (clustering == Clustering.STATIC_CLUSTERING) { @@ -255,13 +255,13 @@ public class CQL3CasRequest implements CASRequest */ private class RowUpdate { - private final Clustering clustering; + private final Clustering clustering; private final ModificationStatement stmt; private final QueryOptions options; private final long timestamp; private final int nowInSeconds; - private RowUpdate(Clustering clustering, ModificationStatement stmt, QueryOptions options, long timestamp, int nowInSeconds) + private RowUpdate(Clustering clustering, ModificationStatement stmt, QueryOptions options, long timestamp, int nowInSeconds) { this.clustering = clustering; this.stmt = stmt; @@ -320,9 +320,9 @@ public class CQL3CasRequest implements CASRequest private static abstract class RowCondition { - public final Clustering clustering; + public final Clustering clustering; - protected RowCondition(Clustering clustering) + protected RowCondition(Clustering clustering) { this.clustering = clustering; } @@ -332,7 +332,7 @@ public class CQL3CasRequest implements CASRequest private static class NotExistCondition extends RowCondition { - private NotExistCondition(Clustering clustering) + private NotExistCondition(Clustering clustering) { super(clustering); } @@ -345,7 +345,7 @@ public class CQL3CasRequest implements CASRequest private static class ExistCondition extends RowCondition { - private ExistCondition(Clustering clustering) + private ExistCondition(Clustering clustering) { super(clustering); } @@ -360,7 +360,7 @@ public class CQL3CasRequest implements CASRequest { private final Multimap, ColumnCondition.Bound> conditions = HashMultimap.create(); - private ColumnsConditions(Clustering clustering) + private ColumnsConditions(Clustering clustering) { super(clustering); } diff --git a/src/java/org/apache/cassandra/cql3/statements/DeleteStatement.java b/src/java/org/apache/cassandra/cql3/statements/DeleteStatement.java index cbba82bd09..1a9219676a 100644 --- a/src/java/org/apache/cassandra/cql3/statements/DeleteStatement.java +++ b/src/java/org/apache/cassandra/cql3/statements/DeleteStatement.java @@ -54,7 +54,7 @@ public class DeleteStatement extends ModificationStatement } @Override - public void addUpdateForKey(PartitionUpdate.Builder updateBuilder, Clustering clustering, UpdateParameters params) + public void addUpdateForKey(PartitionUpdate.Builder updateBuilder, Clustering clustering, UpdateParameters params) throws InvalidRequestException { TableMetadata metadata = metadata(); diff --git a/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java b/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java index 6ff536d94d..c55a75efd4 100644 --- a/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java +++ b/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java @@ -26,6 +26,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.apache.cassandra.auth.Permission; +import org.apache.cassandra.db.marshal.ValueAccessor; import org.apache.cassandra.schema.ColumnMetadata; import org.apache.cassandra.schema.Schema; import org.apache.cassandra.schema.TableMetadata; @@ -180,7 +181,7 @@ public abstract class ModificationStatement implements CQLStatement return restrictions; } - public abstract void addUpdateForKey(PartitionUpdate.Builder updateBuilder, Clustering clustering, UpdateParameters params); + public abstract void addUpdateForKey(PartitionUpdate.Builder updateBuilder, Clustering clustering, UpdateParameters params); public abstract void addUpdateForKey(PartitionUpdate.Builder updateBuilder, Slice slice, UpdateParameters params); @@ -323,7 +324,7 @@ public abstract class ModificationStatement implements CQLStatement return partitionKeys; } - public NavigableSet createClustering(QueryOptions options) + public NavigableSet> createClustering(QueryOptions options) throws InvalidRequestException { if (appliesOnlyToStaticColumns() && !restrictions.hasClusteringColumnsRestrictions()) @@ -503,7 +504,7 @@ public abstract class ModificationStatement implements CQLStatement "IN on the clustering key columns is not supported with conditional %s", type.isUpdate()? "updates" : "deletions"); - Clustering clustering = Iterables.getOnlyElement(createClustering(options)); + Clustering clustering = Iterables.getOnlyElement(createClustering(options)); CQL3CasRequest request = new CQL3CasRequest(metadata(), key, conditionColumns(), updatesRegularRows(), updatesStaticRow()); addConditions(clustering, request, options); @@ -512,7 +513,7 @@ public abstract class ModificationStatement implements CQLStatement return request; } - public void addConditions(Clustering clustering, CQL3CasRequest request, QueryOptions options) throws InvalidRequestException + public void addConditions(Clustering clustering, CQL3CasRequest request, QueryOptions options) throws InvalidRequestException { conditions.addConditionsTo(request, clustering, options); } @@ -717,7 +718,7 @@ public abstract class ModificationStatement implements CQLStatement } else { - NavigableSet clusterings = createClustering(options); + NavigableSet> clusterings = createClustering(options); // If some of the restrictions were unspecified (e.g. empty IN restrictions) we do not need to do anything. if (restrictions.hasClusteringColumnsRestrictions() && clusterings.isEmpty()) @@ -738,15 +739,9 @@ public abstract class ModificationStatement implements CQLStatement } else { - for (Clustering clustering : clusterings) + for (Clustering clustering : clusterings) { - for (ByteBuffer c : clustering.getRawValues()) - { - if (c != null && c.remaining() > FBUtilities.MAX_UNSIGNED_SHORT) - throw new InvalidRequestException(String.format("Key length of %d is longer than maximum of %d", - clustering.dataSize(), - FBUtilities.MAX_UNSIGNED_SHORT)); - } + validateClustering(clustering); addUpdateForKey(updateBuilder, clustering, params); } } @@ -754,16 +749,28 @@ public abstract class ModificationStatement implements CQLStatement } } + private void validateClustering(Clustering clustering) + { + ValueAccessor accessor = clustering.accessor(); + for (V v : clustering.getRawValues()) + { + if (v != null && accessor.size(v) > FBUtilities.MAX_UNSIGNED_SHORT) + throw new InvalidRequestException(String.format("Key length of %d is longer than maximum of %d", + clustering.dataSize(), + FBUtilities.MAX_UNSIGNED_SHORT)); + } + } + Slices createSlices(QueryOptions options) { - SortedSet startBounds = restrictions.getClusteringColumnsBounds(Bound.START, options); - SortedSet endBounds = restrictions.getClusteringColumnsBounds(Bound.END, options); + SortedSet> startBounds = restrictions.getClusteringColumnsBounds(Bound.START, options); + SortedSet> endBounds = restrictions.getClusteringColumnsBounds(Bound.END, options); return toSlices(startBounds, endBounds); } private UpdateParameters makeUpdateParameters(Collection keys, - NavigableSet clusterings, + NavigableSet> clusterings, QueryOptions options, boolean local, long timestamp, @@ -818,14 +825,14 @@ public abstract class ModificationStatement implements CQLStatement lists); } - private Slices toSlices(SortedSet startBounds, SortedSet endBounds) + private Slices toSlices(SortedSet> startBounds, SortedSet> endBounds) { assert startBounds.size() == endBounds.size(); Slices.Builder builder = new Slices.Builder(metadata().comparator); - Iterator starts = startBounds.iterator(); - Iterator ends = endBounds.iterator(); + Iterator> starts = startBounds.iterator(); + Iterator> ends = endBounds.iterator(); while (starts.hasNext()) { diff --git a/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java b/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java index ca80ff6741..1ddb29d082 100644 --- a/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java +++ b/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java @@ -544,7 +544,7 @@ public class SelectStatement implements CQLStatement return ((ClusteringIndexSliceFilter)filter).requestedSlices(); Slices.Builder builder = new Slices.Builder(table.comparator); - for (Clustering clustering: ((ClusteringIndexNamesFilter)filter).requestedRows()) + for (Clustering clustering: ((ClusteringIndexNamesFilter)filter).requestedRows()) builder.add(Slice.make(clustering)); return builder.build(); } @@ -616,7 +616,7 @@ public class SelectStatement implements CQLStatement return new ClusteringIndexSliceFilter(slices, isReversed); } - NavigableSet clusterings = getRequestedRows(options); + NavigableSet> clusterings = getRequestedRows(options); // We can have no clusterings if either we're only selecting the static columns, or if we have // a 'IN ()' for clusterings. In that case, we still want to query if some static columns are // queried. But we're fine otherwise. @@ -630,27 +630,27 @@ public class SelectStatement implements CQLStatement public Slices makeSlices(QueryOptions options) throws InvalidRequestException { - SortedSet startBounds = restrictions.getClusteringColumnsBounds(Bound.START, options); - SortedSet endBounds = restrictions.getClusteringColumnsBounds(Bound.END, options); + SortedSet> startBounds = restrictions.getClusteringColumnsBounds(Bound.START, options); + SortedSet> 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) { - ClusteringBound start = startBounds.first(); - ClusteringBound end = endBounds.first(); + ClusteringBound start = startBounds.first(); + ClusteringBound end = endBounds.first(); return Slice.isEmpty(table.comparator, start, end) ? Slices.NONE : Slices.with(table.comparator, Slice.make(start, end)); } Slices.Builder builder = new Slices.Builder(table.comparator, startBounds.size()); - Iterator startIter = startBounds.iterator(); - Iterator endIter = endBounds.iterator(); + Iterator> startIter = startBounds.iterator(); + Iterator> endIter = endBounds.iterator(); while (startIter.hasNext() && endIter.hasNext()) { - ClusteringBound start = startIter.next(); - ClusteringBound end = endIter.next(); + ClusteringBound start = startIter.next(); + ClusteringBound end = endIter.next(); // Ignore slices that are nonsensical if (Slice.isEmpty(table.comparator, start, end)) @@ -748,7 +748,7 @@ public class SelectStatement implements CQLStatement return userLimit; } - private NavigableSet getRequestedRows(QueryOptions options) throws InvalidRequestException + private NavigableSet> getRequestedRows(QueryOptions options) throws InvalidRequestException { // Note: getRequestedColumns don't handle static columns, but due to CASSANDRA-5762 // we always do a slice for CQL3 tables, so it's ok to ignore them here @@ -860,7 +860,7 @@ public class SelectStatement implements CQLStatement result.add(keyComponents[def.position()]); break; case CLUSTERING: - result.add(row.clustering().get(def.position())); + result.add(row.clustering().bufferAt(def.position())); break; case REGULAR: addValue(result, def, row, nowInSec, protocolVersion); diff --git a/src/java/org/apache/cassandra/cql3/statements/UpdateStatement.java b/src/java/org/apache/cassandra/cql3/statements/UpdateStatement.java index 57d7691dab..34b1b99014 100644 --- a/src/java/org/apache/cassandra/cql3/statements/UpdateStatement.java +++ b/src/java/org/apache/cassandra/cql3/statements/UpdateStatement.java @@ -57,7 +57,7 @@ public class UpdateStatement extends ModificationStatement } @Override - public void addUpdateForKey(PartitionUpdate.Builder updateBuilder, Clustering clustering, UpdateParameters params) + public void addUpdateForKey(PartitionUpdate.Builder updateBuilder, Clustering clustering, UpdateParameters params) { if (updatesRegularRows()) { diff --git a/src/java/org/apache/cassandra/db/AbstractArrayClusteringPrefix.java b/src/java/org/apache/cassandra/db/AbstractArrayClusteringPrefix.java new file mode 100644 index 0000000000..b698f5d9fa --- /dev/null +++ b/src/java/org/apache/cassandra/db/AbstractArrayClusteringPrefix.java @@ -0,0 +1,53 @@ +/* + * 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.db; + + +import java.nio.ByteBuffer; + +import org.apache.cassandra.db.marshal.ByteArrayAccessor; +import org.apache.cassandra.db.marshal.ValueAccessor; + +public abstract class AbstractArrayClusteringPrefix extends AbstractOnHeapClusteringPrefix +{ + public static final byte[][] EMPTY_VALUES_ARRAY = new byte[0][]; + + public AbstractArrayClusteringPrefix(Kind kind, byte[][] values) + { + super(kind, values); + } + + public ValueAccessor accessor() + { + return ByteArrayAccessor.instance; + } + + public ByteBuffer[] getBufferArray() + { + ByteBuffer[] out = new ByteBuffer[values.length]; + for (int i=0; i minimize() + { + return this; + } +} diff --git a/src/java/org/apache/cassandra/db/AbstractBufferClusteringPrefix.java b/src/java/org/apache/cassandra/db/AbstractBufferClusteringPrefix.java index dd4a09551b..457d0c4bef 100644 --- a/src/java/org/apache/cassandra/db/AbstractBufferClusteringPrefix.java +++ b/src/java/org/apache/cassandra/db/AbstractBufferClusteringPrefix.java @@ -19,53 +19,33 @@ package org.apache.cassandra.db; import java.nio.ByteBuffer; -import org.apache.cassandra.utils.ObjectSizes; +import org.apache.cassandra.db.marshal.ByteBufferAccessor; +import org.apache.cassandra.db.marshal.ValueAccessor; +import org.apache.cassandra.utils.ByteBufferUtil; -public abstract class AbstractBufferClusteringPrefix extends AbstractClusteringPrefix +public abstract class AbstractBufferClusteringPrefix extends AbstractOnHeapClusteringPrefix { public static final ByteBuffer[] EMPTY_VALUES_ARRAY = new ByteBuffer[0]; - protected final Kind kind; - protected final ByteBuffer[] values; - protected AbstractBufferClusteringPrefix(Kind kind, ByteBuffer[] values) { - this.kind = kind; - this.values = values; + super(kind, values); } - public Kind kind() + public ValueAccessor accessor() { - return kind; + return ByteBufferAccessor.instance; } - public ClusteringPrefix clustering() + public ByteBuffer[] getBufferArray() { - return this; + return getRawValues(); } - public int size() + public ClusteringPrefix minimize() { - return values.length; - } - - public ByteBuffer get(int i) - { - return values[i]; - } - - public ByteBuffer[] getRawValues() - { - return values; - } - - public long unsharedHeapSize() - { - return Clustering.EMPTY_SIZE + ObjectSizes.sizeOnHeapOf(values); - } - - public long unsharedHeapSizeExcludingData() - { - return Clustering.EMPTY_SIZE + ObjectSizes.sizeOnHeapExcludingData(values); + if (!ByteBufferUtil.canMinimize(values)) + return this; + return new BufferClustering(ByteBufferUtil.minimizeBuffers(values)); } } diff --git a/src/java/org/apache/cassandra/db/AbstractClusteringPrefix.java b/src/java/org/apache/cassandra/db/AbstractClusteringPrefix.java deleted file mode 100644 index 8714936508..0000000000 --- a/src/java/org/apache/cassandra/db/AbstractClusteringPrefix.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * 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.db; - -import java.nio.ByteBuffer; -import java.util.Objects; - -public abstract class AbstractClusteringPrefix implements ClusteringPrefix -{ - public ClusteringPrefix clustering() - { - return this; - } - - public int dataSize() - { - int size = 0; - for (int i = 0; i < size(); i++) - { - ByteBuffer bb = get(i); - size += bb == null ? 0 : bb.remaining(); - } - return size; - } - - public void digest(Digest digest) - { - for (int i = 0; i < size(); i++) - { - ByteBuffer bb = get(i); - if (bb != null) - digest.update(bb); - } - digest.updateWithByte(kind().ordinal()); - } - - @Override - public final int hashCode() - { - int result = 31; - for (int i = 0; i < size(); i++) - result += 31 * Objects.hashCode(get(i)); - return 31 * result + Objects.hashCode(kind()); - } - - @Override - public final boolean equals(Object o) - { - if(!(o instanceof ClusteringPrefix)) - return false; - - ClusteringPrefix that = (ClusteringPrefix)o; - if (this.kind() != that.kind() || this.size() != that.size()) - return false; - - for (int i = 0; i < size(); i++) - if (!Objects.equals(this.get(i), that.get(i))) - return false; - - return true; - } -} diff --git a/src/java/org/apache/cassandra/db/AbstractOnHeapClusteringPrefix.java b/src/java/org/apache/cassandra/db/AbstractOnHeapClusteringPrefix.java new file mode 100644 index 0000000000..3653bc51e3 --- /dev/null +++ b/src/java/org/apache/cassandra/db/AbstractOnHeapClusteringPrefix.java @@ -0,0 +1,67 @@ +/* + * 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.db; + +public abstract class AbstractOnHeapClusteringPrefix implements ClusteringPrefix +{ + protected final Kind kind; + protected final V[] values; + + public AbstractOnHeapClusteringPrefix(Kind kind, V[] values) + { + this.kind = kind; + this.values = values; + } + + public Kind kind() + { + return kind; + } + + public ClusteringPrefix clustering() + { + return this; + } + + public int size() + { + return values.length; + } + + public V get(int i) + { + return values[i]; + } + + public V[] getRawValues() + { + return values; + } + + @Override + public int hashCode() + { + return ClusteringPrefix.hashCode(this); + } + + @Override + public boolean equals(Object o) + { + return ClusteringPrefix.equals(this, o); + } +} diff --git a/src/java/org/apache/cassandra/db/AbstractReadCommandBuilder.java b/src/java/org/apache/cassandra/db/AbstractReadCommandBuilder.java index 2bfaf0ce10..55c5fc513e 100644 --- a/src/java/org/apache/cassandra/db/AbstractReadCommandBuilder.java +++ b/src/java/org/apache/cassandra/db/AbstractReadCommandBuilder.java @@ -45,10 +45,10 @@ public abstract class AbstractReadCommandBuilder protected Set columns; protected final RowFilter filter = RowFilter.create(); - private ClusteringBound lowerClusteringBound; - private ClusteringBound upperClusteringBound; + private ClusteringBound lowerClusteringBound; + private ClusteringBound upperClusteringBound; - private NavigableSet clusterings; + private NavigableSet> clusterings; // Use Util.cmd() instead of this ctor directly AbstractReadCommandBuilder(ColumnFamilyStore cfs) @@ -197,8 +197,8 @@ public abstract class AbstractReadCommandBuilder } else { - Slice slice = Slice.make(lowerClusteringBound == null ? ClusteringBound.BOTTOM : lowerClusteringBound, - upperClusteringBound == null ? ClusteringBound.TOP : upperClusteringBound); + Slice slice = Slice.make(lowerClusteringBound == null ? BufferClusteringBound.BOTTOM : lowerClusteringBound, + upperClusteringBound == null ? BufferClusteringBound.TOP : upperClusteringBound); return new ClusteringIndexSliceFilter(Slices.with(cfs.metadata().comparator, slice), reversed); } } @@ -230,37 +230,6 @@ public abstract class AbstractReadCommandBuilder } } - public static class SinglePartitionSliceBuilder extends AbstractReadCommandBuilder - { - private final DecoratedKey partitionKey; - private Slices.Builder sliceBuilder; - - public SinglePartitionSliceBuilder(ColumnFamilyStore cfs, DecoratedKey key) - { - super(cfs); - this.partitionKey = key; - sliceBuilder = new Slices.Builder(cfs.getComparator()); - } - - public SinglePartitionSliceBuilder addSlice(Slice slice) - { - sliceBuilder.add(slice); - return this; - } - - @Override - protected ClusteringIndexFilter makeFilter() - { - return new ClusteringIndexSliceFilter(sliceBuilder.build(), reversed); - } - - @Override - public ReadCommand build() - { - return SinglePartitionReadCommand.create(cfs.metadata(), nowInSeconds, makeColumnFilter(), filter, makeLimits(), partitionKey, makeFilter()); - } - } - public static class PartitionRangeBuilder extends AbstractReadCommandBuilder { private DecoratedKey startKey; diff --git a/src/java/org/apache/cassandra/db/ArrayClustering.java b/src/java/org/apache/cassandra/db/ArrayClustering.java new file mode 100644 index 0000000000..0d3de4943c --- /dev/null +++ b/src/java/org/apache/cassandra/db/ArrayClustering.java @@ -0,0 +1,46 @@ +/* + * 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.db; + +import org.apache.cassandra.utils.ObjectSizes; + +public class ArrayClustering extends AbstractArrayClusteringPrefix implements Clustering +{ + private static final long EMPTY_SIZE = ObjectSizes.measure(new ArrayClustering(EMPTY_VALUES_ARRAY)); + + public ArrayClustering(byte[]... values) + { + super(Kind.CLUSTERING, values); + } + + public long unsharedHeapSize() + { + return EMPTY_SIZE + ObjectSizes.sizeOfArray(values) + values.length; + } + + public long unsharedHeapSizeExcludingData() + { + return EMPTY_SIZE + ObjectSizes.sizeOfArray(values); + } + + public static ArrayClustering make(byte[]... values) + { + return new ArrayClustering(values); + } +} diff --git a/src/java/org/apache/cassandra/db/ArrayClusteringBound.java b/src/java/org/apache/cassandra/db/ArrayClusteringBound.java new file mode 100644 index 0000000000..3ec4e8c826 --- /dev/null +++ b/src/java/org/apache/cassandra/db/ArrayClusteringBound.java @@ -0,0 +1,58 @@ +/* + * 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.db; + +import java.nio.ByteBuffer; + +import com.google.common.base.Preconditions; + +import org.apache.cassandra.utils.ObjectSizes; +import org.apache.cassandra.utils.memory.AbstractAllocator; + +public class ArrayClusteringBound extends ArrayClusteringBoundOrBoundary implements ClusteringBound +{ + private static final long EMPTY_SIZE = ObjectSizes.measure(new ArrayClusteringBound(ClusteringPrefix.Kind.INCL_START_BOUND, EMPTY_VALUES_ARRAY)); + + public ArrayClusteringBound(Kind kind, byte[][] values) + { + super(kind, values); + } + + public long unsharedHeapSize() + { + return EMPTY_SIZE + ObjectSizes.sizeOfArray(values) + values.length; + } + + @Override + public ClusteringBound invert() + { + return create(kind().invert(), values); + } + + public ClusteringBound copy(AbstractAllocator allocator) + { + return (ClusteringBound) super.copy(allocator); + } + + public static ArrayClusteringBound create(ClusteringPrefix.Kind kind, byte[][] values) + { + Preconditions.checkArgument(!kind.isBoundary(), "Expected bound clustering kind, got %s", kind); + return new ArrayClusteringBound(kind, values); + } +} diff --git a/src/java/org/apache/cassandra/db/ArrayClusteringBoundOrBoundary.java b/src/java/org/apache/cassandra/db/ArrayClusteringBoundOrBoundary.java new file mode 100644 index 0000000000..4fde35fde6 --- /dev/null +++ b/src/java/org/apache/cassandra/db/ArrayClusteringBoundOrBoundary.java @@ -0,0 +1,37 @@ +/* + * 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.db; + +import com.google.common.base.Preconditions; + +public abstract class ArrayClusteringBoundOrBoundary extends AbstractArrayClusteringPrefix implements ClusteringBoundOrBoundary +{ + public ArrayClusteringBoundOrBoundary(Kind kind, byte[][] values) + { + super(kind, values); + Preconditions.checkArgument(values.length > 0 || !kind.isBoundary(), + "Cannot create bounds/boundary objects without clustering values"); + } + public static ClusteringBoundOrBoundary create(Kind kind, byte[][] values) + { + return kind.isBoundary() + ? new ArrayClusteringBoundary(kind, values) + : new ArrayClusteringBound(kind, values); + } +} diff --git a/src/java/org/apache/cassandra/db/ArrayClusteringBoundary.java b/src/java/org/apache/cassandra/db/ArrayClusteringBoundary.java new file mode 100644 index 0000000000..b8c0d6279b --- /dev/null +++ b/src/java/org/apache/cassandra/db/ArrayClusteringBoundary.java @@ -0,0 +1,60 @@ +/* + * 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.db; + +import com.google.common.base.Preconditions; + +import org.apache.cassandra.utils.ObjectSizes; + +public class ArrayClusteringBoundary extends ArrayClusteringBoundOrBoundary implements ClusteringBoundary +{ + private static final long EMPTY_SIZE = ObjectSizes.measure(new ArrayClusteringBoundary(ClusteringPrefix.Kind.INCL_START_BOUND, EMPTY_VALUES_ARRAY)); + + public ArrayClusteringBoundary(Kind kind, byte[][] values) + { + super(kind, values); + } + + public long unsharedHeapSize() + { + return EMPTY_SIZE + ObjectSizes.sizeOfArray(values) + values.length; + } + + public static ClusteringBoundary create(Kind kind, byte[][] values) + { + Preconditions.checkArgument(kind.isBoundary(), "Expected boundary clustering kind, got %s", kind); + return new ArrayClusteringBoundary(kind, values); + } + + @Override + public ClusteringBoundary invert() + { + return create(kind().invert(), values); + } + + public ClusteringBound openBound(boolean reversed) + { + return ArrayClusteringBound.create(kind.openBoundOfBoundary(reversed), values); + } + + public ClusteringBound closeBound(boolean reversed) + { + return ArrayClusteringBound.create(kind.closeBoundOfBoundary(reversed), values); + } +} diff --git a/src/java/org/apache/cassandra/db/BufferClustering.java b/src/java/org/apache/cassandra/db/BufferClustering.java index fc635ab96c..a6dcd1b7c7 100644 --- a/src/java/org/apache/cassandra/db/BufferClustering.java +++ b/src/java/org/apache/cassandra/db/BufferClustering.java @@ -20,6 +20,7 @@ package org.apache.cassandra.db; import java.nio.ByteBuffer; import org.apache.cassandra.utils.ByteBufferUtil; +import org.apache.cassandra.utils.ObjectSizes; /** * The clustering column values for a row. @@ -32,17 +33,27 @@ import org.apache.cassandra.utils.ByteBufferUtil; * {@code null} values (this is currently only allowed in COMPACT table for historical reasons, but we * could imagine lifting that limitation if we decide it make sense from a CQL point of view). */ -public class BufferClustering extends AbstractBufferClusteringPrefix implements Clustering +public class BufferClustering extends AbstractBufferClusteringPrefix implements Clustering { - BufferClustering(ByteBuffer... values) + private static final long EMPTY_SIZE = ObjectSizes.measure(new BufferClustering(EMPTY_VALUES_ARRAY)); + + public BufferClustering(ByteBuffer... values) { super(Kind.CLUSTERING, values); } - public ClusteringPrefix minimize() + public long unsharedHeapSize() { - if (!ByteBufferUtil.canMinimize(values)) - return this; - return new BufferClustering(ByteBufferUtil.minimizeBuffers(values)); + return EMPTY_SIZE + ObjectSizes.sizeOnHeapOf(values); + } + + public long unsharedHeapSizeExcludingData() + { + return EMPTY_SIZE + ObjectSizes.sizeOnHeapExcludingData(values); + } + + public static BufferClustering make(ByteBuffer... values) + { + return new BufferClustering(values); } } diff --git a/src/java/org/apache/cassandra/db/BufferClusteringBound.java b/src/java/org/apache/cassandra/db/BufferClusteringBound.java new file mode 100644 index 0000000000..9b511fafe7 --- /dev/null +++ b/src/java/org/apache/cassandra/db/BufferClusteringBound.java @@ -0,0 +1,79 @@ +/* + * 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.db; + +import java.nio.ByteBuffer; + +import com.google.common.base.Preconditions; + +import org.apache.cassandra.utils.ByteBufferUtil; +import org.apache.cassandra.utils.ObjectSizes; +import org.apache.cassandra.utils.memory.AbstractAllocator; + +public class BufferClusteringBound extends BufferClusteringBoundOrBoundary implements ClusteringBound +{ + private static final long EMPTY_SIZE = ObjectSizes.measure(new BufferClusteringBound(Kind.INCL_START_BOUND, EMPTY_VALUES_ARRAY)); + + public BufferClusteringBound(ClusteringPrefix.Kind kind, ByteBuffer[] values) + { + super(kind, values); + } + + public long unsharedHeapSize() + { + return EMPTY_SIZE + ObjectSizes.sizeOnHeapOf(values); + } + + @Override + public ClusteringBound invert() + { + return create(kind().invert(), values); + } + + public ClusteringBound copy(AbstractAllocator allocator) + { + return (ClusteringBound) super.copy(allocator); + } + + public static BufferClusteringBound create(ClusteringPrefix.Kind kind, ByteBuffer[] values) + { + Preconditions.checkArgument(!kind.isBoundary(), "Expected bound clustering kind, got %s", kind); + return new BufferClusteringBound(kind, values); + } + + public static BufferClusteringBound inclusiveStartOf(ByteBuffer... values) + { + return create(ClusteringPrefix.Kind.INCL_START_BOUND, values); + } + + public static BufferClusteringBound inclusiveEndOf(ByteBuffer... values) + { + return create(ClusteringPrefix.Kind.INCL_END_BOUND, values); + } + + public static BufferClusteringBound exclusiveStartOf(ByteBuffer... values) + { + return create(ClusteringPrefix.Kind.EXCL_START_BOUND, values); + } + + public static BufferClusteringBound exclusiveEndOf(ByteBuffer... values) + { + return create(ClusteringPrefix.Kind.EXCL_END_BOUND, values); + } +} diff --git a/src/java/org/apache/cassandra/db/BufferClusteringBoundOrBoundary.java b/src/java/org/apache/cassandra/db/BufferClusteringBoundOrBoundary.java new file mode 100644 index 0000000000..84c5652ad9 --- /dev/null +++ b/src/java/org/apache/cassandra/db/BufferClusteringBoundOrBoundary.java @@ -0,0 +1,33 @@ +/* + * 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.db; + +import java.nio.ByteBuffer; + +import com.google.common.base.Preconditions; + +public abstract class BufferClusteringBoundOrBoundary extends AbstractBufferClusteringPrefix implements ClusteringBoundOrBoundary +{ + BufferClusteringBoundOrBoundary(Kind kind, ByteBuffer[] values) + { + super(kind, values); + Preconditions.checkArgument(values.length > 0 || !kind.isBoundary(), + "Cannot create bounds/boundary objects without clustering values"); + } +} diff --git a/src/java/org/apache/cassandra/db/BufferClusteringBoundary.java b/src/java/org/apache/cassandra/db/BufferClusteringBoundary.java new file mode 100644 index 0000000000..cad4d87cd2 --- /dev/null +++ b/src/java/org/apache/cassandra/db/BufferClusteringBoundary.java @@ -0,0 +1,70 @@ +/* + * 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.db; + +import java.nio.ByteBuffer; + +import com.google.common.base.Preconditions; + +import org.apache.cassandra.utils.ByteBufferUtil; +import org.apache.cassandra.utils.ObjectSizes; +import org.apache.cassandra.utils.memory.AbstractAllocator; + +public class BufferClusteringBoundary extends BufferClusteringBoundOrBoundary implements ClusteringBoundary +{ + private static final long EMPTY_SIZE = ObjectSizes.measure(new BufferClusteringBoundary(Kind.INCL_START_BOUND, EMPTY_VALUES_ARRAY)); + + public BufferClusteringBoundary(Kind kind, ByteBuffer[] values) + { + super(kind, values); + } + + public long unsharedHeapSize() + { + return EMPTY_SIZE + ObjectSizes.sizeOnHeapOf(values); + } + + public static ClusteringBoundary create(Kind kind, ByteBuffer[] values) + { + Preconditions.checkArgument(kind.isBoundary(), "Expected boundary clustering kind, got %s", kind); + return new BufferClusteringBoundary(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 BufferClusteringBound.create(kind.openBoundOfBoundary(reversed), values); + } + + public ClusteringBound closeBound(boolean reversed) + { + return BufferClusteringBound.create(kind.closeBoundOfBoundary(reversed), values); + } +} diff --git a/src/java/org/apache/cassandra/db/CBuilder.java b/src/java/org/apache/cassandra/db/CBuilder.java index be56394f01..7b28684344 100644 --- a/src/java/org/apache/cassandra/db/CBuilder.java +++ b/src/java/org/apache/cassandra/db/CBuilder.java @@ -22,6 +22,8 @@ import java.util.Arrays; import java.util.List; import org.apache.cassandra.db.marshal.AbstractType; +import org.apache.cassandra.db.marshal.ByteBufferAccessor; +import org.apache.cassandra.db.marshal.ValueAccessor; /** * Allows to build ClusteringPrefixes, either Clustering or ClusteringBound. @@ -45,7 +47,7 @@ public abstract class CBuilder throw new UnsupportedOperationException(); } - public CBuilder add(ByteBuffer value) + public CBuilder add(T value, ValueAccessor accessor) { throw new UnsupportedOperationException(); } @@ -55,37 +57,22 @@ public abstract class CBuilder throw new UnsupportedOperationException(); } - public Clustering build() + public Clustering build() { return Clustering.STATIC_CLUSTERING; } - public ClusteringBound buildBound(boolean isStart, boolean isInclusive) + public ClusteringBound buildBound(boolean isStart, boolean isInclusive) { throw new UnsupportedOperationException(); } - public Slice buildSlice() + public Clustering buildWith(List newValues) { throw new UnsupportedOperationException(); } - public Clustering buildWith(ByteBuffer value) - { - throw new UnsupportedOperationException(); - } - - public Clustering buildWith(List newValues) - { - throw new UnsupportedOperationException(); - } - - public ClusteringBound buildBoundWith(ByteBuffer value, boolean isStart, boolean isInclusive) - { - throw new UnsupportedOperationException(); - } - - public ClusteringBound buildBoundWith(List newValues, boolean isStart, boolean isInclusive) + public ClusteringBound buildBoundWith(List newValues, boolean isStart, boolean isInclusive) { throw new UnsupportedOperationException(); } @@ -99,15 +86,20 @@ public abstract class CBuilder public abstract int count(); public abstract int remainingCount(); public abstract ClusteringComparator comparator(); - public abstract CBuilder add(ByteBuffer value); + public final CBuilder add(ByteBuffer value) + { + return add(value, ByteBufferAccessor.instance); + } + public final CBuilder add(ClusteringPrefix prefix, int i) + { + return add(prefix.get(i), prefix.accessor()); + } + public abstract CBuilder add(V value, ValueAccessor accessor); public abstract CBuilder add(Object value); - public abstract Clustering build(); - public abstract ClusteringBound buildBound(boolean isStart, boolean isInclusive); - public abstract Slice buildSlice(); - public abstract Clustering buildWith(ByteBuffer value); - public abstract Clustering buildWith(List newValues); - public abstract ClusteringBound buildBoundWith(ByteBuffer value, boolean isStart, boolean isInclusive); - public abstract ClusteringBound buildBoundWith(List newValues, boolean isStart, boolean isInclusive); + public abstract Clustering build(); + public abstract ClusteringBound buildBound(boolean isStart, boolean isInclusive); + public abstract Clustering buildWith(List newValues); + public abstract ClusteringBound buildBoundWith(List newValues, boolean isStart, boolean isInclusive); private static class ArrayBackedBuilder extends CBuilder { @@ -137,11 +129,11 @@ public abstract class CBuilder return type; } - public CBuilder add(ByteBuffer value) + public CBuilder add(V value, ValueAccessor accessor) { if (isDone()) throw new IllegalStateException(); - values[size++] = value; + values[size++] = accessor.toBuffer(value); return this; } @@ -155,7 +147,7 @@ public abstract class CBuilder return remainingCount() == 0 || built; } - public Clustering build() + public Clustering build() { // We don't allow to add more element to a builder that has been built so // that we don't have to copy values. @@ -165,41 +157,20 @@ public abstract class CBuilder return size == 0 ? Clustering.EMPTY : Clustering.make(values); } - public ClusteringBound 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 ? ClusteringBound.BOTTOM : ClusteringBound.TOP; + return isStart ? BufferClusteringBound.BOTTOM : BufferClusteringBound.TOP; - return ClusteringBound.create(ClusteringBound.boundKind(isStart, isInclusive), + return BufferClusteringBound.create(ClusteringBound.boundKind(isStart, isInclusive), size == values.length ? values : Arrays.copyOfRange(values, 0, size)); } - public Slice buildSlice() - { - // We don't allow to add more element to a builder that has been built so - // that we don't have to copy values. - built = true; - - if (size == 0) - return Slice.ALL; - - return Slice.make(buildBound(true, true), buildBound(false, true)); - } - - public Clustering buildWith(ByteBuffer value) - { - assert size+1 <= type.size(); - - ByteBuffer[] newValues = Arrays.copyOf(values, type.size()); - newValues[size] = value; - return Clustering.make(newValues); - } - - public Clustering buildWith(List newValues) + public Clustering buildWith(List newValues) { assert size + newValues.size() <= type.size(); ByteBuffer[] buffers = Arrays.copyOf(values, type.size()); @@ -210,21 +181,14 @@ public abstract class CBuilder return Clustering.make(buffers); } - public ClusteringBound buildBoundWith(ByteBuffer value, boolean isStart, boolean isInclusive) - { - ByteBuffer[] newValues = Arrays.copyOf(values, size+1); - newValues[size] = value; - return ClusteringBound.create(ClusteringBound.boundKind(isStart, isInclusive), newValues); - } - - public ClusteringBound buildBoundWith(List newValues, boolean isStart, boolean isInclusive) + public ClusteringBound buildBoundWith(List newValues, boolean isStart, boolean isInclusive) { ByteBuffer[] buffers = Arrays.copyOf(values, size + newValues.size()); int newSize = size; for (ByteBuffer value : newValues) buffers[newSize++] = value; - return ClusteringBound.create(ClusteringBound.boundKind(isStart, isInclusive), buffers); + return BufferClusteringBound.create(ClusteringBound.boundKind(isStart, isInclusive), buffers); } } } diff --git a/src/java/org/apache/cassandra/db/Clusterable.java b/src/java/org/apache/cassandra/db/Clusterable.java index 62ab9dc67c..118b2724f5 100644 --- a/src/java/org/apache/cassandra/db/Clusterable.java +++ b/src/java/org/apache/cassandra/db/Clusterable.java @@ -21,7 +21,7 @@ package org.apache.cassandra.db; * Common class for objects that are identified by a clustering prefix, and can be thus sorted by a * {@link ClusteringComparator}. */ -public interface Clusterable +public interface Clusterable { - public ClusteringPrefix clustering(); + public ClusteringPrefix clustering(); } diff --git a/src/java/org/apache/cassandra/db/Clustering.java b/src/java/org/apache/cassandra/db/Clustering.java index 451a087454..c685638248 100644 --- a/src/java/org/apache/cassandra/db/Clustering.java +++ b/src/java/org/apache/cassandra/db/Clustering.java @@ -22,6 +22,7 @@ import java.io.IOException; import java.nio.ByteBuffer; import java.util.List; +import org.apache.cassandra.db.marshal.ByteArrayAccessor; import org.apache.cassandra.schema.ColumnMetadata; import org.apache.cassandra.schema.TableMetadata; import org.apache.cassandra.db.marshal.AbstractType; @@ -29,20 +30,17 @@ import org.apache.cassandra.io.util.DataInputBuffer; import org.apache.cassandra.io.util.DataInputPlus; import org.apache.cassandra.io.util.DataOutputBuffer; import org.apache.cassandra.io.util.DataOutputPlus; -import org.apache.cassandra.utils.ObjectSizes; import org.apache.cassandra.utils.memory.AbstractAllocator; import static org.apache.cassandra.db.AbstractBufferClusteringPrefix.EMPTY_VALUES_ARRAY; -public interface Clustering extends ClusteringPrefix +public interface Clustering extends ClusteringPrefix { - static final long EMPTY_SIZE = ObjectSizes.measure(new BufferClustering(EMPTY_VALUES_ARRAY)); - public static final Serializer serializer = new Serializer(); public long unsharedHeapSizeExcludingData(); - public default Clustering copy(AbstractAllocator allocator) + public default Clustering copy(AbstractAllocator allocator) { // Important for STATIC_CLUSTERING (but must copy empty native clustering types). if (size() == 0) @@ -51,7 +49,7 @@ public interface Clustering extends ClusteringPrefix ByteBuffer[] newValues = new ByteBuffer[size()]; for (int i = 0; i < size(); i++) { - ByteBuffer val = get(i); + ByteBuffer val = accessor().toBuffer(get(i)); newValues[i] = val == null ? null : allocator.clone(val); } return new BufferClustering(newValues); @@ -63,7 +61,7 @@ public interface Clustering extends ClusteringPrefix for (int i = 0; i < size(); i++) { ColumnMetadata c = metadata.clusteringColumns().get(i); - sb.append(i == 0 ? "" : ", ").append(c.name).append('=').append(get(i) == null ? "null" : c.type.getString(get(i))); + sb.append(i == 0 ? "" : ", ").append(c.name).append('=').append(get(i) == null ? "null" : c.type.getString(get(i), accessor())); } return sb.toString(); } @@ -74,12 +72,12 @@ public interface Clustering extends ClusteringPrefix for (int i = 0; i < size(); i++) { ColumnMetadata c = metadata.clusteringColumns().get(i); - sb.append(i == 0 ? "" : ", ").append(c.type.getString(get(i))); + sb.append(i == 0 ? "" : ", ").append(c.type.getString(get(i), accessor())); } return sb.toString(); } - public static Clustering make(ByteBuffer... values) + public static Clustering make(ByteBuffer... values) { return values.length == 0 ? EMPTY : new BufferClustering(values); } @@ -88,7 +86,7 @@ public interface Clustering extends ClusteringPrefix * The special cased clustering used by all static rows. It is a special case in the * sense that it's always empty, no matter how many clustering columns the table has. */ - public static final Clustering STATIC_CLUSTERING = new BufferClustering(EMPTY_VALUES_ARRAY) + public static final Clustering STATIC_CLUSTERING = new BufferClustering(EMPTY_VALUES_ARRAY) { @Override public Kind kind() @@ -110,7 +108,7 @@ public interface Clustering extends ClusteringPrefix }; /** Empty clustering for tables having no clustering columns. */ - public static final Clustering EMPTY = new BufferClustering(EMPTY_VALUES_ARRAY) + public static final Clustering EMPTY = new BufferClustering(EMPTY_VALUES_ARRAY) { @Override public String toString(TableMetadata metadata) @@ -127,14 +125,14 @@ public interface Clustering extends ClusteringPrefix */ public static class Serializer { - public void serialize(Clustering clustering, DataOutputPlus out, int version, List> types) throws IOException + public void serialize(Clustering clustering, DataOutputPlus out, int version, List> types) throws IOException { assert clustering != STATIC_CLUSTERING : "We should never serialize a static clustering"; assert clustering.size() == types.size() : "Invalid clustering for the table: " + clustering; ClusteringPrefix.serializer.serializeValuesWithoutSize(clustering, out, version, types); } - public ByteBuffer serialize(Clustering clustering, int version, List> types) + public ByteBuffer serialize(Clustering clustering, int version, List> types) { try (DataOutputBuffer buffer = new DataOutputBuffer((int)serializedSize(clustering, version, types))) { @@ -147,7 +145,7 @@ public interface Clustering extends ClusteringPrefix } } - public long serializedSize(Clustering clustering, int version, List> types) + public long serializedSize(Clustering clustering, int version, List> types) { return ClusteringPrefix.serializer.valuesWithoutSizeSerializedSize(clustering, version, types); } @@ -158,16 +156,16 @@ public interface Clustering extends ClusteringPrefix ClusteringPrefix.serializer.skipValuesWithoutSize(in, types.size(), version, types); } - public Clustering deserialize(DataInputPlus in, int version, List> types) throws IOException + public Clustering deserialize(DataInputPlus in, int version, List> types) throws IOException { if (types.isEmpty()) - return EMPTY; + return ByteArrayAccessor.factory.clustering(); - ByteBuffer[] values = ClusteringPrefix.serializer.deserializeValuesWithoutSize(in, types.size(), version, types); - return new BufferClustering(values); + byte[][] values = ClusteringPrefix.serializer.deserializeValuesWithoutSize(in, types.size(), version, types); + return ByteArrayAccessor.factory.clustering(values); } - public Clustering deserialize(ByteBuffer in, int version, List> types) + public Clustering deserialize(ByteBuffer in, int version, List> types) { try (DataInputBuffer buffer = new DataInputBuffer(in, true)) { diff --git a/src/java/org/apache/cassandra/db/ClusteringBound.java b/src/java/org/apache/cassandra/db/ClusteringBound.java index 6ae0816060..364856f212 100644 --- a/src/java/org/apache/cassandra/db/ClusteringBound.java +++ b/src/java/org/apache/cassandra/db/ClusteringBound.java @@ -23,135 +23,55 @@ package org.apache.cassandra.db; import java.nio.ByteBuffer; import java.util.List; -import org.apache.cassandra.utils.ByteBufferUtil; +import org.apache.cassandra.db.marshal.ByteBufferAccessor; 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 +public interface 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); + public static final ClusteringBound BOTTOM = new BufferClusteringBound(ClusteringPrefix.Kind.INCL_START_BOUND, BufferClusteringBound.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); + public static final ClusteringBound TOP = new BufferClusteringBound(ClusteringPrefix.Kind.INCL_END_BOUND, BufferClusteringBound.EMPTY_VALUES_ARRAY); - protected ClusteringBound(Kind kind, ByteBuffer[] values) - { - super(kind, values); - } - - public ClusteringPrefix minimize() - { - if (!ByteBufferUtil.canMinimize(values)) - return this; - return new ClusteringBound(kind, ByteBufferUtil.minimizeBuffers(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) + public static ClusteringPrefix.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); + ? (isInclusive ? ClusteringPrefix.Kind.INCL_START_BOUND : ClusteringPrefix.Kind.EXCL_START_BOUND) + : (isInclusive ? ClusteringPrefix.Kind.INCL_END_BOUND : ClusteringPrefix.Kind.EXCL_END_BOUND); } @Override - public ClusteringBound invert() - { - return create(kind().invert(), values); - } + ClusteringBound invert(); - public ClusteringBound copy(AbstractAllocator allocator) - { - return (ClusteringBound) super.copy(allocator); - } + @Override + ClusteringBound copy(AbstractAllocator allocator); - public boolean isStart() + default boolean isStart() { return kind().isStart(); } - public boolean isEnd() + default boolean isEnd() { return !isStart(); } - public boolean isInclusive() + default boolean isInclusive() { - return kind == Kind.INCL_START_BOUND || kind == Kind.INCL_END_BOUND; + return kind() == Kind.INCL_START_BOUND || kind() == Kind.INCL_END_BOUND; } - public boolean isExclusive() + default boolean isExclusive() { - return kind == Kind.EXCL_START_BOUND || kind == Kind.EXCL_END_BOUND; + 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 sstableBound) + default int compareTo(ClusteringComparator comparator, List sstableBound) { for (int i = 0; i < sstableBound.size(); i++) { @@ -162,7 +82,7 @@ public class ClusteringBound extends ClusteringBoundOrBoundary if (i >= size()) return isStart() ? -1 : 1; - int cmp = comparator.compareComponent(i, get(i), sstableBound.get(i)); + int cmp = comparator.compareComponent(i, get(i), accessor(), sstableBound.get(i), ByteBufferAccessor.instance); if (cmp != 0) return cmp; } @@ -176,4 +96,42 @@ public class ClusteringBound extends ClusteringBoundOrBoundary // 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); } + + static ClusteringBound create(ClusteringPrefix.Kind kind, ClusteringPrefix from) + { + return from.accessor().factory().bound(kind, from.getRawValues()); + } + + public static ClusteringBound inclusiveStartOf(ClusteringPrefix from) + { + return create(ClusteringPrefix.Kind.INCL_START_BOUND, from); + } + + public static ClusteringBound inclusiveEndOf(ClusteringPrefix from) + { + return create(ClusteringPrefix.Kind.INCL_END_BOUND, from); + } + + public static ClusteringBound exclusiveStartOf(ClusteringPrefix from) + { + return create(ClusteringPrefix.Kind.EXCL_START_BOUND, from); + } + + public static ClusteringBound exclusiveEndOf(ClusteringPrefix from) + { + return create(ClusteringPrefix.Kind.EXCL_END_BOUND, from); + } + + 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); + } } diff --git a/src/java/org/apache/cassandra/db/ClusteringBoundOrBoundary.java b/src/java/org/apache/cassandra/db/ClusteringBoundOrBoundary.java index 84a9e30111..7be9ed2b46 100644 --- a/src/java/org/apache/cassandra/db/ClusteringBoundOrBoundary.java +++ b/src/java/org/apache/cassandra/db/ClusteringBoundOrBoundary.java @@ -24,6 +24,8 @@ import java.io.IOException; import java.nio.ByteBuffer; import java.util.List; +import org.apache.cassandra.db.marshal.ByteArrayAccessor; +import org.apache.cassandra.db.marshal.ByteBufferAccessor; import org.apache.cassandra.schema.TableMetadata; import org.apache.cassandra.db.marshal.AbstractType; import org.apache.cassandra.io.util.DataInputPlus; @@ -41,82 +43,39 @@ import org.apache.cassandra.utils.memory.AbstractAllocator; * iterator. See this comment for more details: https://goo.gl/yyB5mR. * 2) This saves some storage space. */ -public abstract class ClusteringBoundOrBoundary extends AbstractBufferClusteringPrefix +public interface ClusteringBoundOrBoundary extends ClusteringPrefix { public static final ClusteringBoundOrBoundary.Serializer serializer = new Serializer(); - protected ClusteringBoundOrBoundary(Kind kind, ByteBuffer[] values) + default boolean isBoundary() { - super(kind, values); - assert values.length > 0 || !kind.isBoundary(); + return kind().isBoundary(); } - public static ClusteringBoundOrBoundary create(Kind kind, ByteBuffer[] values) + default boolean isOpen(boolean reversed) { - return kind.isBoundary() - ? new ClusteringBoundary(kind, values) - : new ClusteringBound(kind, values); + return kind().isOpen(reversed); } - public boolean isBoundary() + default boolean isClose(boolean reversed) { - return kind.isBoundary(); + return kind().isClose(reversed); } - 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) + default 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); + newValues[i] = allocator.clone(get(i), accessor()); + return ByteBufferAccessor.instance.factory().boundOrBoundary(kind(), newValues); } - public String toString(TableMetadata metadata) + default String toString(TableMetadata metadata) { return toString(metadata.comparator); } - public String toString(ClusteringComparator comparator) + default String toString(ClusteringComparator comparator) { StringBuilder sb = new StringBuilder(); sb.append(kind()).append('('); @@ -124,7 +83,7 @@ public abstract class ClusteringBoundOrBoundary extends AbstractBufferClustering { if (i > 0) sb.append(", "); - sb.append(comparator.subtype(i).getString(get(i))); + sb.append(comparator.subtype(i).getString(get(i), accessor())); } return sb.append(')').toString(); } @@ -137,25 +96,25 @@ public abstract class ClusteringBoundOrBoundary extends AbstractBufferClustering * @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 abstract ClusteringBoundOrBoundary invert(); public static class Serializer { - public void serialize(ClusteringBoundOrBoundary bound, DataOutputPlus out, int version, List> types) throws IOException + public void serialize(ClusteringBoundOrBoundary bound, DataOutputPlus out, int version, List> 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> types) + public long serializedSize(ClusteringBoundOrBoundary bound, int version, List> types) { return 1 // kind ordinal + TypeSizes.sizeof((short)bound.size()) + ClusteringPrefix.serializer.valuesWithoutSizeSerializedSize(bound, version, types); } - public ClusteringBoundOrBoundary deserialize(DataInputPlus in, int version, List> types) throws IOException + public ClusteringBoundOrBoundary deserialize(DataInputPlus in, int version, List> types) throws IOException { Kind kind = Kind.values()[in.readByte()]; return deserializeValues(in, kind, version, types); @@ -170,14 +129,14 @@ public abstract class ClusteringBoundOrBoundary extends AbstractBufferClustering ClusteringPrefix.serializer.skipValuesWithoutSize(in, size, version, types); } - public ClusteringBoundOrBoundary deserializeValues(DataInputPlus in, Kind kind, int version, List> types) throws IOException + public ClusteringBoundOrBoundary deserializeValues(DataInputPlus in, Kind kind, int version, List> types) throws IOException { int size = in.readUnsignedShort(); if (size == 0) - return kind.isStart() ? ClusteringBound.BOTTOM : ClusteringBound.TOP; + return ByteArrayAccessor.factory.bound(kind); - ByteBuffer[] values = ClusteringPrefix.serializer.deserializeValuesWithoutSize(in, size, version, types); - return create(kind, values); + byte[][] values = ClusteringPrefix.serializer.deserializeValuesWithoutSize(in, size, version, types); + return ByteArrayAccessor.factory.boundOrBoundary(kind, values); } } } diff --git a/src/java/org/apache/cassandra/db/ClusteringBoundary.java b/src/java/org/apache/cassandra/db/ClusteringBoundary.java index b1dcdb6917..3e50f5264c 100644 --- a/src/java/org/apache/cassandra/db/ClusteringBoundary.java +++ b/src/java/org/apache/cassandra/db/ClusteringBoundary.java @@ -20,54 +20,21 @@ */ package org.apache.cassandra.db; -import java.nio.ByteBuffer; - -import org.apache.cassandra.utils.ByteBufferUtil; -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 +public interface ClusteringBoundary extends ClusteringBoundOrBoundary { - protected ClusteringBoundary(Kind kind, ByteBuffer[] values) - { - super(kind, values); - } - - public ClusteringPrefix minimize() - { - if (!ByteBufferUtil.canMinimize(values)) - return this; - return new ClusteringBoundary(kind, ByteBufferUtil.minimizeBuffers(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); - } + public ClusteringBoundary invert(); - @Override - public ClusteringBoundary copy(AbstractAllocator allocator) - { - return (ClusteringBoundary) super.copy(allocator); - } + public ClusteringBound openBound(boolean reversed); - public ClusteringBound openBound(boolean reversed) - { - return ClusteringBound.create(kind.openBoundOfBoundary(reversed), values); - } + public ClusteringBound closeBound(boolean reversed); - public ClusteringBound closeBound(boolean reversed) + public static ClusteringBoundary create(ClusteringBound.Kind kind, ClusteringPrefix from) { - return ClusteringBound.create(kind.closeBoundOfBoundary(reversed), values); + return from.accessor().factory().boundary(kind, from.getRawValues()); } } diff --git a/src/java/org/apache/cassandra/db/ClusteringComparator.java b/src/java/org/apache/cassandra/db/ClusteringComparator.java index 50cf5bfa59..fdc450813f 100644 --- a/src/java/org/apache/cassandra/db/ClusteringComparator.java +++ b/src/java/org/apache/cassandra/db/ClusteringComparator.java @@ -25,6 +25,7 @@ import java.util.Objects; import com.google.common.base.Joiner; import com.google.common.collect.ImmutableList; +import org.apache.cassandra.db.marshal.ValueAccessor; import org.apache.cassandra.db.rows.Row; import org.apache.cassandra.db.marshal.AbstractType; import org.apache.cassandra.serializers.MarshalException; @@ -46,7 +47,8 @@ public class ClusteringComparator implements Comparator private final Comparator indexReverseComparator; private final Comparator reverseComparator; - private final Comparator rowComparator = (r1, r2) -> compare(r1.clustering(), r2.clustering()); + private final Comparator rowComparator = (r1, r2) -> compare((ClusteringPrefix) r1.clustering(), + (ClusteringPrefix) r2.clustering()); public ClusteringComparator(AbstractType... clusteringTypes) { @@ -58,8 +60,10 @@ public class ClusteringComparator implements Comparator // copy the list to ensure despatch is monomorphic this.clusteringTypes = ImmutableList.copyOf(clusteringTypes); - this.indexComparator = (o1, o2) -> ClusteringComparator.this.compare(o1.lastName, o2.lastName); - this.indexReverseComparator = (o1, o2) -> ClusteringComparator.this.compare(o1.firstName, o2.firstName); + this.indexComparator = (o1, o2) -> ClusteringComparator.this.compare((ClusteringPrefix) o1.lastName, + (ClusteringPrefix) o2.lastName); + this.indexReverseComparator = (o1, o2) -> ClusteringComparator.this.compare((ClusteringPrefix) o1.firstName, + (ClusteringPrefix) o2.firstName); this.reverseComparator = (c1, c2) -> ClusteringComparator.this.compare(c2, c1); for (AbstractType type : clusteringTypes) type.checkComparable(); // this should already be enforced by TableMetadata.Builder.addColumn, but we check again for other constructors @@ -102,7 +106,7 @@ public class ClusteringComparator implements Comparator * * @return the newly created clustering. */ - public Clustering make(Object... values) + public Clustering make(Object... values) { if (values.length != size()) throw new IllegalArgumentException(String.format("Invalid number of components, expecting %d but got %d", size(), values.length)); @@ -120,10 +124,10 @@ public class ClusteringComparator implements Comparator public int compare(Clusterable c1, Clusterable c2) { - return compare(c1.clustering(), c2.clustering()); + return compare((ClusteringPrefix) c1.clustering(), (ClusteringPrefix) c2.clustering()); } - public int compare(ClusteringPrefix c1, ClusteringPrefix c2) + public int compare(ClusteringPrefix c1, ClusteringPrefix c2) { int s1 = c1.size(); int s2 = c2.size(); @@ -131,7 +135,7 @@ public class ClusteringComparator implements Comparator for (int i = 0; i < minSize; i++) { - int cmp = compareComponent(i, c1.get(i), c2.get(i)); + int cmp = compareComponent(i, c1.get(i), c1.accessor(), c2.get(i), c2.accessor()); if (cmp != 0) return cmp; } @@ -142,7 +146,7 @@ public class ClusteringComparator implements Comparator return s1 < s2 ? c1.kind().comparedToClustering : -c2.kind().comparedToClustering; } - public int compare(Clustering c1, Clustering c2) + public int compare(Clustering c1, Clustering c2) { return compare(c1, c2, size()); } @@ -156,25 +160,30 @@ public class ClusteringComparator implements Comparator * @return a negative integer, zero, or a positive integer as the first argument is less than, * equal to, or greater than the second. */ - public int compare(Clustering c1, Clustering c2, int size) + public int compare(Clustering c1, Clustering c2, int size) { for (int i = 0; i < size; i++) { - int cmp = compareComponent(i, c1.get(i), c2.get(i)); + int cmp = compareComponent(i, c1.get(i), c1.accessor(), c2.get(i), c2.accessor()); if (cmp != 0) return cmp; } return 0; } - public int compareComponent(int i, ByteBuffer v1, ByteBuffer v2) + public int compareComponent(int i, V1 v1, ValueAccessor accessor1, V2 v2, ValueAccessor accessor2) { if (v1 == null) return v2 == null ? 0 : -1; if (v2 == null) return 1; - return clusteringTypes.get(i).compare(v1, v2); + return clusteringTypes.get(i).compare(v1, accessor1, v2, accessor2); + } + + public int compareComponent(int i, ClusteringPrefix v1, ClusteringPrefix v2) + { + return compareComponent(i, v1.get(i), v1.accessor(), v2.get(i), v2.accessor()); } /** @@ -212,13 +221,14 @@ public class ClusteringComparator implements Comparator * * @throws MarshalException if {@code clustering} contains some invalid data. */ - public void validate(ClusteringPrefix clustering) + public void validate(ClusteringPrefix clustering) { + ValueAccessor accessor = clustering.accessor(); for (int i = 0; i < clustering.size(); i++) { - ByteBuffer value = clustering.get(i); + T value = clustering.get(i); if (value != null) - subtype(i).validate(value); + subtype(i).validate(value, accessor); } } diff --git a/src/java/org/apache/cassandra/db/ClusteringPrefix.java b/src/java/org/apache/cassandra/db/ClusteringPrefix.java index 357d74630d..a1291c889f 100644 --- a/src/java/org/apache/cassandra/db/ClusteringPrefix.java +++ b/src/java/org/apache/cassandra/db/ClusteringPrefix.java @@ -23,12 +23,16 @@ import java.util.*; import org.apache.cassandra.cache.IMeasurableMemory; import org.apache.cassandra.config.*; +import org.apache.cassandra.db.marshal.ByteArrayAccessor; +import org.apache.cassandra.db.marshal.ByteBufferAccessor; import org.apache.cassandra.db.marshal.CompositeType; +import org.apache.cassandra.db.marshal.ValueAccessor; import org.apache.cassandra.db.rows.*; 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.schema.TableMetadata; +import org.apache.cassandra.utils.ByteArrayUtil; import org.apache.cassandra.utils.ByteBufferUtil; /** @@ -44,7 +48,7 @@ import org.apache.cassandra.utils.ByteBufferUtil; * 3) {@code ClusteringBoundary} represents the threshold between two adjacent range tombstones. * See those classes for more details. */ -public interface ClusteringPrefix extends IMeasurableMemory, Clusterable +public interface ClusteringPrefix extends IMeasurableMemory, Clusterable { public static final Serializer serializer = new Serializer(); @@ -195,6 +199,16 @@ public interface ClusteringPrefix extends IMeasurableMemory, Clusterable } } + default boolean isBottom() + { + return kind() == Kind.INCL_START_BOUND && size() == 0; + } + + default boolean isTop() + { + return kind() == Kind.INCL_END_BOUND && size() == 0; + } + public Kind kind(); /** @@ -206,6 +220,11 @@ public interface ClusteringPrefix extends IMeasurableMemory, Clusterable */ public int size(); + default boolean isEmpty() + { + return size() == 0; + } + /** * Retrieves the ith value of this prefix. * @@ -213,14 +232,40 @@ public interface ClusteringPrefix extends IMeasurableMemory, Clusterable * * @return the ith value of this prefix. Note that a value can be {@code null}. */ - public ByteBuffer get(int i); + public V get(int i); + + public ValueAccessor accessor(); + + default ByteBuffer bufferAt(int i) + { + return accessor().toBuffer(get(i)); + } + + default String stringAt(int i, ClusteringComparator comparator) + { + return comparator.subtype(i).getString(get(i), accessor()); + } + + default void validate(int i, ClusteringComparator comparator) + { + comparator.subtype(i).validate(get(i), accessor()); + } /** * Adds the data of this clustering prefix to the provided Digest instance. * * @param digest the Digest instance to which to add this prefix. */ - public void digest(Digest digest); + default void digest(Digest digest) + { + for (int i = 0; i < size(); i++) + { + V value = get(i); + if (value != null) + digest.update(value, accessor()); + } + digest.updateWithByte(kind().ordinal()); + } /** * The size of the data hold by this prefix. @@ -228,7 +273,16 @@ public interface ClusteringPrefix extends IMeasurableMemory, Clusterable * @return the size of the data hold by this prefix (this is not the size of the object in memory, just * the size of the data it stores). */ - public int dataSize(); + default int dataSize() + { + int size = 0; + for (int i = 0; i < size(); i++) + { + V v = get(i); + size += v == null ? 0 : accessor().size(v); + } + return size; + } /** * Generates a proper string representation of the prefix. @@ -247,12 +301,12 @@ public interface ClusteringPrefix extends IMeasurableMemory, Clusterable default ByteBuffer serializeAsPartitionKey() { if (size() == 1) - return get(0); + return accessor().toBuffer(get(0)); ByteBuffer[] values = new ByteBuffer[size()]; for (int i = 0; i < size(); i++) - values[i] = get(i); - return CompositeType.build(values); + values[i] = accessor().toBuffer(get(i)); + return CompositeType.build(ByteBufferAccessor.instance, values); } /** * The values of this prefix as an array. @@ -263,28 +317,30 @@ public interface ClusteringPrefix extends IMeasurableMemory, Clusterable * * @return the values for this prefix as an array. */ - public ByteBuffer[] getRawValues(); + public V[] getRawValues(); + + public ByteBuffer[] getBufferArray(); /** * If the prefix contains byte buffers that can be minimized (see {@link ByteBufferUtil#minimalBufferFor(ByteBuffer)}), * this will return a copy of the prefix with minimized values, otherwise it returns itself. */ - public ClusteringPrefix minimize(); + public ClusteringPrefix minimize(); public static class Serializer { - public void serialize(ClusteringPrefix clustering, DataOutputPlus out, int version, List> types) throws IOException + public void serialize(ClusteringPrefix clustering, DataOutputPlus out, int version, List> types) throws IOException { // We shouldn't serialize static clusterings assert clustering.kind() != Kind.STATIC_CLUSTERING; if (clustering.kind() == Kind.CLUSTERING) { out.writeByte(clustering.kind().ordinal()); - Clustering.serializer.serialize((Clustering)clustering, out, version, types); + Clustering.serializer.serialize((Clustering)clustering, out, version, types); } else { - ClusteringBoundOrBoundary.serializer.serialize((ClusteringBoundOrBoundary)clustering, out, version, types); + ClusteringBoundOrBoundary.serializer.serialize((ClusteringBoundOrBoundary)clustering, out, version, types); } } @@ -299,7 +355,7 @@ public interface ClusteringPrefix extends IMeasurableMemory, Clusterable ClusteringBoundOrBoundary.serializer.skipValues(in, kind, version, types); } - public ClusteringPrefix deserialize(DataInputPlus in, int version, List> types) throws IOException + public ClusteringPrefix deserialize(DataInputPlus in, int version, List> types) throws IOException { Kind kind = Kind.values()[in.readByte()]; // We shouldn't serialize static clusterings @@ -310,20 +366,21 @@ public interface ClusteringPrefix extends IMeasurableMemory, Clusterable return ClusteringBoundOrBoundary.serializer.deserializeValues(in, kind, version, types); } - public long serializedSize(ClusteringPrefix clustering, int version, List> types) + public long serializedSize(ClusteringPrefix clustering, int version, List> types) { // We shouldn't serialize static clusterings assert clustering.kind() != Kind.STATIC_CLUSTERING; if (clustering.kind() == Kind.CLUSTERING) - return 1 + Clustering.serializer.serializedSize((Clustering)clustering, version, types); + return 1 + Clustering.serializer.serializedSize((Clustering)clustering, version, types); else - return ClusteringBoundOrBoundary.serializer.serializedSize((ClusteringBoundOrBoundary)clustering, version, types); + return ClusteringBoundOrBoundary.serializer.serializedSize((ClusteringBoundOrBoundary)clustering, version, types); } - void serializeValuesWithoutSize(ClusteringPrefix clustering, DataOutputPlus out, int version, List> types) throws IOException + void serializeValuesWithoutSize(ClusteringPrefix clustering, DataOutputPlus out, int version, List> types) throws IOException { int offset = 0; int clusteringSize = clustering.size(); + ValueAccessor accessor = clustering.accessor(); // serialize in batches of 32, to avoid garbage when deserializing headers while (offset < clusteringSize) { @@ -335,15 +392,15 @@ public interface ClusteringPrefix extends IMeasurableMemory, Clusterable out.writeUnsignedVInt(makeHeader(clustering, offset, limit)); while (offset < limit) { - ByteBuffer v = clustering.get(offset); - if (v != null && v.hasRemaining()) - types.get(offset).writeValue(v, out); + V v = clustering.get(offset); + if (v != null && !accessor.isEmpty(v)) + types.get(offset).writeValue(v, accessor, out); offset++; } } } - long valuesWithoutSizeSerializedSize(ClusteringPrefix clustering, int version, List> types) + long valuesWithoutSizeSerializedSize(ClusteringPrefix clustering, int version, List> types) { long result = 0; int offset = 0; @@ -354,22 +411,23 @@ public interface ClusteringPrefix extends IMeasurableMemory, Clusterable result += TypeSizes.sizeofUnsignedVInt(makeHeader(clustering, offset, limit)); offset = limit; } + ValueAccessor accessor = clustering.accessor(); for (int i = 0; i < clusteringSize; i++) { - ByteBuffer v = clustering.get(i); - if (v == null || !v.hasRemaining()) + V v = clustering.get(i); + if (v == null || accessor.isEmpty(v)) continue; // handled in the header - result += types.get(i).writtenLength(v); + result += types.get(i).writtenLength(v, accessor); } return result; } - ByteBuffer[] deserializeValuesWithoutSize(DataInputPlus in, int size, int version, List> types) throws IOException + byte[][] deserializeValuesWithoutSize(DataInputPlus in, int size, int version, List> types) throws IOException { // Callers of this method should handle the case where size = 0 (in all case we want to return a special value anyway). assert size > 0; - ByteBuffer[] values = new ByteBuffer[size]; + byte[][] values = new byte[size][]; int offset = 0; while (offset < size) { @@ -378,8 +436,9 @@ public interface ClusteringPrefix extends IMeasurableMemory, Clusterable while (offset < limit) { values[offset] = isNull(header, offset) - ? null - : (isEmpty(header, offset) ? ByteBufferUtil.EMPTY_BYTE_BUFFER : types.get(offset).readValue(in, DatabaseDescriptor.getMaxValueSize())); + ? null + : (isEmpty(header, offset) ? ByteArrayUtil.EMPTY_BYTE_ARRAY + : types.get(offset).readArray(in, DatabaseDescriptor.getMaxValueSize())); offset++; } } @@ -410,16 +469,17 @@ public interface ClusteringPrefix extends IMeasurableMemory, Clusterable * empty values too. So for that, every clustering prefix includes a "header" that contains 2 bits per element in the prefix. For each element, * those 2 bits encode whether the element is null, empty, or none of those. */ - private static long makeHeader(ClusteringPrefix clustering, int offset, int limit) + private static long makeHeader(ClusteringPrefix clustering, int offset, int limit) { long header = 0; + ValueAccessor accessor = clustering.accessor(); for (int i = offset ; i < limit ; i++) { - ByteBuffer v = clustering.get(i); + V v = clustering.get(i); // no need to do modulo arithmetic for i, since the left-shift execute on the modulus of RH operand by definition if (v == null) header |= (1L << (i * 2) + 1); - else if (!v.hasRemaining()) + else if (accessor.isEmpty(v)) header |= (1L << (i * 2)); } return header; @@ -461,7 +521,8 @@ public interface ClusteringPrefix extends IMeasurableMemory, Clusterable private int nextSize; private ClusteringPrefix.Kind nextKind; private int deserializedSize; - private ByteBuffer[] nextValues; + private byte[][] nextValues; + private final ValueAccessor accessor = ByteArrayAccessor.instance; public Deserializer(ClusteringComparator comparator, DataInputPlus in, SerializationHeader header) { @@ -486,12 +547,12 @@ public interface ClusteringPrefix extends IMeasurableMemory, Clusterable // nextValues is of the proper size. Note that the 2nd condition may not hold for range tombstone bounds, but all // rows have a fixed size clustering, so we'll still save in the common case. if (nextValues == null || nextValues.length != nextSize) - this.nextValues = new ByteBuffer[nextSize]; + this.nextValues = new byte[nextSize][]; } - public int compareNextTo(ClusteringBoundOrBoundary bound) throws IOException + public int compareNextTo(ClusteringBoundOrBoundary bound) throws IOException { - if (bound == ClusteringBound.TOP) + if (bound.isTop()) return -1; for (int i = 0; i < bound.size(); i++) @@ -499,7 +560,7 @@ public interface ClusteringPrefix extends IMeasurableMemory, Clusterable if (!hasComponent(i)) return nextKind.comparedToClustering; - int cmp = comparator.compareComponent(i, nextValues[i], bound.get(i)); + int cmp = comparator.compareComponent(i, nextValues[i], accessor, bound.get(i), bound.accessor()); if (cmp != 0) return cmp; } @@ -533,7 +594,8 @@ public interface ClusteringPrefix extends IMeasurableMemory, Clusterable int i = deserializedSize++; nextValues[i] = Serializer.isNull(nextHeader, i) ? null - : (Serializer.isEmpty(nextHeader, i) ? ByteBufferUtil.EMPTY_BYTE_BUFFER : serializationHeader.clusteringTypes().get(i).readValue(in, DatabaseDescriptor.getMaxValueSize())); + : (Serializer.isEmpty(nextHeader, i) ? ByteArrayUtil.EMPTY_BYTE_ARRAY + : serializationHeader.clusteringTypes().get(i).readArray(in, DatabaseDescriptor.getMaxValueSize())); return true; } @@ -543,20 +605,20 @@ public interface ClusteringPrefix extends IMeasurableMemory, Clusterable continue; } - public ClusteringBoundOrBoundary deserializeNextBound() throws IOException + public ClusteringBoundOrBoundary deserializeNextBound() throws IOException { assert !nextIsRow; deserializeAll(); - ClusteringBoundOrBoundary bound = ClusteringBoundOrBoundary.create(nextKind, nextValues); + ClusteringBoundOrBoundary bound = accessor.factory().boundOrBoundary(nextKind, nextValues); nextValues = null; return bound; } - public Clustering deserializeNextClustering() throws IOException + public Clustering deserializeNextClustering() throws IOException { assert nextIsRow; deserializeAll(); - Clustering clustering = Clustering.make(nextValues); + Clustering clustering = accessor.factory().clustering(nextValues); nextValues = null; return clustering; } @@ -574,4 +636,44 @@ public interface ClusteringPrefix extends IMeasurableMemory, Clusterable return nextKind; } } + + public static int hashCode(ClusteringPrefix prefix) + { + int result = 31; + for (int i = 0; i < prefix.size(); i++) + result += 31 * prefix.accessor().hashCode(prefix.get(i)); + return 31 * result + Objects.hashCode(prefix.kind()); + } + + static boolean equals(ClusteringPrefix left, ClusteringPrefix right) + { + if (left.kind() != right.kind() || left.size() != right.size()) + return false; + + for (int i = 0; i < left.size(); i++) + { + V1 lVal = left.get(i); + V2 rVal = right.get(i); + + if (lVal == null && rVal == null) + continue; + + if (lVal == null || rVal == null) + return false; + + if (!ValueAccessor.equals(lVal, left.accessor(), rVal, right.accessor())) + return false; + } + + return true; + } + + public static boolean equals(ClusteringPrefix prefix, Object o) + { + if(!(o instanceof ClusteringPrefix)) + return false; + + return equals(prefix, (ClusteringPrefix) o); + } + } diff --git a/src/java/org/apache/cassandra/db/ColumnFamilyStore.java b/src/java/org/apache/cassandra/db/ColumnFamilyStore.java index 824005b068..cb6c86be14 100644 --- a/src/java/org/apache/cassandra/db/ColumnFamilyStore.java +++ b/src/java/org/apache/cassandra/db/ColumnFamilyStore.java @@ -2057,14 +2057,14 @@ public class ColumnFamilyStore implements ColumnFamilyStoreMBean invalidateCachedPartition(new RowCacheKey(metadata(), key)); } - public ClockAndCount getCachedCounter(ByteBuffer partitionKey, Clustering clustering, ColumnMetadata column, CellPath path) + public ClockAndCount getCachedCounter(ByteBuffer partitionKey, Clustering clustering, ColumnMetadata column, CellPath path) { if (CacheService.instance.counterCache.getCapacity() == 0L) // counter cache disabled. return null; return CacheService.instance.counterCache.get(CounterCacheKey.create(metadata(), partitionKey, clustering, column, path)); } - public void putCachedCounter(ByteBuffer partitionKey, Clustering clustering, ColumnMetadata column, CellPath path, ClockAndCount clockAndCount) + public void putCachedCounter(ByteBuffer partitionKey, Clustering clustering, ColumnMetadata column, CellPath path, ClockAndCount clockAndCount) { if (CacheService.instance.counterCache.getCapacity() == 0L) // counter cache disabled. return; diff --git a/src/java/org/apache/cassandra/db/ColumnIndex.java b/src/java/org/apache/cassandra/db/ColumnIndex.java index e11f784ec5..b87230083d 100644 --- a/src/java/org/apache/cassandra/db/ColumnIndex.java +++ b/src/java/org/apache/cassandra/db/ColumnIndex.java @@ -65,8 +65,8 @@ public class ColumnIndex private int written; private long previousRowStart; - private ClusteringPrefix firstClustering; - private ClusteringPrefix lastClustering; + private ClusteringPrefix firstClustering; + private ClusteringPrefix lastClustering; private DeletionTime openMarker; diff --git a/src/java/org/apache/cassandra/db/CounterMutation.java b/src/java/org/apache/cassandra/db/CounterMutation.java index 722ad73234..bc0cd85fb0 100644 --- a/src/java/org/apache/cassandra/db/CounterMutation.java +++ b/src/java/org/apache/cassandra/db/CounterMutation.java @@ -30,6 +30,7 @@ import com.google.common.collect.PeekingIterator; import com.google.common.util.concurrent.Striped; import org.apache.cassandra.config.DatabaseDescriptor; +import org.apache.cassandra.db.marshal.ByteBufferAccessor; import org.apache.cassandra.db.rows.*; import org.apache.cassandra.db.filter.*; import org.apache.cassandra.db.partitions.*; @@ -221,7 +222,7 @@ public class CounterMutation implements IMutation private void updateWithCurrentValue(PartitionUpdate.CounterMark mark, ClockAndCount currentValue, ColumnFamilyStore cfs) { long clock = Math.max(FBUtilities.timestampMicros(), currentValue.clock + 1L); - long count = currentValue.count + CounterContext.instance().total(mark.value()); + long count = currentValue.count + CounterContext.instance().total(mark.value(), ByteBufferAccessor.instance); mark.setValue(CounterContext.instance().createGlobal(CounterId.getLocalId(), clock, count)); @@ -249,7 +250,7 @@ public class CounterMutation implements IMutation private void updateWithCurrentValuesFromCFS(List marks, ColumnFamilyStore cfs) { ColumnFilter.Builder builder = ColumnFilter.selectionBuilder(); - BTreeSet.Builder names = BTreeSet.builder(cfs.metadata().comparator); + BTreeSet.Builder> names = BTreeSet.builder(cfs.metadata().comparator); for (PartitionUpdate.CounterMark mark : marks) { if (mark.clustering() != Clustering.STATIC_CLUSTERING) @@ -279,7 +280,7 @@ public class CounterMutation implements IMutation } } - private int compare(Clustering c1, Clustering c2, ColumnFamilyStore cfs) + private int compare(Clustering c1, Clustering c2, ColumnFamilyStore cfs) { if (c1 == Clustering.STATIC_CLUSTERING) return c2 == Clustering.STATIC_CLUSTERING ? 0 : -1; @@ -302,10 +303,10 @@ public class CounterMutation implements IMutation while (cmp == 0) { PartitionUpdate.CounterMark mark = markIter.next(); - Cell cell = mark.path() == null ? row.getCell(mark.column()) : row.getCell(mark.column(), mark.path()); + Cell cell = mark.path() == null ? row.getCell(mark.column()) : row.getCell(mark.column(), mark.path()); if (cell != null) { - updateWithCurrentValue(mark, CounterContext.instance().getLocalClockAndCount(cell.value()), cfs); + updateWithCurrentValue(mark, CounterContext.instance().getLocalClockAndCount(cell.buffer()), cfs); markIter.remove(); } if (!markIter.hasNext()) diff --git a/src/java/org/apache/cassandra/db/DataRange.java b/src/java/org/apache/cassandra/db/DataRange.java index aa23f3d53c..91a62b3225 100644 --- a/src/java/org/apache/cassandra/db/DataRange.java +++ b/src/java/org/apache/cassandra/db/DataRange.java @@ -19,6 +19,7 @@ package org.apache.cassandra.db; import java.io.IOException; import java.nio.ByteBuffer; +import org.apache.cassandra.db.marshal.ByteArrayAccessor; import org.apache.cassandra.schema.ColumnMetadata; import org.apache.cassandra.schema.TableMetadata; import org.apache.cassandra.db.filter.*; @@ -232,7 +233,7 @@ public class DataRange * * @return a new {@code DataRange} suitable for paging {@code this} range given the {@code lastRetuned} result of the previous page. */ - public DataRange forPaging(AbstractBounds range, ClusteringComparator comparator, Clustering lastReturned, boolean inclusive) + public DataRange forPaging(AbstractBounds range, ClusteringComparator comparator, Clustering lastReturned, boolean inclusive) { return new Paging(range, clusteringIndexFilter, comparator, lastReturned, inclusive); } @@ -338,13 +339,13 @@ public class DataRange public static class Paging extends DataRange { private final ClusteringComparator comparator; - private final Clustering lastReturned; + private final Clustering lastReturned; private final boolean inclusive; private Paging(AbstractBounds range, ClusteringIndexFilter filter, ClusteringComparator comparator, - Clustering lastReturned, + Clustering lastReturned, boolean inclusive) { super(range, filter); @@ -380,7 +381,7 @@ public class DataRange /** * @return the last Clustering that was returned (in the previous page) */ - public Clustering getLastReturned() + public Clustering getLastReturned() { return lastReturned; } @@ -430,7 +431,7 @@ public class DataRange if (in.readBoolean()) { ClusteringComparator comparator = metadata.comparator; - Clustering lastReturned = Clustering.serializer.deserialize(in, version, comparator.subtypes()); + Clustering lastReturned = Clustering.serializer.deserialize(in, version, comparator.subtypes()); boolean inclusive = in.readBoolean(); return new Paging(range, filter, comparator, lastReturned, inclusive); } diff --git a/src/java/org/apache/cassandra/db/DeletionInfo.java b/src/java/org/apache/cassandra/db/DeletionInfo.java index 5bec8126a5..b8327e9284 100644 --- a/src/java/org/apache/cassandra/db/DeletionInfo.java +++ b/src/java/org/apache/cassandra/db/DeletionInfo.java @@ -52,7 +52,7 @@ public interface DeletionInfo extends IMeasurableMemory public Iterator rangeIterator(Slice slice, boolean reversed); - public RangeTombstone rangeCovering(Clustering name); + public RangeTombstone rangeCovering(Clustering name); public void collectStats(EncodingStats.Collector collector); diff --git a/src/java/org/apache/cassandra/db/DeletionTime.java b/src/java/org/apache/cassandra/db/DeletionTime.java index b2d9343542..f1471fd359 100644 --- a/src/java/org/apache/cassandra/db/DeletionTime.java +++ b/src/java/org/apache/cassandra/db/DeletionTime.java @@ -140,7 +140,7 @@ public class DeletionTime implements Comparable, IMeasurableMemory return deletes(info.timestamp()); } - public boolean deletes(Cell cell) + public boolean deletes(Cell cell) { return deletes(cell.timestamp()); } diff --git a/src/java/org/apache/cassandra/db/Digest.java b/src/java/org/apache/cassandra/db/Digest.java index bac638699c..6a4ecd8fd1 100644 --- a/src/java/org/apache/cassandra/db/Digest.java +++ b/src/java/org/apache/cassandra/db/Digest.java @@ -24,6 +24,7 @@ import com.google.common.hash.Hasher; import com.google.common.hash.Hashing; import org.apache.cassandra.db.context.CounterContext; +import org.apache.cassandra.db.marshal.ValueAccessor; import org.apache.cassandra.utils.FastByteOperations; public class Digest @@ -63,15 +64,15 @@ public class Digest return new Digest(Hashing.crc32c().newHasher()) { @Override - public Digest updateWithCounterContext(ByteBuffer context) + public Digest updateWithCounterContext(V context, ValueAccessor accessor) { // for the purposes of repaired data tracking on the read path, exclude // contexts with legacy shards as these may be irrevocably different on // different replicas - if (CounterContext.instance().hasLegacyShards(context)) + if (CounterContext.instance().hasLegacyShards(context, accessor)) return this; - return super.updateWithCounterContext(context); + return super.updateWithCounterContext(context, accessor); } }; } @@ -88,6 +89,12 @@ public class Digest return this; } + public Digest update(V input, ValueAccessor accessor) + { + accessor.digest(input, this); + return this; + } + /** * Update the digest with the bytes from the supplied buffer. This does * not modify the position of the supplied buffer, so callers are not @@ -103,7 +110,7 @@ public class Digest * not modify the position of the supplied buffer, so callers are not * required to duplicate() the source buffer before calling */ - private Digest update(ByteBuffer input, int pos, int len) + public Digest update(ByteBuffer input, int pos, int len) { if (len <= 0) return this; @@ -138,15 +145,15 @@ public class Digest * nodes. This means in particular that we always have: * updateDigest(ctx) == updateDigest(clearAllLocal(ctx)) */ - public Digest updateWithCounterContext(ByteBuffer context) + public Digest updateWithCounterContext(V context, ValueAccessor accessor) { // context can be empty due to the optimization from CASSANDRA-10657 - if (!context.hasRemaining()) + if (accessor.isEmpty(context)) return this; - int pos = context.position() + CounterContext.headerLength(context); - int len = context.limit() - pos; - update(context, pos, len); + int pos = CounterContext.headerLength(context, accessor); + int len = accessor.size(context) - pos; + accessor.digest(context, pos, len, this); return this; } diff --git a/src/java/org/apache/cassandra/db/MultiCBuilder.java b/src/java/org/apache/cassandra/db/MultiCBuilder.java index c4cff02fe9..0b5625b26f 100644 --- a/src/java/org/apache/cassandra/db/MultiCBuilder.java +++ b/src/java/org/apache/cassandra/db/MultiCBuilder.java @@ -163,7 +163,7 @@ public abstract class MultiCBuilder * * @return the clusterings */ - public abstract NavigableSet build(); + public abstract NavigableSet> build(); /** * Builds the ClusteringBounds for slice restrictions. @@ -174,10 +174,10 @@ public abstract class MultiCBuilder * @param columnDefs the columns of the slice restriction * @return the ClusteringBounds */ - public abstract NavigableSet buildBoundForSlice(boolean isStart, - boolean isInclusive, - boolean isOtherBoundInclusive, - List columnDefs); + public abstract NavigableSet> buildBoundForSlice(boolean isStart, + boolean isInclusive, + boolean isOtherBoundInclusive, + List columnDefs); /** * Builds the ClusteringBounds @@ -186,7 +186,7 @@ public abstract class MultiCBuilder * @param isInclusive specify if the bound is inclusive or not * @return the ClusteringBounds */ - public abstract NavigableSet buildBound(boolean isStart, boolean isInclusive); + public abstract NavigableSet> buildBound(boolean isStart, boolean isInclusive); /** * Checks if some elements can still be added to the clusterings. @@ -252,7 +252,7 @@ public abstract class MultiCBuilder return addEachElementToAll(values.get(0)); } - public NavigableSet build() + public NavigableSet> build() { built = true; @@ -263,15 +263,15 @@ public abstract class MultiCBuilder } @Override - public NavigableSet buildBoundForSlice(boolean isStart, - boolean isInclusive, - boolean isOtherBoundInclusive, - List columnDefs) + public NavigableSet> buildBoundForSlice(boolean isStart, + boolean isInclusive, + boolean isOtherBoundInclusive, + List columnDefs) { return buildBound(isStart, columnDefs.get(0).isReversedType() ? isOtherBoundInclusive : isInclusive); } - public NavigableSet buildBound(boolean isStart, boolean isInclusive) + public NavigableSet> buildBound(boolean isStart, boolean isInclusive) { built = true; @@ -279,13 +279,13 @@ public abstract class MultiCBuilder return BTreeSet.empty(comparator); if (size == 0) - return BTreeSet.of(comparator, isStart ? ClusteringBound.BOTTOM : ClusteringBound.TOP); + return BTreeSet.of(comparator, isStart ? BufferClusteringBound.BOTTOM : BufferClusteringBound.TOP); ByteBuffer[] newValues = size == elements.length ? elements : Arrays.copyOf(elements, size); - return BTreeSet.of(comparator, ClusteringBound.create(ClusteringBound.boundKind(isStart, isInclusive), newValues)); + return BTreeSet.of(comparator, BufferClusteringBound.create(ClusteringBound.boundKind(isStart, isInclusive), newValues)); } } @@ -397,7 +397,7 @@ public abstract class MultiCBuilder return this; } - public NavigableSet build() + public NavigableSet> build() { built = true; @@ -409,7 +409,7 @@ public abstract class MultiCBuilder if (elementsList.isEmpty()) return BTreeSet.of(builder.comparator(), builder.build()); - BTreeSet.Builder set = BTreeSet.builder(builder.comparator()); + BTreeSet.Builder> set = BTreeSet.builder(builder.comparator()); for (int i = 0, m = elementsList.size(); i < m; i++) { List elements = elementsList.get(i); @@ -418,10 +418,10 @@ public abstract class MultiCBuilder return set.build(); } - public NavigableSet buildBoundForSlice(boolean isStart, - boolean isInclusive, - boolean isOtherBoundInclusive, - List columnDefs) + public NavigableSet> buildBoundForSlice(boolean isStart, + boolean isInclusive, + boolean isOtherBoundInclusive, + List columnDefs) { built = true; @@ -434,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 set = BTreeSet.builder(comparator); + BTreeSet.Builder> 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(); @@ -469,7 +469,7 @@ public abstract class MultiCBuilder return set.build(); } - public NavigableSet buildBound(boolean isStart, boolean isInclusive) + public NavigableSet> buildBound(boolean isStart, boolean isInclusive) { built = true; @@ -482,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 set = BTreeSet.builder(comparator); + BTreeSet.Builder> set = BTreeSet.builder(comparator); for (int i = 0, m = elementsList.size(); i < m; i++) { diff --git a/src/java/org/apache/cassandra/db/MutableDeletionInfo.java b/src/java/org/apache/cassandra/db/MutableDeletionInfo.java index 356d763f86..8544b781ff 100644 --- a/src/java/org/apache/cassandra/db/MutableDeletionInfo.java +++ b/src/java/org/apache/cassandra/db/MutableDeletionInfo.java @@ -160,7 +160,7 @@ public class MutableDeletionInfo implements DeletionInfo return ranges == null ? Collections.emptyIterator() : ranges.iterator(slice, reversed); } - public RangeTombstone rangeCovering(Clustering name) + public RangeTombstone rangeCovering(Clustering name) { return ranges == null ? null : ranges.search(name); } @@ -291,8 +291,8 @@ public class MutableDeletionInfo implements DeletionInfo DeletionTime openDeletion = openMarker.openDeletionTime(reversed); assert marker.closeDeletionTime(reversed).equals(openDeletion); - ClusteringBound open = openMarker.openBound(reversed); - ClusteringBound 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); diff --git a/src/java/org/apache/cassandra/db/NativeClustering.java b/src/java/org/apache/cassandra/db/NativeClustering.java index 780f6a404c..0e4c19db17 100644 --- a/src/java/org/apache/cassandra/db/NativeClustering.java +++ b/src/java/org/apache/cassandra/db/NativeClustering.java @@ -21,12 +21,14 @@ package org.apache.cassandra.db; import java.nio.ByteBuffer; import java.nio.ByteOrder; +import org.apache.cassandra.db.marshal.ByteBufferAccessor; +import org.apache.cassandra.db.marshal.ValueAccessor; import org.apache.cassandra.utils.ObjectSizes; import org.apache.cassandra.utils.concurrent.OpOrder; import org.apache.cassandra.utils.memory.MemoryUtil; import org.apache.cassandra.utils.memory.NativeAllocator; -public class NativeClustering extends AbstractClusteringPrefix implements Clustering +public class NativeClustering implements Clustering { private static final long EMPTY_SIZE = ObjectSizes.measure(new NativeClustering()); @@ -34,12 +36,12 @@ public class NativeClustering extends AbstractClusteringPrefix implements Cluste private NativeClustering() { peer = 0; } - public ClusteringPrefix minimize() + public ClusteringPrefix minimize() { return this; } - public NativeClustering(NativeAllocator allocator, OpOrder.Group writeOp, Clustering clustering) + public NativeClustering(NativeAllocator allocator, OpOrder.Group writeOp, Clustering clustering) { int count = clustering.size(); int metadataSize = (count * 2) + 4; @@ -61,7 +63,7 @@ public class NativeClustering extends AbstractClusteringPrefix implements Cluste { MemoryUtil.setShort(peer + 2 + i * 2, (short) dataOffset); - ByteBuffer value = clustering.get(i); + ByteBuffer value = clustering.bufferAt(i); if (value == null) { long boffset = bitmapStart + (i >>> 3); @@ -84,6 +86,11 @@ public class NativeClustering extends AbstractClusteringPrefix implements Cluste return Kind.CLUSTERING; } + public ClusteringPrefix clustering() + { + return this; + } + public int size() { return MemoryUtil.getShort(peer); @@ -118,6 +125,17 @@ public class NativeClustering extends AbstractClusteringPrefix implements Cluste return values; } + public ByteBuffer[] getBufferArray() + { + return getRawValues(); + } + + public ValueAccessor accessor() + { + // TODO: add a native accessor + return ByteBufferAccessor.instance; + } + public long unsharedHeapSize() { return EMPTY_SIZE; @@ -127,4 +145,16 @@ public class NativeClustering extends AbstractClusteringPrefix implements Cluste { return EMPTY_SIZE; } + + @Override + public final int hashCode() + { + return ClusteringPrefix.hashCode(this); + } + + @Override + public final boolean equals(Object o) + { + return ClusteringPrefix.equals(this, o); + } } diff --git a/src/java/org/apache/cassandra/db/PartitionRangeReadQuery.java b/src/java/org/apache/cassandra/db/PartitionRangeReadQuery.java index 86ee4c00a3..816b783c79 100644 --- a/src/java/org/apache/cassandra/db/PartitionRangeReadQuery.java +++ b/src/java/org/apache/cassandra/db/PartitionRangeReadQuery.java @@ -75,7 +75,7 @@ public interface PartitionRangeReadQuery extends ReadQuery return rowFilter().partitionKeyRestrictionsAreSatisfiedBy(key, metadata().partitionKeyType); } - default boolean selectsClustering(DecoratedKey key, Clustering clustering) + default boolean selectsClustering(DecoratedKey key, Clustering clustering) { if (clustering == Clustering.STATIC_CLUSTERING) return !columnFilter().fetchedColumns().statics.isEmpty(); diff --git a/src/java/org/apache/cassandra/db/RangeTombstoneList.java b/src/java/org/apache/cassandra/db/RangeTombstoneList.java index acc5f17ee0..293596e87b 100644 --- a/src/java/org/apache/cassandra/db/RangeTombstoneList.java +++ b/src/java/org/apache/cassandra/db/RangeTombstoneList.java @@ -55,15 +55,15 @@ public class RangeTombstoneList implements Iterable, 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 ClusteringBound[] starts; - private ClusteringBound[] ends; + private ClusteringBound[] starts; + private ClusteringBound[] ends; private long[] markedAts; private int[] delTimes; private long boundaryHeapSize; private int size; - private RangeTombstoneList(ClusteringComparator comparator, ClusteringBound[] starts, ClusteringBound[] 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; @@ -77,7 +77,7 @@ public class RangeTombstoneList implements Iterable, IMeasurable public RangeTombstoneList(ClusteringComparator comparator, int capacity) { - this(comparator, new ClusteringBound[capacity], new ClusteringBound[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() @@ -108,8 +108,8 @@ public class RangeTombstoneList implements Iterable, IMeasurable public RangeTombstoneList copy(AbstractAllocator allocator) { RangeTombstoneList copy = new RangeTombstoneList(comparator, - new ClusteringBound[size], - new ClusteringBound[size], + new ClusteringBound[size], + new ClusteringBound[size], Arrays.copyOf(markedAts, size), Arrays.copyOf(delTimes, size), boundaryHeapSize, size); @@ -124,12 +124,12 @@ public class RangeTombstoneList implements Iterable, IMeasurable return copy; } - private static ClusteringBound clone(ClusteringBound 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 ClusteringBound(bound.kind(), values); + values[i] = allocator.clone(bound.get(i), bound.accessor()); + return new BufferClusteringBound(bound.kind(), values); } public void add(RangeTombstone tombstone) @@ -146,7 +146,7 @@ public class RangeTombstoneList implements Iterable, 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(ClusteringBound start, ClusteringBound end, long markedAt, int delTime) + public void add(ClusteringBound start, ClusteringBound end, long markedAt, int delTime) { if (isEmpty()) { @@ -233,7 +233,7 @@ public class RangeTombstoneList implements Iterable, IMeasurable * Returns whether the given name/timestamp pair is deleted by one of the tombstone * of this RangeTombstoneList. */ - public boolean isDeleted(Clustering clustering, Cell cell) + public boolean isDeleted(Clustering clustering, Cell cell) { int idx = searchInternal(clustering, 0, size); // No matter what the counter cell's timestamp is, a tombstone always takes precedence. See CASSANDRA-7346. @@ -244,13 +244,13 @@ public class RangeTombstoneList implements Iterable, IMeasurable * Returns the DeletionTime for the tombstone overlapping {@code name} (there can't be more than one), * or null if {@code name} is not covered by any tombstone. */ - public DeletionTime searchDeletionTime(Clustering name) + public DeletionTime searchDeletionTime(Clustering name) { int idx = searchInternal(name, 0, size); return idx < 0 ? null : new DeletionTime(markedAts[idx], delTimes[idx]); } - public RangeTombstone search(Clustering name) + public RangeTombstone search(Clustering name) { int idx = searchInternal(name, 0, size); return idx < 0 ? null : rangeTombstone(idx); @@ -262,7 +262,7 @@ public class RangeTombstoneList implements Iterable, IMeasurable * * Note that bounds are not in the range if they fall on its boundary. */ - private int searchInternal(ClusteringPrefix name, int startIdx, int endIdx) + private int searchInternal(ClusteringPrefix name, int startIdx, int endIdx) { if (isEmpty()) return -1; @@ -325,17 +325,17 @@ public class RangeTombstoneList implements Iterable, IMeasurable return new RangeTombstone(Slice.make(starts[idx], ends[idx]), new DeletionTime(markedAts[idx], delTimes[idx])); } - private RangeTombstone rangeTombstoneWithNewStart(int idx, ClusteringBound 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, ClusteringBound 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, ClusteringBound newStart, ClusteringBound newEnd) + private RangeTombstone rangeTombstoneWithNewBounds(int idx, ClusteringBound newStart, ClusteringBound newEnd) { return new RangeTombstone(Slice.make(newStart, newEnd), new DeletionTime(markedAts[idx], delTimes[idx])); } @@ -382,13 +382,13 @@ public class RangeTombstoneList implements Iterable, IMeasurable private Iterator forwardIterator(final Slice slice) { - int startIdx = slice.start() == ClusteringBound.BOTTOM ? 0 : searchInternal(slice.start(), 0, size); + int startIdx = slice.start().isBottom() ? 0 : searchInternal(slice.start(), 0, size); final int start = startIdx < 0 ? -startIdx-1 : startIdx; if (start >= size) return Collections.emptyIterator(); - int finishIdx = slice.end() == ClusteringBound.TOP ? size - 1 : searchInternal(slice.end(), start, size); + int finishIdx = slice.end().isTop() ? 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; @@ -399,8 +399,8 @@ public class RangeTombstoneList implements Iterable, 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. - 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]; + 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]; if (Slice.isEmpty(comparator, s, e)) return Collections.emptyIterator(); return Iterators.singletonIterator(rangeTombstoneWithNewBounds(start, s, e)); @@ -429,14 +429,14 @@ public class RangeTombstoneList implements Iterable, IMeasurable private Iterator reverseIterator(final Slice slice) { - int startIdx = slice.end() == ClusteringBound.TOP ? size - 1 : searchInternal(slice.end(), 0, size); + int startIdx = slice.end().isTop() ? 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() == ClusteringBound.BOTTOM ? 0 : searchInternal(slice.start(), 0, start + 1); // include same as finish + int finishIdx = slice.start().isBottom() ? 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; @@ -447,8 +447,8 @@ public class RangeTombstoneList implements Iterable, 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. - 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]; + 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]; if (Slice.isEmpty(comparator, s, e)) return Collections.emptyIterator(); return Iterators.singletonIterator(rangeTombstoneWithNewBounds(start, s, e)); @@ -533,7 +533,7 @@ public class RangeTombstoneList implements Iterable, IMeasurable * - e_i <= s_i+1 * Basically, range are non overlapping and in order. */ - private void insertFrom(int i, ClusteringBound start, ClusteringBound end, long markedAt, int delTime) + private void insertFrom(int i, ClusteringBound start, ClusteringBound end, long markedAt, int delTime) { while (i < size) { @@ -552,7 +552,7 @@ public class RangeTombstoneList implements Iterable, IMeasurable // First deal with what might come before the newly added one. if (comparator.compare(starts[i], start) < 0) { - ClusteringBound newEnd = start.invert(); + ClusteringBound newEnd = start.invert(); if (!Slice.isEmpty(comparator, starts[i], newEnd)) { addInternal(i, starts[i], newEnd, markedAts[i], delTimes[i]); @@ -600,7 +600,7 @@ public class RangeTombstoneList implements Iterable, IMeasurable // one to reflect the not overwritten parts. We're then done. addInternal(i, start, end, markedAt, delTime); i++; - ClusteringBound newStart = end.invert(); + ClusteringBound newStart = end.invert(); if (!Slice.isEmpty(comparator, newStart, ends[i])) { setInternal(i, newStart, ends[i], markedAts[i], delTimes[i]); @@ -622,7 +622,7 @@ public class RangeTombstoneList implements Iterable, IMeasurable addInternal(i, start, end, markedAt, delTime); return; } - ClusteringBound newEnd = starts[i].invert(); + ClusteringBound newEnd = starts[i].invert(); if (!Slice.isEmpty(comparator, start, newEnd)) { addInternal(i, start, newEnd, markedAt, delTime); @@ -654,7 +654,7 @@ public class RangeTombstoneList implements Iterable, IMeasurable /* * Adds the new tombstone at index i, growing and/or moving elements to make room for it. */ - private void addInternal(int i, ClusteringBound start, ClusteringBound end, long markedAt, int delTime) + private void addInternal(int i, ClusteringBound start, ClusteringBound end, long markedAt, int delTime) { assert i >= 0; @@ -698,12 +698,12 @@ public class RangeTombstoneList implements Iterable, IMeasurable delTimes = grow(delTimes, size, newLength, i); } - private static ClusteringBound[] grow(ClusteringBound[] 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); - ClusteringBound[] newA = new ClusteringBound[newLength]; + ClusteringBound[] newA = new ClusteringBound[newLength]; System.arraycopy(a, 0, newA, 0, i); System.arraycopy(a, i, newA, i+1, size - i); return newA; @@ -748,7 +748,7 @@ public class RangeTombstoneList implements Iterable, IMeasurable starts[i] = null; } - private void setInternal(int i, ClusteringBound start, ClusteringBound 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(); diff --git a/src/java/org/apache/cassandra/db/ReadCommand.java b/src/java/org/apache/cassandra/db/ReadCommand.java index 60ddaa9e5a..6b19ed9141 100644 --- a/src/java/org/apache/cassandra/db/ReadCommand.java +++ b/src/java/org/apache/cassandra/db/ReadCommand.java @@ -550,7 +550,7 @@ public abstract class ReadCommand extends AbstractReadQuery public Row applyToRow(Row row) { boolean hasTombstones = false; - for (Cell cell : row.cells()) + for (Cell cell : row.cells()) { if (!cell.isLive(ReadCommand.this.nowInSec())) { @@ -579,7 +579,7 @@ public abstract class ReadCommand extends AbstractReadQuery return marker; } - private void countTombstone(ClusteringPrefix clustering) + private void countTombstone(ClusteringPrefix clustering) { ++tombstones; if (tombstones > failureThreshold && respectTombstoneThresholds) diff --git a/src/java/org/apache/cassandra/db/ReadQuery.java b/src/java/org/apache/cassandra/db/ReadQuery.java index fd94aa1adb..bd20c26d9f 100644 --- a/src/java/org/apache/cassandra/db/ReadQuery.java +++ b/src/java/org/apache/cassandra/db/ReadQuery.java @@ -81,7 +81,7 @@ public interface ReadQuery return false; } - public boolean selectsClustering(DecoratedKey key, Clustering clustering) + public boolean selectsClustering(DecoratedKey key, Clustering clustering) { return false; } @@ -192,7 +192,7 @@ public interface ReadQuery * @return true if the read query would select the given clustering, including checks against the row filter, if * checkRowFilter is true */ - public boolean selectsClustering(DecoratedKey key, Clustering clustering); + public boolean selectsClustering(DecoratedKey key, Clustering clustering); /** * The time in seconds to use as "now" for this query. diff --git a/src/java/org/apache/cassandra/db/RowIndexEntry.java b/src/java/org/apache/cassandra/db/RowIndexEntry.java index 546c0c8cd7..215768bc8d 100644 --- a/src/java/org/apache/cassandra/db/RowIndexEntry.java +++ b/src/java/org/apache/cassandra/db/RowIndexEntry.java @@ -629,7 +629,7 @@ public class RowIndexEntry implements IMeasurableMemory this.idxInfoSerializer = idxInfoSerializer; this.fieldsSerializedSize = serializedSize(deletionTime, headerLength, columnIndexCount); - this.offsetsOffset = indexedPartSize + fieldsSerializedSize - columnsIndexCount * TypeSizes.sizeof(0); + this.offsetsOffset = indexedPartSize + fieldsSerializedSize - columnsIndexCount * TypeSizes.INT_SIZE; } /** @@ -650,7 +650,7 @@ public class RowIndexEntry implements IMeasurableMemory this.idxInfoSerializer = idxInfoSerializer; this.fieldsSerializedSize = serializedSize(deletionTime, headerLength, columnsIndexCount); - this.offsetsOffset = indexedPartSize + fieldsSerializedSize - columnsIndexCount * TypeSizes.sizeof(0); + this.offsetsOffset = indexedPartSize + fieldsSerializedSize - columnsIndexCount * TypeSizes.INT_SIZE; } @Override @@ -739,7 +739,7 @@ public class RowIndexEntry implements IMeasurableMemory IndexInfo fetchIndex(int index) throws IOException { // seek to position in "offsets to IndexInfo" table - indexReader.seek(indexInfoFilePosition + offsetsOffset + index * TypeSizes.sizeof(0)); + indexReader.seek(indexInfoFilePosition + offsetsOffset + index * TypeSizes.INT_SIZE); // read offset of IndexInfo int indexInfoPos = indexReader.readInt(); diff --git a/src/java/org/apache/cassandra/db/SimpleBuilders.java b/src/java/org/apache/cassandra/db/SimpleBuilders.java index 98572c548e..f1e34f9b7d 100644 --- a/src/java/org/apache/cassandra/db/SimpleBuilders.java +++ b/src/java/org/apache/cassandra/db/SimpleBuilders.java @@ -53,10 +53,10 @@ public abstract class SimpleBuilders return metadata.partitioner.decorateKey(key); } - private static Clustering makeClustering(TableMetadata metadata, Object... clusteringColumns) + private static Clustering makeClustering(TableMetadata metadata, Object... clusteringColumns) { if (clusteringColumns.length == 1 && clusteringColumns[0] instanceof Clustering) - return (Clustering)clusteringColumns[0]; + return (Clustering)clusteringColumns[0]; if (clusteringColumns.length == 0) { @@ -157,7 +157,7 @@ public abstract class SimpleBuilders { private final TableMetadata metadata; private final DecoratedKey key; - private final Map rowBuilders = new HashMap<>(); + private final Map, RowBuilder> rowBuilders = new HashMap<>(); private List rangeBuilders = null; // We use that rarely, so create lazily private List rangeTombstones = null; @@ -176,7 +176,7 @@ public abstract class SimpleBuilders public Row.SimpleBuilder row(Object... clusteringValues) { - Clustering clustering = makeClustering(metadata, clusteringValues); + Clustering clustering = makeClustering(metadata, clusteringValues); RowBuilder builder = rowBuilders.get(clustering); if (builder == null) { @@ -303,8 +303,8 @@ public abstract class SimpleBuilders private RangeTombstone build() { - ClusteringBound startBound = ClusteringBound.create(comparator, true, startInclusive, start); - ClusteringBound endBound = ClusteringBound.create(comparator, false, endInclusive, end); + ClusteringBound startBound = ClusteringBound.create(comparator, true, startInclusive, start); + ClusteringBound endBound = ClusteringBound.create(comparator, false, endInclusive, end); return new RangeTombstone(Slice.make(startBound, endBound), deletionTime); } } @@ -446,7 +446,7 @@ public abstract class SimpleBuilders return column; } - private Cell cell(ColumnMetadata column, ByteBuffer value, CellPath path) + private Cell cell(ColumnMetadata column, ByteBuffer value, CellPath path) { if (value == null) return BufferCell.tombstone(column, timestamp, nowInSec, path); diff --git a/src/java/org/apache/cassandra/db/SinglePartitionReadCommand.java b/src/java/org/apache/cassandra/db/SinglePartitionReadCommand.java index a4b028b7d2..62d67f1877 100644 --- a/src/java/org/apache/cassandra/db/SinglePartitionReadCommand.java +++ b/src/java/org/apache/cassandra/db/SinglePartitionReadCommand.java @@ -255,7 +255,7 @@ public class SinglePartitionReadCommand extends ReadCommand implements SinglePar * @return a newly created read command that queries the {@code names} in {@code key}. The returned query will * query every columns (without limit or row filtering) and be in forward order. */ - public static SinglePartitionReadCommand create(TableMetadata metadata, int nowInSec, DecoratedKey key, NavigableSet names) + public static SinglePartitionReadCommand create(TableMetadata metadata, int nowInSec, DecoratedKey key, NavigableSet> names) { ClusteringIndexNamesFilter filter = new ClusteringIndexNamesFilter(names, false); return create(metadata, nowInSec, ColumnFilter.all(metadata), RowFilter.NONE, DataLimits.NONE, key, filter); @@ -272,7 +272,7 @@ public class SinglePartitionReadCommand extends ReadCommand implements SinglePar * @return a newly created read command that queries {@code name} in {@code key}. The returned query will * query every columns (without limit or row filtering). */ - public static SinglePartitionReadCommand create(TableMetadata metadata, int nowInSec, DecoratedKey key, Clustering name) + public static SinglePartitionReadCommand create(TableMetadata metadata, int nowInSec, DecoratedKey key, Clustering name) { return create(metadata, nowInSec, key, FBUtilities.singleton(name, metadata.comparator)); } @@ -368,7 +368,7 @@ public class SinglePartitionReadCommand extends ReadCommand implements SinglePar } @Override - public SinglePartitionReadCommand forPaging(Clustering lastReturned, DataLimits limits) + public SinglePartitionReadCommand forPaging(Clustering lastReturned, DataLimits limits) { // We shouldn't have set digest yet when reaching that point assert !isDigestQuery(); @@ -928,10 +928,10 @@ public class SinglePartitionReadCommand extends ReadCommand implements SinglePar if (result == null) return filter; - SearchIterator searchIter = result.searchIterator(columnFilter(), false); + SearchIterator, Row> searchIter = result.searchIterator(columnFilter(), false); RegularAndStaticColumns columns = columnFilter().fetchedColumns(); - NavigableSet clusterings = filter.requestedRows(); + NavigableSet> clusterings = filter.requestedRows(); // We want to remove rows for which we have values for all requested columns. We have to deal with both static and regular rows. // TODO: we could also remove a selected column if we've found values for every requested row but we'll leave @@ -944,8 +944,8 @@ public class SinglePartitionReadCommand extends ReadCommand implements SinglePar removeStatic = staticRow != null && canRemoveRow(staticRow, columns.statics, sstableTimestamp); } - NavigableSet toRemove = null; - for (Clustering clustering : clusterings) + NavigableSet> toRemove = null; + for (Clustering clustering : clusterings) { Row row = searchIter.next(clustering); if (row == null || !canRemoveRow(row, columns.regulars, sstableTimestamp)) @@ -967,7 +967,7 @@ public class SinglePartitionReadCommand extends ReadCommand implements SinglePar if (toRemove != null) { - BTreeSet.Builder newClusterings = BTreeSet.builder(result.metadata().comparator); + BTreeSet.Builder> newClusterings = BTreeSet.builder(result.metadata().comparator); newClusterings.addAll(Sets.difference(clusterings, toRemove)); clusterings = newClusterings.build(); } @@ -984,7 +984,7 @@ public class SinglePartitionReadCommand extends ReadCommand implements SinglePar for (ColumnMetadata column : requestedColumns) { - Cell cell = row.getCell(column); + Cell cell = row.getCell(column); if (cell == null || cell.timestamp() <= sstableTimestamp) return false; } @@ -1113,7 +1113,7 @@ public class SinglePartitionReadCommand extends ReadCommand implements SinglePar IndexMetadata index) throws IOException { - DecoratedKey key = metadata.partitioner.decorateKey(metadata.partitionKeyType.readValue(in, DatabaseDescriptor.getMaxValueSize())); + DecoratedKey key = metadata.partitioner.decorateKey(metadata.partitionKeyType.readBuffer(in, DatabaseDescriptor.getMaxValueSize())); ClusteringIndexFilter filter = ClusteringIndexFilter.serializer.deserialize(in, version, metadata); return new SinglePartitionReadCommand(isDigest, digestVersion, acceptsTransient, metadata, nowInSec, columnFilter, rowFilter, limits, key, filter, index); } diff --git a/src/java/org/apache/cassandra/db/SinglePartitionReadQuery.java b/src/java/org/apache/cassandra/db/SinglePartitionReadQuery.java index f9f001417d..755d55227e 100644 --- a/src/java/org/apache/cassandra/db/SinglePartitionReadQuery.java +++ b/src/java/org/apache/cassandra/db/SinglePartitionReadQuery.java @@ -129,7 +129,7 @@ public interface SinglePartitionReadQuery extends ReadQuery * * @return the newly create query. */ - SinglePartitionReadQuery forPaging(Clustering lastReturned, DataLimits limits); + SinglePartitionReadQuery forPaging(Clustering lastReturned, DataLimits limits); @Override default SinglePartitionPager getPager(PagingState pagingState, ProtocolVersion protocolVersion) @@ -147,7 +147,7 @@ public interface SinglePartitionReadQuery extends ReadQuery return rowFilter().partitionKeyRestrictionsAreSatisfiedBy(key, metadata().partitionKeyType); } - default boolean selectsClustering(DecoratedKey key, Clustering clustering) + default boolean selectsClustering(DecoratedKey key, Clustering clustering) { if (clustering == Clustering.STATIC_CLUSTERING) return !columnFilter().fetchedColumns().statics.isEmpty(); @@ -260,7 +260,7 @@ public interface SinglePartitionReadQuery extends ReadQuery return Iterables.any(queries, c -> c.selectsKey(key)); } - public boolean selectsClustering(DecoratedKey key, Clustering clustering) + public boolean selectsClustering(DecoratedKey key, Clustering clustering) { return Iterables.any(queries, c -> c.selectsClustering(key, clustering)); } diff --git a/src/java/org/apache/cassandra/db/Slice.java b/src/java/org/apache/cassandra/db/Slice.java index 384158f5db..c6f558ff40 100644 --- a/src/java/org/apache/cassandra/db/Slice.java +++ b/src/java/org/apache/cassandra/db/Slice.java @@ -22,9 +22,9 @@ import java.nio.ByteBuffer; import java.util.*; import org.apache.cassandra.db.marshal.AbstractType; +import org.apache.cassandra.db.marshal.ByteArrayAccessor; import org.apache.cassandra.io.util.DataInputPlus; import org.apache.cassandra.io.util.DataOutputPlus; -import org.apache.cassandra.utils.ByteBufferUtil; /** * A slice represents the selection of a range of rows. @@ -38,10 +38,10 @@ public class Slice public static final Serializer serializer = new Serializer(); /** The slice selecting all rows (of a given partition) */ - public static final Slice ALL = new Slice(ClusteringBound.BOTTOM, ClusteringBound.TOP) + public static final Slice ALL = new Slice(BufferClusteringBound.BOTTOM, BufferClusteringBound.TOP) { @Override - public boolean includes(ClusteringComparator comparator, ClusteringPrefix clustering) + public boolean includes(ClusteringComparator comparator, ClusteringPrefix clustering) { return true; } @@ -59,19 +59,19 @@ public class Slice } }; - private final ClusteringBound start; - private final ClusteringBound end; + private final ClusteringBound start; + private final ClusteringBound end; - private Slice(ClusteringBound start, ClusteringBound end) + private Slice(ClusteringBound start, ClusteringBound end) { assert start.isStart() && end.isEnd(); this.start = start; this.end = end; } - public static Slice make(ClusteringBound start, ClusteringBound end) + public static Slice make(ClusteringBound start, ClusteringBound end) { - if (start == ClusteringBound.BOTTOM && end == ClusteringBound.TOP) + if (start.isBottom() && end.isTop()) return ALL; return new Slice(start, end); @@ -90,49 +90,37 @@ public class Slice return new Slice(builder.buildBound(true, true), builder.buildBound(false, true)); } - public static Slice make(Clustering clustering) + public static Slice make(Clustering clustering) { // This doesn't give us what we want with the clustering prefix assert clustering != Clustering.STATIC_CLUSTERING; - ByteBuffer[] values = extractValues(clustering); - return new Slice(ClusteringBound.inclusiveStartOf(values), ClusteringBound.inclusiveEndOf(values)); + return new Slice(ClusteringBound.inclusiveStartOf(clustering), ClusteringBound.inclusiveEndOf(clustering)); } - public static Slice make(Clustering start, Clustering end) + public static Slice make(Clustering start, Clustering end) { // This doesn't give us what we want with the clustering prefix assert start != Clustering.STATIC_CLUSTERING && end != Clustering.STATIC_CLUSTERING; - ByteBuffer[] startValues = extractValues(start); - ByteBuffer[] endValues = extractValues(end); - - return new Slice(ClusteringBound.inclusiveStartOf(startValues), ClusteringBound.inclusiveEndOf(endValues)); + return new Slice(ClusteringBound.inclusiveStartOf(start), ClusteringBound.inclusiveEndOf(end)); } - private static ByteBuffer[] extractValues(ClusteringPrefix clustering) - { - ByteBuffer[] values = new ByteBuffer[clustering.size()]; - for (int i = 0; i < clustering.size(); i++) - values[i] = clustering.get(i); - return values; - } - - public ClusteringBound start() + public ClusteringBound start() { return start; } - public ClusteringBound end() + public ClusteringBound end() { return end; } - public ClusteringBound open(boolean reversed) + public ClusteringBound open(boolean reversed) { return reversed ? end : start; } - public ClusteringBound close(boolean reversed) + public ClusteringBound close(boolean reversed) { return reversed ? start : end; } @@ -157,7 +145,7 @@ public class Slice * @return whether the slice formed by {@code start} and {@code end} is * empty or not. */ - public static boolean isEmpty(ClusteringComparator comparator, ClusteringBound start, ClusteringBound end) + public static boolean isEmpty(ClusteringComparator comparator, ClusteringBound start, ClusteringBound end) { assert start.isStart() && end.isEnd(); @@ -179,7 +167,7 @@ public class Slice * * @return whether {@code bound} is within the bounds of this slice. */ - public boolean includes(ClusteringComparator comparator, ClusteringPrefix bound) + public boolean includes(ClusteringComparator comparator, ClusteringPrefix bound) { return comparator.compare(start, bound) <= 0 && comparator.compare(bound, end) <= 0; } @@ -197,7 +185,7 @@ public class Slice * @return a new slice that selects results coming after {@code lastReturned}, or {@code null} if paging * the resulting slice selects nothing (i.e. if it originally selects nothing coming after {@code lastReturned}). */ - public Slice forPaging(ClusteringComparator comparator, Clustering lastReturned, boolean inclusive, boolean reversed) + public Slice forPaging(ClusteringComparator comparator, Clustering lastReturned, boolean inclusive, boolean reversed) { if (lastReturned == null) return this; @@ -212,8 +200,7 @@ public class Slice if (cmp < 0 || (inclusive && cmp == 0)) return this; - ByteBuffer[] values = extractValues(lastReturned); - return new Slice(start, inclusive ? ClusteringBound.inclusiveEndOf(values) : ClusteringBound.exclusiveEndOf(values)); + return new Slice(start, inclusive ? ClusteringBound.inclusiveEndOf(lastReturned) : ClusteringBound.exclusiveEndOf(lastReturned)); } else { @@ -225,8 +212,7 @@ public class Slice if (cmp < 0 || (inclusive && cmp == 0)) return this; - ByteBuffer[] values = extractValues(lastReturned); - return new Slice(inclusive ? ClusteringBound.inclusiveStartOf(values) : ClusteringBound.exclusiveStartOf(values), end); + return new Slice(inclusive ? ClusteringBound.inclusiveStartOf(lastReturned) : ClusteringBound.exclusiveStartOf(lastReturned), end); } } @@ -255,14 +241,14 @@ public class Slice { if (i > 0) sb.append(':'); - sb.append(comparator.subtype(i).getString(start.get(i))); + sb.append(start.stringAt(i, comparator)); } sb.append(", "); for (int i = 0; i < end.size(); i++) { if (i > 0) sb.append(':'); - sb.append(comparator.subtype(i).getString(end.get(i))); + sb.append(end.stringAt(i, comparator)); } sb.append(end.isInclusive() ? "]" : ")"); return sb.toString(); @@ -301,8 +287,8 @@ public class Slice public Slice deserialize(DataInputPlus in, int version, List> types) throws IOException { - ClusteringBound start = (ClusteringBound) ClusteringBound.serializer.deserialize(in, version, types); - ClusteringBound end = (ClusteringBound) ClusteringBound.serializer.deserialize(in, version, types); + ClusteringBound start = (ClusteringBound) ClusteringBound.serializer.deserialize(in, version, types); + ClusteringBound end = (ClusteringBound) ClusteringBound.serializer.deserialize(in, version, types); return new Slice(start, end); } } diff --git a/src/java/org/apache/cassandra/db/Slices.java b/src/java/org/apache/cassandra/db/Slices.java index 3d19fe999e..441a5d3d88 100644 --- a/src/java/org/apache/cassandra/db/Slices.java +++ b/src/java/org/apache/cassandra/db/Slices.java @@ -59,7 +59,7 @@ public abstract class Slices implements Iterable */ public static Slices with(ClusteringComparator comparator, Slice slice) { - if (slice.start() == ClusteringBound.BOTTOM && slice.end() == ClusteringBound.TOP) + if (slice.start().isBottom() && slice.end().isTop()) return Slices.ALL; Preconditions.checkArgument(!slice.isEmpty(comparator)); @@ -106,7 +106,7 @@ public abstract class Slices implements Iterable * * @return new slices that select results coming after {@code lastReturned}. */ - public abstract Slices forPaging(ClusteringComparator comparator, Clustering lastReturned, boolean inclusive, boolean reversed); + public abstract Slices forPaging(ClusteringComparator comparator, Clustering lastReturned, boolean inclusive, boolean reversed); /** * An object that allows to test whether rows are selected by this {@code Slices} objects assuming those rows @@ -126,7 +126,7 @@ public abstract class Slices implements Iterable * * @return whether a given clustering (row) is selected by this {@code Slices} object. */ - public abstract boolean selects(Clustering clustering); + public abstract boolean selects(Clustering clustering); /** @@ -159,7 +159,7 @@ public abstract class Slices implements Iterable */ public interface InOrderTester { - public boolean includes(Clustering value); + public boolean includes(Clustering value); public boolean isDone(); } @@ -186,7 +186,7 @@ public abstract class Slices implements Iterable this.slices = new ArrayList<>(initialSize); } - public Builder add(ClusteringBound start, ClusteringBound end) + public Builder add(ClusteringBound start, ClusteringBound end) { return add(Slice.make(start, end)); } @@ -335,7 +335,7 @@ public abstract class Slices implements Iterable for (int i = 0; i < size; i++) slices[i] = Slice.serializer.deserialize(in, version, metadata.comparator.subtypes()); - if (size == 1 && slices[0].start() == ClusteringBound.BOTTOM && slices[0].end() == ClusteringBound.TOP) + if (size == 1 && slices[0].start().isBottom() && slices[0].end().isTop()) return ALL; return new ArrayBackedSlices(metadata.comparator, slices); @@ -377,7 +377,7 @@ public abstract class Slices implements Iterable return slices[i]; } - public boolean selects(Clustering clustering) + public boolean selects(Clustering clustering) { for (int i = 0; i < slices.length; i++) { @@ -396,12 +396,12 @@ public abstract class Slices implements Iterable return reversed ? new InReverseOrderTester() : new InForwardOrderTester(); } - public Slices forPaging(ClusteringComparator comparator, Clustering lastReturned, boolean inclusive, boolean reversed) + public Slices forPaging(ClusteringComparator comparator, Clustering lastReturned, boolean inclusive, boolean reversed) { return reversed ? forReversePaging(comparator, lastReturned, inclusive) : forForwardPaging(comparator, lastReturned, inclusive); } - private Slices forForwardPaging(ClusteringComparator comparator, Clustering lastReturned, boolean inclusive) + private Slices forForwardPaging(ClusteringComparator comparator, Clustering lastReturned, boolean inclusive) { for (int i = 0; i < slices.length; i++) { @@ -420,7 +420,7 @@ public abstract class Slices implements Iterable return Slices.NONE; } - private Slices forReversePaging(ClusteringComparator comparator, Clustering lastReturned, boolean inclusive) + private Slices forReversePaging(ClusteringComparator comparator, Clustering lastReturned, boolean inclusive) { for (int i = slices.length - 1; i >= 0; i--) { @@ -459,7 +459,7 @@ public abstract class Slices implements Iterable private int idx; private boolean inSlice; - public boolean includes(Clustering value) + public boolean includes(Clustering value) { while (idx < slices.length) { @@ -502,7 +502,7 @@ public abstract class Slices implements Iterable this.idx = slices.length - 1; } - public boolean includes(Clustering value) + public boolean includes(Clustering value) { while (idx >= 0) { @@ -665,8 +665,8 @@ public abstract class Slices implements Iterable public static ComponentOfSlice fromSlice(int component, Slice slice) { - ClusteringBound start = slice.start(); - ClusteringBound end = slice.end(); + ClusteringBound start = slice.start(); + ClusteringBound end = slice.end(); if (component >= start.size() && component >= end.size()) return null; @@ -676,12 +676,12 @@ public abstract class Slices implements Iterable if (component < start.size()) { startInclusive = start.isInclusive(); - startValue = start.get(component); + startValue = start.bufferAt(component); } if (component < end.size()) { endInclusive = end.isInclusive(); - endValue = end.get(component); + endValue = end.bufferAt(component); } return new ComponentOfSlice(startInclusive, startValue, endInclusive, endValue); } @@ -702,7 +702,7 @@ public abstract class Slices implements Iterable { private static final InOrderTester trivialTester = new InOrderTester() { - public boolean includes(Clustering value) + public boolean includes(Clustering value) { return true; } @@ -733,12 +733,12 @@ public abstract class Slices implements Iterable return false; } - public boolean selects(Clustering clustering) + public boolean selects(Clustering clustering) { return true; } - public Slices forPaging(ClusteringComparator comparator, Clustering lastReturned, boolean inclusive, boolean reversed) + public Slices forPaging(ClusteringComparator comparator, Clustering lastReturned, boolean inclusive, boolean reversed) { return new ArrayBackedSlices(comparator, new Slice[]{ Slice.ALL.forPaging(comparator, lastReturned, inclusive, reversed) }); } @@ -777,7 +777,7 @@ public abstract class Slices implements Iterable { private static final InOrderTester trivialTester = new InOrderTester() { - public boolean includes(Clustering value) + public boolean includes(Clustering value) { return false; } @@ -808,12 +808,12 @@ public abstract class Slices implements Iterable return false; } - public Slices forPaging(ClusteringComparator comparator, Clustering lastReturned, boolean inclusive, boolean reversed) + public Slices forPaging(ClusteringComparator comparator, Clustering lastReturned, boolean inclusive, boolean reversed) { return this; } - public boolean selects(Clustering clustering) + public boolean selects(Clustering clustering) { return false; } diff --git a/src/java/org/apache/cassandra/db/TypeSizes.java b/src/java/org/apache/cassandra/db/TypeSizes.java index b47e300721..aed18a6c04 100644 --- a/src/java/org/apache/cassandra/db/TypeSizes.java +++ b/src/java/org/apache/cassandra/db/TypeSizes.java @@ -27,12 +27,14 @@ public final class TypeSizes private TypeSizes(){} - private static final int BOOL_SIZE = 1; - private static final int BYTE_SIZE = 1; - private static final int SHORT_SIZE = 2; - private static final int INT_SIZE = 4; - private static final int LONG_SIZE = 8; - private static final int UUID_SIZE = 16; + public static final int BOOL_SIZE = 1; + public static final int BYTE_SIZE = 1; + public static final int SHORT_SIZE = 2; + public static final int INT_SIZE = 4; + public static final int LONG_SIZE = 8; + public static final int FLOAT_SIZE = 4; + public static final int DOUBLE_SIZE = 8; + public static final int UUID_SIZE = 16; /** assumes UTF8 */ public static int sizeof(String value) @@ -74,31 +76,49 @@ public final class TypeSizes return sizeofUnsignedVInt(value.remaining()) + value.remaining(); } + @SuppressWarnings("unused") public static int sizeof(boolean value) { return BOOL_SIZE; } + @SuppressWarnings("unused") public static int sizeof(byte value) { return BYTE_SIZE; } + @SuppressWarnings("unused") public static int sizeof(short value) { return SHORT_SIZE; } + @SuppressWarnings("unused") public static int sizeof(int value) { return INT_SIZE; } + @SuppressWarnings("unused") public static int sizeof(long value) { return LONG_SIZE; } + @SuppressWarnings("unused") + public static int sizeof(float value) + { + return FLOAT_SIZE; + } + + @SuppressWarnings("unused") + public static int sizeof(double value) + { + return DOUBLE_SIZE; + } + + @SuppressWarnings("unused") public static int sizeof(UUID value) { return UUID_SIZE; diff --git a/src/java/org/apache/cassandra/db/UnfilteredDeserializer.java b/src/java/org/apache/cassandra/db/UnfilteredDeserializer.java index f9ff1d7175..843054195c 100644 --- a/src/java/org/apache/cassandra/db/UnfilteredDeserializer.java +++ b/src/java/org/apache/cassandra/db/UnfilteredDeserializer.java @@ -19,6 +19,7 @@ package org.apache.cassandra.db; import java.io.IOException; +import org.apache.cassandra.db.marshal.ByteArrayAccessor; import org.apache.cassandra.schema.TableMetadata; import org.apache.cassandra.db.rows.*; import org.apache.cassandra.io.util.DataInputPlus; @@ -105,7 +106,7 @@ public class UnfilteredDeserializer * comparison. Whenever we know what to do with this atom (read it or skip it), * readNext or skipNext should be called. */ - public int compareNextTo(ClusteringBound bound) throws IOException + public int compareNextTo(ClusteringBound bound) throws IOException { if (!isReady) prepareNext(); @@ -134,7 +135,7 @@ public class UnfilteredDeserializer isReady = false; if (UnfilteredSerializer.kind(nextFlags) == Unfiltered.Kind.RANGE_TOMBSTONE_MARKER) { - ClusteringBoundOrBoundary bound = clusteringDeserializer.deserializeNextBound(); + ClusteringBoundOrBoundary bound = clusteringDeserializer.deserializeNextBound(); return UnfilteredSerializer.serializer.deserializeMarkerBody(in, header, bound); } else diff --git a/src/java/org/apache/cassandra/db/VirtualTableSinglePartitionReadQuery.java b/src/java/org/apache/cassandra/db/VirtualTableSinglePartitionReadQuery.java index 11f1f7748d..ba9441ae7f 100644 --- a/src/java/org/apache/cassandra/db/VirtualTableSinglePartitionReadQuery.java +++ b/src/java/org/apache/cassandra/db/VirtualTableSinglePartitionReadQuery.java @@ -122,7 +122,7 @@ public class VirtualTableSinglePartitionReadQuery extends VirtualTableReadQuery } @Override - public SinglePartitionReadQuery forPaging(Clustering lastReturned, DataLimits limits) + public SinglePartitionReadQuery forPaging(Clustering lastReturned, DataLimits limits) { return new VirtualTableSinglePartitionReadQuery(metadata(), nowInSec(), diff --git a/src/java/org/apache/cassandra/db/aggregation/GroupMaker.java b/src/java/org/apache/cassandra/db/aggregation/GroupMaker.java index ff0ecafc2a..90cdab2d19 100644 --- a/src/java/org/apache/cassandra/db/aggregation/GroupMaker.java +++ b/src/java/org/apache/cassandra/db/aggregation/GroupMaker.java @@ -33,7 +33,7 @@ public abstract class GroupMaker */ public static final GroupMaker GROUP_EVERYTHING = new GroupMaker() { - public boolean isNewGroup(DecoratedKey partitionKey, Clustering clustering) + public boolean isNewGroup(DecoratedKey partitionKey, Clustering clustering) { return false; } @@ -62,7 +62,7 @@ public abstract class GroupMaker * @return true if the row belongs to the same group that the previous one, false * otherwise. */ - public abstract boolean isNewGroup(DecoratedKey partitionKey, Clustering clustering); + public abstract boolean isNewGroup(DecoratedKey partitionKey, Clustering clustering); /** * Specify if at least one row must be returned. If the selection is performing some aggregations on all the rows, @@ -95,7 +95,7 @@ public abstract class GroupMaker /** * The last clustering seen */ - private Clustering lastClustering; + private Clustering lastClustering; public PkPrefixGroupMaker(ClusteringComparator comparator, int clusteringPrefixSize, GroupingState state) { @@ -111,7 +111,7 @@ public abstract class GroupMaker } @Override - public boolean isNewGroup(DecoratedKey partitionKey, Clustering clustering) + public boolean isNewGroup(DecoratedKey partitionKey, Clustering clustering) { boolean isNew = false; diff --git a/src/java/org/apache/cassandra/db/aggregation/GroupingState.java b/src/java/org/apache/cassandra/db/aggregation/GroupingState.java index ba5ae28876..2e522c442a 100644 --- a/src/java/org/apache/cassandra/db/aggregation/GroupingState.java +++ b/src/java/org/apache/cassandra/db/aggregation/GroupingState.java @@ -23,6 +23,7 @@ import java.nio.ByteBuffer; import org.apache.cassandra.db.Clustering; import org.apache.cassandra.db.ClusteringComparator; import org.apache.cassandra.db.TypeSizes; +import org.apache.cassandra.db.marshal.ByteArrayAccessor; import org.apache.cassandra.io.util.DataInputPlus; import org.apache.cassandra.io.util.DataOutputPlus; import org.apache.cassandra.utils.ByteBufferUtil; @@ -55,9 +56,9 @@ public final class GroupingState /** * The last row clustering */ - final Clustering clustering; + final Clustering clustering; - public GroupingState(ByteBuffer partitionKey, Clustering clustering) + public GroupingState(ByteBuffer partitionKey, Clustering clustering) { this.partitionKey = partitionKey; this.clustering = clustering; @@ -78,7 +79,7 @@ public final class GroupingState * @return he last row clustering or null if either no rows has been processed yet or the last * row was a static row */ - public Clustering clustering() + public Clustering clustering() { return clustering; } @@ -115,7 +116,7 @@ public final class GroupingState return GroupingState.EMPTY_STATE; ByteBuffer partitionKey = ByteBufferUtil.readWithVIntLength(in); - Clustering clustering = null; + Clustering clustering = null; if (in.readBoolean()) clustering = Clustering.serializer.deserialize(in, version, comparator.subtypes()); diff --git a/src/java/org/apache/cassandra/db/columniterator/AbstractSSTableIterator.java b/src/java/org/apache/cassandra/db/columniterator/AbstractSSTableIterator.java index c631f1ce67..fee45c232f 100644 --- a/src/java/org/apache/cassandra/db/columniterator/AbstractSSTableIterator.java +++ b/src/java/org/apache/cassandra/db/columniterator/AbstractSSTableIterator.java @@ -530,17 +530,17 @@ public abstract class AbstractSSTableIterator implements UnfilteredRowIterator // Finds the index of the first block containing the provided bound, starting at the provided index. // Will be -1 if the bound is before any block, and blocksCount() if it is after every block. - public int findBlockIndex(ClusteringBound bound, int fromIdx) throws IOException + public int findBlockIndex(ClusteringBound bound, int fromIdx) throws IOException { - if (bound == ClusteringBound.BOTTOM) + if (bound.isBottom()) return -1; - if (bound == ClusteringBound.TOP) + if (bound.isTop()) return blocksCount(); return indexFor(bound, fromIdx); } - public int indexFor(ClusteringPrefix name, int lastIndex) throws IOException + public int indexFor(ClusteringPrefix name, int lastIndex) throws IOException { IndexInfo target = new IndexInfo(name, name, 0, 0, null); /* diff --git a/src/java/org/apache/cassandra/db/columniterator/SSTableIterator.java b/src/java/org/apache/cassandra/db/columniterator/SSTableIterator.java index 934634500d..d4362f775b 100644 --- a/src/java/org/apache/cassandra/db/columniterator/SSTableIterator.java +++ b/src/java/org/apache/cassandra/db/columniterator/SSTableIterator.java @@ -75,9 +75,9 @@ public class SSTableIterator extends AbstractSSTableIterator private class ForwardReader extends Reader { // The start of the current slice. This will be null as soon as we know we've passed that bound. - protected ClusteringBound start; + protected ClusteringBound start; // The end of the current slice. Will never be null. - protected ClusteringBound end = ClusteringBound.TOP; + protected ClusteringBound end = BufferClusteringBound.TOP; protected Unfiltered next; // the next element to return: this is computed by hasNextInternal(). @@ -91,7 +91,7 @@ public class SSTableIterator extends AbstractSSTableIterator public void setForSlice(Slice slice) throws IOException { - start = slice.start() == ClusteringBound.BOTTOM ? null : slice.start(); + start = slice.start().isBottom() ? null : slice.start(); end = slice.end(); sliceDone = false; @@ -119,7 +119,7 @@ public class SSTableIterator extends AbstractSSTableIterator updateOpenMarker((RangeTombstoneMarker)deserializer.readNext()); } - ClusteringBound sliceStart = start; + ClusteringBound sliceStart = start; start = null; // We've reached the beginning of our queried slice. If we have an open marker diff --git a/src/java/org/apache/cassandra/db/columniterator/SSTableReversedIterator.java b/src/java/org/apache/cassandra/db/columniterator/SSTableReversedIterator.java index 1e1030cf3d..a60aafa771 100644 --- a/src/java/org/apache/cassandra/db/columniterator/SSTableReversedIterator.java +++ b/src/java/org/apache/cassandra/db/columniterator/SSTableReversedIterator.java @@ -172,8 +172,8 @@ public class SSTableReversedIterator extends AbstractSSTableIterator // Reads the unfiltered from disk and load them into the reader buffer. It stops reading when either the partition // is fully read, or when stopReadingDisk() returns true. - protected void loadFromDisk(ClusteringBound start, - ClusteringBound end, + protected void loadFromDisk(ClusteringBound start, + ClusteringBound end, boolean hasPreviousBlock, boolean hasNextBlock) throws IOException { @@ -209,7 +209,7 @@ public class SSTableReversedIterator extends AbstractSSTableIterator // want to "return" it just yet, we'll wait until we reach it in the next blocks. That's why we trigger // skipLastIteratedItem in that case (this is first item of the block, but we're iterating in reverse order // so it will be last returned by the iterator). - ClusteringBound markerStart = start == null ? ClusteringBound.BOTTOM : start; + ClusteringBound markerStart = start == null ? BufferClusteringBound.BOTTOM : start; buffer.add(new RangeTombstoneBoundMarker(markerStart, openMarker)); if (hasNextBlock) skipLastIteratedItem = true; @@ -243,7 +243,7 @@ public class SSTableReversedIterator extends AbstractSSTableIterator // not breaking ImmutableBTreePartition, we should skip it when returning from the iterator, hence the // skipFirstIteratedItem (this is the last item of the block, but we're iterating in reverse order so it will // be the first returned by the iterator). - ClusteringBound markerEnd = end == null ? ClusteringBound.TOP : end; + ClusteringBound markerEnd = end == null ? BufferClusteringBound.TOP : end; buffer.add(new RangeTombstoneBoundMarker(markerEnd, openMarker)); if (hasPreviousBlock) skipFirstIteratedItem = true; diff --git a/src/java/org/apache/cassandra/db/compaction/Scrubber.java b/src/java/org/apache/cassandra/db/compaction/Scrubber.java index 92cff54d25..681a833e51 100644 --- a/src/java/org/apache/cassandra/db/compaction/Scrubber.java +++ b/src/java/org/apache/cassandra/db/compaction/Scrubber.java @@ -765,14 +765,14 @@ public class Scrubber implements Closeable { if (cd.column().isSimple()) { - Cell cell = (Cell)cd; + Cell cell = (Cell)cd; if (cell.isExpiring() && cell.localDeletionTime() < 0) return true; } else { ComplexColumnData complexData = (ComplexColumnData)cd; - for (Cell cell : complexData) + for (Cell cell : complexData) { if (cell.isExpiring() && cell.localDeletionTime() < 0) return true; @@ -795,14 +795,14 @@ public class Scrubber implements Closeable { if (cd.column().isSimple()) { - Cell cell = (Cell)cd; + Cell cell = (Cell)cd; builder.addCell(cell.isExpiring() && cell.localDeletionTime() < 0 ? cell.withUpdatedTimestampAndLocalDeletionTime(cell.timestamp() + 1, AbstractCell.MAX_DELETION_TIME) : cell); } else { ComplexColumnData complexData = (ComplexColumnData)cd; builder.addComplexDeletion(complexData.column(), complexData.complexDeletion()); - for (Cell cell : complexData) + for (Cell cell : complexData) { builder.addCell(cell.isExpiring() && cell.localDeletionTime() < 0 ? cell.withUpdatedTimestampAndLocalDeletionTime(cell.timestamp() + 1, AbstractCell.MAX_DELETION_TIME) : cell); } diff --git a/src/java/org/apache/cassandra/db/context/CounterContext.java b/src/java/org/apache/cassandra/db/context/CounterContext.java index 6a618ca970..7db8192448 100644 --- a/src/java/org/apache/cassandra/db/context/CounterContext.java +++ b/src/java/org/apache/cassandra/db/context/CounterContext.java @@ -28,6 +28,9 @@ import org.slf4j.LoggerFactory; import org.apache.cassandra.db.ClockAndCount; import org.apache.cassandra.db.TypeSizes; import org.apache.cassandra.db.compaction.CompactionManager; +import org.apache.cassandra.db.marshal.ByteBufferAccessor; +import org.apache.cassandra.db.marshal.ValueAccessor; +import org.apache.cassandra.db.rows.Cell; import org.apache.cassandra.serializers.MarshalException; import org.apache.cassandra.utils.*; @@ -90,7 +93,7 @@ public class CounterContext private static final Logger logger = LoggerFactory.getLogger(CounterContext.class); - public static enum Relationship + public enum Relationship { EQUAL, GREATER_THAN, LESS_THAN, DISJOINT } @@ -167,9 +170,9 @@ public class CounterContext return state.context; } - public static int headerLength(ByteBuffer context) + public static int headerLength(V context, ValueAccessor accessor) { - return HEADER_SIZE_LENGTH + Math.abs(context.getShort(context.position())) * HEADER_ELT_LENGTH; + return HEADER_SIZE_LENGTH + Math.abs(accessor.getShort(context, 0)) * HEADER_ELT_LENGTH; } private static int compareId(ByteBuffer bb1, int pos1, ByteBuffer bb2, int pos2) @@ -566,34 +569,39 @@ public class CounterContext * @param context a counter context * @return the aggregated count represented by {@code context} */ - public long total(ByteBuffer context) + public long total(V context, ValueAccessor accessor) { long total = 0L; // we could use a ContextState but it is easy enough that we avoid the object creation - for (int offset = context.position() + headerLength(context); offset < context.limit(); offset += STEP_LENGTH) - total += context.getLong(offset + CounterId.LENGTH + CLOCK_LENGTH); + for (int offset = headerLength(context, accessor), size=accessor.size(context); offset < size; offset += STEP_LENGTH) + total += accessor.getLong(context, offset + CounterId.LENGTH + CLOCK_LENGTH); return total; } - public boolean shouldClearLocal(ByteBuffer context) + public long total(Cell cell) + { + return total(cell.value(), cell.accessor()); + } + + public boolean shouldClearLocal(V context, ValueAccessor accessor) { // #elt being negative means we have to clean local shards. - return context.getShort(context.position()) < 0; + return accessor.getShort(context, 0) < 0; } /** * Detects whether or not the context has any legacy (local or remote) shards in it. */ - public boolean hasLegacyShards(ByteBuffer context) + public boolean hasLegacyShards(V context, ValueAccessor accessor) { - int totalCount = (context.remaining() - headerLength(context)) / STEP_LENGTH; - int localAndGlobalCount = Math.abs(context.getShort(context.position())); + int totalCount = (accessor.size(context) - headerLength(context, accessor)) / STEP_LENGTH; + int localAndGlobalCount = Math.abs(accessor.getShort(context, 0)); if (localAndGlobalCount < totalCount) return true; // remote shard(s) present for (int i = 0; i < localAndGlobalCount; i++) - if (context.getShort(context.position() + HEADER_SIZE_LENGTH + i * HEADER_ELT_LENGTH) >= 0) + if (accessor.getShort(context, HEADER_SIZE_LENGTH + i * HEADER_ELT_LENGTH) >= 0) return true; // found a local shard return false; @@ -636,22 +644,16 @@ public class CounterContext return marked; } - /** - * Remove all the local of a context (but keep global). - * - * @param context a counter context - * @return a version of {@code context} where no shards are local. - */ - public ByteBuffer clearAllLocal(ByteBuffer context) + public V clearAllLocal(V context, ValueAccessor accessor) { - int count = Math.abs(context.getShort(context.position())); + int count = Math.abs(accessor.getShort(context, 0)); if (count == 0) return context; // no local or global shards present. List globalShardIndexes = new ArrayList<>(count); for (int i = 0; i < count; i++) { - short elt = context.getShort(context.position() + HEADER_SIZE_LENGTH + i * HEADER_ELT_LENGTH); + short elt = accessor.getShort(context, HEADER_SIZE_LENGTH + i * HEADER_ELT_LENGTH); if (elt < 0) globalShardIndexes.add(elt); } @@ -660,25 +662,26 @@ public class CounterContext return context; // no local shards detected. // allocate a smaller BB for the cleared context - with no local header elts. - ByteBuffer cleared = ByteBuffer.allocate(context.remaining() - (count - globalShardIndexes.size()) * HEADER_ELT_LENGTH); + V cleared = accessor.allocate(accessor.size(context) - (count - globalShardIndexes.size()) * HEADER_ELT_LENGTH); - cleared.putShort(cleared.position(), (short) globalShardIndexes.size()); + accessor.putShort(cleared, 0, (short) globalShardIndexes.size()); for (int i = 0; i < globalShardIndexes.size(); i++) - cleared.putShort(cleared.position() + HEADER_SIZE_LENGTH + i * HEADER_ELT_LENGTH, globalShardIndexes.get(i)); + accessor.putShort(cleared, HEADER_SIZE_LENGTH + i * HEADER_ELT_LENGTH, globalShardIndexes.get(i)); - int origHeaderLength = headerLength(context); - ByteBufferUtil.copyBytes(context, - context.position() + origHeaderLength, - cleared, - cleared.position() + headerLength(cleared), - context.remaining() - origHeaderLength); + int origHeaderLength = headerLength(context, accessor); + accessor.copyTo(context, + origHeaderLength, + cleared, + accessor, + headerLength(cleared, accessor), + accessor.size(context) - origHeaderLength); return cleared; } - public void validateContext(ByteBuffer context) throws MarshalException + public void validateContext(V context, ValueAccessor accessor) throws MarshalException { - if ((context.remaining() - headerLength(context)) % STEP_LENGTH != 0) + if ((accessor.size(context) - headerLength(context, accessor)) % STEP_LENGTH != 0) throw new MarshalException("Invalid size for a counter context"); } @@ -719,7 +722,7 @@ public class CounterContext @VisibleForTesting public int findPositionOf(ByteBuffer context, CounterId id) { - int headerLength = headerLength(context); + int headerLength = headerLength(context, ByteBufferAccessor.instance); int offset = context.position() + headerLength; int left = 0; @@ -764,7 +767,7 @@ public class CounterContext private ContextState(ByteBuffer context) { this.context = context; - this.headerLength = this.bodyOffset = headerLength(context); + this.headerLength = this.bodyOffset = headerLength(context, ByteBufferAccessor.instance); this.headerOffset = HEADER_SIZE_LENGTH; updateIsGlobalOrLocal(); } diff --git a/src/java/org/apache/cassandra/db/filter/ClusteringIndexFilter.java b/src/java/org/apache/cassandra/db/filter/ClusteringIndexFilter.java index cdb61c9aa3..d3c6826c43 100644 --- a/src/java/org/apache/cassandra/db/filter/ClusteringIndexFilter.java +++ b/src/java/org/apache/cassandra/db/filter/ClusteringIndexFilter.java @@ -77,7 +77,7 @@ public interface ClusteringIndexFilter * * @return a new filter that selects results coming after {@code lastReturned}. */ - public ClusteringIndexFilter forPaging(ClusteringComparator comparator, Clustering lastReturned, boolean inclusive); + public ClusteringIndexFilter forPaging(ClusteringComparator comparator, Clustering lastReturned, boolean inclusive); /** * Returns whether we can guarantee that a given cached partition contains all the data selected by this filter. @@ -109,7 +109,7 @@ public interface ClusteringIndexFilter * * @return whether the row with clustering {@code clustering} is selected by this filter. */ - public boolean selects(Clustering clustering); + public boolean selects(Clustering clustering); /** * Returns an iterator that only returns the rows of the provided iterator that this filter selects. diff --git a/src/java/org/apache/cassandra/db/filter/ClusteringIndexNamesFilter.java b/src/java/org/apache/cassandra/db/filter/ClusteringIndexNamesFilter.java index 63815a1c10..ff63aca605 100644 --- a/src/java/org/apache/cassandra/db/filter/ClusteringIndexNamesFilter.java +++ b/src/java/org/apache/cassandra/db/filter/ClusteringIndexNamesFilter.java @@ -42,14 +42,14 @@ public class ClusteringIndexNamesFilter extends AbstractClusteringIndexFilter // This could be empty if selectedColumns only has static columns (in which case the filter still // selects the static row) - private final NavigableSet clusterings; + private final NavigableSet> clusterings; // clusterings is always in clustering order (because we need it that way in some methods), but we also // sometimes need those clustering in "query" order (i.e. in reverse clustering order if the query is // reversed), so we keep that too for simplicity. - private final NavigableSet clusteringsInQueryOrder; + private final NavigableSet> clusteringsInQueryOrder; - public ClusteringIndexNamesFilter(NavigableSet clusterings, boolean reversed) + public ClusteringIndexNamesFilter(NavigableSet> clusterings, boolean reversed) { super(reversed); assert !clusterings.contains(Clustering.STATIC_CLUSTERING); @@ -65,7 +65,7 @@ public class ClusteringIndexNamesFilter extends AbstractClusteringIndexFilter * @return the set of requested clustering in clustering order (note that * this is always in clustering order even if the query is reversed). */ - public NavigableSet requestedRows() + public NavigableSet> requestedRows() { return clusterings; } @@ -77,16 +77,16 @@ public class ClusteringIndexNamesFilter extends AbstractClusteringIndexFilter return clusterings.isEmpty(); } - public boolean selects(Clustering clustering) + public boolean selects(Clustering clustering) { return clusterings.contains(clustering); } - public ClusteringIndexNamesFilter forPaging(ClusteringComparator comparator, Clustering lastReturned, boolean inclusive) + public ClusteringIndexNamesFilter forPaging(ClusteringComparator comparator, Clustering lastReturned, boolean inclusive) { - NavigableSet newClusterings = reversed ? - clusterings.headSet(lastReturned, inclusive) : - clusterings.tailSet(lastReturned, inclusive); + NavigableSet> newClusterings = reversed ? + clusterings.headSet(lastReturned, inclusive) : + clusterings.tailSet(lastReturned, inclusive); return new ClusteringIndexNamesFilter(newClusterings, reversed); } @@ -131,15 +131,15 @@ public class ClusteringIndexNamesFilter extends AbstractClusteringIndexFilter public Slices getSlices(TableMetadata metadata) { Slices.Builder builder = new Slices.Builder(metadata.comparator, clusteringsInQueryOrder.size()); - for (Clustering clustering : clusteringsInQueryOrder) + for (Clustering clustering : clusteringsInQueryOrder) builder.add(Slice.make(clustering)); return builder.build(); } public UnfilteredRowIterator getUnfilteredRowIterator(final ColumnFilter columnFilter, final Partition partition) { - final Iterator clusteringIter = clusteringsInQueryOrder.iterator(); - final SearchIterator searcher = partition.searchIterator(columnFilter, reversed); + final Iterator> clusteringIter = clusteringsInQueryOrder.iterator(); + final SearchIterator, Row> searcher = partition.searchIterator(columnFilter, reversed); return new AbstractUnfilteredRowIterator(partition.metadata(), partition.partitionKey(), @@ -169,7 +169,7 @@ public class ClusteringIndexNamesFilter extends AbstractClusteringIndexFilter List maxClusteringValues = sstable.getSSTableMetadata().maxClusteringValues; // If any of the requested clustering is within the bounds covered by the sstable, we need to include the sstable - for (Clustering clustering : clusterings) + for (Clustering clustering : clusterings) { if (Slice.make(clustering).intersects(comparator, minClusteringValues, maxClusteringValues)) return true; @@ -182,7 +182,7 @@ public class ClusteringIndexNamesFilter extends AbstractClusteringIndexFilter StringBuilder sb = new StringBuilder(); sb.append("names("); int i = 0; - for (Clustering clustering : clusterings) + for (Clustering clustering : clusterings) sb.append(i++ == 0 ? "" : ", ").append(clustering.toString(metadata)); if (reversed) sb.append(", reversed"); @@ -198,7 +198,7 @@ public class ClusteringIndexNamesFilter extends AbstractClusteringIndexFilter sb.append('(').append(ColumnMetadata.toCQLString(metadata.clusteringColumns())).append(')'); sb.append(clusterings.size() == 1 ? " = " : " IN ("); int i = 0; - for (Clustering clustering : clusterings) + for (Clustering clustering : clusterings) sb.append(i++ == 0 ? "" : ", ").append('(').append(clustering.toCQLString(metadata)).append(')'); sb.append(clusterings.size() == 1 ? "" : ")"); @@ -229,7 +229,7 @@ public class ClusteringIndexNamesFilter extends AbstractClusteringIndexFilter { ClusteringComparator comparator = (ClusteringComparator)clusterings.comparator(); out.writeUnsignedVInt(clusterings.size()); - for (Clustering clustering : clusterings) + for (Clustering clustering : clusterings) Clustering.serializer.serialize(clustering, out, version, comparator.subtypes()); } @@ -237,7 +237,7 @@ public class ClusteringIndexNamesFilter extends AbstractClusteringIndexFilter { ClusteringComparator comparator = (ClusteringComparator)clusterings.comparator(); long size = TypeSizes.sizeofUnsignedVInt(clusterings.size()); - for (Clustering clustering : clusterings) + for (Clustering clustering : clusterings) size += Clustering.serializer.serializedSize(clustering, version, comparator.subtypes()); return size; } @@ -247,7 +247,7 @@ public class ClusteringIndexNamesFilter extends AbstractClusteringIndexFilter public ClusteringIndexFilter deserialize(DataInputPlus in, int version, TableMetadata metadata, boolean reversed) throws IOException { ClusteringComparator comparator = metadata.comparator; - BTreeSet.Builder clusterings = BTreeSet.builder(comparator); + BTreeSet.Builder> clusterings = BTreeSet.builder(comparator); int size = (int)in.readUnsignedVInt(); for (int i = 0; i < size; i++) clusterings.add(Clustering.serializer.deserialize(in, version, comparator.subtypes())); diff --git a/src/java/org/apache/cassandra/db/filter/ClusteringIndexSliceFilter.java b/src/java/org/apache/cassandra/db/filter/ClusteringIndexSliceFilter.java index 9490adfd51..67113253e4 100644 --- a/src/java/org/apache/cassandra/db/filter/ClusteringIndexSliceFilter.java +++ b/src/java/org/apache/cassandra/db/filter/ClusteringIndexSliceFilter.java @@ -56,12 +56,12 @@ public class ClusteringIndexSliceFilter extends AbstractClusteringIndexFilter return slices.size() == 1 && !slices.hasLowerBound() && !slices.hasUpperBound(); } - public boolean selects(Clustering clustering) + public boolean selects(Clustering clustering) { return slices.selects(clustering); } - public ClusteringIndexSliceFilter forPaging(ClusteringComparator comparator, Clustering lastReturned, boolean inclusive) + public ClusteringIndexSliceFilter forPaging(ClusteringComparator comparator, Clustering lastReturned, boolean inclusive) { Slices newSlices = slices.forPaging(comparator, lastReturned, inclusive, reversed); return slices == newSlices diff --git a/src/java/org/apache/cassandra/db/filter/ColumnFilter.java b/src/java/org/apache/cassandra/db/filter/ColumnFilter.java index 20a1656b46..30c3ed754d 100644 --- a/src/java/org/apache/cassandra/db/filter/ColumnFilter.java +++ b/src/java/org/apache/cassandra/db/filter/ColumnFilter.java @@ -276,7 +276,7 @@ public class ColumnFilter * @param cells the cells to filter. * @return a filtered iterator that only include the cells from {@code cells} that are included by this filter. */ - public Iterator filterComplexCells(ColumnMetadata column, Iterator cells) + public Iterator> filterComplexCells(ColumnMetadata column, Iterator> cells) { Tester tester = newTester(column); if (tester == null) diff --git a/src/java/org/apache/cassandra/db/filter/RowFilter.java b/src/java/org/apache/cassandra/db/filter/RowFilter.java index c8585b1277..aebb067862 100644 --- a/src/java/org/apache/cassandra/db/filter/RowFilter.java +++ b/src/java/org/apache/cassandra/db/filter/RowFilter.java @@ -205,14 +205,14 @@ public abstract class RowFilter implements Iterable * Returns true if all of the expressions within this filter that apply to the clustering key are satisfied by * the given Clustering, false otherwise. */ - public boolean clusteringKeyRestrictionsAreSatisfiedBy(Clustering clustering) + public boolean clusteringKeyRestrictionsAreSatisfiedBy(Clustering clustering) { for (Expression e : expressions) { if (!e.column.isClusteringColumn()) continue; - if (!e.operator().isSatisfiedBy(e.column.type, clustering.get(e.column.position()), e.value)) + if (!e.operator().isSatisfiedBy(e.column.type, clustering.bufferAt(e.column.position()), e.value)) { return false; } @@ -448,10 +448,10 @@ public abstract class RowFilter implements Iterable ? CompositeType.extractComponent(partitionKey.getKey(), column.position()) : partitionKey.getKey(); case CLUSTERING: - return row.clustering().get(column.position()); + return row.clustering().bufferAt(column.position()); default: - Cell cell = row.getCell(column); - return cell == null ? null : cell.value(); + Cell cell = row.getCell(column); + return cell == null ? null : cell.buffer(); } } @@ -616,7 +616,7 @@ public abstract class RowFilter implements Iterable if (foundValue == null) return false; - ByteBuffer counterValue = LongType.instance.decompose(CounterContext.instance().total(foundValue)); + ByteBuffer counterValue = LongType.instance.decompose(CounterContext.instance().total(foundValue, ByteBufferAccessor.instance)); return operator.isSatisfiedBy(LongType.instance, counterValue, value); } else @@ -645,7 +645,7 @@ public abstract class RowFilter implements Iterable ComplexColumnData complexData = row.getComplexColumnData(column); if (complexData != null) { - for (Cell cell : complexData) + for (Cell cell : complexData) { if (type.kind == CollectionType.Kind.SET) { @@ -654,7 +654,7 @@ public abstract class RowFilter implements Iterable } else { - if (type.valueComparator().compare(cell.value(), value) == 0) + if (type.valueComparator().compare(cell.buffer(), value) == 0) return true; } } @@ -760,7 +760,7 @@ public abstract class RowFilter implements Iterable @Override public ByteBuffer getIndexValue() { - return CompositeType.build(key, value); + return CompositeType.build(ByteBufferAccessor.instance, key, value); } public boolean isSatisfiedBy(TableMetadata metadata, DecoratedKey partitionKey, Row row) @@ -776,8 +776,8 @@ public abstract class RowFilter implements Iterable MapType mt = (MapType)column.type; if (column.isComplex()) { - Cell cell = row.getCell(column, CellPath.create(key)); - return cell != null && mt.valueComparator().compare(cell.value(), value) == 0; + Cell cell = row.getCell(column, CellPath.create(key)); + return cell != null && mt.valueComparator().compare(cell.buffer(), value) == 0; } else { diff --git a/src/java/org/apache/cassandra/db/filter/TombstoneOverwhelmingException.java b/src/java/org/apache/cassandra/db/filter/TombstoneOverwhelmingException.java index f7371ec318..28d49ae370 100644 --- a/src/java/org/apache/cassandra/db/filter/TombstoneOverwhelmingException.java +++ b/src/java/org/apache/cassandra/db/filter/TombstoneOverwhelmingException.java @@ -26,13 +26,13 @@ import org.apache.cassandra.db.marshal.*; public class TombstoneOverwhelmingException extends RuntimeException { - public TombstoneOverwhelmingException(int numTombstones, String query, TableMetadata metadata, DecoratedKey lastPartitionKey, ClusteringPrefix lastClustering) + public TombstoneOverwhelmingException(int numTombstones, String query, TableMetadata metadata, DecoratedKey lastPartitionKey, ClusteringPrefix lastClustering) { super(String.format("Scanned over %d tombstones during query '%s' (last scanned row token was %s and partion key was (%s)); query aborted", numTombstones, query, lastPartitionKey.getToken(), makePKString(metadata, lastPartitionKey.getKey(), lastClustering))); } - private static String makePKString(TableMetadata metadata, ByteBuffer partitionKey, ClusteringPrefix clustering) + private static String makePKString(TableMetadata metadata, ByteBuffer partitionKey, ClusteringPrefix clustering) { StringBuilder sb = new StringBuilder(); @@ -61,7 +61,7 @@ public class TombstoneOverwhelmingException extends RuntimeException sb.append(")"); for (int i = 0; i < clustering.size(); i++) - sb.append(", ").append(metadata.comparator.subtype(i).getString(clustering.get(i))); + sb.append(", ").append(clustering.stringAt(i, metadata.comparator)); return sb.toString(); } diff --git a/src/java/org/apache/cassandra/db/marshal/AbstractCompositeType.java b/src/java/org/apache/cassandra/db/marshal/AbstractCompositeType.java index 024862907f..24d283457e 100644 --- a/src/java/org/apache/cassandra/db/marshal/AbstractCompositeType.java +++ b/src/java/org/apache/cassandra/db/marshal/AbstractCompositeType.java @@ -43,72 +43,81 @@ public abstract class AbstractCompositeType extends AbstractType super(ComparisonType.CUSTOM); } - public int compareCustom(ByteBuffer o1, ByteBuffer o2) + public int compareCustom(VL left, ValueAccessor accessorL, VR right, ValueAccessor accessorR) { - if (!o1.hasRemaining() || !o2.hasRemaining()) - return o1.hasRemaining() ? 1 : o2.hasRemaining() ? -1 : 0; + if (accessorL.isEmpty(left) || accessorR.isEmpty(right)) + return Boolean.compare(accessorR.isEmpty(right), accessorL.isEmpty(left)); - ByteBuffer bb1 = o1.duplicate(); - ByteBuffer bb2 = o2.duplicate(); - - boolean isStatic1 = readIsStatic(bb1); - boolean isStatic2 = readIsStatic(bb2); - if (isStatic1 != isStatic2) - return isStatic1 ? -1 : 1; + boolean isStaticL = readIsStatic(left, accessorL); + boolean isStaticR = readIsStatic(right, accessorR); + if (isStaticL != isStaticR) + return isStaticL ? -1 : 1; int i = 0; - ByteBuffer previous = null; + VL previous = null; + int offsetL = startingOffset(isStaticL); + int offsetR = startingOffset(isStaticR); - while (bb1.remaining() > 0 && bb2.remaining() > 0) + while (!accessorL.isEmptyFromOffset(left, offsetL) && !accessorR.isEmptyFromOffset(right, offsetL)) { - AbstractType comparator = getComparator(i, bb1, bb2); + AbstractType comparator = getComparator(i, left, accessorL, right, accessorR, offsetL, offsetR); + offsetL += getComparatorSize(i, left, accessorL, offsetL); + offsetR += getComparatorSize(i, right, accessorR, offsetR); - ByteBuffer value1 = ByteBufferUtil.readBytesWithShortLength(bb1); - ByteBuffer value2 = ByteBufferUtil.readBytesWithShortLength(bb2); + VL value1 = accessorL.sliceWithShortLength(left, offsetL); + offsetL += accessorL.sizeWithShortLength(value1); + VR value2 = accessorR.sliceWithShortLength(right, offsetR); + offsetR += accessorR.sizeWithShortLength(value2); - int cmp = comparator.compareCollectionMembers(value1, value2, previous); + int cmp = comparator.compareCollectionMembers(value1, accessorL, value2, accessorR, previous); if (cmp != 0) return cmp; previous = value1; - byte b1 = bb1.get(); - byte b2 = bb2.get(); - if (b1 != b2) - return b1 - b2; + byte bL = accessorL.getByte(left, offsetL++); + byte bR = accessorR.getByte(right, offsetR++); + if (bL != bR) + return bL - bR; ++i; } - if (bb1.remaining() == 0) - return bb2.remaining() == 0 ? 0 : -1; + if (accessorL.isEmptyFromOffset(left, offsetL)) + return accessorR.sizeFromOffset(right, offsetR) == 0 ? 0 : -1; - // bb1.remaining() > 0 && bb2.remaining() == 0 + // left.remaining() > 0 && right.remaining() == 0 return 1; } // Check if the provided BB represents a static name and advance the // buffer to the real beginning if so. - protected abstract boolean readIsStatic(ByteBuffer bb); + protected abstract boolean readIsStatic(V value, ValueAccessor accessor); + + protected abstract int startingOffset(boolean isStatic); /** * Split a composite column names into it's components. */ - public ByteBuffer[] split(ByteBuffer name) + public ByteBuffer[] split(ByteBuffer bb) { List l = new ArrayList(); - ByteBuffer bb = name.duplicate(); - readIsStatic(bb); + boolean isStatic = readIsStatic(bb, ByteBufferAccessor.instance); + int offset = startingOffset(isStatic); + int i = 0; - while (bb.remaining() > 0) + while (!ByteBufferAccessor.instance.isEmptyFromOffset(bb, offset)) { - getComparator(i++, bb); - l.add(ByteBufferUtil.readBytesWithShortLength(bb)); - bb.get(); // skip end-of-component + offset += getComparatorSize(i++, bb, ByteBufferAccessor.instance, offset); + ByteBuffer value = ByteBufferAccessor.instance.sliceWithShortLength(bb, offset); + offset += ByteBufferAccessor.instance.sizeWithShortLength(value); + l.add(value); + offset++; // skip end-of-component } return l.toArray(new ByteBuffer[l.size()]); } + private static final String COLON = ":"; private static final Pattern COLON_PAT = Pattern.compile(COLON); private static final String ESCAPED_COLON = "\\\\:"; @@ -165,24 +174,27 @@ public abstract class AbstractCompositeType extends AbstractType return res; } - public String getString(ByteBuffer bytes) + public String getString(V input, ValueAccessor accessor) { StringBuilder sb = new StringBuilder(); - ByteBuffer bb = bytes.duplicate(); - readIsStatic(bb); + boolean isStatic = readIsStatic(input, accessor); + int offset = startingOffset(isStatic); + int startOffset = offset; int i = 0; - while (bb.remaining() > 0) + while (!accessor.isEmptyFromOffset(input, offset)) { - if (bb.remaining() != bytes.remaining()) + if (offset != startOffset) sb.append(":"); - AbstractType comparator = getAndAppendComparator(i, bb, sb); - ByteBuffer value = ByteBufferUtil.readBytesWithShortLength(bb); + AbstractType comparator = getAndAppendComparator(i, input, accessor, sb, offset); + offset += getComparatorSize(i, input, accessor, offset); + V value = accessor.sliceWithShortLength(input, offset); + offset += accessor.sizeWithShortLength(value); - sb.append(escape(comparator.getString(value))); + sb.append(escape(comparator.getString(value, accessor))); - byte b = bb.get(); + byte b = accessor.getByte(input, offset++); if (b != 0) { sb.append(b < 0 ? ":_" : ":!"); @@ -258,31 +270,39 @@ public abstract class AbstractCompositeType extends AbstractType } @Override - public void validate(ByteBuffer bytes) throws MarshalException + public void validate(ByteBuffer bb) throws MarshalException { - ByteBuffer bb = bytes.duplicate(); - readIsStatic(bb); + validate(bb, ByteBufferAccessor.instance); + } + + public void validate(V input, ValueAccessor accessor) + { + boolean isStatic = readIsStatic(input, accessor); + int offset = startingOffset(isStatic); int i = 0; - ByteBuffer previous = null; - while (bb.remaining() > 0) + V previous = null; + while (!accessor.isEmptyFromOffset(input, offset)) { - AbstractType comparator = validateComparator(i, bb); + AbstractType comparator = validateComparator(i, input, accessor, offset); + offset += getComparatorSize(i, input, accessor, offset); - if (bb.remaining() < 2) + if (accessor.sizeFromOffset(input, offset) < 2) throw new MarshalException("Not enough bytes to read value size of component " + i); - int length = ByteBufferUtil.readShortLength(bb); + int length = accessor.getShort(input, offset); + offset += 2; - if (bb.remaining() < length) + if (accessor.sizeFromOffset(input, offset) < length) throw new MarshalException("Not enough bytes to read value of component " + i); - ByteBuffer value = ByteBufferUtil.readBytes(bb, length); + V value = accessor.slice(input, offset, length); + offset += length; - comparator.validateCollectionMember(value, previous); + comparator.validateCollectionMember(value, previous, accessor); - if (bb.remaining() == 0) + if (accessor.isEmptyFromOffset(input, offset)) throw new MarshalException("Not enough bytes to read the end-of-component byte of component" + i); - byte b = bb.get(); - if (b != 0 && bb.remaining() != 0) + byte b = accessor.getByte(input, offset++); + if (b != 0 && !accessor.isEmptyFromOffset(input, offset)) throw new MarshalException("Invalid bytes remaining after an end-of-component at component" + i); previous = value; @@ -297,28 +317,29 @@ public abstract class AbstractCompositeType extends AbstractType return BytesSerializer.instance; } + abstract protected int getComparatorSize(int i, V value, ValueAccessor accessor, int offset); /** * @return the comparator for the given component. static CompositeType will consult * @param i DynamicCompositeType will read the type information from @param bb - * @param bb name of type definition + * @param value name of type definition */ - abstract protected AbstractType getComparator(int i, ByteBuffer bb); + abstract protected AbstractType getComparator(int i, V value, ValueAccessor accessor, int offset); /** * Adds DynamicCompositeType type information from @param bb1 to @param bb2. * @param i is ignored. */ - abstract protected AbstractType getComparator(int i, ByteBuffer bb1, ByteBuffer bb2); + abstract protected AbstractType getComparator(int i, VL left, ValueAccessor accessorL, VR right, ValueAccessor accessorR, int offsetL, int offsetR); /** * Adds type information from @param bb to @param sb. @param i is ignored. */ - abstract protected AbstractType getAndAppendComparator(int i, ByteBuffer bb, StringBuilder sb); + abstract protected AbstractType getAndAppendComparator(int i, V value, ValueAccessor accessor, StringBuilder sb, int offset); /** * Like getComparator, but validates that @param i does not exceed the defined range */ - abstract protected AbstractType validateComparator(int i, ByteBuffer bb) throws MarshalException; + abstract protected AbstractType validateComparator(int i, V value, ValueAccessor accessor, int offset) throws MarshalException; /** * Used by fromString diff --git a/src/java/org/apache/cassandra/db/marshal/AbstractType.java b/src/java/org/apache/cassandra/db/marshal/AbstractType.java index 0a34785c7b..0b4764417d 100644 --- a/src/java/org/apache/cassandra/db/marshal/AbstractType.java +++ b/src/java/org/apache/cassandra/db/marshal/AbstractType.java @@ -28,14 +28,10 @@ import java.util.List; import java.util.Map; import java.util.Objects; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import org.apache.cassandra.cql3.AssignmentTestable; import org.apache.cassandra.cql3.CQL3Type; import org.apache.cassandra.cql3.ColumnSpecification; import org.apache.cassandra.cql3.Term; -import org.apache.cassandra.db.TypeSizes; import org.apache.cassandra.exceptions.SyntaxException; import org.apache.cassandra.io.util.DataInputPlus; import org.apache.cassandra.io.util.DataOutputPlus; @@ -43,7 +39,6 @@ import org.apache.cassandra.serializers.MarshalException; import org.apache.cassandra.serializers.TypeSerializer; import org.apache.cassandra.transport.ProtocolVersion; import org.apache.cassandra.utils.ByteBufferUtil; -import org.apache.cassandra.utils.FastByteOperations; import org.github.jamm.Unmetered; import static org.apache.cassandra.db.marshal.AbstractType.ComparisonType.CUSTOM; @@ -59,8 +54,6 @@ import static org.apache.cassandra.db.marshal.AbstractType.ComparisonType.CUSTOM @Unmetered public abstract class AbstractType implements Comparator, AssignmentTestable { - private static final Logger logger = LoggerFactory.getLogger(AbstractType.class); - public final Comparator reverseComparator; public enum ComparisonType @@ -83,6 +76,7 @@ public abstract class AbstractType implements Comparator, Assignm public final ComparisonType comparisonType; public final boolean isByteOrderComparable; + public final ValueComparators comparatorSet; protected AbstractType(ComparisonType comparisonType) { @@ -91,7 +85,7 @@ public abstract class AbstractType implements Comparator, Assignm reverseComparator = (o1, o2) -> AbstractType.this.compare(o2, o1); try { - Method custom = getClass().getMethod("compareCustom", ByteBuffer.class, ByteBuffer.class); + Method custom = getClass().getMethod("compareCustom", Object.class, ValueAccessor.class, Object.class, ValueAccessor.class); if ((custom.getDeclaringClass() == AbstractType.class) == (comparisonType == CUSTOM)) throw new IllegalStateException((comparisonType == CUSTOM ? "compareCustom must be overridden if ComparisonType is CUSTOM" : "compareCustom should not be overridden if ComparisonType is not CUSTOM") @@ -101,6 +95,17 @@ public abstract class AbstractType implements Comparator, Assignm { throw new IllegalStateException(); } + + comparatorSet = new ValueComparators((l, r) -> compare(l, ByteArrayAccessor.instance, r, ByteArrayAccessor.instance), + (l, r) -> compare(l, ByteBufferAccessor.instance, r, ByteBufferAccessor.instance)); + } + + static > int compareComposed(VL left, ValueAccessor accessorL, VR right, ValueAccessor accessorR, AbstractType type) + { + if (accessorL.isEmpty(left) || accessorR.isEmpty(right)) + return Boolean.compare(accessorR.isEmpty(right), accessorL.isEmpty(left)); + + return type.compose(left, accessorL).compareTo(type.compose(right, accessorR)); } public static List asCQLTypeStringList(List> abstractTypes) @@ -111,26 +116,36 @@ public abstract class AbstractType implements Comparator, Assignm return r; } - public T compose(ByteBuffer bytes) + public final T compose(ByteBuffer bytes) { return getSerializer().deserialize(bytes); } + public T compose(V value, ValueAccessor accessor) + { + return getSerializer().deserialize(value, accessor); + } + public ByteBuffer decompose(T value) { return getSerializer().serialize(value); } /** get a string representation of the bytes used for various identifier (NOT just for log messages) */ - public String getString(ByteBuffer bytes) + public String getString(V value, ValueAccessor accessor) { - if (bytes == null) + if (value == null) return "null"; TypeSerializer serializer = getSerializer(); - serializer.validate(bytes); + serializer.validate(value, accessor); - return serializer.toString(serializer.deserialize(bytes)); + return serializer.toString(serializer.deserialize(value, accessor)); + } + + public final String getString(ByteBuffer bytes) + { + return getString(bytes, ByteBufferAccessor.instance); } /** get a byte representation of the given string. */ @@ -156,29 +171,46 @@ public abstract class AbstractType implements Comparator, Assignm return '"' + Objects.toString(getSerializer().deserialize(buffer), "") + '"'; } + public String toJSONString(V value, ValueAccessor accessor, ProtocolVersion protocolVersion) + { + return toJSONString(accessor.toBuffer(value), protocolVersion); // FIXME + } + /* validate that the byte array is a valid sequence for the type we are supposed to be comparing */ public void validate(ByteBuffer bytes) throws MarshalException { - getSerializer().validate(bytes); + validate(bytes, ByteBufferAccessor.instance); + } + + public void validate(V value, ValueAccessor accessor) throws MarshalException + { + getSerializer().validate(value, accessor); } public final int compare(ByteBuffer left, ByteBuffer right) { - return isByteOrderComparable - ? FastByteOperations.compareUnsigned(left, right) - : compareCustom(left, right); + return compare(left, ByteBufferAccessor.instance, right, ByteBufferAccessor.instance); + } + + public final int compare(VL left, ValueAccessor accessorL, VR right, ValueAccessor accessorR) + { + return isByteOrderComparable ? ValueAccessor.compare(left, accessorL, right, accessorR) : compareCustom(left, accessorL, right, accessorR); } /** * Implement IFF ComparisonType is CUSTOM * - * Compares the ByteBuffer representation of two instances of this class, + * Compares the byte representation of two instances of this class, * for types where this cannot be done by simple in-order comparison of the * unsigned bytes * * Standard Java compare semantics + * @param left + * @param accessorL + * @param right + * @param accessorR */ - public int compareCustom(ByteBuffer left, ByteBuffer right) + public int compareCustom(VL left, ValueAccessor accessorL, VR right, ValueAccessor accessorR) { throw new UnsupportedOperationException(); } @@ -191,9 +223,9 @@ public abstract class AbstractType implements Comparator, Assignm * @param cellValue ByteBuffer representing cell value * @throws MarshalException */ - public void validateCellValue(ByteBuffer cellValue) throws MarshalException + public void validateCellValue(V cellValue, ValueAccessor accessor) throws MarshalException { - validate(cellValue); + validate(cellValue, accessor); } /* Most of our internal type should override that. */ @@ -303,19 +335,14 @@ public abstract class AbstractType implements Comparator, Assignm * * Unless you're doing something very similar to CollectionsType, you shouldn't override this. */ - public int compareCollectionMembers(ByteBuffer v1, ByteBuffer v2, ByteBuffer collectionName) + public int compareCollectionMembers(VL left, ValueAccessor accessorL, VR right, ValueAccessor accessorR, VL collectionName) { - return compare(v1, v2); + return compare(left, accessorL, right, accessorR); } - /** - * An alternative validation function used by CollectionsType in conjunction with CompositeType. - * - * This is similar to the compare function above. - */ - public void validateCollectionMember(ByteBuffer bytes, ByteBuffer collectionName) throws MarshalException + public void validateCollectionMember(V value, V collectionName, ValueAccessor accessor) throws MarshalException { - validate(bytes); + getSerializer().validate(value, accessor); } public boolean isCollection() @@ -382,15 +409,6 @@ public abstract class AbstractType implements Comparator, Assignm return this.toString(); } - /** - * The number of subcomponents this type has. - * This is always 1, i.e. the type has only itself as "subcomponents", except for CompositeType. - */ - public int componentsCount() - { - return 1; - } - /** * Return a list of the "subcomponents" this type has. * This always return a singleton list with the type itself except for CompositeType. @@ -411,32 +429,53 @@ public abstract class AbstractType implements Comparator, Assignm // This assumes that no empty values are passed public void writeValue(ByteBuffer value, DataOutputPlus out) throws IOException { - assert value.hasRemaining(); + writeValue(value, ByteBufferAccessor.instance, out); + } + + // This assumes that no empty values are passed + public void writeValue(V value, ValueAccessor accessor, DataOutputPlus out) throws IOException + { + assert !accessor.isEmpty(value); if (valueLengthIfFixed() >= 0) - out.write(value); + accessor.write(value, out); else - ByteBufferUtil.writeWithVIntLength(value, out); + accessor.writeWithVIntLength(value, out); } public long writtenLength(ByteBuffer value) { - assert value.hasRemaining() : "bytes should not be empty for type " + this; - return valueLengthIfFixed() >= 0 - ? value.remaining() - : TypeSizes.sizeofWithVIntLength(value); + return writtenLength(value, ByteBufferAccessor.instance); } - public ByteBuffer readValue(DataInputPlus in) throws IOException + public long writtenLength(V value, ValueAccessor accessor) { - return readValue(in, Integer.MAX_VALUE); + assert !accessor.isEmpty(value) : "bytes should not be empty for type " + this; + return valueLengthIfFixed() >= 0 + ? accessor.size(value) + : accessor.sizeWithVIntLength(value); } - public ByteBuffer readValue(DataInputPlus in, int maxValueSize) throws IOException + public ByteBuffer readBuffer(DataInputPlus in) throws IOException + { + return readBuffer(in, Integer.MAX_VALUE); + } + + public ByteBuffer readBuffer(DataInputPlus in, int maxValueSize) throws IOException + { + return read(ByteBufferAccessor.instance, in, maxValueSize); + } + + public byte[] readArray(DataInputPlus in, int maxValueSize) throws IOException + { + return read(ByteArrayAccessor.instance, in, maxValueSize); + } + + public V read(ValueAccessor accessor, DataInputPlus in, int maxValueSize) throws IOException { int length = valueLengthIfFixed(); if (length >= 0) - return ByteBufferUtil.read(in, length); + return accessor.read(in, length); else { int l = (int)in.readUnsignedVInt(); @@ -448,7 +487,7 @@ public abstract class AbstractType implements Comparator, Assignm "which is set via max_value_size_in_mb in cassandra.yaml", l, maxValueSize)); - return ByteBufferUtil.read(in, l); + return accessor.read(in, l); } } @@ -461,7 +500,12 @@ public abstract class AbstractType implements Comparator, Assignm ByteBufferUtil.skipWithVIntLength(in); } - public boolean referencesUserType(ByteBuffer name) + public final boolean referencesUserType(ByteBuffer name) + { + return referencesUserType(name, ByteBufferAccessor.instance); + } + + public boolean referencesUserType(V name, ValueAccessor accessor) { return false; } diff --git a/src/java/org/apache/cassandra/db/marshal/BooleanType.java b/src/java/org/apache/cassandra/db/marshal/BooleanType.java index 475cae6328..4ef5f95b0b 100644 --- a/src/java/org/apache/cassandra/db/marshal/BooleanType.java +++ b/src/java/org/apache/cassandra/db/marshal/BooleanType.java @@ -43,17 +43,15 @@ public class BooleanType extends AbstractType return true; } - public int compareCustom(ByteBuffer o1, ByteBuffer o2) + public int compareCustom(VL left, ValueAccessor accessorL, VR right, ValueAccessor accessorR) { - if (!o1.hasRemaining() || !o2.hasRemaining()) - return o1.hasRemaining() ? 1 : o2.hasRemaining() ? -1 : 0; + if (accessorL.isEmpty(left) || accessorR.isEmpty(right)) + return Boolean.compare(accessorR.isEmpty(right), accessorL.isEmpty(left)); // False is 0, True is anything else, makes False sort before True. - byte b1 = o1.get(o1.position()); - byte b2 = o2.get(o2.position()); - if (b1 == 0) - return b2 == 0 ? 0 : -1; - return b2 == 0 ? 1 : 0; + int v1 = accessorL.getByte(left, 0) == 0 ? 0 : 1; + int v2 = accessorR.getByte(right, 0) == 0 ? 0 : 1; + return v1 - v2; } public ByteBuffer fromString(String source) throws MarshalException diff --git a/src/java/org/apache/cassandra/db/marshal/ByteArrayAccessor.java b/src/java/org/apache/cassandra/db/marshal/ByteArrayAccessor.java new file mode 100644 index 0000000000..92f18a2216 --- /dev/null +++ b/src/java/org/apache/cassandra/db/marshal/ByteArrayAccessor.java @@ -0,0 +1,294 @@ +/* + * 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.db.marshal; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.charset.CharacterCodingException; +import java.nio.charset.Charset; +import java.util.Arrays; +import java.util.UUID; + +import org.apache.cassandra.db.Digest; +import org.apache.cassandra.db.TypeSizes; +import org.apache.cassandra.io.util.DataInputPlus; +import org.apache.cassandra.io.util.DataOutputPlus; +import org.apache.cassandra.utils.ByteArrayUtil; +import org.apache.cassandra.utils.ByteBufferUtil; +import org.apache.cassandra.utils.FastByteOperations; +import org.apache.cassandra.utils.Hex; +import org.apache.cassandra.utils.UUIDGen; + +public class ByteArrayAccessor implements ValueAccessor +{ + public static final ValueAccessor instance = new ByteArrayAccessor(); + public static final ObjectFactory factory = ByteArrayObjectFactory.instance; + private static final byte[] EMPTY = new byte[0]; + + private ByteArrayAccessor() {} + + public int size(byte[] value) + { + return value.length; + } + + public byte[][] createArray(int length) + { + return new byte[length][]; + } + + public void write(byte[] value, DataOutputPlus out) throws IOException + { + out.write(value); + } + + public void write(byte[] value, ByteBuffer out) + { + out.put(value); + } + + public int copyTo(byte[] src, int srcOffset, V2 dst, ValueAccessor dstAccessor, int dstOffset, int size) + { + dstAccessor.copyByteArrayTo(src, srcOffset, dst, dstOffset, size); + return size; + } + + public int copyByteArrayTo(byte[] src, int srcOffset, byte[] dst, int dstOffset, int size) + { + FastByteOperations.copy(src, srcOffset, dst, dstOffset, size); + return size; + } + + public int copyByteBufferTo(ByteBuffer src, int srcOffset, byte[] dst, int dstOffset, int size) + { + FastByteOperations.copy(src, src.position() + srcOffset, dst, dstOffset, size); + return size; + } + + public void digest(byte[] value, int offset, int size, Digest digest) + { + digest.update(value, offset, size); + } + + public byte[] read(DataInputPlus in, int length) throws IOException + { + byte[] b = new byte[length]; + in.readFully(b); + return b; + } + + public byte[] slice(byte[] input, int offset, int length) + { + return Arrays.copyOfRange(input, offset, offset + length); + } + + public int compare(byte[] left, V2 right, ValueAccessor accessorR) + { + return accessorR.compareByteArrayTo(left, right); + } + + public int compareByteArrayTo(byte[] left, byte[] right) + { + return ByteArrayUtil.compareUnsigned(left, right); + } + + public int compareByteBufferTo(ByteBuffer left, byte[] right) + { + return ByteBufferUtil.compare(left, right); + } + + public ByteBuffer toBuffer(byte[] value) + { + if (value == null) + return null; + return ByteBuffer.wrap(value); + } + + public byte[] toArray(byte[] value) + { + return value; + } + + public byte[] toArray(byte[] value, int offset, int length) + { + if (value == null) + return null; + if (offset == 0 && length == value.length) + return value; + return slice(value, offset, length); + } + + public String toString(byte[] value, Charset charset) throws CharacterCodingException + { + return new String(value, charset); + } + + public String toHex(byte[] value) + { + return Hex.bytesToHex(value); + } + + public byte toByte(byte[] value) + { + return value[0]; + } + + public byte getByte(byte[] value, int offset) + { + return value[offset]; + } + + public short toShort(byte[] value) + { + return getShort(value, 0); + } + + public short getShort(byte[] value, int offset) + { + return ByteArrayUtil.getShort(value, offset); + } + + public int toInt(byte[] value) + { + return getInt(value, 0); + } + + public int getInt(byte[] value, int offset) + { + return ByteArrayUtil.getInt(value, offset); + } + + public long toLong(byte[] value) + { + return getLong(value, 0); + } + + public long getLong(byte[] value, int offset) + { + return ByteArrayUtil.getLong(value, offset); + } + + public float toFloat(byte[] value) + { + return ByteArrayUtil.getFloat(value, 0); + } + + public double toDouble(byte[] value) + { + return ByteArrayUtil.getDouble(value, 0); + } + + public UUID toUUID(byte[] value) + { + return new UUID(getLong(value, 0), getLong(value, 8)); + } + + public int putShort(byte[] dst, int offset, short value) + { + ByteArrayUtil.putShort(dst, offset, value); + return TypeSizes.SHORT_SIZE; + } + + public int putInt(byte[] dst, int offset, int value) + { + ByteArrayUtil.putInt(dst, offset, value); + return TypeSizes.INT_SIZE; + } + + public int putLong(byte[] dst, int offset, long value) + { + ByteArrayUtil.putLong(dst, offset, value); + return TypeSizes.LONG_SIZE; + } + + public byte[] empty() + { + return EMPTY; + } + + public byte[] valueOf(byte[] bytes) + { + return bytes; + } + + public byte[] valueOf(ByteBuffer bytes) + { + return ByteBufferUtil.getArray(bytes); + } + + public byte[] valueOf(String s, Charset charset) + { + return ByteArrayUtil.bytes(s, charset); + } + + public byte[] valueOf(UUID v) + { + return UUIDGen.decompose(v); + } + + public byte[] valueOf(boolean v) + { + return v ? new byte[] {1} : new byte[] {0}; + } + + public byte[] valueOf(byte v) + { + return ByteArrayUtil.bytes(v); + } + + public byte[] valueOf(short v) + { + return ByteArrayUtil.bytes(v); + } + + public byte[] valueOf(int v) + { + return ByteArrayUtil.bytes(v); + } + + public byte[] valueOf(long v) + { + return ByteArrayUtil.bytes(v); + } + + public byte[] valueOf(float v) + { + return ByteArrayUtil.bytes(v); + } + + public byte[] valueOf(double v) + { + return ByteArrayUtil.bytes(v); + } + + public byte[] convert(V2 src, ValueAccessor accessor) + { + return accessor.toArray(src); + } + + public byte[] allocate(int size) + { + return new byte[size]; + } + + public ObjectFactory factory() + { + return factory; + } +} diff --git a/src/java/org/apache/cassandra/db/marshal/ByteArrayObjectFactory.java b/src/java/org/apache/cassandra/db/marshal/ByteArrayObjectFactory.java new file mode 100644 index 0000000000..ea9bf11383 --- /dev/null +++ b/src/java/org/apache/cassandra/db/marshal/ByteArrayObjectFactory.java @@ -0,0 +1,82 @@ +/* + * 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.db.marshal; + +import org.apache.cassandra.db.ArrayClustering; +import org.apache.cassandra.db.ArrayClusteringBound; +import org.apache.cassandra.db.ArrayClusteringBoundary; +import org.apache.cassandra.db.Clustering; +import org.apache.cassandra.db.ClusteringBound; +import org.apache.cassandra.db.ClusteringBoundary; +import org.apache.cassandra.db.ClusteringPrefix; +import org.apache.cassandra.db.rows.ArrayCell; +import org.apache.cassandra.db.rows.Cell; +import org.apache.cassandra.db.rows.CellPath; +import org.apache.cassandra.schema.ColumnMetadata; +import org.apache.cassandra.schema.TableMetadata; + +class ByteArrayObjectFactory implements ValueAccessor.ObjectFactory +{ + private static final Clustering EMPTY_CLUSTERING = new ArrayClustering() + { + public String toString(TableMetadata metadata) + { + return "EMPTY"; + } + }; + + static final ValueAccessor.ObjectFactory instance = new ByteArrayObjectFactory(); + + private ByteArrayObjectFactory() {} + + /** The smallest start bound, i.e. the one that starts before any row. */ + private static final ArrayClusteringBound BOTTOM_BOUND = new ArrayClusteringBound(ClusteringPrefix.Kind.INCL_START_BOUND, new byte[0][]); + /** The biggest end bound, i.e. the one that ends after any row. */ + private static final ArrayClusteringBound TOP_BOUND = new ArrayClusteringBound(ClusteringPrefix.Kind.INCL_END_BOUND, new byte[0][]); + + public Cell cell(ColumnMetadata column, long timestamp, int ttl, int localDeletionTime, byte[] value, CellPath path) + { + return new ArrayCell(column, timestamp, ttl, localDeletionTime, value, path); + } + + public Clustering clustering(byte[]... values) + { + return new ArrayClustering(values); + } + + public Clustering clustering() + { + return EMPTY_CLUSTERING; + } + + public ClusteringBound bound(ClusteringPrefix.Kind kind, byte[]... values) + { + return new ArrayClusteringBound(kind, values); + } + + public ClusteringBound bound(ClusteringPrefix.Kind kind) + { + return kind.isStart() ? BOTTOM_BOUND : TOP_BOUND; + } + + public ClusteringBoundary boundary(ClusteringPrefix.Kind kind, byte[]... values) + { + return new ArrayClusteringBoundary(kind, values); + } +} diff --git a/src/java/org/apache/cassandra/db/marshal/ByteBufferAccessor.java b/src/java/org/apache/cassandra/db/marshal/ByteBufferAccessor.java new file mode 100644 index 0000000000..df27d8baf1 --- /dev/null +++ b/src/java/org/apache/cassandra/db/marshal/ByteBufferAccessor.java @@ -0,0 +1,292 @@ +/* + * 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.db.marshal; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.charset.CharacterCodingException; +import java.nio.charset.Charset; +import java.util.UUID; + +import org.apache.cassandra.db.Digest; +import org.apache.cassandra.db.TypeSizes; +import org.apache.cassandra.io.util.DataInputPlus; +import org.apache.cassandra.io.util.DataOutputPlus; +import org.apache.cassandra.utils.ByteBufferUtil; +import org.apache.cassandra.utils.FastByteOperations; +import org.apache.cassandra.utils.UUIDGen; + +/** + * Accessor for ByteBuffer values. ByteBufferAccessor treates {@link ByteBuffer#position()} as index 0, + * and {@link ByteBuffer#remaining()} as the length. + */ +public class ByteBufferAccessor implements ValueAccessor +{ + public static final ValueAccessor instance = new ByteBufferAccessor(); + + private ByteBufferAccessor() {} + + public int size(ByteBuffer value) + { + return value.remaining(); + } + + public ByteBuffer[] createArray(int length) + { + return new ByteBuffer[length]; + } + + public void write(ByteBuffer value, DataOutputPlus out) throws IOException + { + out.write(value); + } + + public void write(ByteBuffer value, ByteBuffer out) + { + out.put(value.duplicate()); + } + + public int copyTo(ByteBuffer src, int srcOffset, V2 dst, ValueAccessor dstAccessor, int dstOffset, int size) + { + dstAccessor.copyByteBufferTo(src, srcOffset, dst, dstOffset, size); + return size; + } + + public int copyByteArrayTo(byte[] src, int srcOffset, ByteBuffer dst, int dstOffset, int size) + { + FastByteOperations.copy(src, srcOffset, dst, dst.position() + dstOffset, size); + return size; + } + + public int copyByteBufferTo(ByteBuffer src, int srcOffset, ByteBuffer dst, int dstOffset, int size) + { + FastByteOperations.copy(src, src.position() + srcOffset, dst, dst.position() + dstOffset, size); + return size; + } + + public void digest(ByteBuffer value, int offset, int size, Digest digest) + { + digest.update(value, value.position() + offset, size); + } + + public ByteBuffer read(DataInputPlus in, int length) throws IOException + { + return ByteBufferUtil.read(in, length); + } + + public ByteBuffer slice(ByteBuffer input, int offset, int length) + { + ByteBuffer copy = input.duplicate(); + copy.position(copy.position() + offset); + copy.limit(copy.position() + length); + return copy; + } + + public int compare(ByteBuffer left, V2 right, ValueAccessor accessorR) + { + return accessorR.compareByteBufferTo(left, right); + } + + public int compareByteArrayTo(byte[] left, ByteBuffer right) + { + return ByteBufferUtil.compare(left, right); + } + + public int compareByteBufferTo(ByteBuffer left, ByteBuffer right) + { + return ByteBufferUtil.compareUnsigned(left, right); + } + + public ByteBuffer toBuffer(ByteBuffer value) + { + return value; + } + + public byte[] toArray(ByteBuffer value) + { + if (value == null) + return null; + return ByteBufferUtil.getArray(value); + } + + public byte[] toArray(ByteBuffer value, int offset, int length) + { + if (value == null) + return null; + return ByteBufferUtil.getArray(value, value.position() + offset, length); + } + + public String toString(ByteBuffer value, Charset charset) throws CharacterCodingException + { + return ByteBufferUtil.string(value, charset); + } + + public ByteBuffer valueOf(UUID v) + { + return UUIDGen.toByteBuffer(v); + } + + public String toHex(ByteBuffer value) + { + return ByteBufferUtil.bytesToHex(value); + } + + public byte toByte(ByteBuffer value) + { + return ByteBufferUtil.toByte(value); + } + + public byte getByte(ByteBuffer value, int offset) + { + return value.get(value.position() + offset); + } + + public short toShort(ByteBuffer value) + { + return ByteBufferUtil.toShort(value); + } + + public short getShort(ByteBuffer value, int offset) + { + return value.getShort(value.position() + offset); + } + + public int toInt(ByteBuffer value) + { + return ByteBufferUtil.toInt(value); + } + + public int getInt(ByteBuffer value, int offset) + { + return value.getInt(value.position() + offset); + } + + public long toLong(ByteBuffer value) + { + return ByteBufferUtil.toLong(value); + } + + public long getLong(ByteBuffer value, int offset) + { + return value.getLong(value.position() + offset); + } + + public float toFloat(ByteBuffer value) + { + return ByteBufferUtil.toFloat(value); + } + + public double toDouble(ByteBuffer value) + { + return ByteBufferUtil.toDouble(value); + } + + public UUID toUUID(ByteBuffer value) + { + return UUIDGen.getUUID(value); + } + + public int putShort(ByteBuffer dst, int offset, short value) + { + dst.putShort(dst.position() + offset, value); + return TypeSizes.SHORT_SIZE; + } + + public int putInt(ByteBuffer dst, int offset, int value) + { + dst.putInt(dst.position() + offset, value); + return TypeSizes.INT_SIZE; + } + + public int putLong(ByteBuffer dst, int offset, long value) + { + dst.putLong(dst.position() + offset, value); + return TypeSizes.LONG_SIZE; + } + + public ByteBuffer empty() + { + return ByteBufferUtil.EMPTY_BYTE_BUFFER; + } + + public ByteBuffer valueOf(byte[] bytes) + { + return ByteBuffer.wrap(bytes); + } + + public ByteBuffer valueOf(ByteBuffer bytes) + { + return bytes; + } + + public ByteBuffer valueOf(String v, Charset charset) + { + return ByteBufferUtil.bytes(v, charset); + } + + public ByteBuffer valueOf(boolean v) + { + return v ? ByteBuffer.wrap(new byte[] {1}) : ByteBuffer.wrap(new byte[] {0}); + } + + public ByteBuffer valueOf(byte v) + { + return ByteBufferUtil.bytes(v); + } + + public ByteBuffer valueOf(short v) + { + return ByteBufferUtil.bytes(v); + } + + public ByteBuffer valueOf(int v) + { + return ByteBufferUtil.bytes(v); + } + + public ByteBuffer valueOf(long v) + { + return ByteBufferUtil.bytes(v); + } + + public ByteBuffer valueOf(float v) + { + return ByteBufferUtil.bytes(v); + } + + public ByteBuffer valueOf(double v) + { + return ByteBufferUtil.bytes(v); + } + + public ByteBuffer convert(V2 src, ValueAccessor accessor) + { + return accessor.toBuffer(src); + } + + public ByteBuffer allocate(int size) + { + return ByteBuffer.allocate(size); + } + + public ObjectFactory factory() + { + return ByteBufferObjectFactory.instance; + } +} diff --git a/src/java/org/apache/cassandra/db/marshal/ByteBufferObjectFactory.java b/src/java/org/apache/cassandra/db/marshal/ByteBufferObjectFactory.java new file mode 100644 index 0000000000..00f4646341 --- /dev/null +++ b/src/java/org/apache/cassandra/db/marshal/ByteBufferObjectFactory.java @@ -0,0 +1,86 @@ +/* + * 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.db.marshal; + +import java.nio.ByteBuffer; + +import org.apache.cassandra.db.BufferClustering; +import org.apache.cassandra.db.BufferClusteringBound; +import org.apache.cassandra.db.BufferClusteringBoundary; +import org.apache.cassandra.db.Clustering; +import org.apache.cassandra.db.ClusteringBound; +import org.apache.cassandra.db.ClusteringBoundary; +import org.apache.cassandra.db.ClusteringPrefix; +import org.apache.cassandra.db.rows.BufferCell; +import org.apache.cassandra.db.rows.Cell; +import org.apache.cassandra.db.rows.CellPath; +import org.apache.cassandra.schema.ColumnMetadata; +import org.apache.cassandra.schema.TableMetadata; + +class ByteBufferObjectFactory implements ValueAccessor.ObjectFactory +{ + /** Empty clustering for tables having no clustering columns. */ + private static final Clustering EMPTY_CLUSTERING = new BufferClustering() + { + @Override + public String toString(TableMetadata metadata) + { + return "EMPTY"; + } + }; + + /** The smallest start bound, i.e. the one that starts before any row. */ + private static final BufferClusteringBound BOTTOM_BOUND = new BufferClusteringBound(ClusteringPrefix.Kind.INCL_START_BOUND, new ByteBuffer[0]); + /** The biggest end bound, i.e. the one that ends after any row. */ + private static final BufferClusteringBound TOP_BOUND = new BufferClusteringBound(ClusteringPrefix.Kind.INCL_END_BOUND, new ByteBuffer[0]); + + static final ValueAccessor.ObjectFactory instance = new ByteBufferObjectFactory(); + + private ByteBufferObjectFactory() {} + + public Cell cell(ColumnMetadata column, long timestamp, int ttl, int localDeletionTime, ByteBuffer value, CellPath path) + { + return new BufferCell(column, timestamp, ttl, localDeletionTime, value, path); + } + + public Clustering clustering(ByteBuffer... values) + { + return new BufferClustering(values); + } + + public Clustering clustering() + { + return EMPTY_CLUSTERING; + } + + public ClusteringBound bound(ClusteringPrefix.Kind kind, ByteBuffer... values) + { + return new BufferClusteringBound(kind, values); + } + + public ClusteringBound bound(ClusteringPrefix.Kind kind) + { + return kind.isStart() ? BOTTOM_BOUND : TOP_BOUND; + } + + public ClusteringBoundary boundary(ClusteringPrefix.Kind kind, ByteBuffer... values) + { + return new BufferClusteringBoundary(kind, values); + } +} diff --git a/src/java/org/apache/cassandra/db/marshal/ByteType.java b/src/java/org/apache/cassandra/db/marshal/ByteType.java index c19fdd97b2..f94f4bb01c 100644 --- a/src/java/org/apache/cassandra/db/marshal/ByteType.java +++ b/src/java/org/apache/cassandra/db/marshal/ByteType.java @@ -37,9 +37,9 @@ public class ByteType extends NumberType super(ComparisonType.CUSTOM); } // singleton - public int compareCustom(ByteBuffer o1, ByteBuffer o2) + public int compareCustom(VL left, ValueAccessor accessorL, VR right, ValueAccessor accessorR) { - return o1.get(o1.position()) - o2.get(o2.position()); + return accessorL.getByte(left, 0) - accessorR.getByte(right, 0); } public ByteBuffer fromString(String source) throws MarshalException diff --git a/src/java/org/apache/cassandra/db/marshal/CollectionType.java b/src/java/org/apache/cassandra/db/marshal/CollectionType.java index b198e0cdc8..0d627a5cbf 100644 --- a/src/java/org/apache/cassandra/db/marshal/CollectionType.java +++ b/src/java/org/apache/cassandra/db/marshal/CollectionType.java @@ -84,7 +84,7 @@ public abstract class CollectionType extends AbstractType public abstract AbstractType nameComparator(); public abstract AbstractType valueComparator(); - protected abstract List serializedValues(Iterator cells); + protected abstract List serializedValues(Iterator> cells); @Override public abstract CollectionSerializer getSerializer(); @@ -94,9 +94,9 @@ public abstract class CollectionType extends AbstractType return kind.makeCollectionReceiver(collection, isKey); } - public String getString(ByteBuffer bytes) + public String getString(V value, ValueAccessor accessor) { - return BytesType.instance.getString(bytes); + return BytesType.instance.getString(value, accessor); } public ByteBuffer fromString(String source) @@ -117,12 +117,12 @@ public abstract class CollectionType extends AbstractType } @Override - public void validateCellValue(ByteBuffer cellValue) throws MarshalException + public void validateCellValue(V cellValue, ValueAccessor accessor) throws MarshalException { if (isMultiCell()) - valueComparator().validateCellValue(cellValue); + valueComparator().validateCellValue(cellValue, accessor); else - super.validateCellValue(cellValue); + super.validateCellValue(cellValue, accessor); } /** @@ -146,12 +146,12 @@ public abstract class CollectionType extends AbstractType return values.size(); } - public ByteBuffer serializeForNativeProtocol(Iterator cells, ProtocolVersion version) + public ByteBuffer serializeForNativeProtocol(Iterator> cells, ProtocolVersion version) { assert isMultiCell(); List values = serializedValues(cells); int size = collectionSize(values); - return CollectionSerializer.pack(values, size, version); + return CollectionSerializer.pack(values, ByteBufferAccessor.instance, size, version); } @Override diff --git a/src/java/org/apache/cassandra/db/marshal/CompositeType.java b/src/java/org/apache/cassandra/db/marshal/CompositeType.java index e3423ff580..d7041b8e9b 100644 --- a/src/java/org/apache/cassandra/db/marshal/CompositeType.java +++ b/src/java/org/apache/cassandra/db/marshal/CompositeType.java @@ -84,9 +84,31 @@ public class CompositeType extends AbstractCompositeType return getInstance(Arrays.asList(types)); } - protected boolean readIsStatic(ByteBuffer bb) + protected static int startingOffsetInternal(boolean isStatic) { - return readStatic(bb); + return isStatic ? 2 : 0; + } + + protected int startingOffset(boolean isStatic) + { + return startingOffsetInternal(isStatic); + } + + protected static boolean readIsStaticInternal(V value, ValueAccessor accessor) + { + if (accessor.size(value) < 2) + return false; + + int header = accessor.getShort(value, 0); + if ((header & 0xFFFF) != STATIC_MARKER) + return false; + + return true; + } + + protected boolean readIsStatic(V value, ValueAccessor accessor) + { + return readIsStaticInternal(value, accessor); } private static boolean readStatic(ByteBuffer bb) @@ -116,7 +138,7 @@ public class CompositeType extends AbstractCompositeType this.types = ImmutableList.copyOf(types); } - protected AbstractType getComparator(int i, ByteBuffer bb) + protected AbstractType getComparator(int i, V value, ValueAccessor accessor, int offset) { try { @@ -133,12 +155,12 @@ public class CompositeType extends AbstractCompositeType } } - protected AbstractType getComparator(int i, ByteBuffer bb1, ByteBuffer bb2) + protected AbstractType getComparator(int i, VL left, ValueAccessor accessorL, VR right, ValueAccessor accessorR, int offsetL, int offsetR) { - return getComparator(i, bb1); + return getComparator(i, left, accessorL, offsetL); } - protected AbstractType getAndAppendComparator(int i, ByteBuffer bb, StringBuilder sb) + protected AbstractType getAndAppendComparator(int i, V value, ValueAccessor accessor, StringBuilder sb, int offset) { return types.get(i); } @@ -148,13 +170,18 @@ public class CompositeType extends AbstractCompositeType return new StaticParsedComparator(types.get(i), part); } - protected AbstractType validateComparator(int i, ByteBuffer bb) throws MarshalException + protected AbstractType validateComparator(int i, V value, ValueAccessor accessor, int offset) throws MarshalException { if (i >= types.size()) throw new MarshalException("Too many bytes for comparator"); return types.get(i); } + protected int getComparatorSize(int i, V value, ValueAccessor accessor, int offset) + { + return 0; + } + public ByteBuffer decompose(Object... objects) { assert objects.length == types.size(); @@ -165,9 +192,8 @@ public class CompositeType extends AbstractCompositeType ByteBuffer buffer = ((AbstractType) types.get(i)).decompose(objects[i]); serialized[i] = buffer; } - return build(serialized); + return build(ByteBufferAccessor.instance, serialized); } - // Overriding the one of AbstractCompositeType because we can do a tad better @Override public ByteBuffer[] split(ByteBuffer name) @@ -186,15 +212,17 @@ public class CompositeType extends AbstractCompositeType return i == l.length ? l : Arrays.copyOfRange(l, 0, i); } - public static List splitName(ByteBuffer name) + public static List splitName(V name, ValueAccessor accessor) { - List l = new ArrayList<>(); - ByteBuffer bb = name.duplicate(); - readStatic(bb); - while (bb.remaining() > 0) + List l = new ArrayList<>(); + boolean isStatic = readIsStaticInternal(name, accessor); + int offset = startingOffsetInternal(isStatic); + while (!accessor.isEmptyFromOffset(name, offset)) { - l.add(ByteBufferUtil.readBytesWithShortLength(bb)); - bb.get(); // skip end-of-component + V value = accessor.sliceWithShortLength(name, offset); + offset += accessor.sizeWithShortLength(value); + l.add(value); + offset++; // skip end-of-component } return l; } @@ -217,15 +245,9 @@ public class CompositeType extends AbstractCompositeType return null; } - public static boolean isStaticName(ByteBuffer bb) + public static boolean isStaticName(V value, ValueAccessor accessor) { - return bb.remaining() >= 2 && (ByteBufferUtil.getShortLength(bb, bb.position()) & 0xFFFF) == STATIC_MARKER; - } - - @Override - public int componentsCount() - { - return types.size(); + return accessor.size(value) >= 2 && (accessor.getShortLength(value, 0) & 0xFFFF) == STATIC_MARKER; } @Override @@ -283,9 +305,9 @@ public class CompositeType extends AbstractCompositeType } @Override - public boolean referencesUserType(ByteBuffer name) + public boolean referencesUserType(V name, ValueAccessor accessor) { - return any(types, t -> t.referencesUserType(name)); + return any(types, t -> t.referencesUserType(name, accessor)); } @Override @@ -340,31 +362,31 @@ public class CompositeType extends AbstractCompositeType return getClass().getName() + TypeParser.stringifyTypeParameters(types); } - public static ByteBuffer build(ByteBuffer... buffers) + @SafeVarargs + public static V build(ValueAccessor accessor, V... values) { - return build(false, buffers); + return build(accessor, false, values); } - public static ByteBuffer build(boolean isStatic, ByteBuffer... buffers) + @SafeVarargs + public static V build(ValueAccessor accessor, boolean isStatic, V... values) { int totalLength = isStatic ? 2 : 0; - for (ByteBuffer bb : buffers) - totalLength += 2 + bb.remaining() + 1; + for (V v : values) + totalLength += 2 + accessor.size(v) + 1; ByteBuffer out = ByteBuffer.allocate(totalLength); if (isStatic) out.putShort((short)STATIC_MARKER); - for (ByteBuffer bb : buffers) + for (V v : values) { - ByteBufferUtil.writeShortLength(out, bb.remaining()); - int toCopy = bb.remaining(); - ByteBufferUtil.copyBytes(bb, bb.position(), out, out.position(), toCopy); - out.position(out.position() + toCopy); + ByteBufferUtil.writeShortLength(out, accessor.size(v)); + accessor.write(v, out); out.put((byte) 0); } out.flip(); - return out; + return accessor.valueOf(out); } } diff --git a/src/java/org/apache/cassandra/db/marshal/CounterColumnType.java b/src/java/org/apache/cassandra/db/marshal/CounterColumnType.java index 8777e0e929..0dae0927f4 100644 --- a/src/java/org/apache/cassandra/db/marshal/CounterColumnType.java +++ b/src/java/org/apache/cassandra/db/marshal/CounterColumnType.java @@ -44,10 +44,9 @@ public class CounterColumnType extends NumberType return true; } - @Override - public Long compose(ByteBuffer bytes) + public Long compose(V value, ValueAccessor accessor) { - return CounterContext.instance().total(bytes); + return CounterContext.instance().total(value, accessor); } @Override @@ -57,14 +56,14 @@ public class CounterColumnType extends NumberType } @Override - public void validateCellValue(ByteBuffer cellValue) throws MarshalException + public void validateCellValue(V cellValue, ValueAccessor accessor) throws MarshalException { - CounterContext.instance().validateContext(cellValue); + CounterContext.instance().validateContext(cellValue, accessor); } - public String getString(ByteBuffer bytes) + public String getString(V value, ValueAccessor accessor) { - return ByteBufferUtil.bytesToHex(bytes); + return accessor.toHex(value); } public ByteBuffer fromString(String source) diff --git a/src/java/org/apache/cassandra/db/marshal/DecimalType.java b/src/java/org/apache/cassandra/db/marshal/DecimalType.java index dd47ded7dd..5740fdcc0f 100644 --- a/src/java/org/apache/cassandra/db/marshal/DecimalType.java +++ b/src/java/org/apache/cassandra/db/marshal/DecimalType.java @@ -54,12 +54,9 @@ public class DecimalType extends NumberType return true; } - public int compareCustom(ByteBuffer o1, ByteBuffer o2) + public int compareCustom(VL left, ValueAccessor accessorL, VR right, ValueAccessor accessorR) { - if (!o1.hasRemaining() || !o2.hasRemaining()) - return o1.hasRemaining() ? 1 : o2.hasRemaining() ? -1 : 0; - - return compose(o1).compareTo(compose(o2)); + return compareComposed(left, accessorL, right, accessorR, this); } public ByteBuffer fromString(String source) throws MarshalException diff --git a/src/java/org/apache/cassandra/db/marshal/DoubleType.java b/src/java/org/apache/cassandra/db/marshal/DoubleType.java index 6ed98dc640..570d420a75 100644 --- a/src/java/org/apache/cassandra/db/marshal/DoubleType.java +++ b/src/java/org/apache/cassandra/db/marshal/DoubleType.java @@ -45,12 +45,9 @@ public class DoubleType extends NumberType return true; } - public int compareCustom(ByteBuffer o1, ByteBuffer o2) + public int compareCustom(VL left, ValueAccessor accessorL, VR right, ValueAccessor accessorR) { - if (!o1.hasRemaining() || !o2.hasRemaining()) - return o1.hasRemaining() ? 1 : o2.hasRemaining() ? -1 : 0; - - return compose(o1).compareTo(compose(o2)); + return compareComposed(left, accessorL, right, accessorR, this); } public ByteBuffer fromString(String source) throws MarshalException diff --git a/src/java/org/apache/cassandra/db/marshal/DynamicCompositeType.java b/src/java/org/apache/cassandra/db/marshal/DynamicCompositeType.java index 0458dc8a4c..5df3600995 100644 --- a/src/java/org/apache/cassandra/db/marshal/DynamicCompositeType.java +++ b/src/java/org/apache/cassandra/db/marshal/DynamicCompositeType.java @@ -27,6 +27,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.apache.cassandra.cql3.Term; +import org.apache.cassandra.db.TypeSizes; import org.apache.cassandra.exceptions.ConfigurationException; import org.apache.cassandra.exceptions.SyntaxException; import org.apache.cassandra.serializers.MarshalException; @@ -82,20 +83,39 @@ public class DynamicCompositeType extends AbstractCompositeType this.aliases = aliases; } - protected boolean readIsStatic(ByteBuffer bb) + protected boolean readIsStatic(V value, ValueAccessor accessor) { // We don't have the static nothing for DCT return false; } - private AbstractType getComparator(ByteBuffer bb) + protected int startingOffset(boolean isStatic) + { + return 0; + } + + protected int getComparatorSize(int i, V value, ValueAccessor accessor, int offset) + { + int header = accessor.getShort(value, offset); + if ((header & 0x8000) == 0) + { + return 2 + header; + } + else + { + return 2; + } + } + + private AbstractType getComparator(V value, ValueAccessor accessor, int offset) { try { - int header = ByteBufferUtil.readShortLength(bb); + int header = accessor.getShort(value, offset); if ((header & 0x8000) == 0) { - String name = ByteBufferUtil.string(ByteBufferUtil.readBytes(bb, header)); + + String name = accessor.toString(accessor.slice(value, offset + 2, header)); return TypeParser.parse(name); } else @@ -109,15 +129,15 @@ public class DynamicCompositeType extends AbstractCompositeType } } - protected AbstractType getComparator(int i, ByteBuffer bb) + protected AbstractType getComparator(int i, V value, ValueAccessor accessor, int offset) { - return getComparator(bb); + return getComparator(value, accessor, offset); } - protected AbstractType getComparator(int i, ByteBuffer bb1, ByteBuffer bb2) + protected AbstractType getComparator(int i, VL left, ValueAccessor accessorL, VR right, ValueAccessor accessorR, int offsetL, int offsetR) { - AbstractType comp1 = getComparator(bb1); - AbstractType comp2 = getComparator(bb2); + AbstractType comp1 = getComparator(left, accessorL, offsetL); + AbstractType comp2 = getComparator(right, accessorR, offsetR); AbstractType rawComp = comp1; /* @@ -154,14 +174,14 @@ public class DynamicCompositeType extends AbstractCompositeType return rawComp; } - protected AbstractType getAndAppendComparator(int i, ByteBuffer bb, StringBuilder sb) + protected AbstractType getAndAppendComparator(int i, V value, ValueAccessor accessor, StringBuilder sb, int offset) { try { - int header = ByteBufferUtil.readShortLength(bb); + int header = accessor.getShort(value, offset); if ((header & 0x8000) == 0) { - String name = ByteBufferUtil.string(ByteBufferUtil.readBytes(bb, header)); + String name = accessor.toString(accessor.slice(value, offset + 2, header)); sb.append(name).append("@"); return TypeParser.parse(name); } @@ -182,22 +202,23 @@ public class DynamicCompositeType extends AbstractCompositeType return new DynamicParsedComparator(part); } - protected AbstractType validateComparator(int i, ByteBuffer bb) throws MarshalException + protected AbstractType validateComparator(int i, V input, ValueAccessor accessor, int offset) throws MarshalException { AbstractType comparator = null; - if (bb.remaining() < 2) + if (accessor.sizeFromOffset(input, offset) < 2) throw new MarshalException("Not enough bytes to header of the comparator part of component " + i); - int header = ByteBufferUtil.readShortLength(bb); + int header = accessor.getShort(input, offset); + offset += TypeSizes.SHORT_SIZE; if ((header & 0x8000) == 0) { - if (bb.remaining() < header) + if (accessor.sizeFromOffset(input, offset) < header) throw new MarshalException("Not enough bytes to read comparator name of component " + i); - ByteBuffer value = ByteBufferUtil.readBytes(bb, header); + V value = accessor.slice(input, offset, header); String valueStr = null; try { - valueStr = ByteBufferUtil.string(value); + valueStr = accessor.toString(value); comparator = TypeParser.parse(valueStr); } catch (CharacterCodingException ce) @@ -257,9 +278,9 @@ public class DynamicCompositeType extends AbstractCompositeType } @Override - public boolean referencesUserType(ByteBuffer name) + public boolean referencesUserType(V name, ValueAccessor accessor) { - return any(aliases.values(), t -> t.referencesUserType(name)); + return any(aliases.values(), t -> t.referencesUserType(name, accessor)); } @Override @@ -370,24 +391,23 @@ public class DynamicCompositeType extends AbstractCompositeType this.cmp = cmp; } - public int compareCustom(ByteBuffer v1, ByteBuffer v2) + public int compareCustom(VL left, ValueAccessor accessorL, VR right, ValueAccessor accessorR) { return cmp; } @Override - public Void compose(ByteBuffer bytes) + public Void compose(V value, ValueAccessor accessor) { throw new UnsupportedOperationException(); } - @Override public ByteBuffer decompose(Void value) { throw new UnsupportedOperationException(); } - public String getString(ByteBuffer bytes) + public String getString(V value, ValueAccessor accessor) { throw new UnsupportedOperationException(); } diff --git a/src/java/org/apache/cassandra/db/marshal/EmptyType.java b/src/java/org/apache/cassandra/db/marshal/EmptyType.java index 808402ff73..357b6e85ad 100644 --- a/src/java/org/apache/cassandra/db/marshal/EmptyType.java +++ b/src/java/org/apache/cassandra/db/marshal/EmptyType.java @@ -68,12 +68,12 @@ public class EmptyType extends AbstractType private EmptyType() {super(ComparisonType.CUSTOM);} // singleton - public int compareCustom(ByteBuffer o1, ByteBuffer o2) + public int compareCustom(VL left, ValueAccessor accessorL, VR right, ValueAccessor accessorR) { return 0; } - public String getString(ByteBuffer bytes) + public String getString(V value, ValueAccessor accessor) { return ""; } @@ -121,21 +121,20 @@ public class EmptyType extends AbstractType } @Override - public long writtenLength(ByteBuffer value) + public long writtenLength(V value, ValueAccessor accessor) { // default implemenation requires non-empty bytes but this always requires empty bytes, so special case - validate(value); + validate(value, accessor); return 0; } - @Override - public ByteBuffer readValue(DataInputPlus in) + public ByteBuffer readBuffer(DataInputPlus in) { return ByteBufferUtil.EMPTY_BYTE_BUFFER; } @Override - public ByteBuffer readValue(DataInputPlus in, int maxValueSize) + public ByteBuffer readBuffer(DataInputPlus in, int maxValueSize) { return ByteBufferUtil.EMPTY_BYTE_BUFFER; } diff --git a/src/java/org/apache/cassandra/db/marshal/FloatType.java b/src/java/org/apache/cassandra/db/marshal/FloatType.java index af63d80c4e..35abee0f98 100644 --- a/src/java/org/apache/cassandra/db/marshal/FloatType.java +++ b/src/java/org/apache/cassandra/db/marshal/FloatType.java @@ -46,12 +46,9 @@ public class FloatType extends NumberType return true; } - public int compareCustom(ByteBuffer o1, ByteBuffer o2) + public int compareCustom(VL left, ValueAccessor accessorL, VR right, ValueAccessor accessorR) { - if (!o1.hasRemaining() || !o2.hasRemaining()) - return o1.hasRemaining() ? 1 : o2.hasRemaining() ? -1 : 0; - - return compose(o1).compareTo(compose(o2)); + return compareComposed(left, accessorL, right, accessorR, this); } public ByteBuffer fromString(String source) throws MarshalException diff --git a/src/java/org/apache/cassandra/db/marshal/FrozenType.java b/src/java/org/apache/cassandra/db/marshal/FrozenType.java index 6cabb53982..64a5b6ae03 100644 --- a/src/java/org/apache/cassandra/db/marshal/FrozenType.java +++ b/src/java/org/apache/cassandra/db/marshal/FrozenType.java @@ -47,7 +47,7 @@ public class FrozenType extends AbstractType return innerType.freeze(); } - public String getString(ByteBuffer bytes) + public String getString(V value, ValueAccessor accessor) { throw new UnsupportedOperationException(); } diff --git a/src/java/org/apache/cassandra/db/marshal/Int32Type.java b/src/java/org/apache/cassandra/db/marshal/Int32Type.java index a486289ac5..98f4c83cf6 100644 --- a/src/java/org/apache/cassandra/db/marshal/Int32Type.java +++ b/src/java/org/apache/cassandra/db/marshal/Int32Type.java @@ -43,16 +43,16 @@ public class Int32Type extends NumberType return true; } - public int compareCustom(ByteBuffer o1, ByteBuffer o2) + public int compareCustom(VL left, ValueAccessor accessorL, VR right, ValueAccessor accessorR) { - if (!o1.hasRemaining() || !o2.hasRemaining()) - return o1.hasRemaining() ? 1 : o2.hasRemaining() ? -1 : 0; + if (accessorL.isEmpty(left) || accessorR.isEmpty(right)) + return Boolean.compare(accessorR.isEmpty(right), accessorL.isEmpty(left)); - int diff = o1.get(o1.position()) - o2.get(o2.position()); + int diff = accessorL.getByte(left, 0) - accessorR.getByte(right, 0); if (diff != 0) return diff; - return ByteBufferUtil.compareUnsigned(o1, o2); + return ValueAccessor.compare(left, accessorL, right, accessorR); } public ByteBuffer fromString(String source) throws MarshalException diff --git a/src/java/org/apache/cassandra/db/marshal/IntegerType.java b/src/java/org/apache/cassandra/db/marshal/IntegerType.java index 044fe6ed8c..4c913d50af 100644 --- a/src/java/org/apache/cassandra/db/marshal/IntegerType.java +++ b/src/java/org/apache/cassandra/db/marshal/IntegerType.java @@ -35,16 +35,16 @@ public final class IntegerType extends NumberType { public static final IntegerType instance = new IntegerType(); - private static int findMostSignificantByte(ByteBuffer bytes) + private static int findMostSignificantByte(V value, ValueAccessor accessor) { - int len = bytes.remaining() - 1; + int len = accessor.size(value) - 1; int i = 0; for (; i < len; i++) { - byte b0 = bytes.get(bytes.position() + i); + byte b0 = accessor.getByte(value, i); if (b0 != 0 && b0 != -1) break; - byte b1 = bytes.get(bytes.position() + i + 1); + byte b1 = accessor.getByte(value, i + 1); if (b0 == 0 && b1 != 0) { if (b1 > 0) @@ -68,30 +68,30 @@ public final class IntegerType extends NumberType return true; } - public int compareCustom(ByteBuffer lhs, ByteBuffer rhs) + public int compareCustom(VL left, ValueAccessor accessorL, VR right, ValueAccessor accessorR) { - return IntegerType.compareIntegers(lhs, rhs); + return IntegerType.compareIntegers(left, accessorL, right, accessorR); } - public static int compareIntegers(ByteBuffer lhs, ByteBuffer rhs) + public static int compareIntegers(VL lhs, ValueAccessor accessorL, VR rhs, ValueAccessor accessorR) { - int lhsLen = lhs.remaining(); - int rhsLen = rhs.remaining(); + int lhsLen = accessorL.size(lhs); + int rhsLen = accessorR.size(rhs); if (lhsLen == 0) return rhsLen == 0 ? 0 : -1; if (rhsLen == 0) return 1; - int lhsMsbIdx = findMostSignificantByte(lhs); - int rhsMsbIdx = findMostSignificantByte(rhs); + int lhsMsbIdx = findMostSignificantByte(lhs, accessorL); + int rhsMsbIdx = findMostSignificantByte(rhs, accessorR); //diffs contain number of "meaningful" bytes (i.e. ignore padding) int lhsLenDiff = lhsLen - lhsMsbIdx; int rhsLenDiff = rhsLen - rhsMsbIdx; - byte lhsMsb = lhs.get(lhs.position() + lhsMsbIdx); - byte rhsMsb = rhs.get(rhs.position() + rhsMsbIdx); + byte lhsMsb = accessorL.getByte(lhs, lhsMsbIdx); + byte rhsMsb = accessorR.getByte(rhs, rhsMsbIdx); /* + - * ----------- @@ -121,8 +121,8 @@ public final class IntegerType extends NumberType // remaining bytes are compared unsigned while (lhsMsbIdx < lhsLen) { - lhsMsb = lhs.get(lhs.position() + lhsMsbIdx++); - rhsMsb = rhs.get(rhs.position() + rhsMsbIdx++); + lhsMsb = accessorL.getByte(lhs, lhsMsbIdx++); + rhsMsb = accessorR.getByte(rhs, rhsMsbIdx++); if (lhsMsb != rhsMsb) return (lhsMsb & 0xFF) - (rhsMsb & 0xFF); diff --git a/src/java/org/apache/cassandra/db/marshal/LexicalUUIDType.java b/src/java/org/apache/cassandra/db/marshal/LexicalUUIDType.java index de32a56dd1..6dd41616f0 100644 --- a/src/java/org/apache/cassandra/db/marshal/LexicalUUIDType.java +++ b/src/java/org/apache/cassandra/db/marshal/LexicalUUIDType.java @@ -26,7 +26,6 @@ import org.apache.cassandra.serializers.TypeSerializer; import org.apache.cassandra.serializers.MarshalException; import org.apache.cassandra.serializers.UUIDSerializer; import org.apache.cassandra.utils.ByteBufferUtil; -import org.apache.cassandra.utils.UUIDGen; public class LexicalUUIDType extends AbstractType { @@ -42,12 +41,11 @@ public class LexicalUUIDType extends AbstractType return true; } - public int compareCustom(ByteBuffer o1, ByteBuffer o2) + public int compareCustom(VL left, ValueAccessor accessorL, VR right, ValueAccessor accessorR) { - if (!o1.hasRemaining() || !o2.hasRemaining()) - return o1.hasRemaining() ? 1 : o2.hasRemaining() ? -1 : 0; - - return UUIDGen.getUUID(o1).compareTo(UUIDGen.getUUID(o2)); + if (accessorL.isEmpty(left) || accessorR.isEmpty(right)) + return Boolean.compare(accessorR.isEmpty(right), accessorL.isEmpty(left)); + return accessorL.toUUID(left).compareTo(accessorR.toUUID(right)); } public ByteBuffer fromString(String source) throws MarshalException diff --git a/src/java/org/apache/cassandra/db/marshal/ListType.java b/src/java/org/apache/cassandra/db/marshal/ListType.java index c6e02625ae..cc6393751b 100644 --- a/src/java/org/apache/cassandra/db/marshal/ListType.java +++ b/src/java/org/apache/cassandra/db/marshal/ListType.java @@ -24,6 +24,7 @@ import java.util.concurrent.ConcurrentHashMap; import org.apache.cassandra.cql3.Json; import org.apache.cassandra.cql3.Lists; import org.apache.cassandra.cql3.Term; +import org.apache.cassandra.db.TypeSizes; import org.apache.cassandra.db.rows.Cell; import org.apache.cassandra.exceptions.ConfigurationException; import org.apache.cassandra.exceptions.SyntaxException; @@ -69,9 +70,9 @@ public class ListType extends CollectionType> } @Override - public boolean referencesUserType(ByteBuffer name) + public boolean referencesUserType(V name, ValueAccessor accessor) { - return elements.referencesUserType(name); + return elements.referencesUserType(name, accessor); } @Override @@ -164,34 +165,34 @@ public class ListType extends CollectionType> return this.elements.isValueCompatibleWithInternal(((ListType) previous).elements); } - @Override - public int compareCustom(ByteBuffer o1, ByteBuffer o2) + public int compareCustom(VL left, ValueAccessor accessorL, VR right, ValueAccessor accessorR) { - return compareListOrSet(elements, o1, o2); + return compareListOrSet(elements, left, accessorL, right, accessorR); } - static int compareListOrSet(AbstractType elementsComparator, ByteBuffer o1, ByteBuffer o2) + static int compareListOrSet(AbstractType elementsComparator, VL left, ValueAccessor accessorL, VR right, ValueAccessor accessorR) { // Note that this is only used if the collection is frozen - if (!o1.hasRemaining() || !o2.hasRemaining()) - return o1.hasRemaining() ? 1 : o2.hasRemaining() ? -1 : 0; + if (accessorL.isEmpty(left) || accessorR.isEmpty(right)) + return Boolean.compare(accessorR.isEmpty(right), accessorL.isEmpty(left)); - ByteBuffer bb1 = o1.duplicate(); - ByteBuffer bb2 = o2.duplicate(); + int sizeL = CollectionSerializer.readCollectionSize(left, accessorL, ProtocolVersion.V3); + int offsetL = CollectionSerializer.sizeOfCollectionSize(sizeL, ProtocolVersion.V3); + int sizeR = CollectionSerializer.readCollectionSize(right, accessorR, ProtocolVersion.V3); + int offsetR = TypeSizes.INT_SIZE; - int size1 = CollectionSerializer.readCollectionSize(bb1, ProtocolVersion.V3); - int size2 = CollectionSerializer.readCollectionSize(bb2, ProtocolVersion.V3); - - for (int i = 0; i < Math.min(size1, size2); i++) + for (int i = 0; i < Math.min(sizeL, sizeR); i++) { - ByteBuffer v1 = CollectionSerializer.readValue(bb1, ProtocolVersion.V3); - ByteBuffer v2 = CollectionSerializer.readValue(bb2, ProtocolVersion.V3); - int cmp = elementsComparator.compare(v1, v2); + VL v1 = CollectionSerializer.readValue(left, accessorL, offsetL, ProtocolVersion.V3); + offsetL += CollectionSerializer.sizeOfValue(v1, accessorL, ProtocolVersion.V3); + VR v2 = CollectionSerializer.readValue(right, accessorR, offsetR, ProtocolVersion.V3); + offsetR += CollectionSerializer.sizeOfValue(v2, accessorR, ProtocolVersion.V3); + int cmp = elementsComparator.compare(v1, accessorL, v2, accessorR); if (cmp != 0) return cmp; } - return size1 == size2 ? 0 : (size1 < size2 ? -1 : 1); + return sizeL == sizeR ? 0 : (sizeL < sizeR ? -1 : 1); } @Override @@ -209,12 +210,12 @@ public class ListType extends CollectionType> return sb.toString(); } - public List serializedValues(Iterator cells) + public List serializedValues(Iterator> cells) { assert isMultiCell; List bbs = new ArrayList(); while (cells.hasNext()) - bbs.add(cells.next().value()); + bbs.add(cells.next().buffer()); return bbs; } @@ -245,11 +246,14 @@ public class ListType extends CollectionType> ByteBuffer value = buffer.duplicate(); StringBuilder sb = new StringBuilder("["); int size = CollectionSerializer.readCollectionSize(value, protocolVersion); + int offset = CollectionSerializer.sizeOfCollectionSize(size, protocolVersion); for (int i = 0; i < size; i++) { if (i > 0) sb.append(", "); - sb.append(elementsType.toJSONString(CollectionSerializer.readValue(value, protocolVersion), protocolVersion)); + ByteBuffer element = CollectionSerializer.readValue(value, ByteBufferAccessor.instance, offset, protocolVersion); + offset += CollectionSerializer.sizeOfValue(element, ByteBufferAccessor.instance, protocolVersion); + sb.append(elementsType.toJSONString(element, protocolVersion)); } return sb.append("]").toString(); } diff --git a/src/java/org/apache/cassandra/db/marshal/LongType.java b/src/java/org/apache/cassandra/db/marshal/LongType.java index 07954580c6..ad539f70de 100644 --- a/src/java/org/apache/cassandra/db/marshal/LongType.java +++ b/src/java/org/apache/cassandra/db/marshal/LongType.java @@ -40,21 +40,21 @@ public class LongType extends NumberType return true; } - public int compareCustom(ByteBuffer o1, ByteBuffer o2) + public int compareCustom(VL left, ValueAccessor accessorL, VR right, ValueAccessor accessorR) { - return compareLongs(o1, o2); + return compareLongs(left, accessorL, right, accessorR); } - public static int compareLongs(ByteBuffer o1, ByteBuffer o2) + public static int compareLongs(VL left, ValueAccessor accessorL, VR right, ValueAccessor accessorR) { - if (!o1.hasRemaining() || !o2.hasRemaining()) - return o1.hasRemaining() ? 1 : o2.hasRemaining() ? -1 : 0; + if (accessorL.isEmpty(left)|| accessorR.isEmpty(right)) + return Boolean.compare(accessorR.isEmpty(right), accessorL.isEmpty(left)); - int diff = o1.get(o1.position()) - o2.get(o2.position()); + int diff = accessorL.getByte(left, 0) - accessorR.getByte(right, 0); if (diff != 0) return diff; - return ByteBufferUtil.compareUnsigned(o1, o2); + return ValueAccessor.compare(left, accessorL, right, accessorR); } public ByteBuffer fromString(String source) throws MarshalException diff --git a/src/java/org/apache/cassandra/db/marshal/MapType.java b/src/java/org/apache/cassandra/db/marshal/MapType.java index 6abe388789..9473e29136 100644 --- a/src/java/org/apache/cassandra/db/marshal/MapType.java +++ b/src/java/org/apache/cassandra/db/marshal/MapType.java @@ -68,14 +68,16 @@ public class MapType extends CollectionType> super(ComparisonType.CUSTOM, Kind.MAP); this.keys = keys; this.values = values; - this.serializer = MapSerializer.getInstance(keys.getSerializer(), values.getSerializer(), keys); + this.serializer = MapSerializer.getInstance(keys.getSerializer(), + values.getSerializer(), + keys.comparatorSet); this.isMultiCell = isMultiCell; } @Override - public boolean referencesUserType(ByteBuffer name) + public boolean referencesUserType(T name, ValueAccessor accessor) { - return keys.referencesUserType(name) || values.referencesUserType(name); + return keys.referencesUserType(name, accessor) || values.referencesUserType(name, accessor); } @Override @@ -176,40 +178,44 @@ public class MapType extends CollectionType> return keys.isCompatibleWith(tprev.keys) && values.isValueCompatibleWith(tprev.values); } - @Override - public int compareCustom(ByteBuffer o1, ByteBuffer o2) + public int compareCustom(RL left, ValueAccessor accessorL, TR right, ValueAccessor accessorR) { - return compareMaps(keys, values, o1, o2); + return compareMaps(keys, values, left, accessorL, right, accessorR); } - public static int compareMaps(AbstractType keysComparator, AbstractType valuesComparator, ByteBuffer o1, ByteBuffer o2) + public static int compareMaps(AbstractType keysComparator, AbstractType valuesComparator, TL left, ValueAccessor accessorL, TR right, ValueAccessor accessorR) { - if (!o1.hasRemaining() || !o2.hasRemaining()) - return o1.hasRemaining() ? 1 : o2.hasRemaining() ? -1 : 0; + if (accessorL.isEmpty(left) || accessorR.isEmpty(right)) + return Boolean.compare(accessorR.isEmpty(right), accessorL.isEmpty(left)); - ByteBuffer bb1 = o1.duplicate(); - ByteBuffer bb2 = o2.duplicate(); ProtocolVersion protocolVersion = ProtocolVersion.V3; - int size1 = CollectionSerializer.readCollectionSize(bb1, protocolVersion); - int size2 = CollectionSerializer.readCollectionSize(bb2, protocolVersion); + int sizeL = CollectionSerializer.readCollectionSize(left, accessorL, protocolVersion); + int sizeR = CollectionSerializer.readCollectionSize(right, accessorR, protocolVersion); - for (int i = 0; i < Math.min(size1, size2); i++) + int offsetL = CollectionSerializer.sizeOfCollectionSize(sizeL, protocolVersion); + int offsetR = CollectionSerializer.sizeOfCollectionSize(sizeR, protocolVersion); + + for (int i = 0; i < Math.min(sizeL, sizeR); i++) { - ByteBuffer k1 = CollectionSerializer.readValue(bb1, protocolVersion); - ByteBuffer k2 = CollectionSerializer.readValue(bb2, protocolVersion); - int cmp = keysComparator.compare(k1, k2); + TL k1 = CollectionSerializer.readValue(left, accessorL, offsetL, protocolVersion); + offsetL += CollectionSerializer.sizeOfValue(k1, accessorL, protocolVersion); + TR k2 = CollectionSerializer.readValue(right, accessorR, offsetR, protocolVersion); + offsetR += CollectionSerializer.sizeOfValue(k2, accessorR, protocolVersion); + int cmp = keysComparator.compare(k1, accessorL, k2, accessorR); if (cmp != 0) return cmp; - ByteBuffer v1 = CollectionSerializer.readValue(bb1, protocolVersion); - ByteBuffer v2 = CollectionSerializer.readValue(bb2, protocolVersion); - cmp = valuesComparator.compare(v1, v2); + TL v1 = CollectionSerializer.readValue(left, accessorL, offsetL, protocolVersion); + offsetL += CollectionSerializer.sizeOfValue(v1, accessorL, protocolVersion); + TR v2 = CollectionSerializer.readValue(right, accessorR, offsetR, protocolVersion); + offsetR += CollectionSerializer.sizeOfValue(v2, accessorR, protocolVersion); + cmp = valuesComparator.compare(v1, accessorL, v2, accessorR); if (cmp != 0) return cmp; } - return size1 == size2 ? 0 : (size1 < size2 ? -1 : 1); + return sizeL == sizeR ? 0 : (sizeL < sizeR ? -1 : 1); } @Override @@ -237,15 +243,15 @@ public class MapType extends CollectionType> return sb.toString(); } - public List serializedValues(Iterator cells) + public List serializedValues(Iterator> cells) { assert isMultiCell; List bbs = new ArrayList(); while (cells.hasNext()) { - Cell c = cells.next(); + Cell c = cells.next(); bbs.add(c.path().get(0)); - bbs.add(c.value()); + bbs.add(c.buffer()); } return bbs; } @@ -281,20 +287,25 @@ public class MapType extends CollectionType> ByteBuffer value = buffer.duplicate(); StringBuilder sb = new StringBuilder("{"); int size = CollectionSerializer.readCollectionSize(value, protocolVersion); + int offset = CollectionSerializer.sizeOfCollectionSize(size, protocolVersion); for (int i = 0; i < size; i++) { if (i > 0) sb.append(", "); // map keys must be JSON strings, so convert non-string keys to strings - String key = keys.toJSONString(CollectionSerializer.readValue(value, protocolVersion), protocolVersion); + ByteBuffer kv = CollectionSerializer.readValue(value, ByteBufferAccessor.instance, offset, protocolVersion); + offset += CollectionSerializer.sizeOfValue(kv, ByteBufferAccessor.instance, protocolVersion); + String key = keys.toJSONString(kv, protocolVersion); if (key.startsWith("\"")) sb.append(key); else sb.append('"').append(Json.quoteAsJsonString(key)).append('"'); sb.append(": "); - sb.append(values.toJSONString(CollectionSerializer.readValue(value, protocolVersion), protocolVersion)); + ByteBuffer vv = CollectionSerializer.readValue(value, ByteBufferAccessor.instance, offset, protocolVersion); + offset += CollectionSerializer.sizeOfValue(vv, ByteBufferAccessor.instance, protocolVersion); + sb.append(values.toJSONString(vv, protocolVersion)); } return sb.append("}").toString(); } diff --git a/src/java/org/apache/cassandra/db/marshal/PartitionerDefinedOrder.java b/src/java/org/apache/cassandra/db/marshal/PartitionerDefinedOrder.java index 397c3be155..89241b416b 100644 --- a/src/java/org/apache/cassandra/db/marshal/PartitionerDefinedOrder.java +++ b/src/java/org/apache/cassandra/db/marshal/PartitionerDefinedOrder.java @@ -27,7 +27,6 @@ import org.apache.cassandra.serializers.TypeSerializer; import org.apache.cassandra.serializers.MarshalException; import org.apache.cassandra.dht.IPartitioner; import org.apache.cassandra.transport.ProtocolVersion; -import org.apache.cassandra.utils.ByteBufferUtil; import org.apache.cassandra.utils.FBUtilities; /** for sorting columns representing row keys in the row ordering as determined by a partitioner. @@ -55,20 +54,20 @@ public class PartitionerDefinedOrder extends AbstractType } @Override - public ByteBuffer compose(ByteBuffer bytes) + public ByteBuffer compose(V value, ValueAccessor accessor) { throw new UnsupportedOperationException("You can't do this with a local partitioner."); } @Override - public ByteBuffer decompose(ByteBuffer bytes) + public ByteBuffer decompose(ByteBuffer value) { throw new UnsupportedOperationException("You can't do this with a local partitioner."); } - public String getString(ByteBuffer bytes) + public String getString(V value, ValueAccessor accessor) { - return ByteBufferUtil.bytesToHex(bytes); + return accessor.toHex(value); } public ByteBuffer fromString(String source) @@ -88,10 +87,10 @@ public class PartitionerDefinedOrder extends AbstractType throw new UnsupportedOperationException(); } - public int compareCustom(ByteBuffer o1, ByteBuffer o2) + public int compareCustom(VL left, ValueAccessor accessorL, VR right, ValueAccessor accessorR) { // o1 and o2 can be empty so we need to use PartitionPosition, not DecoratedKey - return PartitionPosition.ForKey.get(o1, partitioner).compareTo(PartitionPosition.ForKey.get(o2, partitioner)); + return PartitionPosition.ForKey.get(accessorL.toBuffer(left), partitioner).compareTo(PartitionPosition.ForKey.get(accessorR.toBuffer(right), partitioner)); } @Override diff --git a/src/java/org/apache/cassandra/db/marshal/ReversedType.java b/src/java/org/apache/cassandra/db/marshal/ReversedType.java index 63a900a1a5..8a4b58dca2 100644 --- a/src/java/org/apache/cassandra/db/marshal/ReversedType.java +++ b/src/java/org/apache/cassandra/db/marshal/ReversedType.java @@ -63,9 +63,9 @@ public class ReversedType extends AbstractType return baseType.isEmptyValueMeaningless(); } - public int compareCustom(ByteBuffer o1, ByteBuffer o2) + public int compareCustom(VL left, ValueAccessor accessorL, VR right, ValueAccessor accessorR) { - return baseType.compare(o2, o1); + return baseType.compare(right, accessorR, left, accessorL); } @Override @@ -74,9 +74,9 @@ public class ReversedType extends AbstractType return baseType.compare(v1, v2); } - public String getString(ByteBuffer bytes) + public String getString(V value, ValueAccessor accessor) { - return baseType.getString(bytes); + return baseType.getString(value, accessor); } public ByteBuffer fromString(String source) @@ -123,9 +123,9 @@ public class ReversedType extends AbstractType } @Override - public boolean referencesUserType(ByteBuffer name) + public boolean referencesUserType(V name, ValueAccessor accessor) { - return baseType.referencesUserType(name); + return baseType.referencesUserType(name, accessor); } @Override diff --git a/src/java/org/apache/cassandra/db/marshal/SetType.java b/src/java/org/apache/cassandra/db/marshal/SetType.java index 6d17b67e12..e5bdadab25 100644 --- a/src/java/org/apache/cassandra/db/marshal/SetType.java +++ b/src/java/org/apache/cassandra/db/marshal/SetType.java @@ -63,14 +63,14 @@ public class SetType extends CollectionType> { super(ComparisonType.CUSTOM, Kind.SET); this.elements = elements; - this.serializer = SetSerializer.getInstance(elements.getSerializer(), elements); + this.serializer = SetSerializer.getInstance(elements.getSerializer(), elements.comparatorSet); this.isMultiCell = isMultiCell; } @Override - public boolean referencesUserType(ByteBuffer name) + public boolean referencesUserType(V name, ValueAccessor accessor) { - return elements.referencesUserType(name); + return elements.referencesUserType(name, accessor); } @Override @@ -152,10 +152,9 @@ public class SetType extends CollectionType> return isCompatibleWithFrozen(previous); } - @Override - public int compareCustom(ByteBuffer o1, ByteBuffer o2) + public int compareCustom(VL left, ValueAccessor accessorL, VR right, ValueAccessor accessorR) { - return ListType.compareListOrSet(elements, o1, o2); + return ListType.compareListOrSet(elements, left, accessorL, right, accessorR); } public SetSerializer getSerializer() @@ -178,7 +177,7 @@ public class SetType extends CollectionType> return sb.toString(); } - public List serializedValues(Iterator cells) + public List serializedValues(Iterator> cells) { List bbs = new ArrayList(); while (cells.hasNext()) diff --git a/src/java/org/apache/cassandra/db/marshal/ShortType.java b/src/java/org/apache/cassandra/db/marshal/ShortType.java index 84d538b674..03dcf5d314 100644 --- a/src/java/org/apache/cassandra/db/marshal/ShortType.java +++ b/src/java/org/apache/cassandra/db/marshal/ShortType.java @@ -38,13 +38,12 @@ public class ShortType extends NumberType super(ComparisonType.CUSTOM); } // singleton - public int compareCustom(ByteBuffer o1, ByteBuffer o2) + public int compareCustom(VL left, ValueAccessor accessorL, VR right, ValueAccessor accessorR) { - int diff = o1.get(o1.position()) - o2.get(o2.position()); + int diff = accessorL.getByte(left, 0) - accessorR.getByte(right, 0); if (diff != 0) return diff; - - return ByteBufferUtil.compareUnsigned(o1, o2); + return ValueAccessor.compare(left, accessorL, right, accessorR); } public ByteBuffer fromString(String source) throws MarshalException diff --git a/src/java/org/apache/cassandra/db/marshal/TimeUUIDType.java b/src/java/org/apache/cassandra/db/marshal/TimeUUIDType.java index 39d1513eb1..6cf137596c 100644 --- a/src/java/org/apache/cassandra/db/marshal/TimeUUIDType.java +++ b/src/java/org/apache/cassandra/db/marshal/TimeUUIDType.java @@ -43,23 +43,20 @@ public class TimeUUIDType extends TemporalType return true; } - public int compareCustom(ByteBuffer b1, ByteBuffer b2) + public int compareCustom(VL left, ValueAccessor accessorL, VR right, ValueAccessor accessorR) { // Compare for length - int s1 = b1.position(), s2 = b2.position(); - int l1 = b1.limit(), l2 = b2.limit(); - - // should we assert exactly 16 bytes (or 0)? seems prudent - boolean p1 = l1 - s1 == 16, p2 = l2 - s2 == 16; + boolean p1 = accessorL.size(left) == 16, p2 = accessorR.size(right) == 16; if (!(p1 & p2)) { - assert p1 | (l1 == s1); - assert p2 | (l2 == s2); + // should we assert exactly 16 bytes (or 0)? seems prudent + assert p1 || accessorL.isEmpty(left); + assert p2 || accessorR.isEmpty(right); return p1 ? 1 : p2 ? -1 : 0; } - long msb1 = b1.getLong(s1); - long msb2 = b2.getLong(s2); + long msb1 = accessorL.getLong(left, 0); + long msb2 = accessorR.getLong(right, 0); msb1 = reorderTimestampBytes(msb1); msb2 = reorderTimestampBytes(msb2); @@ -72,8 +69,8 @@ public class TimeUUIDType extends TemporalType // this has to be a signed per-byte comparison for compatibility // so we transform the bytes so that a simple long comparison is equivalent - long lsb1 = signedBytesToNativeLong(b1.getLong(s1 + 8)); - long lsb2 = signedBytesToNativeLong(b2.getLong(s2 + 8)); + long lsb1 = signedBytesToNativeLong(accessorL.getLong(left, 8)); + long lsb2 = signedBytesToNativeLong(accessorR.getLong(right, 8)); return Long.compare(lsb1, lsb2); } diff --git a/src/java/org/apache/cassandra/db/marshal/TimestampType.java b/src/java/org/apache/cassandra/db/marshal/TimestampType.java index cfe05e9ab8..0dac6b0394 100644 --- a/src/java/org/apache/cassandra/db/marshal/TimestampType.java +++ b/src/java/org/apache/cassandra/db/marshal/TimestampType.java @@ -56,9 +56,9 @@ public class TimestampType extends TemporalType return true; } - public int compareCustom(ByteBuffer o1, ByteBuffer o2) + public int compareCustom(VL left, ValueAccessor accessorL, VR right, ValueAccessor accessorR) { - return LongType.compareLongs(o1, o2); + return LongType.compareLongs(left, accessorL, right, accessorR); } public ByteBuffer fromString(String source) throws MarshalException diff --git a/src/java/org/apache/cassandra/db/marshal/TupleType.java b/src/java/org/apache/cassandra/db/marshal/TupleType.java index dfdb8c264b..8a2f7eeb4c 100644 --- a/src/java/org/apache/cassandra/db/marshal/TupleType.java +++ b/src/java/org/apache/cassandra/db/marshal/TupleType.java @@ -28,6 +28,7 @@ import com.google.common.base.Objects; import com.google.common.collect.Lists; import org.apache.cassandra.cql3.*; +import org.apache.cassandra.db.TypeSizes; import org.apache.cassandra.exceptions.ConfigurationException; import org.apache.cassandra.exceptions.InvalidRequestException; import org.apache.cassandra.exceptions.SyntaxException; @@ -91,9 +92,9 @@ public class TupleType extends AbstractType } @Override - public boolean referencesUserType(ByteBuffer name) + public boolean referencesUserType(V name, ValueAccessor accessor) { - return any(types, t -> t.referencesUserType(name)); + return any(types, t -> t.referencesUserType(name, accessor)); } @Override @@ -142,49 +143,55 @@ public class TupleType extends AbstractType return true; } - public int compareCustom(ByteBuffer o1, ByteBuffer o2) + public int compareCustom(VL left, ValueAccessor accessorL, VR right, ValueAccessor accessorR) { - if (!o1.hasRemaining() || !o2.hasRemaining()) - return o1.hasRemaining() ? 1 : o2.hasRemaining() ? -1 : 0; + if (accessorL.isEmpty(left) || accessorR.isEmpty(right)) + return Boolean.compare(accessorR.isEmpty(right), accessorL.isEmpty(left)); - ByteBuffer bb1 = o1.duplicate(); - ByteBuffer bb2 = o2.duplicate(); + int offsetL = 0; + int offsetR = 0; - for (int i = 0; bb1.remaining() > 0 && bb2.remaining() > 0; i++) + for (int i = 0; !accessorL.isEmptyFromOffset(left, offsetL) && !accessorR.isEmptyFromOffset(right, offsetR); i++) { AbstractType comparator = types.get(i); - int size1 = bb1.getInt(); - int size2 = bb2.getInt(); + int sizeL = accessorL.getInt(left, offsetL); + offsetL += TypeSizes.INT_SIZE; + int sizeR = accessorR.getInt(right, offsetR); + offsetR += TypeSizes.INT_SIZE; // Handle nulls - if (size1 < 0) + if (sizeL < 0) { - if (size2 < 0) + if (sizeR < 0) continue; return -1; } - if (size2 < 0) + if (sizeR < 0) return 1; - ByteBuffer value1 = ByteBufferUtil.readBytes(bb1, size1); - ByteBuffer value2 = ByteBufferUtil.readBytes(bb2, size2); - int cmp = comparator.compare(value1, value2); + VL valueL = accessorL.slice(left, offsetL, sizeL); + offsetL += sizeL; + VR valueR = accessorR.slice(right, offsetR, sizeR); + offsetR += sizeR; + int cmp = comparator.compare(valueL, accessorL, valueR, accessorR); if (cmp != 0) return cmp; } // handle trailing nulls - while (bb1.remaining() > 0) + while (!accessorL.isEmptyFromOffset(left, offsetL)) { - int size = bb1.getInt(); + int size = accessorL.getInt(left, offsetL); + offsetL += TypeSizes.INT_SIZE; if (size > 0) // non-null return 1; } - while (bb2.remaining() > 0) + while (!accessorR.isEmptyFromOffset(right, offsetR)) { - int size = bb2.getInt(); + int size = accessorR.getInt(right, offsetR); + offsetR += TypeSizes.INT_SIZE; if (size > 0) // non-null return -1; } @@ -217,63 +224,71 @@ public class TupleType extends AbstractType if (input.hasRemaining()) { throw new InvalidRequestException(String.format( - "Expected %s %s for %s column, but got more", - size(), size() == 1 ? "value" : "values", this.asCQL3Type())); + "Expected %s %s for %s column, but got more", + size(), size() == 1 ? "value" : "values", this.asCQL3Type())); } return components; } - public static ByteBuffer buildValue(ByteBuffer[] components) + public static V buildValue(ValueAccessor accessor, V[] components) { int totalLength = 0; - for (ByteBuffer component : components) - totalLength += 4 + (component == null ? 0 : component.remaining()); + for (V component : components) + totalLength += 4 + (component == null ? 0 : accessor.size(component)); - ByteBuffer result = ByteBuffer.allocate(totalLength); - for (ByteBuffer component : components) + int offset = 0; + V result = accessor.allocate(totalLength); + for (V component : components) { if (component == null) { - result.putInt(-1); + offset += accessor.putInt(result, offset, -1); + } else { - result.putInt(component.remaining()); - result.put(component.duplicate()); + offset += accessor.putInt(result, offset, accessor.size(component)); + offset += accessor.copyTo(component, 0, result, accessor, offset, accessor.size(component)); } } - result.rewind(); return result; } - @Override - public String getString(ByteBuffer value) + public static ByteBuffer buildValue(ByteBuffer[] components) { - if (value == null) + return buildValue(ByteBufferAccessor.instance, components); + } + + @Override + public String getString(V input, ValueAccessor accessor) + { + if (input == null) return "null"; StringBuilder sb = new StringBuilder(); - ByteBuffer input = value.duplicate(); + int offset = 0; for (int i = 0; i < size(); i++) { - if (!input.hasRemaining()) + if (accessor.isEmptyFromOffset(input, offset)) return sb.toString(); if (i > 0) sb.append(":"); AbstractType type = type(i); - int size = input.getInt(); + int size = accessor.getInt(input, offset); + offset += TypeSizes.INT_SIZE; if (size < 0) { sb.append("@"); continue; } - ByteBuffer field = ByteBufferUtil.readBytes(input, size); + V field = accessor.slice(input, offset, size); + offset += size; // We use ':' as delimiter, and @ to represent null, so escape them in the generated string - String fld = COLON_PAT.matcher(type.getString(field)).replaceAll(ESCAPED_COLON); + String fld = COLON_PAT.matcher(type.getString(field, accessor)).replaceAll(ESCAPED_COLON); fld = AT_PAT.matcher(fld).replaceAll(ESCAPED_AT); sb.append(fld); } @@ -344,13 +359,15 @@ public class TupleType extends AbstractType public String toJSONString(ByteBuffer buffer, ProtocolVersion protocolVersion) { ByteBuffer duplicated = buffer.duplicate(); + int offset = 0; StringBuilder sb = new StringBuilder("["); for (int i = 0; i < types.size(); i++) { if (i > 0) sb.append(", "); - ByteBuffer value = CollectionSerializer.readValue(duplicated, protocolVersion); + ByteBuffer value = CollectionSerializer.readValue(duplicated, ByteBufferAccessor.instance, offset, protocolVersion); + offset += CollectionSerializer.sizeOfValue(value, ByteBufferAccessor.instance, protocolVersion); if (value == null) sb.append("null"); else diff --git a/src/java/org/apache/cassandra/db/marshal/UTF8Type.java b/src/java/org/apache/cassandra/db/marshal/UTF8Type.java index 46e0d90f04..db62b577be 100644 --- a/src/java/org/apache/cassandra/db/marshal/UTF8Type.java +++ b/src/java/org/apache/cassandra/db/marshal/UTF8Type.java @@ -43,7 +43,6 @@ public class UTF8Type extends AbstractType return decompose(source); } - @Override public Term fromJSONObject(Object parsed) throws MarshalException { diff --git a/src/java/org/apache/cassandra/db/marshal/UUIDType.java b/src/java/org/apache/cassandra/db/marshal/UUIDType.java index 27e33605f8..55ce59dae7 100644 --- a/src/java/org/apache/cassandra/db/marshal/UUIDType.java +++ b/src/java/org/apache/cassandra/db/marshal/UUIDType.java @@ -56,24 +56,22 @@ public class UUIDType extends AbstractType return true; } - public int compareCustom(ByteBuffer b1, ByteBuffer b2) + public int compareCustom(VL left, ValueAccessor accessorL, VR right, ValueAccessor accessorR) { - // Compare for length - int s1 = b1.position(), s2 = b2.position(); - int l1 = b1.limit(), l2 = b2.limit(); - // should we assert exactly 16 bytes (or 0)? seems prudent - boolean p1 = l1 - s1 == 16, p2 = l2 - s2 == 16; + // Compare for length + boolean p1 = accessorL.size(left) == 16, p2 = accessorR.size(right) == 16; if (!(p1 & p2)) { - assert p1 | (l1 == s1); - assert p2 | (l2 == s2); + // should we assert exactly 16 bytes (or 0)? seems prudent + assert p1 || accessorL.isEmpty(left); + assert p2 || accessorR.isEmpty(right); return p1 ? 1 : p2 ? -1 : 0; } // Compare versions - long msb1 = b1.getLong(s1); - long msb2 = b2.getLong(s2); + long msb1 = accessorL.getLong(left, 0); + long msb2 = accessorR.getLong(right, 0); int version1 = (int) ((msb1 >>> 12) & 0xf); int version2 = (int) ((msb2 >>> 12) & 0xf); @@ -98,7 +96,7 @@ public class UUIDType extends AbstractType return c; } - return UnsignedLongs.compare(b1.getLong(s1 + 8), b2.getLong(s2 + 8)); + return UnsignedLongs.compare(accessorL.getLong(left, 8), accessorR.getLong(right, 8)); } @Override diff --git a/src/java/org/apache/cassandra/db/marshal/UserType.java b/src/java/org/apache/cassandra/db/marshal/UserType.java index dfc726d9a1..f3cd7d7ad5 100644 --- a/src/java/org/apache/cassandra/db/marshal/UserType.java +++ b/src/java/org/apache/cassandra/db/marshal/UserType.java @@ -167,7 +167,7 @@ public class UserType extends TupleType implements SchemaElement return ShortType.instance; } - public ByteBuffer serializeForNativeProtocol(Iterator cells, ProtocolVersion protocolVersion) + public ByteBuffer serializeForNativeProtocol(Iterator> cells, ProtocolVersion protocolVersion) { assert isMultiCell; @@ -175,14 +175,14 @@ public class UserType extends TupleType implements SchemaElement short fieldPosition = 0; while (cells.hasNext()) { - Cell cell = cells.next(); + Cell cell = cells.next(); // handle null fields that aren't at the end short fieldPositionOfCell = ByteBufferUtil.toShort(cell.path().get(0)); while (fieldPosition < fieldPositionOfCell) components[fieldPosition++] = null; - components[fieldPosition++] = cell.value(); + components[fieldPosition++] = cell.buffer(); } // append trailing nulls for missing cells @@ -192,18 +192,18 @@ public class UserType extends TupleType implements SchemaElement return TupleType.buildValue(components); } - public void validateCell(Cell cell) throws MarshalException + public void validateCell(Cell cell) throws MarshalException { if (isMultiCell) { ByteBuffer path = cell.path().get(0); nameComparator().validate(path); Short fieldPosition = nameComparator().getSerializer().deserialize(path); - fieldType(fieldPosition).validate(cell.value()); + fieldType(fieldPosition).validate(cell.value(), cell.accessor()); } else { - validate(cell.value()); + validate(cell.value(), cell.accessor()); } } @@ -389,9 +389,9 @@ public class UserType extends TupleType implements SchemaElement } @Override - public boolean referencesUserType(ByteBuffer name) + public boolean referencesUserType(V name, ValueAccessor accessor) { - return this.name.equals(name) || any(fieldTypes(), t -> t.referencesUserType(name)); + return this.name.equals(name) || any(fieldTypes(), t -> t.referencesUserType(name, accessor)); } @Override diff --git a/src/java/org/apache/cassandra/db/marshal/ValueAccessor.java b/src/java/org/apache/cassandra/db/marshal/ValueAccessor.java new file mode 100644 index 0000000000..8ab1569385 --- /dev/null +++ b/src/java/org/apache/cassandra/db/marshal/ValueAccessor.java @@ -0,0 +1,418 @@ +/* + * 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.db.marshal; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.charset.CharacterCodingException; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.UUID; + +import org.apache.cassandra.db.Clustering; +import org.apache.cassandra.db.ClusteringBound; +import org.apache.cassandra.db.ClusteringBoundOrBoundary; +import org.apache.cassandra.db.ClusteringBoundary; +import org.apache.cassandra.db.ClusteringPrefix; +import org.apache.cassandra.db.Digest; +import org.apache.cassandra.db.TypeSizes; +import org.apache.cassandra.db.rows.Cell; +import org.apache.cassandra.db.rows.CellPath; +import org.apache.cassandra.io.util.DataInputPlus; +import org.apache.cassandra.io.util.DataOutputPlus; +import org.apache.cassandra.schema.ColumnMetadata; + +import static org.apache.cassandra.db.ClusteringPrefix.Kind.*; + +/** + * ValueAccessor allows serializers and other code dealing with raw bytes to operate on different backing types + * (ie: byte arrays, byte buffers, etc) without requiring that the supported backing types share a common type + * ancestor and without incuring the allocation cost of a wrapper object. + * + * A note on byte buffers for implementors: the "value" of a byte buffer is always interpreted as beginning at + * it's {@link ByteBuffer#position()} and having a length of {@link ByteBuffer#remaining()}. ValueAccessor + * implementations need to maintain this internally. ValueAccessors should also never modify the state of the + * byte buffers view (ie: offset, limit). This would also apply to value accessors for simlilar types + * (ie: netty's ByteBuf}. + * + * @param the backing type + */ +public interface ValueAccessor +{ + + /** + * Creates db objects using the given accessors value type. ObjectFactory instances are meant to be returned + * by the factory() method of a value accessor. + * @param the backing type + */ + public interface ObjectFactory + { + Cell cell(ColumnMetadata column, long timestamp, int ttl, int localDeletionTime, V value, CellPath path); + Clustering clustering(V... values); + Clustering clustering(); + ClusteringBound bound(ClusteringPrefix.Kind kind, V... values); + ClusteringBound bound(ClusteringPrefix.Kind kind); + ClusteringBoundary boundary(ClusteringPrefix.Kind kind, V... values); + default ClusteringBoundOrBoundary boundOrBoundary(ClusteringPrefix.Kind kind, V... values) + { + return kind.isBoundary() ? boundary(kind, values) : bound(kind, values); + } + + default ClusteringBound inclusiveOpen(boolean reversed, V[] boundValues) + { + return bound(reversed ? INCL_END_BOUND : INCL_START_BOUND, boundValues); + } + + default ClusteringBound exclusiveOpen(boolean reversed, V[] boundValues) + { + return bound(reversed ? EXCL_END_BOUND : EXCL_START_BOUND, boundValues); + } + + default ClusteringBound inclusiveClose(boolean reversed, V[] boundValues) + { + return bound(reversed ? INCL_START_BOUND : INCL_END_BOUND, boundValues); + } + + default ClusteringBound exclusiveClose(boolean reversed, V[] boundValues) + { + return bound(reversed ? EXCL_START_BOUND : EXCL_END_BOUND, boundValues); + } + + default ClusteringBoundary inclusiveCloseExclusiveOpen(boolean reversed, V[] boundValues) + { + return boundary(reversed ? EXCL_END_INCL_START_BOUNDARY : INCL_END_EXCL_START_BOUNDARY, boundValues); + } + + default ClusteringBoundary exclusiveCloseInclusiveOpen(boolean reversed, V[] boundValues) + { + return boundary(reversed ? INCL_END_EXCL_START_BOUNDARY : EXCL_END_INCL_START_BOUNDARY, boundValues); + } + + } + /** + * @return the size of the given value + */ + int size(V value); + + /** serializes size including a vint length prefix */ + default int sizeWithVIntLength(V value) + { + int size = size(value); + return TypeSizes.sizeofUnsignedVInt(size) + size; + } + + /** serialized size including a short length prefix */ + default int sizeWithShortLength(V value) + { + return 2 + size(value); + } + + /** + * @return true if the size of the given value is zero, false otherwise + */ + default boolean isEmpty(V value) + { + return size(value) == 0; + } + + /** + * @return the number of bytes remaining in the value from the given offset + */ + default int sizeFromOffset(V value, int offset) + { + return size(value) - offset; + } + + /** + * @return true if there are no bytes present after the given offset, false otherwise + */ + default boolean isEmptyFromOffset(V value, int offset) + { + return sizeFromOffset(value, offset) == 0; + } + + /** + * allocate an instance of the accessors backing type + * @param length size of backing typ to allocate + */ + V[] createArray(int length); + + /** + * Write the contents of the given value into the a DataOutputPlus + */ + void write(V value, DataOutputPlus out) throws IOException; + + default void writeWithVIntLength(V value, DataOutputPlus out) throws IOException + { + out.writeUnsignedVInt(size(value)); + write(value, out); + } + + /** + * Write the contents of the given value into the ByteBuffer + */ + void write(V value, ByteBuffer out); + + /** + * copy the {@param size} bytes from the {@param src} value, starting at the offset {@param srcOffset} into + * the {@param dst} value, starting at the offset {@param dstOffset}, using the accessor {@param dstAccessor} + * @param the destination value type + * @return the number of bytes copied ({@param size}) + */ + int copyTo(V src, int srcOffset, V2 dst, ValueAccessor dstAccessor, int dstOffset, int size); + + /** + * copies a byte array into this accessors value. + */ + int copyByteArrayTo(byte[] src, int srcOffset, V dst, int dstOffset, int size); + + /** + * copies a byte buffer into this accessors value. + */ + int copyByteBufferTo(ByteBuffer src, int srcOffset, V dst, int dstOffset, int size); + + /** + * updates {@param digest} with {@param size} bytes from the contents of {@param value} starting + * at offset {@param offset} + */ + void digest(V value, int offset, int size, Digest digest); + + /** + * updates {@param digest} with te contents of {@param value} + */ + default void digest(V value, Digest digest) + { + digest(value, 0, size(value), digest); + } + + /** + * Reads a value of {@param length} bytes from {@param in} + */ + V read(DataInputPlus in, int length) throws IOException; + + /** + * Returns a value with the contents of {@param input} from {@param offset} to {@param length}. + * + * Depending on the accessor implementation, this method may: + * * allocate a new {@param } object of {@param length}, and copy data into it + * * return a view of {@param input} where changes to one will be reflected in the other + */ + V slice(V input, int offset, int length); + + /** + * same as {@link ValueAccessor#slice(Object, int, int)}, except the length is taked from the first + * 2 bytes from the given offset (and not included in the return value) + */ + default V sliceWithShortLength(V input, int offset) + { + int size = getShort(input, offset); + return slice(input, offset + 2, size); + } + + /** + * @return a short length prefix starting at {@param offset} + */ + default int getShortLength(V v, int offset) + { + return getShort(v, offset); + } + + /** + * lexicographically compare {@param left} to {@param right} + * @param backing type of + */ + int compare(V left, VR right, ValueAccessor accessorR); + + /** + * compare a byte array on the left with a {@param } on the right} + */ + int compareByteArrayTo(byte[] left, V right); + + /** + * compare a byte buffer on the left with a {@param } on the right} + */ + int compareByteBufferTo(ByteBuffer left, V right); + + default int hashCode(V value) + { + if (value == null) + return 0; + + int result = 1; + for (int i=0, isize=size(value); i} + * + * {@param src} and the returned value may share a common byte array instance, so caller should + * assume that modifying the returned value will also modify the contents of {@param src} + */ + V convert(V2 src, ValueAccessor accessor); + + /** + * Allocate and return a {@param } instance of {@param size} bytes on the heap. + */ + V allocate(int size); + + /** + * returns the {@link ValueAccessor.ObjectFactory} for the backing type {@param } + */ + ObjectFactory factory(); + + /** + * lexicographically compare {@param left} to {@param right} + */ + public static int compare(L left, ValueAccessor leftAccessor, R right, ValueAccessor rightAccessor) + { + return leftAccessor.compare(left, right, rightAccessor); + } + + public static boolean equals(L left, ValueAccessor leftAccessor, R right, ValueAccessor rightAccessor) + { + return compare(left, leftAccessor, right, rightAccessor) == 0; + } +} diff --git a/src/java/org/apache/cassandra/db/marshal/ValueComparators.java b/src/java/org/apache/cassandra/db/marshal/ValueComparators.java new file mode 100644 index 0000000000..d7180327c6 --- /dev/null +++ b/src/java/org/apache/cassandra/db/marshal/ValueComparators.java @@ -0,0 +1,43 @@ +/* + * 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.db.marshal; + +import java.nio.ByteBuffer; +import java.util.Comparator; + +public class ValueComparators +{ + public final Comparator array; + public final Comparator buffer; + + public ValueComparators(Comparator array, Comparator buffer) + { + this.array = array; + this.buffer = buffer; + } + + public Comparator getForAccessor(ValueAccessor accessor) + { + if (accessor == ByteArrayAccessor.instance) + return array; + if (accessor == ByteBufferAccessor.instance) + return buffer; + throw new UnsupportedOperationException("Unsupported accessor: " + accessor.getClass().getName()); + } +} diff --git a/src/java/org/apache/cassandra/db/partitions/AbstractBTreePartition.java b/src/java/org/apache/cassandra/db/partitions/AbstractBTreePartition.java index fc50de6e21..3059eb4100 100644 --- a/src/java/org/apache/cassandra/db/partitions/AbstractBTreePartition.java +++ b/src/java/org/apache/cassandra/db/partitions/AbstractBTreePartition.java @@ -106,7 +106,7 @@ public abstract class AbstractBTreePartition implements Partition, Iterable return holder().stats; } - public Row getRow(Clustering clustering) + public Row getRow(Clustering clustering) { Row row = searchIterator(ColumnFilter.selection(columns()), false).next(clustering); // Note that for statics, this will never return null, this will return an empty row. However, @@ -124,16 +124,16 @@ public abstract class AbstractBTreePartition implements Partition, Iterable return row == null ? Rows.EMPTY_STATIC_ROW : row; } - public SearchIterator searchIterator(final ColumnFilter columns, final boolean reversed) + public SearchIterator, Row> searchIterator(final ColumnFilter columns, final boolean reversed) { // TODO: we could optimize comparison for "NativeRow" à la #6755 final Holder current = holder(); - return new SearchIterator() + return new SearchIterator, Row>() { private final SearchIterator rawIter = BTree.slice(current.tree, metadata().comparator, desc(reversed)); private final DeletionTime partitionDeletion = current.deletionInfo.getPartitionDeletion(); - public Row next(Clustering clustering) + public Row next(Clustering clustering) { if (clustering == Clustering.STATIC_CLUSTERING) return staticRow(current, columns, true); @@ -189,8 +189,8 @@ public abstract class AbstractBTreePartition implements Partition, Iterable private UnfilteredRowIterator sliceIterator(ColumnFilter selection, Slice slice, boolean reversed, Holder current, Row staticRow) { - ClusteringBound start = slice.start() == ClusteringBound.BOTTOM ? null : slice.start(); - ClusteringBound end = slice.end() == ClusteringBound.TOP ? null : slice.end(); + ClusteringBound start = slice.start().isBottom() ? null : slice.start(); + ClusteringBound end = slice.end().isTop() ? null : slice.end(); Iterator rowIter = BTree.slice(current.tree, metadata().comparator, start, true, end, true, desc(reversed)); Iterator deleteIter = current.deletionInfo.rangeIterator(slice, reversed); return merge(rowIter, deleteIter, selection, reversed, current, staticRow); diff --git a/src/java/org/apache/cassandra/db/partitions/AtomicBTreePartition.java b/src/java/org/apache/cassandra/db/partitions/AtomicBTreePartition.java index 486bec7410..ca20e5f434 100644 --- a/src/java/org/apache/cassandra/db/partitions/AtomicBTreePartition.java +++ b/src/java/org/apache/cassandra/db/partitions/AtomicBTreePartition.java @@ -212,7 +212,7 @@ public final class AtomicBTreePartition extends AbstractBTreePartition } @Override - public Row getRow(Clustering clustering) + public Row getRow(Clustering clustering) { return allocator.ensureOnHeap().applyToRow(super.getRow(clustering)); } @@ -224,7 +224,7 @@ public final class AtomicBTreePartition extends AbstractBTreePartition } @Override - public SearchIterator searchIterator(ColumnFilter columns, boolean reversed) + public SearchIterator, Row> searchIterator(ColumnFilter columns, boolean reversed) { return allocator.ensureOnHeap().applyToPartition(super.searchIterator(columns, reversed)); } @@ -352,7 +352,7 @@ public final class AtomicBTreePartition extends AbstractBTreePartition this.indexer = indexer; } - private Row.Builder builder(Clustering clustering) + private Row.Builder builder(Clustering clustering) { boolean isStatic = clustering == Clustering.STATIC_CLUSTERING; // We know we only insert/update one static per PartitionUpdate, so no point in saving the builder diff --git a/src/java/org/apache/cassandra/db/partitions/CachedBTreePartition.java b/src/java/org/apache/cassandra/db/partitions/CachedBTreePartition.java index 9a2b331515..2183a9852a 100644 --- a/src/java/org/apache/cassandra/db/partitions/CachedBTreePartition.java +++ b/src/java/org/apache/cassandra/db/partitions/CachedBTreePartition.java @@ -92,7 +92,7 @@ public class CachedBTreePartition extends ImmutableBTreePartition implements Cac ++cachedLiveRows; boolean hasNonExpiringLiveCell = false; - for (Cell cell : row.cells()) + for (Cell cell : row.cells()) { if (!cell.isTombstone() && !cell.isExpiring()) { diff --git a/src/java/org/apache/cassandra/db/partitions/Partition.java b/src/java/org/apache/cassandra/db/partitions/Partition.java index baeb6d5830..2ee9c6d5a3 100644 --- a/src/java/org/apache/cassandra/db/partitions/Partition.java +++ b/src/java/org/apache/cassandra/db/partitions/Partition.java @@ -50,12 +50,12 @@ public interface Partition /** * Returns the row corresponding to the provided clustering, or null if there is not such row. */ - public Row getRow(Clustering clustering); + public Row getRow(Clustering clustering); /** * Returns an iterator that allows to search specific rows efficiently. */ - public SearchIterator searchIterator(ColumnFilter columns, boolean reversed); + public SearchIterator, Row> searchIterator(ColumnFilter columns, boolean reversed); /** * Returns an UnfilteredRowIterator over all the rows/RT contained by this partition. diff --git a/src/java/org/apache/cassandra/db/partitions/PartitionStatisticsCollector.java b/src/java/org/apache/cassandra/db/partitions/PartitionStatisticsCollector.java index 510b9c8294..6d37640146 100644 --- a/src/java/org/apache/cassandra/db/partitions/PartitionStatisticsCollector.java +++ b/src/java/org/apache/cassandra/db/partitions/PartitionStatisticsCollector.java @@ -24,7 +24,7 @@ public interface PartitionStatisticsCollector { public void update(LivenessInfo info); public void update(DeletionTime deletionTime); - public void update(Cell cell); + public void update(Cell cell); public void updateColumnSetPerRow(long columnSetInRow); public void updateHasLegacyCounterShards(boolean hasLegacyCounterShards); } diff --git a/src/java/org/apache/cassandra/db/partitions/PartitionUpdate.java b/src/java/org/apache/cassandra/db/partitions/PartitionUpdate.java index 076c975a54..0bf45b0b0f 100644 --- a/src/java/org/apache/cassandra/db/partitions/PartitionUpdate.java +++ b/src/java/org/apache/cassandra/db/partitions/PartitionUpdate.java @@ -395,13 +395,13 @@ public class PartitionUpdate extends AbstractBTreePartition { if (cd.column().isSimple()) { - maxTimestamp = Math.max(maxTimestamp, ((Cell)cd).timestamp()); + maxTimestamp = Math.max(maxTimestamp, ((Cell)cd).timestamp()); } else { ComplexColumnData complexData = (ComplexColumnData)cd; maxTimestamp = Math.max(maxTimestamp, complexData.complexDeletion().markedForDeleteAt()); - for (Cell cell : complexData) + for (Cell cell : complexData) maxTimestamp = Math.max(maxTimestamp, cell.timestamp()); } } @@ -413,13 +413,13 @@ public class PartitionUpdate extends AbstractBTreePartition { if (cd.column().isSimple()) { - maxTimestamp = Math.max(maxTimestamp, ((Cell) cd).timestamp()); + maxTimestamp = Math.max(maxTimestamp, ((Cell) cd).timestamp()); } else { ComplexColumnData complexData = (ComplexColumnData) cd; maxTimestamp = Math.max(maxTimestamp, complexData.complexDeletion().markedForDeleteAt()); - for (Cell cell : complexData) + for (Cell cell : complexData) maxTimestamp = Math.max(maxTimestamp, cell.timestamp()); } } @@ -447,7 +447,7 @@ public class PartitionUpdate extends AbstractBTreePartition private static void addMarksForRow(Row row, List marks) { - for (Cell cell : row.cells()) + for (Cell cell : row.cells()) { if (cell.isCounterCell()) marks.add(new CounterMark(row, cell.column(), cell.path())); @@ -695,7 +695,7 @@ public class PartitionUpdate extends AbstractBTreePartition this.path = path; } - public Clustering clustering() + public Clustering clustering() { return row.clustering(); } @@ -713,8 +713,8 @@ public class PartitionUpdate extends AbstractBTreePartition public ByteBuffer value() { return path == null - ? row.getCell(column).value() - : row.getCell(column, path).value(); + ? row.getCell(column).buffer() + : row.getCell(column, path).buffer(); } public void setValue(ByteBuffer value) diff --git a/src/java/org/apache/cassandra/db/rows/AbstractCell.java b/src/java/org/apache/cassandra/db/rows/AbstractCell.java index 3f2da966e8..5d4fc3c19e 100644 --- a/src/java/org/apache/cassandra/db/rows/AbstractCell.java +++ b/src/java/org/apache/cassandra/db/rows/AbstractCell.java @@ -26,6 +26,7 @@ import org.apache.cassandra.db.TypeSizes; import org.apache.cassandra.db.context.CounterContext; import org.apache.cassandra.db.marshal.AbstractType; import org.apache.cassandra.db.marshal.CollectionType; +import org.apache.cassandra.db.marshal.ValueAccessor; import org.apache.cassandra.schema.ColumnMetadata; import org.apache.cassandra.serializers.MarshalException; import org.apache.cassandra.utils.ByteBufferUtil; @@ -37,7 +38,7 @@ import org.apache.cassandra.utils.memory.AbstractAllocator; * Unless you have a very good reason not to, every cell implementation * should probably extend this class. */ -public abstract class AbstractCell extends Cell +public abstract class AbstractCell extends Cell { protected AbstractCell(ColumnMetadata column) { @@ -64,17 +65,17 @@ public abstract class AbstractCell extends Cell return ttl() != NO_TTL; } - public Cell markCounterLocalToBeCleared() + public Cell markCounterLocalToBeCleared() { if (!isCounterCell()) return this; - ByteBuffer value = value(); + ByteBuffer value = buffer(); ByteBuffer marked = CounterContext.instance().markLocalToBeCleared(value); return marked == value ? this : new BufferCell(column, timestamp(), ttl(), localDeletionTime(), marked, path()); } - public Cell purge(DeletionPurger purger, int nowInSec) + public Cell purge(DeletionPurger purger, int nowInSec) { if (!isLive(nowInSec)) { @@ -97,16 +98,16 @@ public abstract class AbstractCell extends Cell return this; } - public Cell copy(AbstractAllocator allocator) + public Cell copy(AbstractAllocator allocator) { CellPath path = path(); - return new BufferCell(column, timestamp(), ttl(), localDeletionTime(), allocator.clone(value()), path == null ? null : path.copy(allocator)); + return new BufferCell(column, timestamp(), ttl(), localDeletionTime(), allocator.clone(buffer()), path == null ? null : path.copy(allocator)); } // note: while the cell returned may be different, the value is the same, so if the value is offheap it must be referenced inside a guarded context (or copied) - public Cell updateAllTimestamp(long newTimestamp) + public Cell updateAllTimestamp(long newTimestamp) { - return new BufferCell(column, isTombstone() ? newTimestamp - 1 : newTimestamp, ttl(), localDeletionTime(), value(), path()); + return new BufferCell(column, isTombstone() ? newTimestamp - 1 : newTimestamp, ttl(), localDeletionTime(), buffer(), path()); } public int dataSize() @@ -115,16 +116,16 @@ public abstract class AbstractCell extends Cell return TypeSizes.sizeof(timestamp()) + TypeSizes.sizeof(ttl()) + TypeSizes.sizeof(localDeletionTime()) - + value().remaining() + + valueSize() + (path == null ? 0 : path.dataSize()); } public void digest(Digest digest) { if (isCounterCell()) - digest.updateWithCounterContext(value()); + digest.updateWithCounterContext(value(), accessor()); else - digest.update(value()); + digest.update(value(), accessor()); digest.updateWithLong(timestamp()) .updateWithInt(ttl()) @@ -161,6 +162,17 @@ public abstract class AbstractCell extends Cell return timestamp(); } + public static boolean equals(Cell left, Cell right) + { + return left.column().equals(right.column()) + && left.isCounterCell() == right.isCounterCell() + && left.timestamp() == right.timestamp() + && left.ttl() == right.ttl() + && left.localDeletionTime() == right.localDeletionTime() + && ValueAccessor.equals(left.value(), left.accessor(), right.value(), right.accessor()) + && Objects.equals(left.path(), right.path()); + } + @Override public boolean equals(Object other) { @@ -170,27 +182,20 @@ public abstract class AbstractCell extends Cell if(!(other instanceof Cell)) return false; - Cell that = (Cell)other; - return this.column().equals(that.column()) - && this.isCounterCell() == that.isCounterCell() - && this.timestamp() == that.timestamp() - && this.ttl() == that.ttl() - && this.localDeletionTime() == that.localDeletionTime() - && Objects.equals(this.value(), that.value()) - && Objects.equals(this.path(), that.path()); + return equals(this, (Cell) other); } @Override public int hashCode() { - return Objects.hash(column(), isCounterCell(), timestamp(), ttl(), localDeletionTime(), value(), path()); + return Objects.hash(column(), isCounterCell(), timestamp(), ttl(), localDeletionTime(), accessor().hashCode(value()), path()); } @Override public String toString() { if (isCounterCell()) - return String.format("[%s=%d ts=%d]", column().name, CounterContext.instance().total(value()), timestamp()); + return String.format("[%s=%d ts=%d]", column().name, CounterContext.instance().total(value(), accessor()), timestamp()); AbstractType type = column().type; if (type instanceof CollectionType && type.isMultiCell()) @@ -199,24 +204,24 @@ public abstract class AbstractCell extends Cell return String.format("[%s[%s]=%s %s]", column().name, ct.nameComparator().getString(path().get(0)), - ct.valueComparator().getString(value()), + ct.valueComparator().getString(value(), accessor()), livenessInfoString()); } if (isTombstone()) return String.format("[%s= %s]", column().name, livenessInfoString()); else - return String.format("[%s=%s %s]", column().name, safeToString(type, value()), livenessInfoString()); + return String.format("[%s=%s %s]", column().name, safeToString(type), livenessInfoString()); } - private static String safeToString(AbstractType type, ByteBuffer data) + private String safeToString(AbstractType type) { try { - return type.getString(data); + return type.getString(value(), accessor()); } catch (Exception e) { - return "0x" + ByteBufferUtil.bytesToHex(data); + return "0x" + ByteBufferUtil.bytesToHex(buffer()); } } diff --git a/src/java/org/apache/cassandra/db/rows/AbstractRangeTombstoneMarker.java b/src/java/org/apache/cassandra/db/rows/AbstractRangeTombstoneMarker.java index a7c48c139a..7dac1fae70 100644 --- a/src/java/org/apache/cassandra/db/rows/AbstractRangeTombstoneMarker.java +++ b/src/java/org/apache/cassandra/db/rows/AbstractRangeTombstoneMarker.java @@ -22,7 +22,7 @@ import java.nio.ByteBuffer; import org.apache.cassandra.schema.TableMetadata; import org.apache.cassandra.db.ClusteringBoundOrBoundary; -public abstract class AbstractRangeTombstoneMarker implements RangeTombstoneMarker +public abstract class AbstractRangeTombstoneMarker> implements RangeTombstoneMarker { protected final B bound; @@ -58,12 +58,10 @@ public abstract class AbstractRangeTombstoneMarker bound = clustering(); for (int i = 0; i < bound.size(); i++) { - ByteBuffer value = bound.get(i); - if (value != null) - metadata.comparator.subtype(i).validate(value); + bound.validate(i, metadata.comparator); } } diff --git a/src/java/org/apache/cassandra/db/rows/AbstractRow.java b/src/java/org/apache/cassandra/db/rows/AbstractRow.java index fc90e34038..74f111a4ed 100644 --- a/src/java/org/apache/cassandra/db/rows/AbstractRow.java +++ b/src/java/org/apache/cassandra/db/rows/AbstractRow.java @@ -16,7 +16,6 @@ */ package org.apache.cassandra.db.rows; -import java.nio.ByteBuffer; import java.util.Objects; import java.util.function.Function; import java.util.stream.Collectors; @@ -24,6 +23,7 @@ import java.util.stream.StreamSupport; import com.google.common.collect.Iterables; +import org.apache.cassandra.db.marshal.ValueAccessor; import org.apache.cassandra.db.Clustering; import org.apache.cassandra.db.Digest; import org.apache.cassandra.db.marshal.CollectionType; @@ -70,17 +70,17 @@ public abstract class AbstractRow implements Row apply(ColumnData::digest, digest); } - public void validateData(TableMetadata metadata) + private void validateClustering(TableMetadata metadata, Clustering clustering) { - Clustering clustering = clustering(); + ValueAccessor accessor = clustering.accessor(); for (int i = 0; i < clustering.size(); i++) { - ByteBuffer value = clustering.get(i); + V value = clustering.get(i); if (value != null) { try { - metadata.comparator.subtype(i).validate(value); + metadata.comparator.subtype(i).validate(value, accessor); } catch (Exception e) { @@ -88,6 +88,11 @@ public abstract class AbstractRow implements Row } } } + } + + public void validateData(TableMetadata metadata) + { + validateClustering(metadata, clustering()); primaryKeyLivenessInfo().validate(); if (deletion().time().localDeletionTime() < 0) @@ -155,7 +160,7 @@ public abstract class AbstractRow implements Row ComplexColumnData complexData = (ComplexColumnData)cd; if (!complexData.complexDeletion().isLive()) sb.append("del(").append(cd.column().name).append(")=").append(complexData.complexDeletion()); - for (Cell cell : complexData) + for (Cell cell : complexData) sb.append(", ").append(cell); } } @@ -163,24 +168,24 @@ public abstract class AbstractRow implements Row { if (cd.column().isSimple()) { - Cell cell = (Cell)cd; + Cell cell = (Cell)cd; sb.append(cell.column().name).append('='); if (cell.isTombstone()) sb.append(""); else - sb.append(cell.column().type.getString(cell.value())); + sb.append(Cells.valueString(cell)); } else { sb.append(cd.column().name).append('='); ComplexColumnData complexData = (ComplexColumnData) cd; - Function transform = null; + Function, String> transform = null; if (cd.column().type.isCollection()) { CollectionType ct = (CollectionType) cd.column().type; transform = cell -> String.format("%s -> %s", ct.nameComparator().getString(cell.path().get(0)), - ct.valueComparator().getString(cell.value())); + Cells.valueString(cell, ct.valueComparator())); } else if (cd.column().type.isUDT()) @@ -190,7 +195,7 @@ public abstract class AbstractRow implements Row Short fId = ut.nameComparator().getSerializer().deserialize(cell.path().get(0)); return String.format("%s -> %s", ut.fieldNameAsString(fId), - ut.fieldType(fId).getString(cell.value())); + Cells.valueString(cell, ut.fieldType(fId))); }; } else diff --git a/src/java/org/apache/cassandra/db/rows/ArrayCell.java b/src/java/org/apache/cassandra/db/rows/ArrayCell.java new file mode 100644 index 0000000000..5911e42eda --- /dev/null +++ b/src/java/org/apache/cassandra/db/rows/ArrayCell.java @@ -0,0 +1,111 @@ +/* + * 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.db.rows; + +import java.nio.ByteBuffer; + +import org.apache.cassandra.db.ExpirationDateOverflowHandling; +import org.apache.cassandra.db.marshal.ByteArrayAccessor; +import org.apache.cassandra.db.marshal.ByteType; +import org.apache.cassandra.db.marshal.ValueAccessor; +import org.apache.cassandra.schema.ColumnMetadata; +import org.apache.cassandra.utils.ByteArrayUtil; +import org.apache.cassandra.utils.ByteBufferUtil; +import org.apache.cassandra.utils.ObjectSizes; +import org.apache.cassandra.utils.memory.AbstractAllocator; + +public class ArrayCell extends AbstractCell +{ + private static final long EMPTY_SIZE = ObjectSizes.measure(new ArrayCell(ColumnMetadata.regularColumn("", "", "", ByteType.instance), 0L, 0, 0, ByteArrayUtil.EMPTY_BYTE_ARRAY, null)); + + private final long timestamp; + private final int ttl; + private final int localDeletionTime; + + private final byte[] value; + private final CellPath path; + + public ArrayCell(ColumnMetadata column, long timestamp, int ttl, int localDeletionTime, byte[] value, CellPath path) + { + super(column); + this.timestamp = timestamp; + this.ttl = ttl; + this.localDeletionTime = localDeletionTime; + this.value = value; + this.path = path; + } + + public long timestamp() + { + return timestamp; + } + + public int ttl() + { + return ttl; + } + + public int localDeletionTime() + { + return localDeletionTime; + } + + public byte[] value() + { + return value; + } + + public ValueAccessor accessor() + { + return ByteArrayAccessor.instance; + } + + public CellPath path() + { + return path; + } + + public Cell withUpdatedColumn(ColumnMetadata newColumn) + { + return new ArrayCell(newColumn, timestamp, ttl, localDeletionTime, value, path); + } + + public Cell withUpdatedValue(ByteBuffer newValue) + { + return new ArrayCell(column, timestamp, ttl, localDeletionTime, ByteBufferUtil.getArray(newValue), path); + } + + public Cell withUpdatedTimestampAndLocalDeletionTime(long newTimestamp, int newLocalDeletionTime) + { + return new ArrayCell(column, newTimestamp, ttl, newLocalDeletionTime, value, path); + } + + public Cell copy(AbstractAllocator allocator) + { + if (value.length == 0) + return this; + + return new BufferCell(column, timestamp, ttl, localDeletionTime, allocator.clone(value), path == null ? null : path.copy(allocator)); + } + + public long unsharedHeapSizeExcludingData() + { + return EMPTY_SIZE + ObjectSizes.sizeOfArray(value) + value.length + (path == null ? 0 : path.unsharedHeapSizeExcludingData()); + } +} diff --git a/src/java/org/apache/cassandra/db/rows/BTreeRow.java b/src/java/org/apache/cassandra/db/rows/BTreeRow.java index bc9e7fe767..4a03af2348 100644 --- a/src/java/org/apache/cassandra/db/rows/BTreeRow.java +++ b/src/java/org/apache/cassandra/db/rows/BTreeRow.java @@ -67,7 +67,7 @@ public class BTreeRow extends AbstractRow { private static final long EMPTY_SIZE = ObjectSizes.measure(emptyRow(Clustering.EMPTY)); - private final Clustering clustering; + private final Clustering clustering; private final LivenessInfo primaryKeyLivenessInfo; private final Deletion deletion; @@ -102,13 +102,13 @@ public class BTreeRow extends AbstractRow this.minLocalDeletionTime = minLocalDeletionTime; } - private BTreeRow(Clustering clustering, Object[] btree, int minLocalDeletionTime) + private BTreeRow(Clustering clustering, Object[] btree, int minLocalDeletionTime) { this(clustering, LivenessInfo.EMPTY, Deletion.LIVE, btree, minLocalDeletionTime); } // Note that it's often easier/safer to use the sortedBuilder/unsortedBuilder or one of the static creation method below. Only directly useful in a small amount of cases. - public static BTreeRow create(Clustering clustering, + public static BTreeRow create(Clustering clustering, LivenessInfo primaryKeyLivenessInfo, Deletion deletion, Object[] btree) @@ -123,7 +123,7 @@ public class BTreeRow extends AbstractRow return create(clustering, primaryKeyLivenessInfo, deletion, btree, minDeletionTime); } - public static BTreeRow create(Clustering clustering, + public static BTreeRow create(Clustering clustering, LivenessInfo primaryKeyLivenessInfo, Deletion deletion, Object[] btree, @@ -132,27 +132,27 @@ public class BTreeRow extends AbstractRow return new BTreeRow(clustering, primaryKeyLivenessInfo, deletion, btree, minDeletionTime); } - public static BTreeRow emptyRow(Clustering clustering) + public static BTreeRow emptyRow(Clustering clustering) { return new BTreeRow(clustering, BTree.empty(), Integer.MAX_VALUE); } - public static BTreeRow singleCellRow(Clustering clustering, Cell cell) + public static BTreeRow singleCellRow(Clustering clustering, Cell cell) { if (cell.column().isSimple()) return new BTreeRow(clustering, BTree.singleton(cell), minDeletionTime(cell)); - ComplexColumnData complexData = new ComplexColumnData(cell.column(), new Cell[]{ cell }, DeletionTime.LIVE); + ComplexColumnData complexData = new ComplexColumnData(cell.column(), new Cell[]{ cell }, DeletionTime.LIVE); return new BTreeRow(clustering, BTree.singleton(complexData), minDeletionTime(cell)); } - public static BTreeRow emptyDeletedRow(Clustering clustering, Deletion deletion) + public static BTreeRow emptyDeletedRow(Clustering clustering, Deletion deletion) { assert !deletion.isLive(); return new BTreeRow(clustering, LivenessInfo.EMPTY, deletion, BTree.empty(), Integer.MIN_VALUE); } - public static BTreeRow noCellLiveRow(Clustering clustering, LivenessInfo primaryKeyLivenessInfo) + public static BTreeRow noCellLiveRow(Clustering clustering, LivenessInfo primaryKeyLivenessInfo) { assert !primaryKeyLivenessInfo.isEmpty(); return new BTreeRow(clustering, @@ -162,7 +162,7 @@ public class BTreeRow extends AbstractRow minDeletionTime(primaryKeyLivenessInfo)); } - private static int minDeletionTime(Cell cell) + private static int minDeletionTime(Cell cell) { return cell.isTombstone() ? Integer.MIN_VALUE : cell.localDeletionTime(); } @@ -180,7 +180,7 @@ public class BTreeRow extends AbstractRow private static int minDeletionTime(ComplexColumnData cd) { int min = minDeletionTime(cd.complexDeletion()); - for (Cell cell : cd) + for (Cell cell : cd) { min = Math.min(min, minDeletionTime(cell)); if (min == Integer.MIN_VALUE) @@ -191,7 +191,7 @@ public class BTreeRow extends AbstractRow private static int minDeletionTime(ColumnData cd) { - return cd.column().isSimple() ? minDeletionTime((Cell) cd) : minDeletionTime((ComplexColumnData)cd); + return cd.column().isSimple() ? minDeletionTime((Cell) cd) : minDeletionTime((ComplexColumnData)cd); } public void apply(Consumer function) @@ -239,7 +239,7 @@ public class BTreeRow extends AbstractRow return Ints.checkedCast(min); } - public Clustering clustering() + public Clustering clustering() { return clustering; } @@ -271,13 +271,13 @@ public class BTreeRow extends AbstractRow return deletion; } - public Cell getCell(ColumnMetadata c) + public Cell getCell(ColumnMetadata c) { assert !c.isComplex(); - return (Cell) BTree.find(btree, ColumnMetadata.asymmetricColumnDataComparator, c); + return (Cell) BTree.find(btree, ColumnMetadata.asymmetricColumnDataComparator, c); } - public Cell getCell(ColumnMetadata c, CellPath path) + public Cell getCell(ColumnMetadata c, CellPath path) { assert c.isComplex(); ComplexColumnData cd = getComplexColumnData(c); @@ -307,7 +307,7 @@ public class BTreeRow extends AbstractRow return searchIterator(); } - public Iterable cells() + public Iterable> cells() { return CellIterator::new; } @@ -358,7 +358,7 @@ public class BTreeRow extends AbstractRow if (column.isComplex()) return ((ComplexColumnData) cd).filter(filter, mayHaveShadowed ? activeDeletion : DeletionTime.LIVE, dropped, rowLiveness); - Cell cell = (Cell) cd; + Cell cell = (Cell) cd; // We include the cell unless it is 1) shadowed, 2) for a dropped column or 3) skippable. // And a cell is skippable if it is for a column that is not queried by the user and its timestamp // is lower than the row timestamp (see #10657 or SerializationHelper.includes() for details). @@ -517,22 +517,22 @@ public class BTreeRow extends AbstractRow { ColumnData current = (ColumnData) BTree.find(btree, ColumnMetadata.asymmetricColumnDataComparator, column); if (column.isSimple()) - BTree.replaceInSitu(btree, ColumnData.comparator, current, ((Cell) current).withUpdatedValue(value)); + BTree.replaceInSitu(btree, ColumnData.comparator, current, ((Cell) current).withUpdatedValue(value)); else ((ComplexColumnData) current).setValue(path, value); } - public Iterable cellsInLegacyOrder(TableMetadata metadata, boolean reversed) + public Iterable> cellsInLegacyOrder(TableMetadata metadata, boolean reversed) { return () -> new CellInLegacyOrderIterator(metadata, reversed); } - private class CellIterator extends AbstractIterator + private class CellIterator extends AbstractIterator> { private Iterator columnData = iterator(); - private Iterator complexCells; + private Iterator> complexCells; - protected Cell computeNext() + protected Cell computeNext() { while (true) { @@ -551,19 +551,19 @@ public class BTreeRow extends AbstractRow if (cd.column().isComplex()) complexCells = ((ComplexColumnData)cd).iterator(); else - return (Cell)cd; + return (Cell)cd; } } } - private class CellInLegacyOrderIterator extends AbstractIterator + private class CellInLegacyOrderIterator extends AbstractIterator> { private final Comparator comparator; private final boolean reversed; private final int firstComplexIdx; private int simpleIdx; private int complexIdx; - private Iterator complexCells; + private Iterator> complexCells; private final Object[] data; private CellInLegacyOrderIterator(TableMetadata metadata, boolean reversed) @@ -605,13 +605,13 @@ public class BTreeRow extends AbstractRow return idx; } - private Iterator makeComplexIterator(Object complexData) + private Iterator> makeComplexIterator(Object complexData) { ComplexColumnData ccd = (ComplexColumnData)complexData; return reversed ? ccd.reverseIterator() : ccd.iterator(); } - protected Cell computeNext() + protected Cell computeNext() { while (true) { @@ -633,10 +633,10 @@ public class BTreeRow extends AbstractRow else { if (complexIdx >= data.length) - return (Cell)data[getSimpleIdxAndIncrement()]; + return (Cell)data[getSimpleIdxAndIncrement()]; if (comparator.compare(((ColumnData) data[getSimpleIdx()]).column().name.bytes, ((ColumnData) data[getComplexIdx()]).column().name.bytes) < 0) - return (Cell)data[getSimpleIdxAndIncrement()]; + return (Cell)data[getSimpleIdxAndIncrement()]; else complexCells = makeComplexIterator(data[getComplexIdxAndIncrement()]); } @@ -662,12 +662,12 @@ public class BTreeRow extends AbstractRow public ColumnData resolve(Object[] cells, int lb, int ub) { - Cell cell = (Cell) cells[lb]; + Cell cell = (Cell) cells[lb]; ColumnMetadata column = cell.column; if (cell.column.isSimple()) { while (++lb < ub) - cell = Cells.reconcile(cell, (Cell) cells[lb]); + cell = Cells.reconcile(cell, (Cell) cells[lb]); return cell; } @@ -681,7 +681,7 @@ public class BTreeRow extends AbstractRow // legacy sstables (see #10743). while (lb < ub) { - cell = (Cell) cells[lb]; + cell = (Cell) cells[lb]; if (!(cell instanceof ComplexColumnDeletion)) break; @@ -691,10 +691,10 @@ public class BTreeRow extends AbstractRow } List buildFrom = new ArrayList<>(ub - lb); - Cell previous = null; + Cell previous = null; for (int i = lb; i < ub; i++) { - Cell c = (Cell) cells[i]; + Cell c = (Cell) cells[i]; if (deletion == DeletionTime.LIVE || c.timestamp() >= deletion.markedForDeleteAt()) { @@ -716,12 +716,12 @@ public class BTreeRow extends AbstractRow } } - protected Clustering clustering; + protected Clustering clustering; protected LivenessInfo primaryKeyLivenessInfo = LivenessInfo.EMPTY; protected Deletion deletion = Deletion.LIVE; private final boolean isSorted; - private BTree.Builder cells_; + private BTree.Builder> cells_; private boolean hasComplex = false; // For complex column at index i of 'columns', we store at complexDeletions[i] its complex deletion. @@ -732,7 +732,7 @@ public class BTreeRow extends AbstractRow this.isSorted = isSorted; } - private BTree.Builder getCells() + private BTree.Builder> getCells() { if (cells_ == null) { @@ -763,13 +763,13 @@ public class BTreeRow extends AbstractRow return isSorted; } - public void newRow(Clustering clustering) + public void newRow(Clustering clustering) { assert this.clustering == null; // Ensures we've properly called build() if we've use this builder before this.clustering = clustering; } - public Clustering clustering() + public Clustering clustering() { return clustering; } @@ -798,7 +798,7 @@ public class BTreeRow extends AbstractRow this.primaryKeyLivenessInfo = LivenessInfo.EMPTY; } - public void addCell(Cell cell) + public void addCell(Cell cell) { assert cell.column().isStatic() == (clustering == Clustering.STATIC_CLUSTERING) : "Column is " + cell.column() + ", clustering = " + clustering; diff --git a/src/java/org/apache/cassandra/db/rows/BufferCell.java b/src/java/org/apache/cassandra/db/rows/BufferCell.java index 8bf8f7de67..786ac3c845 100644 --- a/src/java/org/apache/cassandra/db/rows/BufferCell.java +++ b/src/java/org/apache/cassandra/db/rows/BufferCell.java @@ -20,13 +20,15 @@ package org.apache.cassandra.db.rows; import java.nio.ByteBuffer; import org.apache.cassandra.db.ExpirationDateOverflowHandling; +import org.apache.cassandra.db.marshal.ByteBufferAccessor; +import org.apache.cassandra.db.marshal.ValueAccessor; import org.apache.cassandra.schema.ColumnMetadata; import org.apache.cassandra.db.marshal.ByteType; import org.apache.cassandra.utils.ByteBufferUtil; import org.apache.cassandra.utils.ObjectSizes; import org.apache.cassandra.utils.memory.AbstractAllocator; -public class BufferCell extends AbstractCell +public class BufferCell extends AbstractCell { private static final long EMPTY_SIZE = ObjectSizes.measure(new BufferCell(ColumnMetadata.regularColumn("", "", "", ByteType.instance), 0L, 0, 0, ByteBufferUtil.EMPTY_BYTE_BUFFER, null)); @@ -100,27 +102,32 @@ public class BufferCell extends AbstractCell return value; } + public ValueAccessor accessor() + { + return ByteBufferAccessor.instance; + } + public CellPath path() { return path; } - public Cell withUpdatedColumn(ColumnMetadata newColumn) + public Cell withUpdatedColumn(ColumnMetadata newColumn) { return new BufferCell(newColumn, timestamp, ttl, localDeletionTime, value, path); } - public Cell withUpdatedValue(ByteBuffer newValue) + public Cell withUpdatedValue(ByteBuffer newValue) { return new BufferCell(column, timestamp, ttl, localDeletionTime, newValue, path); } - public Cell withUpdatedTimestampAndLocalDeletionTime(long newTimestamp, int newLocalDeletionTime) + public Cell withUpdatedTimestampAndLocalDeletionTime(long newTimestamp, int newLocalDeletionTime) { return new BufferCell(column, newTimestamp, ttl, newLocalDeletionTime, value, path); } - public Cell copy(AbstractAllocator allocator) + public Cell copy(AbstractAllocator allocator) { if (!value.hasRemaining()) return this; diff --git a/src/java/org/apache/cassandra/db/rows/Cell.java b/src/java/org/apache/cassandra/db/rows/Cell.java index 959676a192..6dd8f6178f 100644 --- a/src/java/org/apache/cassandra/db/rows/Cell.java +++ b/src/java/org/apache/cassandra/db/rows/Cell.java @@ -23,10 +23,10 @@ import java.util.Comparator; import org.apache.cassandra.config.*; import org.apache.cassandra.db.*; +import org.apache.cassandra.db.marshal.ValueAccessor; import org.apache.cassandra.io.util.DataOutputPlus; import org.apache.cassandra.io.util.DataInputPlus; import org.apache.cassandra.schema.ColumnMetadata; -import org.apache.cassandra.utils.ByteBufferUtil; import org.apache.cassandra.utils.memory.AbstractAllocator; /** @@ -38,13 +38,13 @@ import org.apache.cassandra.utils.memory.AbstractAllocator; * 2) expiring cells: on top of regular cells, those have a ttl and a local deletion time (when they are expired). * 3) tombstone cells: those won't have value, but they have a local deletion time (when the tombstone was created). */ -public abstract class Cell extends ColumnData +public abstract class Cell extends ColumnData { public static final int NO_TTL = 0; public static final int NO_DELETION_TIME = Integer.MAX_VALUE; public static final int MAX_DELETION_TIME = Integer.MAX_VALUE - 1; - public final static Comparator comparator = (c1, c2) -> + public final static Comparator> comparator = (c1, c2) -> { int cmp = c1.column().compareTo(c2.column()); if (cmp != 0) @@ -56,6 +56,11 @@ public abstract class Cell extends ColumnData public static final Serializer serializer = new BufferCell.Serializer(); + public interface Factory + { + Cell create(ColumnMetadata column, long timestamp, int ttl, int localDeletionTime, V value, CellPath path); + } + protected Cell(ColumnMetadata column) { super(column); @@ -68,12 +73,19 @@ public abstract class Cell extends ColumnData */ public abstract boolean isCounterCell(); - /** - * The cell value. - * - * @return the cell value. - */ - public abstract ByteBuffer value(); + public abstract V value(); + + public abstract ValueAccessor accessor(); + + public int valueSize() + { + return accessor().size(value()); + } + + public ByteBuffer buffer() + { + return accessor().toBuffer(value()); + } /** * The cell timestamp. @@ -132,21 +144,21 @@ public abstract class Cell extends ColumnData */ public abstract CellPath path(); - public abstract Cell withUpdatedColumn(ColumnMetadata newColumn); + public abstract Cell withUpdatedColumn(ColumnMetadata newColumn); - public abstract Cell withUpdatedValue(ByteBuffer newValue); + public abstract Cell withUpdatedValue(ByteBuffer newValue); - public abstract Cell withUpdatedTimestampAndLocalDeletionTime(long newTimestamp, int newLocalDeletionTime); + public abstract Cell withUpdatedTimestampAndLocalDeletionTime(long newTimestamp, int newLocalDeletionTime); - public abstract Cell copy(AbstractAllocator allocator); + public abstract Cell copy(AbstractAllocator allocator); @Override // Overrides super type to provide a more precise return type. - public abstract Cell markCounterLocalToBeCleared(); + public abstract Cell markCounterLocalToBeCleared(); @Override // Overrides super type to provide a more precise return type. - public abstract Cell purge(DeletionPurger purger, int nowInSec); + public abstract Cell purge(DeletionPurger purger, int nowInSec); /** * The serialization format for cell is: @@ -175,10 +187,10 @@ public abstract class Cell extends ColumnData private final static int USE_ROW_TIMESTAMP_MASK = 0x08; // Wether the cell has the same timestamp than the row this is a cell of. private final static int USE_ROW_TTL_MASK = 0x10; // Wether the cell has the same ttl than the row this is a cell of. - public void serialize(Cell cell, ColumnMetadata column, DataOutputPlus out, LivenessInfo rowLiveness, SerializationHeader header) throws IOException + public void serialize(Cell cell, ColumnMetadata column, DataOutputPlus out, LivenessInfo rowLiveness, SerializationHeader header) throws IOException { assert cell != null; - boolean hasValue = cell.value().hasRemaining(); + boolean hasValue = cell.valueSize() > 0; boolean isDeleted = cell.isTombstone(); boolean isExpiring = cell.isExpiring(); boolean useRowTimestamp = !rowLiveness.isEmpty() && cell.timestamp() == rowLiveness.timestamp(); @@ -211,10 +223,10 @@ public abstract class Cell extends ColumnData column.cellPathSerializer().serialize(cell.path(), out); if (hasValue) - header.getType(column).writeValue(cell.value(), out); + header.getType(column).writeValue(cell.value(), cell.accessor(), out); } - public Cell deserialize(DataInputPlus in, LivenessInfo rowLiveness, ColumnMetadata column, SerializationHeader header, DeserializationHelper helper) throws IOException + public Cell deserialize(DataInputPlus in, LivenessInfo rowLiveness, ColumnMetadata column, SerializationHeader header, DeserializationHelper helper, ValueAccessor accessor) throws IOException { int flags = in.readUnsignedByte(); boolean hasValue = (flags & HAS_EMPTY_VALUE_MASK) == 0; @@ -235,7 +247,7 @@ public abstract class Cell extends ColumnData ? column.cellPathSerializer().deserialize(in) : null; - ByteBuffer value = ByteBufferUtil.EMPTY_BYTE_BUFFER; + V value = accessor.empty(); if (hasValue) { if (helper.canSkipValue(column) || (path != null && helper.canSkipValue(path))) @@ -246,19 +258,19 @@ public abstract class Cell extends ColumnData { boolean isCounter = localDeletionTime == NO_DELETION_TIME && column.type.isCounter(); - value = header.getType(column).readValue(in, DatabaseDescriptor.getMaxValueSize()); + value = header.getType(column).read(accessor, in, DatabaseDescriptor.getMaxValueSize()); if (isCounter) - value = helper.maybeClearCounterValue(value); + value = helper.maybeClearCounterValue(value, accessor); } } - return new BufferCell(column, timestamp, ttl, localDeletionTime, value, path); + return accessor.factory().cell(column, timestamp, ttl, localDeletionTime, value, path); } - public long serializedSize(Cell cell, ColumnMetadata column, LivenessInfo rowLiveness, SerializationHeader header) + public long serializedSize(Cell cell, ColumnMetadata column, LivenessInfo rowLiveness, SerializationHeader header) { long size = 1; // flags - boolean hasValue = cell.value().hasRemaining(); + boolean hasValue = cell.valueSize() > 0; boolean isDeleted = cell.isTombstone(); boolean isExpiring = cell.isExpiring(); boolean useRowTimestamp = !rowLiveness.isEmpty() && cell.timestamp() == rowLiveness.timestamp(); @@ -276,7 +288,7 @@ public abstract class Cell extends ColumnData size += column.cellPathSerializer().serializedSize(cell.path()); if (hasValue) - size += header.getType(column).writtenLength(cell.value()); + size += header.getType(column).writtenLength(cell.value(), cell.accessor()); return size; } diff --git a/src/java/org/apache/cassandra/db/rows/Cells.java b/src/java/org/apache/cassandra/db/rows/Cells.java index 45d69e8afc..ea968d9eb6 100644 --- a/src/java/org/apache/cassandra/db/rows/Cells.java +++ b/src/java/org/apache/cassandra/db/rows/Cells.java @@ -22,6 +22,8 @@ import java.util.Comparator; import java.util.Iterator; import org.apache.cassandra.db.context.CounterContext; +import org.apache.cassandra.db.marshal.AbstractType; +import org.apache.cassandra.db.marshal.ValueAccessor; import org.apache.cassandra.schema.ColumnMetadata; import org.apache.cassandra.db.DeletionTime; import org.apache.cassandra.db.partitions.PartitionStatisticsCollector; @@ -39,7 +41,7 @@ public abstract class Cells * @param cell the cell for which to collect stats. * @param collector the stats collector. */ - public static void collectStats(Cell cell, PartitionStatisticsCollector collector) + public static void collectStats(Cell cell, PartitionStatisticsCollector collector) { collector.update(cell); @@ -70,8 +72,8 @@ public abstract class Cells * @return the timestamp delta between existing and update, or {@code Long.MAX_VALUE} if one * of them is {@code null} or deleted by {@code deletion}). */ - public static long reconcile(Cell existing, - Cell update, + public static long reconcile(Cell existing, + Cell update, DeletionTime deletion, Row.Builder builder) { @@ -90,7 +92,7 @@ public abstract class Cells return Long.MAX_VALUE; } - Cell reconciled = reconcile(existing, update); + Cell reconciled = reconcile(existing, update); builder.addCell(reconciled); return Math.abs(existing.timestamp() - update.timestamp()); @@ -112,7 +114,7 @@ public abstract class Cells * For non-counter cells, this will always be either {@code c1} or {@code c2}, but for * counter cells this can be a newly allocated cell. */ - public static Cell reconcile(Cell c1, Cell c2) + public static Cell reconcile(Cell c1, Cell c2) { if (c1 == null || c2 == null) return c2 == null ? c1 : c2; @@ -123,7 +125,7 @@ public abstract class Cells return resolveRegular(c1, c2); } - private static Cell resolveRegular(Cell left, Cell right) + private static Cell resolveRegular(Cell left, Cell right) { long leftTimestamp = left.timestamp(); long rightTimestamp = right.timestamp(); @@ -162,12 +164,10 @@ public abstract class Cells return leftLocalDeletionTime > rightLocalDeletionTime ? left : right; } - ByteBuffer leftValue = left.value(); - ByteBuffer rightValue = right.value(); - return leftValue.compareTo(rightValue) >= 0 ? left : right; + return compareValues(left, right) >= 0 ? left : right; } - private static Cell resolveCounter(Cell left, Cell right) + private static Cell resolveCounter(Cell left, Cell right) { long leftTimestamp = left.timestamp(); long rightTimestamp = right.timestamp(); @@ -182,8 +182,8 @@ public abstract class Cells return leftIsTombstone ? left : right; } - ByteBuffer leftValue = left.value(); - ByteBuffer rightValue = right.value(); + ByteBuffer leftValue = left.buffer(); + ByteBuffer rightValue = right.buffer(); // Handle empty values. Counters can't truly have empty values, but we can have a counter cell that temporarily // has one on read if the column for the cell is not queried by the user due to the optimization of #10657. We @@ -239,14 +239,14 @@ public abstract class Cells * returns {@code Long.MAX_VALUE}. */ public static long reconcileComplex(ColumnMetadata column, - Iterator existing, - Iterator update, + Iterator> existing, + Iterator> update, DeletionTime deletion, Row.Builder builder) { Comparator comparator = column.cellPathComparator(); - Cell nextExisting = getNext(existing); - Cell nextUpdate = getNext(update); + Cell nextExisting = getNext(existing); + Cell nextUpdate = getNext(update); long timeDelta = Long.MAX_VALUE; while (nextExisting != null || nextUpdate != null) { @@ -287,15 +287,15 @@ public abstract class Cells * This deletion time may delete both {@code existing} or {@code update}. * @param builder the row builder to which the result of the filtering is written. */ - public static void addNonShadowed(Cell existing, - Cell update, + public static void addNonShadowed(Cell existing, + Cell update, DeletionTime deletion, Row.Builder builder) { if (deletion.deletes(existing)) return; - Cell reconciled = reconcile(existing, update); + Cell reconciled = reconcile(existing, update); if (reconciled != update) builder.addCell(existing); } @@ -316,14 +316,14 @@ public abstract class Cells * @param builder the row builder to which the result of the filtering is written. */ public static void addNonShadowedComplex(ColumnMetadata column, - Iterator existing, - Iterator update, + Iterator> existing, + Iterator> update, DeletionTime deletion, Row.Builder builder) { Comparator comparator = column.cellPathComparator(); - Cell nextExisting = getNext(existing); - Cell nextUpdate = getNext(update); + Cell nextExisting = getNext(existing); + Cell nextUpdate = getNext(update); while (nextExisting != null) { int cmp = nextUpdate == null ? -1 : comparator.compare(nextExisting.path(), nextUpdate.path()); @@ -345,8 +345,33 @@ public abstract class Cells } } - private static Cell getNext(Iterator iterator) + private static Cell getNext(Iterator> iterator) { return iterator == null || !iterator.hasNext() ? null : iterator.next(); } + + private static int compareValues(Cell left, Cell right) + { + return ValueAccessor.compare(left.value(), left.accessor(), right.value(), right.accessor()); + } + + public static boolean valueEqual(Cell left, Cell right) + { + return ValueAccessor.equals(left.value(), left.accessor(), right.value(), right.accessor()); + } + + public static T composeValue(Cell cell, AbstractType type) + { + return type.compose(cell.value(), cell.accessor()); + } + + public static String valueString(Cell cell, AbstractType type) + { + return type.getString(cell.value(), cell.accessor()); + } + + public static String valueString(Cell cell) + { + return valueString(cell, cell.column().type); + } } diff --git a/src/java/org/apache/cassandra/db/rows/ComplexColumnData.java b/src/java/org/apache/cassandra/db/rows/ComplexColumnData.java index 5b0350439d..d421af29a3 100644 --- a/src/java/org/apache/cassandra/db/rows/ComplexColumnData.java +++ b/src/java/org/apache/cassandra/db/rows/ComplexColumnData.java @@ -30,7 +30,6 @@ import org.apache.cassandra.db.LivenessInfo; import org.apache.cassandra.db.filter.ColumnFilter; import org.apache.cassandra.db.marshal.ByteType; import org.apache.cassandra.db.marshal.SetType; -import org.apache.cassandra.db.partitions.PartitionStatisticsCollector; import org.apache.cassandra.schema.ColumnMetadata; import org.apache.cassandra.schema.DroppedColumn; import org.apache.cassandra.utils.BiLongAccumulator; @@ -42,9 +41,9 @@ import org.apache.cassandra.utils.btree.BTree; * The data for a complex column, that is it's cells and potential complex * deletion time. */ -public class ComplexColumnData extends ColumnData implements Iterable +public class ComplexColumnData extends ColumnData implements Iterable> { - static final Cell[] NO_CELLS = new Cell[0]; + static final Cell[] NO_CELLS = new Cell[0]; private static final long EMPTY_SIZE = ObjectSizes.measure(new ComplexColumnData(ColumnMetadata.regularColumn("", "", "", SetType.getInstance(ByteType.instance, true)), NO_CELLS, new DeletionTime(0, 0))); @@ -68,12 +67,12 @@ public class ComplexColumnData extends ColumnData implements Iterable return BTree.size(cells); } - public Cell getCell(CellPath path) + public Cell getCell(CellPath path) { - return (Cell) BTree.find(cells, column.asymmetricCellPathComparator(), path); + return (Cell) BTree.find(cells, column.asymmetricCellPathComparator(), path); } - public Cell getCellByIndex(int idx) + public Cell getCellByIndex(int idx) { return BTree.findByIndex(cells, idx); } @@ -94,22 +93,22 @@ public class ComplexColumnData extends ColumnData implements Iterable return complexDeletion; } - public Iterator iterator() + public Iterator> iterator() { return BTree.iterator(cells); } - public Iterator reverseIterator() + public Iterator> reverseIterator() { return BTree.iterator(cells, BTree.Dir.DESC); } - public long accumulate(LongAccumulator accumulator, long initialValue) + public long accumulate(LongAccumulator> accumulator, long initialValue) { return BTree.accumulate(cells, accumulator, initialValue); } - public long accumulate(BiLongAccumulator accumulator, A arg, long initialValue) + public long accumulate(BiLongAccumulator> accumulator, A arg, long initialValue) { return BTree.accumulate(cells, accumulator, arg, initialValue); } @@ -117,7 +116,7 @@ public class ComplexColumnData extends ColumnData implements Iterable public int dataSize() { int size = complexDeletion.dataSize(); - for (Cell cell : this) + for (Cell cell : this) size += cell.dataSize(); return size; } @@ -126,14 +125,14 @@ public class ComplexColumnData extends ColumnData implements Iterable { long heapSize = EMPTY_SIZE + ObjectSizes.sizeOfArray(cells); // TODO: this can be turned into a simple multiplication, at least while we have only one Cell implementation - for (Cell cell : this) + for (Cell cell : this) heapSize += cell.unsharedHeapSizeExcludingData(); return heapSize; } public void validate() { - for (Cell cell : this) + for (Cell cell : this) cell.validate(); } @@ -142,7 +141,7 @@ public class ComplexColumnData extends ColumnData implements Iterable if (!complexDeletion.isLive()) complexDeletion.digest(digest); - for (Cell cell : this) + for (Cell cell : this) cell.digest(digest); } @@ -150,7 +149,7 @@ public class ComplexColumnData extends ColumnData implements Iterable { if (!complexDeletion.validate()) return true; - for (Cell cell : this) + for (Cell cell : this) if (cell.hasInvalidDeletions()) return true; return false; @@ -189,7 +188,7 @@ public class ComplexColumnData extends ColumnData implements Iterable return transformAndFilter(complexDeletion, (cell) -> filter.fetchedCellIsQueried(column, cell.path()) ? null : cell); } - private ComplexColumnData transformAndFilter(DeletionTime newDeletion, Function function) + private ComplexColumnData transformAndFilter(DeletionTime newDeletion, Function, ? extends Cell> function) { Object[] transformed = BTree.transformAndFilter(cells, function); @@ -205,13 +204,13 @@ public class ComplexColumnData extends ColumnData implements Iterable public ComplexColumnData updateAllTimestamp(long newTimestamp) { DeletionTime newDeletion = complexDeletion.isLive() ? complexDeletion : new DeletionTime(newTimestamp - 1, complexDeletion.localDeletionTime()); - return transformAndFilter(newDeletion, (cell) -> (Cell) cell.updateAllTimestamp(newTimestamp)); + return transformAndFilter(newDeletion, (cell) -> (Cell) cell.updateAllTimestamp(newTimestamp)); } public long maxTimestamp() { long timestamp = complexDeletion.markedForDeleteAt(); - for (Cell cell : this) + for (Cell cell : this) timestamp = Math.max(timestamp, cell.timestamp()); return timestamp; } @@ -220,7 +219,7 @@ public class ComplexColumnData extends ColumnData implements Iterable // version is: "don't use that method". void setValue(CellPath path, ByteBuffer value) { - Cell current = (Cell) BTree.find(cells, column.asymmetricCellPathComparator(), path); + Cell current = (Cell) BTree.find(cells, column.asymmetricCellPathComparator(), path); BTree.replaceInSitu(cells, column.cellComparator(), current, current.withUpdatedValue(value)); } @@ -254,7 +253,7 @@ public class ComplexColumnData extends ColumnData implements Iterable { private DeletionTime complexDeletion; private ColumnMetadata column; - private BTree.Builder builder; + private BTree.Builder> builder; public void newColumn(ColumnMetadata column) { @@ -271,7 +270,7 @@ public class ComplexColumnData extends ColumnData implements Iterable this.complexDeletion = complexDeletion; } - public void addCell(Cell cell) + public void addCell(Cell cell) { builder.add(cell); } diff --git a/src/java/org/apache/cassandra/db/rows/CounterCells.java b/src/java/org/apache/cassandra/db/rows/CounterCells.java index 732f195ae9..db7d873758 100644 --- a/src/java/org/apache/cassandra/db/rows/CounterCells.java +++ b/src/java/org/apache/cassandra/db/rows/CounterCells.java @@ -25,8 +25,8 @@ public abstract class CounterCells private static final CounterContext contextManager = CounterContext.instance(); - public static boolean hasLegacyShards(Cell cell) + public static boolean hasLegacyShards(Cell cell) { - return contextManager.hasLegacyShards(cell.value()); + return contextManager.hasLegacyShards(cell.value(), cell.accessor()); } } diff --git a/src/java/org/apache/cassandra/db/rows/DeserializationHelper.java b/src/java/org/apache/cassandra/db/rows/DeserializationHelper.java index 386e6ef9bd..9404cc772d 100644 --- a/src/java/org/apache/cassandra/db/rows/DeserializationHelper.java +++ b/src/java/org/apache/cassandra/db/rows/DeserializationHelper.java @@ -20,6 +20,7 @@ package org.apache.cassandra.db.rows; import java.nio.ByteBuffer; import java.util.*; +import org.apache.cassandra.db.marshal.ValueAccessor; import org.apache.cassandra.schema.ColumnMetadata; import org.apache.cassandra.schema.TableMetadata; import org.apache.cassandra.db.*; @@ -75,7 +76,7 @@ public class DeserializationHelper return columnsToFetch == null || columnsToFetch.fetches(column); } - public boolean includes(Cell cell, LivenessInfo rowLiveness) + public boolean includes(Cell cell, LivenessInfo rowLiveness) { if (columnsToFetch == null) return true; @@ -126,7 +127,7 @@ public class DeserializationHelper this.tester = null; } - public boolean isDropped(Cell cell, boolean isComplex) + public boolean isDropped(Cell cell, boolean isComplex) { if (!hasDroppedColumns) return false; @@ -140,10 +141,10 @@ public class DeserializationHelper return currentDroppedComplex != null && complexDeletion.markedForDeleteAt() <= currentDroppedComplex.droppedTime; } - public ByteBuffer maybeClearCounterValue(ByteBuffer value) + public V maybeClearCounterValue(V value, ValueAccessor accessor) { - return flag == Flag.FROM_REMOTE || (flag == Flag.LOCAL && CounterContext.instance().shouldClearLocal(value)) - ? CounterContext.instance().clearAllLocal(value) - : value; + return flag == Flag.FROM_REMOTE || (flag == Flag.LOCAL && CounterContext.instance().shouldClearLocal(value, accessor)) + ? CounterContext.instance().clearAllLocal(value, accessor) + : value; } } diff --git a/src/java/org/apache/cassandra/db/rows/EncodingStats.java b/src/java/org/apache/cassandra/db/rows/EncodingStats.java index c73728d968..f2fb3407c3 100644 --- a/src/java/org/apache/cassandra/db/rows/EncodingStats.java +++ b/src/java/org/apache/cassandra/db/rows/EncodingStats.java @@ -183,7 +183,7 @@ public class EncodingStats } } - public void update(Cell cell) + public void update(Cell cell) { updateTimestamp(cell.timestamp()); if (cell.isExpiring()) diff --git a/src/java/org/apache/cassandra/db/rows/NativeCell.java b/src/java/org/apache/cassandra/db/rows/NativeCell.java index c4cb6c1342..fe6f403f8b 100644 --- a/src/java/org/apache/cassandra/db/rows/NativeCell.java +++ b/src/java/org/apache/cassandra/db/rows/NativeCell.java @@ -20,13 +20,15 @@ package org.apache.cassandra.db.rows; import java.nio.ByteBuffer; import java.nio.ByteOrder; +import org.apache.cassandra.db.marshal.ByteBufferAccessor; +import org.apache.cassandra.db.marshal.ValueAccessor; import org.apache.cassandra.schema.ColumnMetadata; import org.apache.cassandra.utils.ObjectSizes; import org.apache.cassandra.utils.concurrent.OpOrder; import org.apache.cassandra.utils.memory.MemoryUtil; import org.apache.cassandra.utils.memory.NativeAllocator; -public class NativeCell extends AbstractCell +public class NativeCell extends AbstractCell { private static final long EMPTY_SIZE = ObjectSizes.measure(new NativeCell()); @@ -47,7 +49,7 @@ public class NativeCell extends AbstractCell public NativeCell(NativeAllocator allocator, OpOrder.Group writeOp, - Cell cell) + Cell cell) { this(allocator, writeOp, @@ -55,7 +57,7 @@ public class NativeCell extends AbstractCell cell.timestamp(), cell.ttl(), cell.localDeletionTime(), - cell.value(), + cell.buffer(), cell.path()); } @@ -122,12 +124,17 @@ public class NativeCell extends AbstractCell return MemoryUtil.getInt(peer + DELETION); } - public ByteBuffer value() + public ByteBuffer value()// FIXME: add native accessor { int length = MemoryUtil.getInt(peer + LENGTH); return MemoryUtil.getByteBuffer(peer + VALUE, length, ByteOrder.BIG_ENDIAN); } + public ValueAccessor accessor() + { + return ByteBufferAccessor.instance; // FIXME: add native accessor + } + public CellPath path() { if (MemoryUtil.getByte(peer+ HAS_CELLPATH) == 0) @@ -138,17 +145,17 @@ public class NativeCell extends AbstractCell return CellPath.create(MemoryUtil.getByteBuffer(offset + 4, size, ByteOrder.BIG_ENDIAN)); } - public Cell withUpdatedValue(ByteBuffer newValue) + public Cell withUpdatedValue(ByteBuffer newValue) { throw new UnsupportedOperationException(); } - public Cell withUpdatedTimestampAndLocalDeletionTime(long newTimestamp, int newLocalDeletionTime) + public Cell withUpdatedTimestampAndLocalDeletionTime(long newTimestamp, int newLocalDeletionTime) { return new BufferCell(column, newTimestamp, ttl(), newLocalDeletionTime, value(), path()); } - public Cell withUpdatedColumn(ColumnMetadata column) + public Cell withUpdatedColumn(ColumnMetadata column) { return new BufferCell(column, timestamp(), ttl(), localDeletionTime(), value(), path()); } diff --git a/src/java/org/apache/cassandra/db/rows/RangeTombstoneBoundMarker.java b/src/java/org/apache/cassandra/db/rows/RangeTombstoneBoundMarker.java index 51d82648fa..20bc48415f 100644 --- a/src/java/org/apache/cassandra/db/rows/RangeTombstoneBoundMarker.java +++ b/src/java/org/apache/cassandra/db/rows/RangeTombstoneBoundMarker.java @@ -17,9 +17,9 @@ */ package org.apache.cassandra.db.rows; -import java.nio.ByteBuffer; import java.util.Objects; +import org.apache.cassandra.db.marshal.ValueAccessor; import org.apache.cassandra.schema.TableMetadata; import org.apache.cassandra.db.*; import org.apache.cassandra.utils.memory.AbstractAllocator; @@ -27,40 +27,60 @@ import org.apache.cassandra.utils.memory.AbstractAllocator; /** * A range tombstone marker that indicates the bound of a range tombstone (start or end). */ -public class RangeTombstoneBoundMarker extends AbstractRangeTombstoneMarker +public class RangeTombstoneBoundMarker extends AbstractRangeTombstoneMarker> { private final DeletionTime deletion; - public RangeTombstoneBoundMarker(ClusteringBound bound, DeletionTime deletion) + public RangeTombstoneBoundMarker(ClusteringBound bound, DeletionTime deletion) { super(bound); this.deletion = deletion; } - public static RangeTombstoneBoundMarker inclusiveOpen(boolean reversed, ByteBuffer[] boundValues, DeletionTime deletion) + public static RangeTombstoneBoundMarker inclusiveOpen(boolean reversed, V[] boundValues, ValueAccessor accessor, DeletionTime deletion) { - ClusteringBound bound = ClusteringBound.inclusiveOpen(reversed, boundValues); + ClusteringBound bound = accessor.factory().inclusiveOpen(reversed, boundValues); return new RangeTombstoneBoundMarker(bound, deletion); } - public static RangeTombstoneBoundMarker exclusiveOpen(boolean reversed, ByteBuffer[] boundValues, DeletionTime deletion) + public static RangeTombstoneBoundMarker inclusiveOpen(boolean reversed, ClusteringPrefix from, DeletionTime deletion) { - ClusteringBound bound = ClusteringBound.exclusiveOpen(reversed, boundValues); + return inclusiveOpen(reversed, from.getRawValues(), from.accessor(), deletion); + } + + public static RangeTombstoneBoundMarker exclusiveOpen(boolean reversed, V[] boundValues, ValueAccessor accessor, DeletionTime deletion) + { + ClusteringBound bound = accessor.factory().exclusiveOpen(reversed, boundValues); return new RangeTombstoneBoundMarker(bound, deletion); } - public static RangeTombstoneBoundMarker inclusiveClose(boolean reversed, ByteBuffer[] boundValues, DeletionTime deletion) + public static RangeTombstoneBoundMarker exclusiveOpen(boolean reversed, ClusteringPrefix from, DeletionTime deletion) { - ClusteringBound bound = ClusteringBound.inclusiveClose(reversed, boundValues); + return exclusiveOpen(reversed, from.getRawValues(), from.accessor(), deletion); + } + + public static RangeTombstoneBoundMarker inclusiveClose(boolean reversed, V[] boundValues, ValueAccessor accessor, DeletionTime deletion) + { + ClusteringBound bound = accessor.factory().inclusiveClose(reversed, boundValues); return new RangeTombstoneBoundMarker(bound, deletion); } - public static RangeTombstoneBoundMarker exclusiveClose(boolean reversed, ByteBuffer[] boundValues, DeletionTime deletion) + public static RangeTombstoneBoundMarker inclusiveClose(boolean reversed, ClusteringPrefix from, DeletionTime deletion) { - ClusteringBound bound = ClusteringBound.exclusiveClose(reversed, boundValues); + return inclusiveClose(reversed, from.getRawValues(), from.accessor(), deletion); + } + + public static RangeTombstoneBoundMarker exclusiveClose(boolean reversed, V[] boundValues, ValueAccessor accessor, DeletionTime deletion) + { + ClusteringBound bound = accessor.factory().exclusiveClose(reversed, boundValues); return new RangeTombstoneBoundMarker(bound, deletion); } + public static RangeTombstoneBoundMarker exclusiveClose(boolean reversed, ClusteringPrefix from, DeletionTime deletion) + { + return exclusiveClose(reversed, from.getRawValues(), from.accessor(), deletion); + } + public boolean isBoundary() { return false; @@ -107,12 +127,12 @@ public class RangeTombstoneBoundMarker extends AbstractRangeTombstoneMarker openBound(boolean reversed) { return isOpen(reversed) ? clustering() : null; } - public ClusteringBound closeBound(boolean reversed) + public ClusteringBound closeBound(boolean reversed) { return isClose(reversed) ? clustering() : null; } diff --git a/src/java/org/apache/cassandra/db/rows/RangeTombstoneBoundaryMarker.java b/src/java/org/apache/cassandra/db/rows/RangeTombstoneBoundaryMarker.java index 6a931c93d0..7079981e48 100644 --- a/src/java/org/apache/cassandra/db/rows/RangeTombstoneBoundaryMarker.java +++ b/src/java/org/apache/cassandra/db/rows/RangeTombstoneBoundaryMarker.java @@ -20,6 +20,7 @@ package org.apache.cassandra.db.rows; import java.nio.ByteBuffer; import java.util.Objects; +import org.apache.cassandra.db.marshal.ValueAccessor; import org.apache.cassandra.schema.TableMetadata; import org.apache.cassandra.db.*; import org.apache.cassandra.utils.memory.AbstractAllocator; @@ -27,12 +28,12 @@ import org.apache.cassandra.utils.memory.AbstractAllocator; /** * A range tombstone marker that represents a boundary between 2 range tombstones (i.e. it closes one range and open another). */ -public class RangeTombstoneBoundaryMarker extends AbstractRangeTombstoneMarker +public class RangeTombstoneBoundaryMarker extends AbstractRangeTombstoneMarker> { private final DeletionTime endDeletion; private final DeletionTime startDeletion; - public RangeTombstoneBoundaryMarker(ClusteringBoundary bound, DeletionTime endDeletion, DeletionTime startDeletion) + public RangeTombstoneBoundaryMarker(ClusteringBoundary bound, DeletionTime endDeletion, DeletionTime startDeletion) { super(bound); assert bound.isBoundary(); @@ -40,22 +41,47 @@ public class RangeTombstoneBoundaryMarker extends AbstractRangeTombstoneMarker RangeTombstoneBoundaryMarker exclusiveCloseInclusiveOpen(boolean reversed, + V[] boundValues, + ValueAccessor accessor, + DeletionTime closeDeletion, + DeletionTime openDeletion) { - ClusteringBoundary bound = ClusteringBoundary.exclusiveCloseInclusiveOpen(reversed, boundValues); + ClusteringBoundary bound = accessor.factory().exclusiveCloseInclusiveOpen(reversed, boundValues); DeletionTime endDeletion = reversed ? openDeletion : closeDeletion; DeletionTime startDeletion = reversed ? closeDeletion : openDeletion; return new RangeTombstoneBoundaryMarker(bound, endDeletion, startDeletion); } - public static RangeTombstoneBoundaryMarker inclusiveCloseExclusiveOpen(boolean reversed, ByteBuffer[] boundValues, DeletionTime closeDeletion, DeletionTime openDeletion) + public static RangeTombstoneBoundaryMarker exclusiveCloseInclusiveOpen(boolean reversed, + ClusteringPrefix from, + DeletionTime closeDeletion, + DeletionTime openDeletion) { - ClusteringBoundary bound = ClusteringBoundary.inclusiveCloseExclusiveOpen(reversed, boundValues); + return exclusiveCloseInclusiveOpen(reversed, from.getRawValues(), from.accessor(), closeDeletion, openDeletion); + } + + public static RangeTombstoneBoundaryMarker inclusiveCloseExclusiveOpen(boolean reversed, + V[] boundValues, + ValueAccessor accessor, + DeletionTime closeDeletion, + DeletionTime openDeletion) + { + ClusteringBoundary bound = accessor.factory().inclusiveCloseExclusiveOpen(reversed, boundValues); DeletionTime endDeletion = reversed ? openDeletion : closeDeletion; DeletionTime startDeletion = reversed ? closeDeletion : openDeletion; return new RangeTombstoneBoundaryMarker(bound, endDeletion, startDeletion); } + + public static RangeTombstoneBoundaryMarker inclusiveCloseExclusiveOpen(boolean reversed, + ClusteringPrefix from, + DeletionTime closeDeletion, + DeletionTime openDeletion) + { + return inclusiveCloseExclusiveOpen(reversed, from.getRawValues(), from.accessor(), closeDeletion, openDeletion); + } + /** * The deletion time for the range tombstone this boundary ends (in clustering order). */ @@ -87,12 +113,12 @@ public class RangeTombstoneBoundaryMarker extends AbstractRangeTombstoneMarker openBound(boolean reversed) { return bound.openBound(reversed); } - public ClusteringBound closeBound(boolean reversed) + public ClusteringBound closeBound(boolean reversed) { return bound.closeBound(reversed); } @@ -121,21 +147,27 @@ public class RangeTombstoneBoundaryMarker extends AbstractRangeTombstoneMarker) clustering().copy(allocator), endDeletion, startDeletion); } public RangeTombstoneBoundaryMarker withNewOpeningDeletionTime(boolean reversed, DeletionTime newDeletionTime) { - return new RangeTombstoneBoundaryMarker(clustering(), reversed ? newDeletionTime : endDeletion, reversed ? startDeletion : newDeletionTime); + return new RangeTombstoneBoundaryMarker(clustering(), + reversed ? newDeletionTime : endDeletion, + reversed ? startDeletion : newDeletionTime); } - public static RangeTombstoneBoundaryMarker makeBoundary(boolean reversed, ClusteringBound close, ClusteringBound open, DeletionTime closeDeletion, DeletionTime openDeletion) + public static RangeTombstoneBoundaryMarker makeBoundary(boolean reversed, + ClusteringBound close, + ClusteringBound open, + DeletionTime closeDeletion, + DeletionTime openDeletion) { assert ClusteringPrefix.Kind.compare(close.kind(), open.kind()) == 0 : "Both bound don't form a boundary"; boolean isExclusiveClose = close.isExclusive() || (close.isInclusive() && open.isInclusive() && openDeletion.supersedes(closeDeletion)); return isExclusiveClose - ? exclusiveCloseInclusiveOpen(reversed, close.getRawValues(), closeDeletion, openDeletion) - : inclusiveCloseExclusiveOpen(reversed, close.getRawValues(), closeDeletion, openDeletion); + ? exclusiveCloseInclusiveOpen(reversed, close.getRawValues(), close.accessor(), closeDeletion, openDeletion) + : inclusiveCloseExclusiveOpen(reversed, close.getRawValues(), close.accessor(), closeDeletion, openDeletion); } public RangeTombstoneBoundMarker createCorrespondingCloseMarker(boolean reversed) diff --git a/src/java/org/apache/cassandra/db/rows/RangeTombstoneMarker.java b/src/java/org/apache/cassandra/db/rows/RangeTombstoneMarker.java index f4bcdf52fc..d7fa37a2ba 100644 --- a/src/java/org/apache/cassandra/db/rows/RangeTombstoneMarker.java +++ b/src/java/org/apache/cassandra/db/rows/RangeTombstoneMarker.java @@ -17,7 +17,6 @@ */ package org.apache.cassandra.db.rows; -import java.nio.ByteBuffer; import java.util.*; import org.apache.cassandra.db.*; @@ -31,7 +30,7 @@ import org.apache.cassandra.utils.memory.AbstractAllocator; public interface RangeTombstoneMarker extends Unfiltered { @Override - public ClusteringBoundOrBoundary clustering(); + public ClusteringBoundOrBoundary clustering(); public boolean isBoundary(); @@ -43,8 +42,8 @@ public interface RangeTombstoneMarker extends Unfiltered public boolean openIsInclusive(boolean reversed); public boolean closeIsInclusive(boolean reversed); - public ClusteringBound openBound(boolean reversed); - public ClusteringBound closeBound(boolean reversed); + public ClusteringBound openBound(boolean reversed); + public ClusteringBound closeBound(boolean reversed); public RangeTombstoneMarker copy(AbstractAllocator allocator); @@ -74,7 +73,7 @@ public interface RangeTombstoneMarker extends Unfiltered private final DeletionTime partitionDeletion; private final boolean reversed; - private ClusteringBoundOrBoundary bound; + private ClusteringBoundOrBoundary bound; private final RangeTombstoneMarker[] markers; // For each iterator, what is the currently open marker deletion time (or null if there is no open marker on that iterator) @@ -125,25 +124,24 @@ public interface RangeTombstoneMarker extends Unfiltered if (reversed) isBeforeClustering = !isBeforeClustering; - ByteBuffer[] values = bound.getRawValues(); RangeTombstoneMarker merged; if (previousDeletionTimeInMerged.isLive()) { merged = isBeforeClustering - ? RangeTombstoneBoundMarker.inclusiveOpen(reversed, values, newDeletionTimeInMerged) - : RangeTombstoneBoundMarker.exclusiveOpen(reversed, values, newDeletionTimeInMerged); + ? RangeTombstoneBoundMarker.inclusiveOpen(reversed, bound, newDeletionTimeInMerged) + : RangeTombstoneBoundMarker.exclusiveOpen(reversed, bound, newDeletionTimeInMerged); } else if (newDeletionTimeInMerged.isLive()) { merged = isBeforeClustering - ? RangeTombstoneBoundMarker.exclusiveClose(reversed, values, previousDeletionTimeInMerged) - : RangeTombstoneBoundMarker.inclusiveClose(reversed, values, previousDeletionTimeInMerged); + ? RangeTombstoneBoundMarker.exclusiveClose(reversed, bound, previousDeletionTimeInMerged) + : RangeTombstoneBoundMarker.inclusiveClose(reversed, bound, previousDeletionTimeInMerged); } else { merged = isBeforeClustering - ? RangeTombstoneBoundaryMarker.exclusiveCloseInclusiveOpen(reversed, values, previousDeletionTimeInMerged, newDeletionTimeInMerged) - : RangeTombstoneBoundaryMarker.inclusiveCloseExclusiveOpen(reversed, values, previousDeletionTimeInMerged, newDeletionTimeInMerged); + ? RangeTombstoneBoundaryMarker.exclusiveCloseInclusiveOpen(reversed, bound, previousDeletionTimeInMerged, newDeletionTimeInMerged) + : RangeTombstoneBoundaryMarker.inclusiveCloseExclusiveOpen(reversed, bound, previousDeletionTimeInMerged, newDeletionTimeInMerged); } return merged; diff --git a/src/java/org/apache/cassandra/db/rows/Row.java b/src/java/org/apache/cassandra/db/rows/Row.java index 3703d54938..ec43783049 100644 --- a/src/java/org/apache/cassandra/db/rows/Row.java +++ b/src/java/org/apache/cassandra/db/rows/Row.java @@ -53,7 +53,7 @@ public interface Row extends Unfiltered, Iterable * The clustering values for this row. */ @Override - public Clustering clustering(); + public Clustering clustering(); /** * An in-natural-order collection of the columns for which data (incl. simple tombstones) @@ -125,7 +125,7 @@ public interface Row extends Unfiltered, Iterable * @param c the simple column for which to fetch the cell. * @return the corresponding cell or {@code null} if the row has no such cell. */ - public Cell getCell(ColumnMetadata c); + public Cell getCell(ColumnMetadata c); /** * Return a cell for a given complex column and cell path. @@ -134,7 +134,7 @@ public interface Row extends Unfiltered, Iterable * @param path the cell path for which to fetch the cell. * @return the corresponding cell or {@code null} if the row has no such cell. */ - public Cell getCell(ColumnMetadata c, CellPath path); + public Cell getCell(ColumnMetadata c, CellPath path); /** * The data for a complex column. @@ -153,7 +153,7 @@ public interface Row extends Unfiltered, Iterable * * @return an iterable over the cells of this row. */ - public Iterable cells(); + public Iterable> cells(); /** * A collection of the ColumnData representation of this row, for columns with some data (possibly not live) present @@ -175,7 +175,7 @@ public interface Row extends Unfiltered, Iterable * @param reversed if cells should returned in reverse order. * @return an iterable over the cells of this row in "legacy order". */ - public Iterable cellsInLegacyOrder(TableMetadata metadata, boolean reversed); + public Iterable> cellsInLegacyOrder(TableMetadata metadata, boolean reversed); /** * Whether the row stores any (non-live) complex deletion for any complex column. @@ -397,7 +397,7 @@ public interface Row extends Unfiltered, Iterable return time.deletes(info); } - public boolean deletes(Cell cell) + public boolean deletes(Cell cell) { return time.deletes(cell); } @@ -482,7 +482,7 @@ public interface Row extends Unfiltered, Iterable * * @param clustering the clustering for the new row. */ - public void newRow(Clustering clustering); + public void newRow(Clustering clustering); /** * The clustering for the row that is currently being built. @@ -490,7 +490,7 @@ public interface Row extends Unfiltered, Iterable * @return the clustering for the row that is currently being built, or {@code null} if {@link #newRow} hasn't * yet been called. */ - public Clustering clustering(); + public Clustering clustering(); /** * Adds the liveness information for the partition key columns of this row. @@ -515,7 +515,7 @@ public interface Row extends Unfiltered, Iterable * * @param cell the cell to add. */ - public void addCell(Cell cell); + public void addCell(Cell cell); /** * Adds a complex deletion. @@ -640,7 +640,7 @@ public interface Row extends Unfiltered, Iterable private final Row[] rows; private final List> columnDataIterators; - private Clustering clustering; + private Clustering clustering; private int rowsToMerge; private int lastRowSet = -1; @@ -725,7 +725,7 @@ public interface Row extends Unfiltered, Iterable : BTreeRow.create(clustering, rowInfo, rowDeletion, BTree.build(dataBuffer, UpdateFunction.noOp())); } - public Clustering mergedClustering() + public Clustering mergedClustering() { return clustering; } @@ -743,7 +743,7 @@ public interface Row extends Unfiltered, Iterable private DeletionTime activeDeletion; private final ComplexColumnData.Builder complexBuilder; - private final List> complexCells; + private final List>> complexCells; private final CellReducer cellReducer; public ColumnDataReducer(int size, boolean hasComplex) @@ -785,10 +785,10 @@ public interface Row extends Unfiltered, Iterable { if (column.isSimple()) { - Cell merged = null; + Cell merged = null; for (int i=0, isize=versions.size(); i cell = (Cell) versions.get(i); if (!activeDeletion.deletes(cell)) merged = merged == null ? cell : Cells.reconcile(merged, cell); } @@ -818,10 +818,10 @@ public interface Row extends Unfiltered, Iterable cellReducer.setActiveDeletion(activeDeletion); } - Iterator cells = MergeIterator.get(complexCells, Cell.comparator, cellReducer); + Iterator> cells = MergeIterator.get(complexCells, Cell.comparator, cellReducer); while (cells.hasNext()) { - Cell merged = cells.next(); + Cell merged = cells.next(); if (merged != null) complexBuilder.addCell(merged); } @@ -836,10 +836,10 @@ public interface Row extends Unfiltered, Iterable } } - private static class CellReducer extends MergeIterator.Reducer + private static class CellReducer extends MergeIterator.Reducer, Cell> { private DeletionTime activeDeletion; - private Cell merged; + private Cell merged; public void setActiveDeletion(DeletionTime activeDeletion) { @@ -847,13 +847,13 @@ public interface Row extends Unfiltered, Iterable onKeyChange(); } - public void reduce(int idx, Cell cell) + public void reduce(int idx, Cell cell) { if (!activeDeletion.deletes(cell)) merged = merged == null ? cell : Cells.reconcile(merged, cell); } - protected Cell getReduced() + protected Cell getReduced() { return merged; } diff --git a/src/java/org/apache/cassandra/db/rows/RowAndDeletionMergeIterator.java b/src/java/org/apache/cassandra/db/rows/RowAndDeletionMergeIterator.java index 7552d60686..0053ec24c8 100644 --- a/src/java/org/apache/cassandra/db/rows/RowAndDeletionMergeIterator.java +++ b/src/java/org/apache/cassandra/db/rows/RowAndDeletionMergeIterator.java @@ -192,12 +192,12 @@ public class RowAndDeletionMergeIterator extends AbstractUnfilteredRowIterator return range; } - private ClusteringBound openBound(RangeTombstone range) + private ClusteringBound openBound(RangeTombstone range) { return range.deletedSlice().open(isReverseOrder()); } - private ClusteringBound closeBound(RangeTombstone range) + private ClusteringBound closeBound(RangeTombstone range) { return range.deletedSlice().close(isReverseOrder()); } diff --git a/src/java/org/apache/cassandra/db/rows/RowDiffListener.java b/src/java/org/apache/cassandra/db/rows/RowDiffListener.java index 88a9bae70f..28f7aefcb5 100644 --- a/src/java/org/apache/cassandra/db/rows/RowDiffListener.java +++ b/src/java/org/apache/cassandra/db/rows/RowDiffListener.java @@ -39,7 +39,7 @@ public interface RowDiffListener * @param original the primary key liveness info of input {@code i}. May be {@code null} if input {@code i} * has not primary key liveness info (i.e. it has {@code LivenessInfo.NONE}) but the merged result has. */ - public void onPrimaryKeyLivenessInfo(int i, Clustering clustering, LivenessInfo merged, LivenessInfo original); + public void onPrimaryKeyLivenessInfo(int i, Clustering clustering, LivenessInfo merged, LivenessInfo original); /** * Called for the row deletion of input {@code i}. @@ -50,7 +50,7 @@ public interface RowDiffListener * but the merged result doesn't (i.e. the deletion has been shadowed). * @param original the deletion of input {@code i}. May be {@code null} if input {@code i} had no deletion but the merged row has. */ - public void onDeletion(int i, Clustering clustering, Row.Deletion merged, Row.Deletion original); + public void onDeletion(int i, Clustering clustering, Row.Deletion merged, Row.Deletion original); /** * Called for every (non-live) complex deletion of any complex column present in either the merged row of input {@code i}. @@ -63,7 +63,7 @@ public interface RowDiffListener * @param original the complex deletion of input {@code i} for column {@code column}. May be {@code null} if input {@code i} * had no complex deletion but the merged row has. */ - public void onComplexDeletion(int i, Clustering clustering, ColumnMetadata column, DeletionTime merged, DeletionTime original); + public void onComplexDeletion(int i, Clustering clustering, ColumnMetadata column, DeletionTime merged, DeletionTime original); /** * Called for any cell that is either in the merged row or in input {@code i}. @@ -74,5 +74,5 @@ public interface RowDiffListener * in the merged result (it has been deleted/shadowed). * @param original the cell of input {@code i}. May be {@code null} if input {@code i} had cell corresponding to {@code merged}. */ - public void onCell(int i, Clustering clustering, Cell merged, Cell original); + public void onCell(int i, Clustering clustering, Cell merged, Cell original); } diff --git a/src/java/org/apache/cassandra/db/rows/Rows.java b/src/java/org/apache/cassandra/db/rows/Rows.java index 58284ac4b9..82abb03d7e 100644 --- a/src/java/org/apache/cassandra/db/rows/Rows.java +++ b/src/java/org/apache/cassandra/db/rows/Rows.java @@ -46,13 +46,13 @@ public abstract class Rows { if (cd.column().isSimple()) { - builder.addCell((Cell)cd); + builder.addCell((Cell)cd); } else { ComplexColumnData complexData = (ComplexColumnData)cd; builder.addComplexDeletion(complexData.column(), complexData.complexDeletion()); - for (Cell cell : complexData) + for (Cell cell : complexData) builder.addCell(cell); } } @@ -79,7 +79,7 @@ public abstract class Rows private static final long COLUMN_INCR = 1L << 32; private static final long CELL_INCR = 1L; - private static long accumulateOnCell(PartitionStatisticsCollector collector, Cell cell, long l) + private static long accumulateOnCell(PartitionStatisticsCollector collector, Cell cell, long l) { Cells.collectStats(cell, collector); return l + CELL_INCR; @@ -89,7 +89,7 @@ public abstract class Rows { if (cd.column().isSimple()) { - l = accumulateOnCell(collector, (Cell) cd, l) + COLUMN_INCR; + l = accumulateOnCell(collector, (Cell) cd, l) + COLUMN_INCR; } else { @@ -148,7 +148,7 @@ public abstract class Rows @SuppressWarnings("resource") public static void diff(RowDiffListener diffListener, Row merged, Row...inputs) { - Clustering clustering = merged.clustering(); + Clustering clustering = merged.clustering(); LivenessInfo mergedInfo = merged.primaryKeyLivenessInfo().isEmpty() ? null : merged.primaryKeyLivenessInfo(); Row.Deletion mergedDeletion = merged.deletion().isLive() ? null : merged.deletion(); for (int i = 0; i < inputs.length; i++) @@ -190,7 +190,7 @@ public abstract class Rows ColumnMetadata column = (mergedData != null ? mergedData : input).column; if (column.isSimple()) { - diffListener.onCell(i, clustering, (Cell) mergedData, (Cell) input); + diffListener.onCell(i, clustering, (Cell) mergedData, (Cell) input); } else { @@ -201,7 +201,7 @@ public abstract class Rows // Everything in inputData has been shadowed if (!inputData.complexDeletion().isLive()) diffListener.onComplexDeletion(i, clustering, column, null, inputData.complexDeletion()); - for (Cell inputCell : inputData) + for (Cell inputCell : inputData) diffListener.onCell(i, clustering, null, inputCell); } else if (inputData == null) @@ -209,7 +209,7 @@ public abstract class Rows // Everything in inputData is new if (!mergedData.complexDeletion().isLive()) diffListener.onComplexDeletion(i, clustering, column, mergedData.complexDeletion(), null); - for (Cell mergedCell : mergedData) + for (Cell mergedCell : mergedData) diffListener.onCell(i, clustering, mergedCell, null); } else @@ -218,8 +218,8 @@ public abstract class Rows if (!mergedData.complexDeletion().isLive() || !inputData.complexDeletion().isLive()) diffListener.onComplexDeletion(i, clustering, column, mergedData.complexDeletion(), inputData.complexDeletion()); - PeekingIterator mergedCells = Iterators.peekingIterator(mergedData.iterator()); - PeekingIterator inputCells = Iterators.peekingIterator(inputData.iterator()); + PeekingIterator> mergedCells = Iterators.peekingIterator(mergedData.iterator()); + PeekingIterator> inputCells = Iterators.peekingIterator(inputData.iterator()); while (mergedCells.hasNext() && inputCells.hasNext()) { int cmp = column.cellPathComparator().compare(mergedCells.peek().path(), inputCells.peek().path()); @@ -279,7 +279,7 @@ public abstract class Rows Row update, Row.Builder builder) { - Clustering clustering = existing.clustering(); + Clustering clustering = existing.clustering(); builder.newRow(clustering); LivenessInfo existingInfo = existing.primaryKeyLivenessInfo(); @@ -311,7 +311,7 @@ public abstract class Rows ColumnMetadata column = getColumnMetadata(cura, curb); if (column.isSimple()) { - timeDelta = Math.min(timeDelta, Cells.reconcile((Cell) cura, (Cell) curb, deletion, builder)); + timeDelta = Math.min(timeDelta, Cells.reconcile((Cell) cura, (Cell) curb, deletion, builder)); } else { @@ -326,8 +326,8 @@ public abstract class Rows else maxDt = deletion; - Iterator existingCells = existingData == null ? null : existingData.iterator(); - Iterator updateCells = updateData == null ? null : updateData.iterator(); + Iterator> existingCells = existingData == null ? null : existingData.iterator(); + Iterator> updateCells = updateData == null ? null : updateData.iterator(); timeDelta = Math.min(timeDelta, Cells.reconcileComplex(column, existingCells, updateCells, maxDt, builder)); } @@ -351,7 +351,7 @@ public abstract class Rows public static Row removeShadowedCells(Row existing, Row update, DeletionTime rangeDeletion) { Row.Builder builder = BTreeRow.sortedBuilder(); - Clustering clustering = existing.clustering(); + Clustering clustering = existing.clustering(); builder.newRow(clustering); DeletionTime deletion = update.deletion().time(); @@ -378,7 +378,7 @@ public abstract class Rows ColumnData curb = comparison == 0 ? nextb : null; if (column.isSimple()) { - Cells.addNonShadowed((Cell) cura, (Cell) curb, deletion, builder); + Cells.addNonShadowed((Cell) cura, (Cell) curb, deletion, builder); } else { @@ -395,8 +395,8 @@ public abstract class Rows maxDt = existingDt; } - Iterator existingCells = existingData.iterator(); - Iterator updateCells = updateData == null ? null : updateData.iterator(); + Iterator> existingCells = existingData.iterator(); + Iterator> updateCells = updateData == null ? null : updateData.iterator(); Cells.addNonShadowedComplex(column, existingCells, updateCells, maxDt, builder); } nexta = a.hasNext() ? a.next() : null; diff --git a/src/java/org/apache/cassandra/db/rows/ThrottledUnfilteredIterator.java b/src/java/org/apache/cassandra/db/rows/ThrottledUnfilteredIterator.java index a2e8425052..40be716347 100644 --- a/src/java/org/apache/cassandra/db/rows/ThrottledUnfilteredIterator.java +++ b/src/java/org/apache/cassandra/db/rows/ThrottledUnfilteredIterator.java @@ -180,12 +180,11 @@ public class ThrottledUnfilteredIterator extends AbstractIterator clustering(); + /** * Digest the atom using the provided {@link Digest}. * diff --git a/src/java/org/apache/cassandra/db/rows/UnfilteredRowIteratorWithLowerBound.java b/src/java/org/apache/cassandra/db/rows/UnfilteredRowIteratorWithLowerBound.java index e3f10dc883..49976411f3 100644 --- a/src/java/org/apache/cassandra/db/rows/UnfilteredRowIteratorWithLowerBound.java +++ b/src/java/org/apache/cassandra/db/rows/UnfilteredRowIteratorWithLowerBound.java @@ -25,6 +25,7 @@ import java.nio.ByteBuffer; import java.util.Comparator; import java.util.List; +import org.apache.cassandra.db.marshal.ByteBufferAccessor; import org.apache.cassandra.schema.TableMetadata; import org.apache.cassandra.db.*; import org.apache.cassandra.db.filter.ClusteringIndexFilter; @@ -50,7 +51,7 @@ public class UnfilteredRowIteratorWithLowerBound extends LazilyInitializedUnfilt private final ClusteringIndexFilter filter; private final ColumnFilter selectedColumns; private final SSTableReadsListener listener; - private ClusteringBound lowerBound; + private ClusteringBound lowerBound; private boolean firstItemRetrieved; public UnfilteredRowIteratorWithLowerBound(DecoratedKey partitionKey, @@ -76,11 +77,11 @@ public class UnfilteredRowIteratorWithLowerBound extends LazilyInitializedUnfilt // The partition index lower bound is more accurate than the sstable metadata lower bound but it is only // present if the iterator has already been initialized, which we only do when there are tombstones since in // this case we cannot use the sstable metadata clustering values - ClusteringBound ret = getPartitionIndexLowerBound(); + ClusteringBound ret = getPartitionIndexLowerBound(); return ret != null ? makeBound(ret) : makeBound(getMetadataLowerBound()); } - private Unfiltered makeBound(ClusteringBound bound) + private Unfiltered makeBound(ClusteringBound bound) { if (bound == null) return null; @@ -169,10 +170,15 @@ public class UnfilteredRowIteratorWithLowerBound extends LazilyInitializedUnfilt return super.staticRow(); } + private static ClusteringBound createInclusiveOpen(boolean isReversed, ClusteringPrefix from) + { + return from.accessor().factory().inclusiveOpen(isReversed, from.getRawValues()); + } + /** * @return the lower bound stored on the index entry for this partition, if available. */ - private ClusteringBound getPartitionIndexLowerBound() + private ClusteringBound getPartitionIndexLowerBound() { // NOTE: CASSANDRA-11206 removed the lookup against the key-cache as the IndexInfo objects are no longer // in memory for not heap backed IndexInfo objects (so, these are on disk). @@ -190,13 +196,13 @@ public class UnfilteredRowIteratorWithLowerBound extends LazilyInitializedUnfilt try (RowIndexEntry.IndexInfoRetriever onHeapRetriever = rowIndexEntry.openWithIndex(null)) { IndexInfo column = onHeapRetriever.columnsIndex(filter.isReversed() ? rowIndexEntry.columnsIndexCount() - 1 : 0); - ClusteringPrefix lowerBoundPrefix = filter.isReversed() ? column.lastName : column.firstName; + ClusteringPrefix lowerBoundPrefix = filter.isReversed() ? column.lastName : column.firstName; assert lowerBoundPrefix.getRawValues().length <= metadata().comparator.size() : String.format("Unexpected number of clustering values %d, expected %d or fewer for %s", lowerBoundPrefix.getRawValues().length, metadata().comparator.size(), sstable.getFilename()); - return ClusteringBound.inclusiveOpen(filter.isReversed(), lowerBoundPrefix.getRawValues()); + return createInclusiveOpen(filter.isReversed(), lowerBoundPrefix); } catch (IOException e) { @@ -239,7 +245,7 @@ public class UnfilteredRowIteratorWithLowerBound extends LazilyInitializedUnfilt * @return a global lower bound made from the clustering values stored in the sstable metadata, note that * this currently does not correctly compare tombstone bounds, especially ranges. */ - private ClusteringBound getMetadataLowerBound() + private ClusteringBound getMetadataLowerBound() { if (!canUseMetadataLowerBound()) return null; @@ -251,6 +257,6 @@ public class UnfilteredRowIteratorWithLowerBound extends LazilyInitializedUnfilt vals.size(), metadata().comparator.size(), sstable.getFilename()); - return ClusteringBound.inclusiveOpen(filter.isReversed(), vals.toArray(new ByteBuffer[vals.size()])); + return ByteBufferAccessor.instance.factory().inclusiveOpen(filter.isReversed(), vals.toArray(new ByteBuffer[vals.size()])); } } diff --git a/src/java/org/apache/cassandra/db/rows/UnfilteredSerializer.java b/src/java/org/apache/cassandra/db/rows/UnfilteredSerializer.java index a5fad1435b..9313eda932 100644 --- a/src/java/org/apache/cassandra/db/rows/UnfilteredSerializer.java +++ b/src/java/org/apache/cassandra/db/rows/UnfilteredSerializer.java @@ -20,6 +20,7 @@ package org.apache.cassandra.db.rows; import java.io.IOException; import net.nicoulaj.compilecommand.annotations.Inline; +import org.apache.cassandra.db.marshal.ByteArrayAccessor; import org.apache.cassandra.schema.ColumnMetadata; import org.apache.cassandra.db.*; import org.apache.cassandra.db.rows.Row.Deletion; @@ -245,7 +246,7 @@ public class UnfilteredSerializer try { if (cd.column.isSimple()) - Cell.serializer.serialize((Cell) cd, column, out, pkLiveness, header); + Cell.serializer.serialize((Cell) cd, column, out, pkLiveness, header); else writeComplexColumn((ComplexColumnData) cd, column, (flags & HAS_COMPLEX_DELETION) != 0, pkLiveness, header, out); } @@ -271,7 +272,7 @@ public class UnfilteredSerializer header.writeDeletionTime(data.complexDeletion(), out); out.writeUnsignedVInt(data.cellsCount()); - for (Cell cell : data) + for (Cell cell : data) Cell.serializer.serialize(cell, column, out, rowLiveness, header); } @@ -360,7 +361,7 @@ public class UnfilteredSerializer assert column != null; if (data.column.isSimple()) - return v + Cell.serializer.serializedSize((Cell) data, column, pkLiveness, header); + return v + Cell.serializer.serializedSize((Cell) data, column, pkLiveness, header); else return v + sizeOfComplexColumn((ComplexColumnData) data, column, hasComplexDeletion, pkLiveness, header); }, size); @@ -374,7 +375,7 @@ public class UnfilteredSerializer size += header.deletionTimeSerializedSize(data.complexDeletion()); size += TypeSizes.sizeofUnsignedVInt(data.cellsCount()); - for (Cell cell : data) + for (Cell cell : data) size += Cell.serializer.serializedSize(cell, column, rowLiveness, header); return size; @@ -466,7 +467,7 @@ public class UnfilteredSerializer if (kind(flags) == Unfiltered.Kind.RANGE_TOMBSTONE_MARKER) { - ClusteringBoundOrBoundary bound = ClusteringBoundOrBoundary.serializer.deserialize(in, helper.version, header.clusteringTypes()); + ClusteringBoundOrBoundary bound = ClusteringBoundOrBoundary.serializer.deserialize(in, helper.version, header.clusteringTypes()); return deserializeMarkerBody(in, header, bound); } else @@ -493,7 +494,7 @@ public class UnfilteredSerializer if (kind(flags) == Unfiltered.Kind.RANGE_TOMBSTONE_MARKER) { - ClusteringBoundOrBoundary bound = ClusteringBoundOrBoundary.serializer.deserialize(in, helper.version, header.clusteringTypes()); + ClusteringBoundOrBoundary bound = ClusteringBoundOrBoundary.serializer.deserialize(in, helper.version, header.clusteringTypes()); return deserializeMarkerBody(in, header, bound); } else @@ -505,7 +506,7 @@ public class UnfilteredSerializer boolean hasTimestamp = (flags & HAS_TIMESTAMP) != 0; boolean hasTTL = (flags & HAS_TTL) != 0; boolean deletionIsShadowable = (extendedFlags & HAS_SHADOWABLE_DELETION) != 0; - Clustering clustering = Clustering.serializer.deserialize(in, helper.version, header.clusteringTypes()); + Clustering clustering = Clustering.serializer.deserialize(in, helper.version, header.clusteringTypes()); long nextPosition = in.readUnsignedVInt() + in.getFilePointer(); in.readUnsignedVInt(); // skip previous unfiltered size if (hasTimestamp) @@ -543,7 +544,7 @@ public class UnfilteredSerializer return deserializeRowBody(in, header, helper, flags, extendedFlags, builder); } - public RangeTombstoneMarker deserializeMarkerBody(DataInputPlus in, SerializationHeader header, ClusteringBoundOrBoundary bound) + public RangeTombstoneMarker deserializeMarkerBody(DataInputPlus in, SerializationHeader header, ClusteringBoundOrBoundary bound) throws IOException { if (header.isForSSTable()) @@ -553,9 +554,9 @@ public class UnfilteredSerializer } if (bound.isBoundary()) - return new RangeTombstoneBoundaryMarker((ClusteringBoundary) bound, header.readDeletionTime(in), header.readDeletionTime(in)); + return new RangeTombstoneBoundaryMarker((ClusteringBoundary) bound, header.readDeletionTime(in), header.readDeletionTime(in)); else - return new RangeTombstoneBoundMarker((ClusteringBound) bound, header.readDeletionTime(in)); + return new RangeTombstoneBoundMarker((ClusteringBound) bound, header.readDeletionTime(in)); } public Row deserializeRowBody(DataInputPlus in, @@ -640,7 +641,7 @@ public class UnfilteredSerializer { if (helper.includes(column)) { - Cell cell = Cell.serializer.deserialize(in, rowLiveness, column, header, helper); + Cell cell = Cell.serializer.deserialize(in, rowLiveness, column, header, helper, ByteArrayAccessor.instance); if (helper.includes(cell, rowLiveness) && !helper.isDropped(cell, false)) builder.addCell(cell); } @@ -666,7 +667,7 @@ public class UnfilteredSerializer int count = (int) in.readUnsignedVInt(); while (--count >= 0) { - Cell cell = Cell.serializer.deserialize(in, rowLiveness, column, header, helper); + Cell cell = Cell.serializer.deserialize(in, rowLiveness, column, header, helper, ByteArrayAccessor.instance); if (helper.includes(cell, rowLiveness) && !helper.isDropped(cell, true)) builder.addCell(cell); } diff --git a/src/java/org/apache/cassandra/db/transform/DuplicateRowChecker.java b/src/java/org/apache/cassandra/db/transform/DuplicateRowChecker.java index aa1305a7c4..16fabcf15b 100644 --- a/src/java/org/apache/cassandra/db/transform/DuplicateRowChecker.java +++ b/src/java/org/apache/cassandra/db/transform/DuplicateRowChecker.java @@ -39,7 +39,7 @@ public class DuplicateRowChecker extends Transformation> { private static final Logger logger = LoggerFactory.getLogger(DuplicateRowChecker.class); - Clustering previous = null; + Clustering previous = null; int duplicatesDetected = 0; final String stage; diff --git a/src/java/org/apache/cassandra/db/transform/RTBoundCloser.java b/src/java/org/apache/cassandra/db/transform/RTBoundCloser.java index 5dea6e7193..eb10805005 100644 --- a/src/java/org/apache/cassandra/db/transform/RTBoundCloser.java +++ b/src/java/org/apache/cassandra/db/transform/RTBoundCloser.java @@ -63,7 +63,7 @@ public final class RTBoundCloser extends Transformation { private final UnfilteredRowIterator partition; - private Clustering lastRowClustering; + private Clustering lastRowClustering; private DeletionTime openMarkerDeletionTime; private RowsTransformation(UnfilteredRowIterator partition) @@ -108,7 +108,7 @@ public final class RTBoundCloser extends Transformation // create an artificial inclusive closing RT bound with bound matching last seen row's clustering RangeTombstoneBoundMarker closingBound = - RangeTombstoneBoundMarker.inclusiveClose(partition.isReverseOrder(), lastRowClustering.getRawValues(), openMarkerDeletionTime); + RangeTombstoneBoundMarker.inclusiveClose(partition.isReverseOrder(), lastRowClustering, openMarkerDeletionTime); return UnfilteredRowIterators.singleton(closingBound, partition.metadata(), diff --git a/src/java/org/apache/cassandra/db/view/TableViews.java b/src/java/org/apache/cassandra/db/view/TableViews.java index 09490e8bd7..5b88fc7155 100644 --- a/src/java/org/apache/cassandra/db/view/TableViews.java +++ b/src/java/org/apache/cassandra/db/view/TableViews.java @@ -412,7 +412,7 @@ public class TableViews extends AbstractCollection // If we had some slices from the deletions above, we'll continue using that. Otherwise, it's more efficient to build // a names query. - BTreeSet.Builder namesBuilder = sliceBuilder == null ? BTreeSet.builder(metadata.comparator) : null; + BTreeSet.Builder> namesBuilder = sliceBuilder == null ? BTreeSet.builder(metadata.comparator) : null; for (Row row : updates) { // Don't read the existing state if we can prove the update won't affect any views @@ -425,7 +425,7 @@ public class TableViews extends AbstractCollection namesBuilder.add(row.clustering()); } - NavigableSet names = namesBuilder == null ? null : namesBuilder.build(); + NavigableSet> names = namesBuilder == null ? null : namesBuilder.build(); // If we have a slice builder, it means we had some deletions and we have to read. But if we had // only row updates, it's possible none of them affected the views, in which case we have nothing // to do. @@ -482,7 +482,7 @@ public class TableViews extends AbstractCollection generator.addBaseTableUpdate(existingBaseRow, mergedBaseRow); } - private static Row emptyRow(Clustering clustering, DeletionTime deletion) + private static Row emptyRow(Clustering clustering, DeletionTime deletion) { // Returning null for an empty row is slightly ugly, but the case where there is no pre-existing row is fairly common // (especially when building the view), so we want to avoid a dummy allocation of an empty row every time. diff --git a/src/java/org/apache/cassandra/db/view/ViewUpdateGenerator.java b/src/java/org/apache/cassandra/db/view/ViewUpdateGenerator.java index bb22a71bda..090ed0ce49 100644 --- a/src/java/org/apache/cassandra/db/view/ViewUpdateGenerator.java +++ b/src/java/org/apache/cassandra/db/view/ViewUpdateGenerator.java @@ -24,6 +24,7 @@ import java.util.stream.Collectors; import com.google.common.collect.Iterators; import com.google.common.collect.PeekingIterator; +import org.apache.cassandra.db.marshal.ByteBufferAccessor; import org.apache.cassandra.schema.ColumnMetadata; import org.apache.cassandra.schema.Schema; import org.apache.cassandra.schema.TableMetadata; @@ -186,8 +187,8 @@ public class ViewUpdateGenerator ColumnMetadata baseColumn = view.baseNonPKColumnsInViewPK.get(0); assert !baseColumn.isComplex() : "A complex column couldn't be part of the view PK"; - Cell before = existingBaseRow == null ? null : existingBaseRow.getCell(baseColumn); - Cell after = mergedBaseRow.getCell(baseColumn); + Cell before = existingBaseRow == null ? null : existingBaseRow.getCell(baseColumn); + Cell after = mergedBaseRow.getCell(baseColumn); // If the update didn't modified this column, the cells will be the same object so it's worth checking if (before == after) @@ -200,7 +201,7 @@ public class ViewUpdateGenerator return UpdateAction.DELETE_OLD; } - return baseColumn.cellValueType().compare(before.value(), after.value()) == 0 + return baseColumn.cellValueType().compare(before.buffer(), after.buffer()) == 0 ? UpdateAction.UPDATE_EXISTING : UpdateAction.SWITCH_ENTRY; } @@ -210,7 +211,7 @@ public class ViewUpdateGenerator return view.matchesViewFilter(baseDecoratedKey, baseRow, nowInSec); } - private boolean isLive(Cell cell) + private boolean isLive(Cell cell) { return cell != null && cell.isLive(nowInSec); } @@ -333,10 +334,10 @@ public class ViewUpdateGenerator if (mergedComplexData.complexDeletion().supersedes(existingComplexData.complexDeletion())) currentViewEntryBuilder.addComplexDeletion(viewColumn, mergedComplexData.complexDeletion()); - PeekingIterator existingCells = Iterators.peekingIterator(existingComplexData.iterator()); - for (Cell mergedCell : mergedComplexData) + PeekingIterator> existingCells = Iterators.peekingIterator(existingComplexData.iterator()); + for (Cell mergedCell : mergedComplexData) { - Cell existingCell = null; + Cell existingCell = null; // Find if there is corresponding cell in the existing row while (existingCells.hasNext()) { @@ -344,7 +345,7 @@ public class ViewUpdateGenerator if (cmp > 0) break; - Cell next = existingCells.next(); + Cell next = existingCells.next(); if (cmp == 0) { existingCell = next; @@ -359,7 +360,7 @@ public class ViewUpdateGenerator else { // Note that we've already eliminated the case where merged == existing - addCell(viewColumn, (Cell)mergedData); + addCell(viewColumn, (Cell)mergedData); } } } @@ -458,8 +459,8 @@ public class ViewUpdateGenerator long timestamp = baseLiveness.timestamp(); boolean hasNonExpiringLiveCell = false; - Cell biggestExpirationCell = null; - for (Cell cell : baseRow.cells()) + Cell biggestExpirationCell = null; + for (Cell cell : baseRow.cells()) { if (view.getViewColumn(cell.column()) != null) continue; @@ -490,7 +491,7 @@ public class ViewUpdateGenerator return baseLiveness; } - Cell cell = baseRow.getCell(view.baseNonPKColumnsInViewPK.get(0)); + Cell cell = baseRow.getCell(view.baseNonPKColumnsInViewPK.get(0)); assert isLive(cell) : "We shouldn't have got there if the base row had no associated entry"; return LivenessInfo.withExpirationTime(cell.timestamp(), cell.ttl(), cell.localDeletionTime()); @@ -505,7 +506,7 @@ public class ViewUpdateGenerator if (view.getDefinition().includeAllColumns) return timestamp; - for (Cell cell : existingBaseRow.cells()) + for (Cell cell : existingBaseRow.cells()) { // selected column should not contribute to view deletion, itself is already included in view row if (view.getViewColumn(cell.column()) != null) @@ -516,7 +517,7 @@ public class ViewUpdateGenerator return timestamp; } // has base non-pk column in view pk - Cell before = existingBaseRow.getCell(view.baseNonPKColumnsInViewPK.get(0)); + Cell before = existingBaseRow.getCell(view.baseNonPKColumnsInViewPK.get(0)); assert isLive(before) : "We shouldn't have got there if the base row had no associated entry"; return deletion.deletes(before) ? deletion.markedForDeleteAt() : before.timestamp(); } @@ -526,17 +527,17 @@ public class ViewUpdateGenerator assert viewColumn.isComplex() == baseTableData.column().isComplex(); if (!viewColumn.isComplex()) { - addCell(viewColumn, (Cell)baseTableData); + addCell(viewColumn, (Cell)baseTableData); return; } ComplexColumnData complexData = (ComplexColumnData)baseTableData; currentViewEntryBuilder.addComplexDeletion(viewColumn, complexData.complexDeletion()); - for (Cell cell : complexData) + for (Cell cell : complexData) addCell(viewColumn, cell); } - private void addCell(ColumnMetadata viewColumn, Cell baseTableCell) + private void addCell(ColumnMetadata viewColumn, Cell baseTableCell) { assert !viewColumn.isPrimaryKeyColumn(); currentViewEntryBuilder.addCell(baseTableCell.withUpdatedColumn(viewColumn)); @@ -569,7 +570,7 @@ public class ViewUpdateGenerator { ByteBuffer rawKey = viewMetadata.partitionKeyColumns().size() == 1 ? currentViewEntryPartitionKey[0] - : CompositeType.build(currentViewEntryPartitionKey); + : CompositeType.build(ByteBufferAccessor.instance, currentViewEntryPartitionKey); return viewMetadata.partitioner.decorateKey(rawKey); } @@ -581,10 +582,10 @@ public class ViewUpdateGenerator case PARTITION_KEY: return basePartitionKey[column.position()]; case CLUSTERING: - return row.clustering().get(column.position()); + return row.clustering().bufferAt(column.position()); default: // This shouldn't NPE as we shouldn't get there if the value can be null (or there is a bug in updateAction()) - return row.getCell(column).value(); + return row.getCell(column).buffer(); } } } diff --git a/src/java/org/apache/cassandra/db/virtual/SimpleDataSet.java b/src/java/org/apache/cassandra/db/virtual/SimpleDataSet.java index 00acaedc02..8b6f7ca59c 100644 --- a/src/java/org/apache/cassandra/db/virtual/SimpleDataSet.java +++ b/src/java/org/apache/cassandra/db/virtual/SimpleDataSet.java @@ -27,6 +27,7 @@ import org.apache.cassandra.db.*; import org.apache.cassandra.db.filter.ClusteringIndexFilter; import org.apache.cassandra.db.filter.ColumnFilter; import org.apache.cassandra.db.marshal.AbstractType; +import org.apache.cassandra.db.marshal.ByteBufferAccessor; import org.apache.cassandra.db.marshal.CompositeType; import org.apache.cassandra.db.rows.*; import org.apache.cassandra.schema.ColumnMetadata; @@ -60,7 +61,7 @@ public class SimpleDataSet extends AbstractVirtualTable.AbstractDataSet System.arraycopy(primaryKeyValues, partitionKeyValues.length, clusteringValues, 0, clusteringValues.length); DecoratedKey partitionKey = makeDecoratedKey(partitionKeyValues); - Clustering clustering = makeClustering(clusteringValues); + Clustering clustering = makeClustering(clusteringValues); currentRow = new Row(metadata, clustering); SimplePartition partition = (SimplePartition) partitions.computeIfAbsent(partitionKey, pk -> new SimplePartition(metadata, pk)); @@ -83,11 +84,11 @@ public class SimpleDataSet extends AbstractVirtualTable.AbstractDataSet { ByteBuffer partitionKey = partitionKeyValues.length == 1 ? decompose(metadata.partitionKeyType, partitionKeyValues[0]) - : ((CompositeType) metadata.partitionKeyType).decompose(partitionKeyValues); + : ((CompositeType) metadata.partitionKeyType).decompose(ByteBufferAccessor.instance, partitionKeyValues); return metadata.partitioner.decorateKey(partitionKey); } - private Clustering makeClustering(Object... clusteringValues) + private Clustering makeClustering(Object... clusteringValues) { if (clusteringValues.length == 0) return Clustering.EMPTY; @@ -101,7 +102,7 @@ public class SimpleDataSet extends AbstractVirtualTable.AbstractDataSet private static final class SimplePartition implements AbstractVirtualTable.Partition { private final DecoratedKey key; - private final NavigableMap rows; + private final NavigableMap, Row> rows; private SimplePartition(TableMetadata metadata, DecoratedKey key) { @@ -151,11 +152,11 @@ public class SimpleDataSet extends AbstractVirtualTable.AbstractDataSet private static class Row { private final TableMetadata metadata; - private final Clustering clustering; + private final Clustering clustering; private final Map values = new HashMap<>(); - private Row(TableMetadata metadata, Clustering clustering) + private Row(TableMetadata metadata, Clustering clustering) { this.metadata = metadata; this.clustering = clustering; diff --git a/src/java/org/apache/cassandra/gms/TokenSerializer.java b/src/java/org/apache/cassandra/gms/TokenSerializer.java index c371d64f35..40d14f85c2 100644 --- a/src/java/org/apache/cassandra/gms/TokenSerializer.java +++ b/src/java/org/apache/cassandra/gms/TokenSerializer.java @@ -19,7 +19,7 @@ package org.apache.cassandra.gms; import org.apache.cassandra.dht.IPartitioner; import org.apache.cassandra.dht.Token; -import org.apache.cassandra.utils.ByteBufferUtil; +import org.apache.cassandra.utils.ByteArrayUtil; import org.apache.cassandra.utils.FBUtilities; import org.slf4j.Logger; @@ -41,7 +41,7 @@ public class TokenSerializer { ByteBuffer tokenBuffer = partitioner.getTokenFactory().toByteArray(token); assert tokenBuffer.arrayOffset() == 0; - ByteBufferUtil.writeWithLength(tokenBuffer.array(), out); + ByteArrayUtil.writeWithLength(tokenBuffer.array(), out); } out.writeInt(0); } diff --git a/src/java/org/apache/cassandra/hadoop/cql3/CqlRecordWriter.java b/src/java/org/apache/cassandra/hadoop/cql3/CqlRecordWriter.java index 989d154f15..4bce989602 100644 --- a/src/java/org/apache/cassandra/hadoop/cql3/CqlRecordWriter.java +++ b/src/java/org/apache/cassandra/hadoop/cql3/CqlRecordWriter.java @@ -29,6 +29,7 @@ import org.slf4j.LoggerFactory; import com.datastax.driver.core.*; import com.datastax.driver.core.exceptions.*; +import org.apache.cassandra.db.marshal.ByteBufferAccessor; import org.apache.cassandra.db.marshal.CompositeType; import org.apache.cassandra.dht.IPartitioner; import org.apache.cassandra.dht.Token; @@ -460,7 +461,7 @@ class CqlRecordWriter extends RecordWriter, List clustering, LivenessInfo merged, LivenessInfo original) { } - public void onDeletion(int i, Clustering clustering, Row.Deletion merged, Row.Deletion original) + public void onDeletion(int i, Clustering clustering, Row.Deletion merged, Row.Deletion original) { } - public void onComplexDeletion(int i, Clustering clustering, ColumnMetadata column, DeletionTime merged, DeletionTime original) + public void onComplexDeletion(int i, Clustering clustering, ColumnMetadata column, DeletionTime merged, DeletionTime original) { } - public void onCell(int i, Clustering clustering, Cell merged, Cell original) + public void onCell(int i, Clustering clustering, Cell merged, Cell original) { if (merged != null && !merged.equals(original)) toInsert.addCell(merged); @@ -1314,7 +1315,7 @@ public class SecondaryIndexManager implements IndexRegistry, INotificationConsum indexer.finish(); } - private boolean shouldCleanupOldValue(Cell oldCell, Cell newCell) + private boolean shouldCleanupOldValue(Cell oldCell, Cell newCell) { // If either the value or timestamp is different, then we // should delete from the index. If not, then we can infer that @@ -1325,7 +1326,7 @@ public class SecondaryIndexManager implements IndexRegistry, INotificationConsum // Completely identical cells (including expiring columns with // identical ttl & localExpirationTime) will not get this far due // to the oldCell.equals(newCell) in StandardUpdater.update - return !oldCell.value().equals(newCell.value()) || oldCell.timestamp() != newCell.timestamp(); + return !Cells.valueEqual(oldCell, newCell) || oldCell.timestamp() != newCell.timestamp(); } } @@ -1374,27 +1375,27 @@ public class SecondaryIndexManager implements IndexRegistry, INotificationConsum final Row.Builder[] builders = new Row.Builder[versions.length]; RowDiffListener diffListener = new RowDiffListener() { - public void onPrimaryKeyLivenessInfo(int i, Clustering clustering, LivenessInfo merged, LivenessInfo original) + public void onPrimaryKeyLivenessInfo(int i, Clustering clustering, LivenessInfo merged, LivenessInfo original) { if (original != null && (merged == null || !merged.isLive(nowInSec))) getBuilder(i, clustering).addPrimaryKeyLivenessInfo(original); } - public void onDeletion(int i, Clustering clustering, Row.Deletion merged, Row.Deletion original) + public void onDeletion(int i, Clustering clustering, Row.Deletion merged, Row.Deletion original) { } - public void onComplexDeletion(int i, Clustering clustering, ColumnMetadata column, DeletionTime merged, DeletionTime original) + public void onComplexDeletion(int i, Clustering clustering, ColumnMetadata column, DeletionTime merged, DeletionTime original) { } - public void onCell(int i, Clustering clustering, Cell merged, Cell original) + public void onCell(int i, Clustering clustering, Cell merged, Cell original) { if (original != null && (merged == null || !merged.isLive(nowInSec))) getBuilder(i, clustering).addCell(original); } - private Row.Builder getBuilder(int index, Clustering clustering) + private Row.Builder getBuilder(int index, Clustering clustering) { if (builders[index] == null) { diff --git a/src/java/org/apache/cassandra/index/internal/CassandraIndex.java b/src/java/org/apache/cassandra/index/internal/CassandraIndex.java index 3d52edfe75..ea5f8e2f61 100644 --- a/src/java/org/apache/cassandra/index/internal/CassandraIndex.java +++ b/src/java/org/apache/cassandra/index/internal/CassandraIndex.java @@ -105,8 +105,8 @@ public abstract class CassandraIndex implements Index * @param path from the base data being indexed * @return a clustering prefix to be used to insert into the index table */ - protected abstract CBuilder buildIndexClusteringPrefix(ByteBuffer partitionKey, - ClusteringPrefix prefix, + protected abstract CBuilder buildIndexClusteringPrefix(ByteBuffer partitionKey, + ClusteringPrefix prefix, CellPath path); /** @@ -140,7 +140,7 @@ public abstract class CassandraIndex implements Index * key in the index table */ protected abstract ByteBuffer getIndexedValue(ByteBuffer partitionKey, - Clustering clustering, + Clustering clustering, CellPath path, ByteBuffer cellValue); @@ -426,16 +426,16 @@ public abstract class CassandraIndex implements Index { } - private void indexCells(Clustering clustering, Iterable cells) + private void indexCells(Clustering clustering, Iterable> cells) { if (cells == null) return; - for (Cell cell : cells) + for (Cell cell : cells) indexCell(clustering, cell); } - private void indexCell(Clustering clustering, Cell cell) + private void indexCell(Clustering clustering, Cell cell) { if (cell == null || !cell.isLive(nowInSec)) return; @@ -447,16 +447,16 @@ public abstract class CassandraIndex implements Index ctx); } - private void removeCells(Clustering clustering, Iterable cells) + private void removeCells(Clustering clustering, Iterable> cells) { if (cells == null) return; - for (Cell cell : cells) + for (Cell cell : cells) removeCell(clustering, cell); } - private void removeCell(Clustering clustering, Cell cell) + private void removeCell(Clustering clustering, Cell cell) { if (cell == null || !cell.isLive(nowInSec)) return; @@ -464,7 +464,7 @@ public abstract class CassandraIndex implements Index delete(key.getKey(), clustering, cell, ctx, nowInSec); } - private void indexPrimaryKey(final Clustering clustering, + private void indexPrimaryKey(final Clustering clustering, final LivenessInfo liveness, final Row.Deletion deletion) { @@ -479,7 +479,7 @@ public abstract class CassandraIndex implements Index { long timestamp = row.primaryKeyLivenessInfo().timestamp(); int ttl = row.primaryKeyLivenessInfo().ttl(); - for (Cell cell : row.cells()) + for (Cell cell : row.cells()) { long cellTimestamp = cell.timestamp(); if (cell.isLive(nowInSec)) @@ -505,7 +505,7 @@ public abstract class CassandraIndex implements Index * @param ctx the write context under which to perform the deletion */ public void deleteStaleEntry(DecoratedKey indexKey, - Clustering indexClustering, + Clustering indexClustering, DeletionTime deletion, WriteContext ctx) { @@ -517,8 +517,8 @@ public abstract class CassandraIndex implements Index * Called when adding a new entry to the index */ private void insert(ByteBuffer rowKey, - Clustering clustering, - Cell cell, + Clustering clustering, + Cell cell, LivenessInfo info, WriteContext ctx) { @@ -535,8 +535,8 @@ public abstract class CassandraIndex implements Index * Called when deleting entries on non-primary key columns */ private void delete(ByteBuffer rowKey, - Clustering clustering, - Cell cell, + Clustering clustering, + Cell cell, WriteContext ctx, int nowInSec) { @@ -553,7 +553,7 @@ public abstract class CassandraIndex implements Index * Called when deleting entries from indexes on primary key columns */ private void delete(ByteBuffer rowKey, - Clustering clustering, + Clustering clustering, DeletionTime deletion, WriteContext ctx) { @@ -567,7 +567,7 @@ public abstract class CassandraIndex implements Index } private void doDelete(DecoratedKey indexKey, - Clustering indexClustering, + Clustering indexClustering, DeletionTime deletion, WriteContext ctx) { @@ -600,9 +600,9 @@ public abstract class CassandraIndex implements Index ComplexColumnData data = row.getComplexColumnData(indexedColumn); if (data != null) { - for (Cell cell : data) + for (Cell cell : data) { - validateIndexedValue(getIndexedValue(null, null, cell.path(), cell.value())); + validateIndexedValue(getIndexedValue(null, null, cell.path(), cell.buffer())); } } } @@ -626,19 +626,19 @@ public abstract class CassandraIndex implements Index } private ByteBuffer getIndexedValue(ByteBuffer rowKey, - Clustering clustering, - Cell cell) + Clustering clustering, + Cell cell) { return getIndexedValue(rowKey, clustering, cell == null ? null : cell.path(), - cell == null ? null : cell.value() + cell == null ? null : cell.buffer() ); } - private Clustering buildIndexClustering(ByteBuffer rowKey, - Clustering clustering, - Cell cell) + private Clustering buildIndexClustering(ByteBuffer rowKey, + Clustering clustering, + Cell cell) { return buildIndexClusteringPrefix(rowKey, clustering, diff --git a/src/java/org/apache/cassandra/index/internal/CassandraIndexSearcher.java b/src/java/org/apache/cassandra/index/internal/CassandraIndexSearcher.java index 81c05d6771..e2e0600aae 100644 --- a/src/java/org/apache/cassandra/index/internal/CassandraIndexSearcher.java +++ b/src/java/org/apache/cassandra/index/internal/CassandraIndexSearcher.java @@ -94,9 +94,9 @@ public abstract class CassandraIndexSearcher implements Index.Searcher if (filter instanceof ClusteringIndexNamesFilter) { - NavigableSet requested = ((ClusteringIndexNamesFilter)filter).requestedRows(); - BTreeSet.Builder clusterings = BTreeSet.builder(index.getIndexComparator()); - for (Clustering c : requested) + NavigableSet> requested = ((ClusteringIndexNamesFilter)filter).requestedRows(); + BTreeSet.Builder> clusterings = BTreeSet.builder(index.getIndexComparator()); + for (Clustering c : requested) clusterings.add(makeIndexClustering(pk, c)); return new ClusteringIndexNamesFilter(clusterings.build(), filter.isReversed()); } @@ -132,8 +132,8 @@ public abstract class CassandraIndexSearcher implements Index.Searcher DecoratedKey startKey = (DecoratedKey) range.left; DecoratedKey endKey = (DecoratedKey) range.right; - ClusteringBound start = ClusteringBound.BOTTOM; - ClusteringBound end = ClusteringBound.TOP; + ClusteringBound start = BufferClusteringBound.BOTTOM; + ClusteringBound end = BufferClusteringBound.TOP; /* * For index queries over a range, we can't do a whole lot better than querying everything for the @@ -167,21 +167,21 @@ public abstract class CassandraIndexSearcher implements Index.Searcher else { // otherwise, just start the index slice from the key we do have - slice = Slice.make(makeIndexBound(((DecoratedKey)range.left).getKey(), ClusteringBound.BOTTOM), - ClusteringBound.TOP); + slice = Slice.make(makeIndexBound(((DecoratedKey)range.left).getKey(), BufferClusteringBound.BOTTOM), + BufferClusteringBound.TOP); } } return new ClusteringIndexSliceFilter(Slices.with(index.getIndexComparator(), slice), false); } } - private ClusteringBound makeIndexBound(ByteBuffer rowKey, ClusteringBound bound) + private ClusteringBound makeIndexBound(ByteBuffer rowKey, ClusteringBound bound) { return index.buildIndexClusteringPrefix(rowKey, bound, null) .buildBound(bound.isStart(), bound.isInclusive()); } - protected Clustering makeIndexClustering(ByteBuffer rowKey, Clustering clustering) + protected Clustering makeIndexClustering(ByteBuffer rowKey, Clustering clustering) { return index.buildIndexClusteringPrefix(rowKey, clustering, null).build(); } diff --git a/src/java/org/apache/cassandra/index/internal/IndexEntry.java b/src/java/org/apache/cassandra/index/internal/IndexEntry.java index 3e4e41bac9..c8e9955d57 100644 --- a/src/java/org/apache/cassandra/index/internal/IndexEntry.java +++ b/src/java/org/apache/cassandra/index/internal/IndexEntry.java @@ -33,17 +33,17 @@ import org.apache.cassandra.db.DecoratedKey; public final class IndexEntry { public final DecoratedKey indexValue; - public final Clustering indexClustering; + public final Clustering indexClustering; public final long timestamp; public final ByteBuffer indexedKey; - public final Clustering indexedEntryClustering; + public final Clustering indexedEntryClustering; public IndexEntry(DecoratedKey indexValue, - Clustering indexClustering, + Clustering indexClustering, long timestamp, ByteBuffer indexedKey, - Clustering indexedEntryClustering) + Clustering indexedEntryClustering) { this.indexValue = indexValue; this.indexClustering = indexClustering; diff --git a/src/java/org/apache/cassandra/index/internal/composites/ClusteringColumnIndex.java b/src/java/org/apache/cassandra/index/internal/composites/ClusteringColumnIndex.java index 17ab814661..560986b7b8 100644 --- a/src/java/org/apache/cassandra/index/internal/composites/ClusteringColumnIndex.java +++ b/src/java/org/apache/cassandra/index/internal/composites/ClusteringColumnIndex.java @@ -57,22 +57,22 @@ public class ClusteringColumnIndex extends CassandraIndex public ByteBuffer getIndexedValue(ByteBuffer partitionKey, - Clustering clustering, + Clustering clustering, CellPath path, ByteBuffer cellValue) { - return clustering.get(indexedColumn.position()); + return clustering.bufferAt(indexedColumn.position()); } - public CBuilder buildIndexClusteringPrefix(ByteBuffer partitionKey, - ClusteringPrefix prefix, - CellPath path) + public CBuilder buildIndexClusteringPrefix(ByteBuffer partitionKey, + ClusteringPrefix prefix, + CellPath path) { CBuilder builder = CBuilder.create(getIndexComparator()); builder.add(partitionKey); for (int i = 0; i < Math.min(indexedColumn.position(), prefix.size()); i++) - builder.add(prefix.get(i)); + builder.add(prefix.get(i), prefix.accessor()); for (int i = indexedColumn.position() + 1; i < prefix.size(); i++) - builder.add(prefix.get(i)); + builder.add(prefix.get(i), prefix.accessor()); return builder; } @@ -81,20 +81,20 @@ public class ClusteringColumnIndex extends CassandraIndex { int ckCount = baseCfs.metadata().clusteringColumns().size(); - Clustering clustering = indexEntry.clustering(); + Clustering clustering = indexEntry.clustering(); CBuilder builder = CBuilder.create(baseCfs.getComparator()); for (int i = 0; i < indexedColumn.position(); i++) - builder.add(clustering.get(i + 1)); + builder.add(clustering, i + 1); builder.add(indexedValue.getKey()); for (int i = indexedColumn.position() + 1; i < ckCount; i++) - builder.add(clustering.get(i)); + builder.add(clustering, i); return new IndexEntry(indexedValue, clustering, indexEntry.primaryKeyLivenessInfo().timestamp(), - clustering.get(0), + clustering.bufferAt(0), builder.build()); } diff --git a/src/java/org/apache/cassandra/index/internal/composites/CollectionEntryIndex.java b/src/java/org/apache/cassandra/index/internal/composites/CollectionEntryIndex.java index efe84b6283..e4b2126df5 100644 --- a/src/java/org/apache/cassandra/index/internal/composites/CollectionEntryIndex.java +++ b/src/java/org/apache/cassandra/index/internal/composites/CollectionEntryIndex.java @@ -19,6 +19,7 @@ package org.apache.cassandra.index.internal.composites; import java.nio.ByteBuffer; +import org.apache.cassandra.db.marshal.ByteBufferAccessor; import org.apache.cassandra.schema.ColumnMetadata; import org.apache.cassandra.db.Clustering; import org.apache.cassandra.db.ColumnFamilyStore; @@ -45,10 +46,10 @@ public class CollectionEntryIndex extends CollectionKeyIndexBase } public ByteBuffer getIndexedValue(ByteBuffer partitionKey, - Clustering clustering, + Clustering clustering, CellPath path, ByteBuffer cellValue) { - return CompositeType.build(path.get(0), cellValue); + return CompositeType.build(ByteBufferAccessor.instance, path.get(0), cellValue); } public boolean isStale(Row data, ByteBuffer indexValue, int nowInSec) @@ -58,11 +59,11 @@ public class CollectionEntryIndex extends CollectionKeyIndexBase ByteBuffer mapValue = components[1]; ColumnMetadata columnDef = indexedColumn; - Cell cell = data.getCell(columnDef, CellPath.create(mapKey)); + Cell cell = data.getCell(columnDef, CellPath.create(mapKey)); if (cell == null || !cell.isLive(nowInSec)) return true; AbstractType valueComparator = ((CollectionType)columnDef.type).valueComparator(); - return valueComparator.compare(mapValue, cell.value()) != 0; + return valueComparator.compare(mapValue, cell.buffer()) != 0; } } diff --git a/src/java/org/apache/cassandra/index/internal/composites/CollectionKeyIndex.java b/src/java/org/apache/cassandra/index/internal/composites/CollectionKeyIndex.java index 4fc20ae458..f7b0bef1da 100644 --- a/src/java/org/apache/cassandra/index/internal/composites/CollectionKeyIndex.java +++ b/src/java/org/apache/cassandra/index/internal/composites/CollectionKeyIndex.java @@ -43,7 +43,7 @@ public class CollectionKeyIndex extends CollectionKeyIndexBase } public ByteBuffer getIndexedValue(ByteBuffer partitionKey, - Clustering clustering, + Clustering clustering, CellPath path, ByteBuffer cellValue) { @@ -52,7 +52,7 @@ public class CollectionKeyIndex extends CollectionKeyIndexBase public boolean isStale(Row data, ByteBuffer indexValue, int nowInSec) { - Cell cell = data.getCell(indexedColumn, CellPath.create(indexValue)); + Cell cell = data.getCell(indexedColumn, CellPath.create(indexValue)); return cell == null || !cell.isLive(nowInSec); } diff --git a/src/java/org/apache/cassandra/index/internal/composites/CollectionKeyIndexBase.java b/src/java/org/apache/cassandra/index/internal/composites/CollectionKeyIndexBase.java index fccf522d0e..f0201e1eff 100644 --- a/src/java/org/apache/cassandra/index/internal/composites/CollectionKeyIndexBase.java +++ b/src/java/org/apache/cassandra/index/internal/composites/CollectionKeyIndexBase.java @@ -48,9 +48,9 @@ public abstract class CollectionKeyIndexBase extends CassandraIndex super(baseCfs, indexDef); } - public CBuilder buildIndexClusteringPrefix(ByteBuffer partitionKey, - ClusteringPrefix prefix, - CellPath path) + public CBuilder buildIndexClusteringPrefix(ByteBuffer partitionKey, + ClusteringPrefix prefix, + CellPath path) { CBuilder builder = CBuilder.create(getIndexComparator()); builder.add(partitionKey); @@ -58,7 +58,7 @@ public abstract class CollectionKeyIndexBase extends CassandraIndex // When indexing a static column, prefix will be empty but only the // partition key is needed at query time. for (int i = 0; i < prefix.size(); i++) - builder.add(prefix.get(i)); + builder.add(prefix.get(i), prefix.accessor()); return builder; } @@ -66,9 +66,9 @@ public abstract class CollectionKeyIndexBase extends CassandraIndex public IndexEntry decodeEntry(DecoratedKey indexedValue, Row indexEntry) { - Clustering clustering = indexEntry.clustering(); + Clustering clustering = indexEntry.clustering(); - Clustering indexedEntryClustering = null; + Clustering indexedEntryClustering = null; if (getIndexedColumn().isStatic()) indexedEntryClustering = Clustering.STATIC_CLUSTERING; else @@ -76,14 +76,14 @@ public abstract class CollectionKeyIndexBase extends CassandraIndex int count = 1 + baseCfs.metadata().clusteringColumns().size(); CBuilder builder = CBuilder.create(baseCfs.getComparator()); for (int i = 0; i < count - 1; i++) - builder.add(clustering.get(i + 1)); + builder.add(clustering, i + 1); indexedEntryClustering = builder.build(); } return new IndexEntry(indexedValue, clustering, indexEntry.primaryKeyLivenessInfo().timestamp(), - clustering.get(0), + clustering.bufferAt(0), indexedEntryClustering); } } diff --git a/src/java/org/apache/cassandra/index/internal/composites/CollectionValueIndex.java b/src/java/org/apache/cassandra/index/internal/composites/CollectionValueIndex.java index 4f0f2df4a0..1247727bcf 100644 --- a/src/java/org/apache/cassandra/index/internal/composites/CollectionValueIndex.java +++ b/src/java/org/apache/cassandra/index/internal/composites/CollectionValueIndex.java @@ -48,20 +48,20 @@ public class CollectionValueIndex extends CassandraIndex } public ByteBuffer getIndexedValue(ByteBuffer partitionKey, - Clustering clustering, + Clustering clustering, CellPath path, ByteBuffer cellValue) { return cellValue; } - public CBuilder buildIndexClusteringPrefix(ByteBuffer partitionKey, - ClusteringPrefix prefix, - CellPath path) + public CBuilder buildIndexClusteringPrefix(ByteBuffer partitionKey, + ClusteringPrefix prefix, + CellPath path) { CBuilder builder = CBuilder.create(getIndexComparator()); builder.add(partitionKey); for (int i = 0; i < prefix.size(); i++) - builder.add(prefix.get(i)); + builder.add(prefix.get(i), prefix.accessor()); // When indexing a static column, prefix will be empty but only the // partition key is needed at query time. @@ -75,22 +75,22 @@ public class CollectionValueIndex extends CassandraIndex public IndexEntry decodeEntry(DecoratedKey indexedValue, Row indexEntry) { - Clustering clustering = indexEntry.clustering(); - Clustering indexedEntryClustering = null; + Clustering clustering = indexEntry.clustering(); + Clustering indexedEntryClustering = null; if (getIndexedColumn().isStatic()) indexedEntryClustering = Clustering.STATIC_CLUSTERING; else { CBuilder builder = CBuilder.create(baseCfs.getComparator()); for (int i = 0; i < baseCfs.getComparator().size(); i++) - builder.add(clustering.get(i + 1)); + builder.add(clustering, i + 1); indexedEntryClustering = builder.build(); } return new IndexEntry(indexedValue, clustering, indexEntry.primaryKeyLivenessInfo().timestamp(), - clustering.get(0), + clustering.bufferAt(0), indexedEntryClustering); } @@ -106,10 +106,10 @@ public class CollectionValueIndex extends CassandraIndex if (complexData == null) return true; - for (Cell cell : complexData) + for (Cell cell : complexData) { if (cell.isLive(nowInSec) && ((CollectionType) columnDef.type).valueComparator() - .compare(indexValue, cell.value()) == 0) + .compare(indexValue, cell.buffer()) == 0) return false; } return true; diff --git a/src/java/org/apache/cassandra/index/internal/composites/CompositesSearcher.java b/src/java/org/apache/cassandra/index/internal/composites/CompositesSearcher.java index ba747ec885..815b881f1a 100644 --- a/src/java/org/apache/cassandra/index/internal/composites/CompositesSearcher.java +++ b/src/java/org/apache/cassandra/index/internal/composites/CompositesSearcher.java @@ -135,7 +135,7 @@ public class CompositesSearcher extends CassandraIndexSearcher // in memory so we should consider adding some paging mechanism. However, index hits should // be relatively small so it's much better than the previous code that was materializing all // *data* for a given partition. - BTreeSet.Builder clusterings = BTreeSet.builder(index.baseCfs.getComparator()); + BTreeSet.Builder> clusterings = BTreeSet.builder(index.baseCfs.getComparator()); while (nextEntry != null && partitionKey.getKey().equals(nextEntry.indexedKey)) { // We're queried a slice of the index, but some hits may not match some of the clustering column constraints @@ -267,13 +267,13 @@ public class CompositesSearcher extends CassandraIndexSearcher return null; } - private IndexEntry findEntry(Clustering clustering) + private IndexEntry findEntry(Clustering clustering) { assert entriesIdx < entries.size(); while (entriesIdx < entries.size()) { IndexEntry entry = entries.get(entriesIdx++); - Clustering indexedEntryClustering = entry.indexedEntryClustering; + Clustering indexedEntryClustering = entry.indexedEntryClustering; // The entries are in clustering order. So that the requested entry should be the // next entry, the one at 'entriesIdx'. However, we can have stale entries, entries // that have no corresponding row in the base table typically because of a range @@ -296,7 +296,7 @@ public class CompositesSearcher extends CassandraIndexSearcher throw new AssertionError(); } - private boolean containsOnlyNullValues(Clustering indexedEntryClustering) + private boolean containsOnlyNullValues(Clustering indexedEntryClustering) { int i = 0; for (; i < indexedEntryClustering.size() && indexedEntryClustering.get(i) == null; i++); diff --git a/src/java/org/apache/cassandra/index/internal/composites/PartitionKeyIndex.java b/src/java/org/apache/cassandra/index/internal/composites/PartitionKeyIndex.java index 9b03213f0e..3e5f1fd2e5 100644 --- a/src/java/org/apache/cassandra/index/internal/composites/PartitionKeyIndex.java +++ b/src/java/org/apache/cassandra/index/internal/composites/PartitionKeyIndex.java @@ -55,7 +55,7 @@ public class PartitionKeyIndex extends CassandraIndex } public ByteBuffer getIndexedValue(ByteBuffer partitionKey, - Clustering clustering, + Clustering clustering, CellPath path, ByteBuffer cellValue) { @@ -64,29 +64,29 @@ public class PartitionKeyIndex extends CassandraIndex return components[indexedColumn.position()]; } - public CBuilder buildIndexClusteringPrefix(ByteBuffer partitionKey, - ClusteringPrefix prefix, - CellPath path) + public CBuilder buildIndexClusteringPrefix(ByteBuffer partitionKey, + ClusteringPrefix prefix, + CellPath path) { CBuilder builder = CBuilder.create(getIndexComparator()); builder.add(partitionKey); for (int i = 0; i < prefix.size(); i++) - builder.add(prefix.get(i)); + builder.add(prefix.get(i), prefix.accessor()); return builder; } public IndexEntry decodeEntry(DecoratedKey indexedValue, Row indexEntry) { int ckCount = baseCfs.metadata().clusteringColumns().size(); - Clustering clustering = indexEntry.clustering(); + Clustering clustering = indexEntry.clustering(); CBuilder builder = CBuilder.create(baseCfs.getComparator()); for (int i = 0; i < ckCount; i++) - builder.add(clustering.get(i + 1)); + builder.add(clustering, i + 1); return new IndexEntry(indexedValue, clustering, indexEntry.primaryKeyLivenessInfo().timestamp(), - clustering.get(0), + clustering.bufferAt(0), builder.build()); } diff --git a/src/java/org/apache/cassandra/index/internal/composites/RegularColumnIndex.java b/src/java/org/apache/cassandra/index/internal/composites/RegularColumnIndex.java index 9cbfe035e1..19eff3e7c2 100644 --- a/src/java/org/apache/cassandra/index/internal/composites/RegularColumnIndex.java +++ b/src/java/org/apache/cassandra/index/internal/composites/RegularColumnIndex.java @@ -20,6 +20,8 @@ package org.apache.cassandra.index.internal.composites; import java.nio.ByteBuffer; import org.apache.cassandra.db.*; +import org.apache.cassandra.db.marshal.AbstractType; +import org.apache.cassandra.db.marshal.ByteBufferAccessor; import org.apache.cassandra.db.rows.Cell; import org.apache.cassandra.db.rows.CellPath; import org.apache.cassandra.db.rows.Row; @@ -52,21 +54,21 @@ public class RegularColumnIndex extends CassandraIndex } public ByteBuffer getIndexedValue(ByteBuffer partitionKey, - Clustering clustering, + Clustering clustering, CellPath path, ByteBuffer cellValue) { return cellValue; } - public CBuilder buildIndexClusteringPrefix(ByteBuffer partitionKey, - ClusteringPrefix prefix, + public CBuilder buildIndexClusteringPrefix(ByteBuffer partitionKey, + ClusteringPrefix prefix, CellPath path) { CBuilder builder = CBuilder.create(getIndexComparator()); builder.add(partitionKey); for (int i = 0; i < prefix.size(); i++) - builder.add(prefix.get(i)); + builder.add(prefix.get(i), prefix.accessor()); // Note: if indexing a static column, prefix will be Clustering.STATIC_CLUSTERING // so the Clustering obtained from builder::build will contain a value for only @@ -77,9 +79,9 @@ public class RegularColumnIndex extends CassandraIndex public IndexEntry decodeEntry(DecoratedKey indexedValue, Row indexEntry) { - Clustering clustering = indexEntry.clustering(); + Clustering clustering = indexEntry.clustering(); - Clustering indexedEntryClustering = null; + Clustering indexedEntryClustering = null; if (getIndexedColumn().isStatic()) indexedEntryClustering = Clustering.STATIC_CLUSTERING; else @@ -87,22 +89,27 @@ public class RegularColumnIndex extends CassandraIndex ClusteringComparator baseComparator = baseCfs.getComparator(); CBuilder builder = CBuilder.create(baseComparator); for (int i = 0; i < baseComparator.size(); i++) - builder.add(clustering.get(i + 1)); + builder.add(clustering, i + 1); indexedEntryClustering = builder.build(); } return new IndexEntry(indexedValue, - clustering, - indexEntry.primaryKeyLivenessInfo().timestamp(), - clustering.get(0), - indexedEntryClustering); + clustering, + indexEntry.primaryKeyLivenessInfo().timestamp(), + clustering.bufferAt(0), + indexedEntryClustering); + } + + private static boolean valueIsEqual(AbstractType type, Cell cell, ByteBuffer value) + { + return type.compare(cell.value(), cell.accessor(), value, ByteBufferAccessor.instance) == 0; } public boolean isStale(Row data, ByteBuffer indexValue, int nowInSec) { - Cell cell = data.getCell(indexedColumn); + Cell cell = data.getCell(indexedColumn); return cell == null || !cell.isLive(nowInSec) - || indexedColumn.type.compare(indexValue, cell.value()) != 0; + || !valueIsEqual(indexedColumn.type, cell, indexValue); } } diff --git a/src/java/org/apache/cassandra/index/internal/keys/KeysIndex.java b/src/java/org/apache/cassandra/index/internal/keys/KeysIndex.java index 9687958ce7..b044bbee4d 100644 --- a/src/java/org/apache/cassandra/index/internal/keys/KeysIndex.java +++ b/src/java/org/apache/cassandra/index/internal/keys/KeysIndex.java @@ -22,6 +22,7 @@ package org.apache.cassandra.index.internal.keys; import java.nio.ByteBuffer; +import org.apache.cassandra.db.marshal.ByteBufferAccessor; import org.apache.cassandra.schema.TableMetadata; import org.apache.cassandra.schema.TableMetadataRef; import org.apache.cassandra.schema.ColumnMetadata; @@ -48,17 +49,17 @@ public class KeysIndex extends CassandraIndex return builder; } - protected CBuilder buildIndexClusteringPrefix(ByteBuffer partitionKey, - ClusteringPrefix prefix, - CellPath path) + protected CBuilder buildIndexClusteringPrefix(ByteBuffer partitionKey, + ClusteringPrefix prefix, + CellPath path) { CBuilder builder = CBuilder.create(getIndexComparator()); - builder.add(partitionKey); + builder.add(partitionKey, ByteBufferAccessor.instance); return builder; } protected ByteBuffer getIndexedValue(ByteBuffer partitionKey, - Clustering clustering, + Clustering clustering, CellPath path, ByteBuffer cellValue) { return cellValue; @@ -69,15 +70,20 @@ public class KeysIndex extends CassandraIndex throw new UnsupportedOperationException("KEYS indexes do not use a specialized index entry format"); } + private int compare(ByteBuffer left, Cell right) + { + return indexedColumn.type.compare(left, ByteBufferAccessor.instance, right.value(), right.accessor()); + } + public boolean isStale(Row row, ByteBuffer indexValue, int nowInSec) { if (row == null) return true; - Cell cell = row.getCell(indexedColumn); + Cell cell = row.getCell(indexedColumn); return (cell == null || !cell.isLive(nowInSec) - || indexedColumn.type.compare(indexValue, cell.value()) != 0); + || compare(indexValue, cell) != 0); } } \ No newline at end of file diff --git a/src/java/org/apache/cassandra/index/internal/keys/KeysSearcher.java b/src/java/org/apache/cassandra/index/internal/keys/KeysSearcher.java index c3849be7db..2114d4249e 100644 --- a/src/java/org/apache/cassandra/index/internal/keys/KeysSearcher.java +++ b/src/java/org/apache/cassandra/index/internal/keys/KeysSearcher.java @@ -79,7 +79,7 @@ public class KeysSearcher extends CassandraIndexSearcher while (next == null && indexHits.hasNext()) { Row hit = indexHits.next(); - DecoratedKey key = index.baseCfs.decorateKey(hit.clustering().get(0)); + DecoratedKey key = index.baseCfs.decorateKey(hit.clustering().bufferAt(0)); if (!command.selectsKey(key)) continue; diff --git a/src/java/org/apache/cassandra/index/sasi/conf/ColumnIndex.java b/src/java/org/apache/cassandra/index/sasi/conf/ColumnIndex.java index 269fc953de..4c9c59e199 100644 --- a/src/java/org/apache/cassandra/index/sasi/conf/ColumnIndex.java +++ b/src/java/org/apache/cassandra/index/sasi/conf/ColumnIndex.java @@ -241,7 +241,7 @@ public class ColumnIndex if (row.isStatic()) return null; - return row.clustering().get(column.position()); + return row.clustering().bufferAt(column.position()); // treat static cell retrieval the same was as regular // only if row kind is STATIC otherwise return null @@ -249,8 +249,8 @@ public class ColumnIndex if (!row.isStatic()) return null; case REGULAR: - Cell cell = row.getCell(column); - return cell == null || !cell.isLive(nowInSecs) ? null : cell.value(); + Cell cell = row.getCell(column); + return cell == null || !cell.isLive(nowInSecs) ? null : cell.buffer(); default: return null; diff --git a/src/java/org/apache/cassandra/io/sstable/CQLSSTableWriter.java b/src/java/org/apache/cassandra/io/sstable/CQLSSTableWriter.java index 3601ab065d..0ac189c9e7 100644 --- a/src/java/org/apache/cassandra/io/sstable/CQLSSTableWriter.java +++ b/src/java/org/apache/cassandra/io/sstable/CQLSSTableWriter.java @@ -237,7 +237,7 @@ public class CQLSSTableWriter implements Closeable QueryOptions options = QueryOptions.forInternalCalls(null, values); List keys = insert.buildPartitionKeyNames(options); - SortedSet clusterings = insert.createClustering(options); + SortedSet> clusterings = insert.createClustering(options); long now = System.currentTimeMillis(); // Note that we asks indexes to not validate values (the last 'false' arg below) because that triggers a 'Keyspace.open' @@ -254,7 +254,7 @@ public class CQLSSTableWriter implements Closeable { for (ByteBuffer key : keys) { - for (Clustering clustering : clusterings) + for (Clustering clustering : clusterings) insert.addUpdateForKey(writer.getUpdateFor(key), clustering, params); } return this; diff --git a/src/java/org/apache/cassandra/io/sstable/IndexInfo.java b/src/java/org/apache/cassandra/io/sstable/IndexInfo.java index 03246c59c6..e24436d017 100644 --- a/src/java/org/apache/cassandra/io/sstable/IndexInfo.java +++ b/src/java/org/apache/cassandra/io/sstable/IndexInfo.java @@ -27,6 +27,7 @@ import org.apache.cassandra.db.RowIndexEntry; import org.apache.cassandra.db.SerializationHeader; import org.apache.cassandra.db.TypeSizes; import org.apache.cassandra.db.marshal.AbstractType; +import org.apache.cassandra.db.marshal.ByteArrayAccessor; import org.apache.cassandra.io.ISerializer; import org.apache.cassandra.io.sstable.format.Version; import org.apache.cassandra.io.util.DataInputPlus; @@ -62,15 +63,15 @@ public class IndexInfo public final long offset; public final long width; - public final ClusteringPrefix firstName; - public final ClusteringPrefix lastName; + public final ClusteringPrefix firstName; + public final ClusteringPrefix lastName; // If at the end of the index block there is an open range tombstone marker, this marker // deletion infos. null otherwise. public final DeletionTime endOpenMarker; - public IndexInfo(ClusteringPrefix firstName, - ClusteringPrefix lastName, + public IndexInfo(ClusteringPrefix firstName, + ClusteringPrefix lastName, long offset, long width, DeletionTime endOpenMarker) @@ -128,8 +129,8 @@ public class IndexInfo public IndexInfo deserialize(DataInputPlus in) throws IOException { - ClusteringPrefix firstName = ClusteringPrefix.serializer.deserialize(in, version, clusteringTypes); - ClusteringPrefix lastName = ClusteringPrefix.serializer.deserialize(in, version, clusteringTypes); + ClusteringPrefix firstName = ClusteringPrefix.serializer.deserialize(in, version, clusteringTypes); + ClusteringPrefix lastName = ClusteringPrefix.serializer.deserialize(in, version, clusteringTypes); long offset = in.readUnsignedVInt(); long width = in.readVInt() + WIDTH_BASE; DeletionTime endOpenMarker = null; diff --git a/src/java/org/apache/cassandra/io/sstable/metadata/CompactionMetadata.java b/src/java/org/apache/cassandra/io/sstable/metadata/CompactionMetadata.java index c9dfe3926c..6279068813 100644 --- a/src/java/org/apache/cassandra/io/sstable/metadata/CompactionMetadata.java +++ b/src/java/org/apache/cassandra/io/sstable/metadata/CompactionMetadata.java @@ -26,6 +26,7 @@ import org.apache.cassandra.db.TypeSizes; import org.apache.cassandra.io.sstable.format.Version; import org.apache.cassandra.io.util.DataInputPlus; import org.apache.cassandra.io.util.DataOutputPlus; +import org.apache.cassandra.utils.ByteArrayUtil; import org.apache.cassandra.utils.ByteBufferUtil; /** @@ -81,7 +82,7 @@ public class CompactionMetadata extends MetadataComponent public void serialize(Version version, CompactionMetadata component, DataOutputPlus out) throws IOException { - ByteBufferUtil.writeWithLength(component.cardinalityEstimator.getBytes(), out); + ByteArrayUtil.writeWithLength(component.cardinalityEstimator.getBytes(), out); } public CompactionMetadata deserialize(Version version, DataInputPlus in) throws IOException diff --git a/src/java/org/apache/cassandra/io/sstable/metadata/MetadataCollector.java b/src/java/org/apache/cassandra/io/sstable/metadata/MetadataCollector.java index 92d955b5d0..570ede79bb 100755 --- a/src/java/org/apache/cassandra/io/sstable/metadata/MetadataCollector.java +++ b/src/java/org/apache/cassandra/io/sstable/metadata/MetadataCollector.java @@ -102,8 +102,8 @@ public class MetadataCollector implements PartitionStatisticsCollector protected double compressionRatio = NO_COMPRESSION_RATIO; protected StreamingTombstoneHistogramBuilder estimatedTombstoneDropTime = new StreamingTombstoneHistogramBuilder(SSTable.TOMBSTONE_HISTOGRAM_BIN_SIZE, SSTable.TOMBSTONE_HISTOGRAM_SPOOL_SIZE, SSTable.TOMBSTONE_HISTOGRAM_TTL_ROUND_SECONDS); protected int sstableLevel; - private ClusteringPrefix minClustering = null; - private ClusteringPrefix maxClustering = null; + private ClusteringPrefix minClustering = null; + private ClusteringPrefix maxClustering = null; protected boolean hasLegacyCounterShards = false; protected long totalColumnsSet; protected long totalRows; @@ -176,7 +176,7 @@ public class MetadataCollector implements PartitionStatisticsCollector updateLocalDeletionTime(newInfo.localExpirationTime()); } - public void update(Cell cell) + public void update(Cell cell) { updateTimestamp(cell.timestamp()); updateTTL(cell.ttl()); @@ -227,7 +227,7 @@ public class MetadataCollector implements PartitionStatisticsCollector return this; } - public MetadataCollector updateClusteringValues(ClusteringPrefix clustering) + public MetadataCollector updateClusteringValues(ClusteringPrefix clustering) { minClustering = minClustering == null || comparator.compare(clustering, minClustering) < 0 ? clustering.minimize() : minClustering; maxClustering = maxClustering == null || comparator.compare(clustering, maxClustering) > 0 ? clustering.minimize() : maxClustering; @@ -243,8 +243,8 @@ public class MetadataCollector implements PartitionStatisticsCollector { Preconditions.checkState((minClustering == null && maxClustering == null) || comparator.compare(maxClustering, minClustering) >= 0); - ByteBuffer[] minValues = minClustering != null ? minClustering.getRawValues() : EMPTY_CLUSTERING; - ByteBuffer[] maxValues = maxClustering != null ? maxClustering.getRawValues() : EMPTY_CLUSTERING; + ByteBuffer[] minValues = minClustering != null ? minClustering.getBufferArray() : EMPTY_CLUSTERING; + ByteBuffer[] maxValues = maxClustering != null ? maxClustering.getBufferArray() : EMPTY_CLUSTERING; Map components = new EnumMap<>(MetadataType.class); components.put(MetadataType.VALIDATION, new ValidationMetadata(partitioner, bloomFilterFPChance)); components.put(MetadataType.STATS, new StatsMetadata(estimatedPartitionSize, diff --git a/src/java/org/apache/cassandra/schema/ColumnMetadata.java b/src/java/org/apache/cassandra/schema/ColumnMetadata.java index a4876310a1..d48ca06775 100644 --- a/src/java/org/apache/cassandra/schema/ColumnMetadata.java +++ b/src/java/org/apache/cassandra/schema/ColumnMetadata.java @@ -86,7 +86,7 @@ public final class ColumnMetadata extends ColumnSpecification implements Selecta private final Comparator cellPathComparator; private final Comparator asymmetricCellPathComparator; - private final Comparator cellComparator; + private final Comparator> cellComparator; private int hash; @@ -171,7 +171,7 @@ public final class ColumnMetadata extends ColumnSpecification implements Selecta this.position = position; this.cellPathComparator = makeCellPathComparator(kind, type); this.cellComparator = cellPathComparator == null ? ColumnData.comparator : (a, b) -> cellPathComparator.compare(a.path(), b.path()); - this.asymmetricCellPathComparator = cellPathComparator == null ? null : (a, b) -> cellPathComparator.compare(((Cell)a).path(), (CellPath) b); + this.asymmetricCellPathComparator = cellPathComparator == null ? null : (a, b) -> cellPathComparator.compare(((Cell)a).path(), (CellPath) b); this.comparisonOrder = comparisonOrder(kind, isComplex(), Math.max(0, position), name); } @@ -370,7 +370,7 @@ public final class ColumnMetadata extends ColumnSpecification implements Selecta return asymmetricCellPathComparator; } - public Comparator cellComparator() + public Comparator> cellComparator() { return cellComparator; } @@ -391,11 +391,11 @@ public final class ColumnMetadata extends ColumnSpecification implements Selecta return CollectionType.cellPathSerializer; } - public void validateCell(Cell cell) + public void validateCell(Cell cell) { if (cell.isTombstone()) { - if (cell.value().hasRemaining()) + if (cell.valueSize() > 0) throw new MarshalException("A tombstone should not have a value"); if (cell.path() != null) validateCellPath(cell.path()); @@ -408,7 +408,7 @@ public final class ColumnMetadata extends ColumnSpecification implements Selecta } else { - type.validateCellValue(cell.value()); + type.validateCellValue(cell.value(), cell.accessor()); if (cell.path() != null) validateCellPath(cell.path()); } diff --git a/src/java/org/apache/cassandra/serializers/AbstractTextSerializer.java b/src/java/org/apache/cassandra/serializers/AbstractTextSerializer.java index 7a3afed7dc..a1362536b0 100644 --- a/src/java/org/apache/cassandra/serializers/AbstractTextSerializer.java +++ b/src/java/org/apache/cassandra/serializers/AbstractTextSerializer.java @@ -23,9 +23,10 @@ import java.nio.charset.Charset; import org.apache.commons.lang3.StringUtils; +import org.apache.cassandra.db.marshal.ValueAccessor; import org.apache.cassandra.utils.ByteBufferUtil; -public abstract class AbstractTextSerializer implements TypeSerializer +public abstract class AbstractTextSerializer extends TypeSerializer { private final Charset charset; @@ -34,15 +35,15 @@ public abstract class AbstractTextSerializer implements TypeSerializer this.charset = charset; } - public String deserialize(ByteBuffer bytes) + public String deserialize(V value, ValueAccessor accessor) { try { - return ByteBufferUtil.string(bytes, charset); + return accessor.toString(value, charset); } catch (CharacterCodingException e) { - throw new MarshalException("Invalid " + charset + " bytes " + ByteBufferUtil.bytesToHex(bytes)); + throw new MarshalException("Invalid " + charset + " bytes " + accessor.toHex(value)); } } @@ -51,7 +52,8 @@ public abstract class AbstractTextSerializer implements TypeSerializer return ByteBufferUtil.bytes(value, charset); } - public String toString(String value) + + public String toString(String value) { return value; } @@ -69,7 +71,7 @@ public abstract class AbstractTextSerializer implements TypeSerializer public String toCQLLiteral(ByteBuffer buffer) { return buffer == null - ? "null" - : '\'' + StringUtils.replace(deserialize(buffer), "'", "''") + '\''; + ? "null" + : '\'' + StringUtils.replace(deserialize(buffer), "'", "''") + '\''; } } diff --git a/src/java/org/apache/cassandra/serializers/AsciiSerializer.java b/src/java/org/apache/cassandra/serializers/AsciiSerializer.java index e265cb285e..7608ef6f40 100644 --- a/src/java/org/apache/cassandra/serializers/AsciiSerializer.java +++ b/src/java/org/apache/cassandra/serializers/AsciiSerializer.java @@ -17,9 +17,10 @@ */ package org.apache.cassandra.serializers; -import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; +import org.apache.cassandra.db.marshal.ValueAccessor; + public class AsciiSerializer extends AbstractTextSerializer { public static final AsciiSerializer instance = new AsciiSerializer(); @@ -29,12 +30,12 @@ public class AsciiSerializer extends AbstractTextSerializer super(StandardCharsets.US_ASCII); } - public void validate(ByteBuffer bytes) throws MarshalException + public void validate(V value, ValueAccessor accessor) throws MarshalException { // 0-127 - for (int i = bytes.position(); i < bytes.limit(); i++) + for (int i=0, size=accessor.size(value); i < size; i++) { - byte b = bytes.get(i); + byte b = accessor.getByte(value, i); if (b < 0) throw new MarshalException("Invalid byte for ascii: " + Byte.toString(b)); } diff --git a/src/java/org/apache/cassandra/serializers/BooleanSerializer.java b/src/java/org/apache/cassandra/serializers/BooleanSerializer.java index 0d6580ea7f..d372a2ad77 100644 --- a/src/java/org/apache/cassandra/serializers/BooleanSerializer.java +++ b/src/java/org/apache/cassandra/serializers/BooleanSerializer.java @@ -17,36 +17,36 @@ */ package org.apache.cassandra.serializers; -import org.apache.cassandra.utils.ByteBufferUtil; - import java.nio.ByteBuffer; -public class BooleanSerializer implements TypeSerializer +import org.apache.cassandra.db.marshal.ValueAccessor; +import org.apache.cassandra.utils.ByteBufferUtil; + +public class BooleanSerializer extends TypeSerializer { private static final ByteBuffer TRUE = ByteBuffer.wrap(new byte[] {1}); private static final ByteBuffer FALSE = ByteBuffer.wrap(new byte[] {0}); public static final BooleanSerializer instance = new BooleanSerializer(); - public Boolean deserialize(ByteBuffer bytes) + public Boolean deserialize(V value, ValueAccessor accessor) { - if (bytes == null || bytes.remaining() == 0) + if (value == null || accessor.isEmpty(value)) return null; - byte value = bytes.get(bytes.position()); - return value != 0; + return accessor.getByte(value, 0) != 0; } public ByteBuffer serialize(Boolean value) { return (value == null) ? ByteBufferUtil.EMPTY_BYTE_BUFFER - : value ? TRUE : FALSE; // false + : value ? TRUE : FALSE; // false } - public void validate(ByteBuffer bytes) throws MarshalException + public void validate(V value, ValueAccessor accessor) throws MarshalException { - if (bytes.remaining() != 1 && bytes.remaining() != 0) - throw new MarshalException(String.format("Expected 1 or 0 byte value (%d)", bytes.remaining())); + if (accessor.size(value) > 1) + throw new MarshalException(String.format("Expected 1 or 0 byte value (%d)", accessor.size(value))); } public String toString(Boolean value) diff --git a/src/java/org/apache/cassandra/serializers/ByteSerializer.java b/src/java/org/apache/cassandra/serializers/ByteSerializer.java index 8428e62ade..ce894582a7 100644 --- a/src/java/org/apache/cassandra/serializers/ByteSerializer.java +++ b/src/java/org/apache/cassandra/serializers/ByteSerializer.java @@ -18,17 +18,18 @@ package org.apache.cassandra.serializers; -import org.apache.cassandra.utils.ByteBufferUtil; - import java.nio.ByteBuffer; -public class ByteSerializer implements TypeSerializer +import org.apache.cassandra.db.marshal.ValueAccessor; +import org.apache.cassandra.utils.ByteBufferUtil; + +public class ByteSerializer extends TypeSerializer { public static final ByteSerializer instance = new ByteSerializer(); - public Byte deserialize(ByteBuffer bytes) + public Byte deserialize(V value, ValueAccessor accessor) { - return bytes == null || bytes.remaining() == 0 ? null : ByteBufferUtil.toByte(bytes); + return value == null || accessor.isEmpty(value) ? null : accessor.toByte(value); } public ByteBuffer serialize(Byte value) @@ -36,10 +37,10 @@ public class ByteSerializer implements TypeSerializer return value == null ? ByteBufferUtil.EMPTY_BYTE_BUFFER : ByteBufferUtil.bytes(value); } - public void validate(ByteBuffer bytes) throws MarshalException + public void validate(V value, ValueAccessor accessor) throws MarshalException { - if (bytes.remaining() != 1) - throw new MarshalException(String.format("Expected 1 byte for a tinyint (%d)", bytes.remaining())); + if (accessor.size(value) != 1) + throw new MarshalException(String.format("Expected 1 byte for a tinyint (%d)", accessor.size(value))); } public String toString(Byte value) diff --git a/src/java/org/apache/cassandra/serializers/BytesSerializer.java b/src/java/org/apache/cassandra/serializers/BytesSerializer.java index ed0bf77278..b9fe4b393f 100644 --- a/src/java/org/apache/cassandra/serializers/BytesSerializer.java +++ b/src/java/org/apache/cassandra/serializers/BytesSerializer.java @@ -18,11 +18,12 @@ package org.apache.cassandra.serializers; +import org.apache.cassandra.db.marshal.ValueAccessor; import org.apache.cassandra.utils.ByteBufferUtil; import java.nio.ByteBuffer; -public class BytesSerializer implements TypeSerializer +public class BytesSerializer extends TypeSerializer { public static final BytesSerializer instance = new BytesSerializer(); @@ -32,13 +33,13 @@ public class BytesSerializer implements TypeSerializer return bytes.duplicate(); } - public ByteBuffer deserialize(ByteBuffer value) + public ByteBuffer deserialize(V value, ValueAccessor accessor) { // This is from the DB, so it is not shared with someone else - return value; + return accessor.toBuffer(value); } - public void validate(ByteBuffer bytes) throws MarshalException + public void validate(V value, ValueAccessor accessor) throws MarshalException { // all bytes are legal. } @@ -57,7 +58,7 @@ public class BytesSerializer implements TypeSerializer public String toCQLLiteral(ByteBuffer buffer) { return buffer == null - ? "null" - : "0x" + toString(deserialize(buffer)); + ? "null" + : "0x" + toString(deserialize(buffer)); } } diff --git a/src/java/org/apache/cassandra/serializers/CollectionSerializer.java b/src/java/org/apache/cassandra/serializers/CollectionSerializer.java index 3efdef987c..eb2991b8d7 100644 --- a/src/java/org/apache/cassandra/serializers/CollectionSerializer.java +++ b/src/java/org/apache/cassandra/serializers/CollectionSerializer.java @@ -22,52 +22,68 @@ import java.nio.ByteBuffer; import java.util.Collection; import java.util.List; +import org.apache.cassandra.db.TypeSizes; +import org.apache.cassandra.db.marshal.ByteBufferAccessor; +import org.apache.cassandra.db.marshal.ValueAccessor; import org.apache.cassandra.transport.ProtocolVersion; import org.apache.cassandra.db.marshal.AbstractType; import org.apache.cassandra.utils.ByteBufferUtil; -public abstract class CollectionSerializer implements TypeSerializer +public abstract class CollectionSerializer extends TypeSerializer { protected abstract List serializeValues(T value); protected abstract int getElementCount(T value); - public abstract T deserializeForNativeProtocol(ByteBuffer buffer, ProtocolVersion version); - public abstract void validateForNativeProtocol(ByteBuffer buffer, ProtocolVersion version); + public abstract T deserializeForNativeProtocol(V value, ValueAccessor accessor, ProtocolVersion version); - public ByteBuffer serialize(T value) + public T deserializeForNativeProtocol(ByteBuffer value, ProtocolVersion version) { - List values = serializeValues(value); - // See deserialize() for why using the protocol v3 variant is the right thing to do. - return pack(values, getElementCount(value), ProtocolVersion.V3); + return deserializeForNativeProtocol(value, ByteBufferAccessor.instance, version); } - public T deserialize(ByteBuffer bytes) + public abstract void validateForNativeProtocol(V value, ValueAccessor accessor, ProtocolVersion version); + + public ByteBuffer serialize(T input) + { + List values = serializeValues(input); + // See deserialize() for why using the protocol v3 variant is the right thing to do. + return pack(values, ByteBufferAccessor.instance, getElementCount(input), ProtocolVersion.V3); + } + + public T deserialize(V value, ValueAccessor accessor) { // The only cases we serialize/deserialize collections internally (i.e. not for the protocol sake), // is: // 1) when collections are frozen // 2) for internal calls. // In both case, using the protocol 3 version variant is the right thing to do. - return deserializeForNativeProtocol(bytes, ProtocolVersion.V3); + return deserializeForNativeProtocol(value, accessor, ProtocolVersion.V3); } - public void validate(ByteBuffer bytes) throws MarshalException + public void validate(T1 value, ValueAccessor accessor) throws MarshalException { // Same thing as above - validateForNativeProtocol(bytes, ProtocolVersion.V3); + validateForNativeProtocol(value, accessor, ProtocolVersion.V3); } - public static ByteBuffer pack(Collection buffers, int elements, ProtocolVersion version) + public static ByteBuffer pack(Collection values, int elements, ProtocolVersion version) + { + return pack(values, ByteBufferAccessor.instance, elements, version); + } + + public static V pack(Collection values, ValueAccessor accessor, int elements, ProtocolVersion version) { int size = 0; - for (ByteBuffer bb : buffers) - size += sizeOfValue(bb, version); + for (V value : values) + size += sizeOfValue(value, accessor, version); ByteBuffer result = ByteBuffer.allocate(sizeOfCollectionSize(elements, version) + size); writeCollectionSize(result, elements, version); - for (ByteBuffer bb : buffers) - writeValue(result, bb, version); - return (ByteBuffer)result.flip(); + for (V value : values) + { + writeValue(result, value, accessor, version); + } + return accessor.valueOf((ByteBuffer) result.flip()); } protected static void writeCollectionSize(ByteBuffer output, int elements, ProtocolVersion version) @@ -77,15 +93,20 @@ public abstract class CollectionSerializer implements TypeSerializer public static int readCollectionSize(ByteBuffer input, ProtocolVersion version) { - return input.getInt(); + return readCollectionSize(input, ByteBufferAccessor.instance, version); } - protected static int sizeOfCollectionSize(int elements, ProtocolVersion version) + public static int readCollectionSize(V value, ValueAccessor accessor, ProtocolVersion version) { - return 4; + return accessor.toInt(value); } - public static void writeValue(ByteBuffer output, ByteBuffer value, ProtocolVersion version) + public static int sizeOfCollectionSize(int elements, ProtocolVersion version) + { + return TypeSizes.INT_SIZE; + } + + public static void writeValue(ByteBuffer output, V value, ValueAccessor accessor, ProtocolVersion version) { if (value == null) { @@ -93,17 +114,17 @@ public abstract class CollectionSerializer implements TypeSerializer return; } - output.putInt(value.remaining()); - output.put(value.duplicate()); + output.putInt(accessor.size(value)); + accessor.write(value, output); } - public static ByteBuffer readValue(ByteBuffer input, ProtocolVersion version) + public static V readValue(V input, ValueAccessor accessor, int offset, ProtocolVersion version) { - int size = input.getInt(); + int size = accessor.getInt(input, offset); if (size < 0) return null; - return ByteBufferUtil.readBytes(input, size); + return accessor.slice(input, offset + TypeSizes.INT_SIZE, size); } protected static void skipValue(ByteBuffer input, ProtocolVersion version) @@ -112,9 +133,15 @@ public abstract class CollectionSerializer implements TypeSerializer input.position(input.position() + size); } - public static int sizeOfValue(ByteBuffer value, ProtocolVersion version) + public static int skipValue(V input, ValueAccessor accessor, int offset, ProtocolVersion version) { - return value == null ? 4 : 4 + value.remaining(); + int size = accessor.getInt(input, offset); + return TypeSizes.sizeof(size) + size; + } + + public static int sizeOfValue(V value, ValueAccessor accessor, ProtocolVersion version) + { + return value == null ? 4 : 4 + accessor.size(value); } /** diff --git a/src/java/org/apache/cassandra/serializers/DecimalSerializer.java b/src/java/org/apache/cassandra/serializers/DecimalSerializer.java index 819789f372..724c42ee0a 100644 --- a/src/java/org/apache/cassandra/serializers/DecimalSerializer.java +++ b/src/java/org/apache/cassandra/serializers/DecimalSerializer.java @@ -17,28 +17,25 @@ */ package org.apache.cassandra.serializers; +import org.apache.cassandra.db.marshal.ValueAccessor; import org.apache.cassandra.utils.ByteBufferUtil; import java.math.BigDecimal; import java.math.BigInteger; import java.nio.ByteBuffer; -public class DecimalSerializer implements TypeSerializer +public class DecimalSerializer extends TypeSerializer { public static final DecimalSerializer instance = new DecimalSerializer(); - public BigDecimal deserialize(ByteBuffer bytes) + public BigDecimal deserialize(V value, ValueAccessor accessor) { - if (bytes == null || bytes.remaining() == 0) + if (value == null || accessor.isEmpty(value)) return null; // do not consume the contents of the ByteBuffer - bytes = bytes.duplicate(); - int scale = bytes.getInt(); - byte[] bibytes = new byte[bytes.remaining()]; - bytes.get(bibytes); - - BigInteger bi = new BigInteger(bibytes); + int scale = accessor.getInt(value, 0); + BigInteger bi = new BigInteger(accessor.toArray(value, 4, accessor.size(value) - 4)); return new BigDecimal(bi, scale); } @@ -58,11 +55,11 @@ public class DecimalSerializer implements TypeSerializer return bytes; } - public void validate(ByteBuffer bytes) throws MarshalException + public void validate(T value, ValueAccessor accessor) throws MarshalException { // We at least store the scale. - if (bytes.remaining() != 0 && bytes.remaining() < 4) - throw new MarshalException(String.format("Expected 0 or at least 4 bytes (%d)", bytes.remaining())); + if (!accessor.isEmpty(value) && accessor.size(value) < 4) + throw new MarshalException(String.format("Expected 0 or at least 4 bytes (%d)", accessor.size(value))); } public String toString(BigDecimal value) diff --git a/src/java/org/apache/cassandra/serializers/DoubleSerializer.java b/src/java/org/apache/cassandra/serializers/DoubleSerializer.java index 13ca33bcde..f38c78deb8 100644 --- a/src/java/org/apache/cassandra/serializers/DoubleSerializer.java +++ b/src/java/org/apache/cassandra/serializers/DoubleSerializer.java @@ -18,19 +18,20 @@ package org.apache.cassandra.serializers; -import org.apache.cassandra.utils.ByteBufferUtil; - import java.nio.ByteBuffer; -public class DoubleSerializer implements TypeSerializer +import org.apache.cassandra.db.marshal.ValueAccessor; +import org.apache.cassandra.utils.ByteBufferUtil; + +public class DoubleSerializer extends TypeSerializer { public static final DoubleSerializer instance = new DoubleSerializer(); - public Double deserialize(ByteBuffer bytes) + public Double deserialize(V value, ValueAccessor accessor) { - if (bytes.remaining() == 0) + if (accessor.isEmpty(value)) return null; - return ByteBufferUtil.toDouble(bytes); + return accessor.toDouble(value); } public ByteBuffer serialize(Double value) @@ -38,10 +39,10 @@ public class DoubleSerializer implements TypeSerializer return (value == null) ? ByteBufferUtil.EMPTY_BYTE_BUFFER : ByteBufferUtil.bytes(value); } - public void validate(ByteBuffer bytes) throws MarshalException + public void validate(T value, ValueAccessor accessor) throws MarshalException { - if (bytes.remaining() != 8 && bytes.remaining() != 0) - throw new MarshalException(String.format("Expected 8 or 0 byte value for a double (%d)", bytes.remaining())); + if (accessor.size(value) != 8 && !accessor.isEmpty(value)) + throw new MarshalException(String.format("Expected 8 or 0 byte value for a double (%d)", accessor.size(value))); } public String toString(Double value) diff --git a/src/java/org/apache/cassandra/serializers/DurationSerializer.java b/src/java/org/apache/cassandra/serializers/DurationSerializer.java index c752c40477..254b2b09a4 100644 --- a/src/java/org/apache/cassandra/serializers/DurationSerializer.java +++ b/src/java/org/apache/cassandra/serializers/DurationSerializer.java @@ -21,12 +21,13 @@ import java.io.IOException; import java.nio.ByteBuffer; import org.apache.cassandra.cql3.Duration; +import org.apache.cassandra.db.marshal.ValueAccessor; import org.apache.cassandra.io.util.DataInputBuffer; import org.apache.cassandra.io.util.DataOutputBufferFixed; import org.apache.cassandra.utils.ByteBufferUtil; import org.apache.cassandra.utils.vint.VIntCoding; -public final class DurationSerializer implements TypeSerializer +public final class DurationSerializer extends TypeSerializer { public static final DurationSerializer instance = new DurationSerializer(); @@ -40,8 +41,8 @@ public final class DurationSerializer implements TypeSerializer long nanoseconds = duration.getNanoseconds(); int size = VIntCoding.computeVIntSize(months) - + VIntCoding.computeVIntSize(days) - + VIntCoding.computeVIntSize(nanoseconds); + + VIntCoding.computeVIntSize(days) + + VIntCoding.computeVIntSize(nanoseconds); try (DataOutputBufferFixed output = new DataOutputBufferFixed(size)) { @@ -57,12 +58,12 @@ public final class DurationSerializer implements TypeSerializer } } - public Duration deserialize(ByteBuffer bytes) + public Duration deserialize(V value, ValueAccessor accessor) { - if (bytes.remaining() == 0) + if (accessor.isEmpty(value)) return null; - try (DataInputBuffer in = new DataInputBuffer(bytes, true)) + try (DataInputBuffer in = new DataInputBuffer(accessor.toBuffer(value), true)) // TODO: make a value input buffer { int months = (int) in.readVInt(); int days = (int) in.readVInt(); @@ -76,12 +77,12 @@ public final class DurationSerializer implements TypeSerializer } } - public void validate(ByteBuffer bytes) throws MarshalException + public void validate(V value, ValueAccessor accessor) throws MarshalException { - if (bytes.remaining() < 3) - throw new MarshalException(String.format("Expected at least 3 bytes for a duration (%d)", bytes.remaining())); + if (accessor.size(value) < 3) + throw new MarshalException(String.format("Expected at least 3 bytes for a duration (%d)", accessor.size(value))); - try (DataInputBuffer in = new DataInputBuffer(bytes, true)) + try (DataInputBuffer in = new DataInputBuffer(accessor.toBuffer(value), true)) // FIXME: value input buffer { long monthsAsLong = in.readVInt(); long daysAsLong = in.readVInt(); diff --git a/src/java/org/apache/cassandra/serializers/EmptySerializer.java b/src/java/org/apache/cassandra/serializers/EmptySerializer.java index 733e179ef0..65ab6122d6 100644 --- a/src/java/org/apache/cassandra/serializers/EmptySerializer.java +++ b/src/java/org/apache/cassandra/serializers/EmptySerializer.java @@ -18,17 +18,18 @@ package org.apache.cassandra.serializers; -import org.apache.cassandra.utils.ByteBufferUtil; - import java.nio.ByteBuffer; -public class EmptySerializer implements TypeSerializer +import org.apache.cassandra.db.marshal.ValueAccessor; +import org.apache.cassandra.utils.ByteBufferUtil; + +public class EmptySerializer extends TypeSerializer { public static final EmptySerializer instance = new EmptySerializer(); - public Void deserialize(ByteBuffer bytes) + public Void deserialize(V value, ValueAccessor accessor) { - validate(bytes); + validate(value, accessor); return null; } @@ -37,9 +38,9 @@ public class EmptySerializer implements TypeSerializer return ByteBufferUtil.EMPTY_BYTE_BUFFER; } - public void validate(ByteBuffer bytes) throws MarshalException + public void validate(V value, ValueAccessor accessor) throws MarshalException { - if (bytes.remaining() > 0) + if (!accessor.isEmpty(value)) throw new MarshalException("EmptyType only accept empty values"); } diff --git a/src/java/org/apache/cassandra/serializers/FloatSerializer.java b/src/java/org/apache/cassandra/serializers/FloatSerializer.java index 94a24fec62..af008691d7 100644 --- a/src/java/org/apache/cassandra/serializers/FloatSerializer.java +++ b/src/java/org/apache/cassandra/serializers/FloatSerializer.java @@ -18,20 +18,21 @@ package org.apache.cassandra.serializers; -import org.apache.cassandra.utils.ByteBufferUtil; - import java.nio.ByteBuffer; -public class FloatSerializer implements TypeSerializer +import org.apache.cassandra.db.marshal.ValueAccessor; +import org.apache.cassandra.utils.ByteBufferUtil; + +public class FloatSerializer extends TypeSerializer { public static final FloatSerializer instance = new FloatSerializer(); - public Float deserialize(ByteBuffer bytes) + public Float deserialize(V value, ValueAccessor accessor) { - if (bytes.remaining() == 0) + if (accessor.isEmpty(value)) return null; - return ByteBufferUtil.toFloat(bytes); + return accessor.toFloat(value); } public ByteBuffer serialize(Float value) @@ -39,10 +40,10 @@ public class FloatSerializer implements TypeSerializer return (value == null) ? ByteBufferUtil.EMPTY_BYTE_BUFFER : ByteBufferUtil.bytes(value); } - public void validate(ByteBuffer bytes) throws MarshalException + public void validate(V value, ValueAccessor accessor) throws MarshalException { - if (bytes.remaining() != 4 && bytes.remaining() != 0) - throw new MarshalException(String.format("Expected 4 or 0 byte value for a float (%d)", bytes.remaining())); + if (accessor.size(value) != 4 && !accessor.isEmpty(value)) + throw new MarshalException(String.format("Expected 4 or 0 byte value for a float (%d)", accessor.size(value))); } public String toString(Float value) diff --git a/src/java/org/apache/cassandra/serializers/InetAddressSerializer.java b/src/java/org/apache/cassandra/serializers/InetAddressSerializer.java index 3014753f30..992de6251d 100644 --- a/src/java/org/apache/cassandra/serializers/InetAddressSerializer.java +++ b/src/java/org/apache/cassandra/serializers/InetAddressSerializer.java @@ -18,24 +18,25 @@ package org.apache.cassandra.serializers; +import org.apache.cassandra.db.marshal.ValueAccessor; import org.apache.cassandra.utils.ByteBufferUtil; import java.net.InetAddress; import java.net.UnknownHostException; import java.nio.ByteBuffer; -public class InetAddressSerializer implements TypeSerializer +public class InetAddressSerializer extends TypeSerializer { public static final InetAddressSerializer instance = new InetAddressSerializer(); - public InetAddress deserialize(ByteBuffer bytes) + public InetAddress deserialize(V value, ValueAccessor accessor) { - if (bytes.remaining() == 0) + if (accessor.isEmpty(value)) return null; try { - return InetAddress.getByAddress(ByteBufferUtil.getArray(bytes)); + return InetAddress.getByAddress(accessor.toArray(value)); } catch (UnknownHostException e) { @@ -48,18 +49,18 @@ public class InetAddressSerializer implements TypeSerializer return value == null ? ByteBufferUtil.EMPTY_BYTE_BUFFER : ByteBuffer.wrap(value.getAddress()); } - public void validate(ByteBuffer bytes) throws MarshalException + public void validate(V value, ValueAccessor accessor) throws MarshalException { - if (bytes.remaining() == 0) + if (accessor.isEmpty(value)) return; try { - InetAddress.getByAddress(ByteBufferUtil.getArray(bytes)); + InetAddress.getByAddress(accessor.toArray(value)); } catch (UnknownHostException e) { - throw new MarshalException(String.format("Expected 4 or 16 byte inetaddress; got %s", ByteBufferUtil.bytesToHex(bytes))); + throw new MarshalException(String.format("Expected 4 or 16 byte inetaddress; got %s", accessor.toHex(value))); } } diff --git a/src/java/org/apache/cassandra/serializers/Int32Serializer.java b/src/java/org/apache/cassandra/serializers/Int32Serializer.java index 73e350ff10..71020d1255 100644 --- a/src/java/org/apache/cassandra/serializers/Int32Serializer.java +++ b/src/java/org/apache/cassandra/serializers/Int32Serializer.java @@ -18,17 +18,18 @@ package org.apache.cassandra.serializers; -import org.apache.cassandra.utils.ByteBufferUtil; - import java.nio.ByteBuffer; -public class Int32Serializer implements TypeSerializer +import org.apache.cassandra.db.marshal.ValueAccessor; +import org.apache.cassandra.utils.ByteBufferUtil; + +public class Int32Serializer extends TypeSerializer { public static final Int32Serializer instance = new Int32Serializer(); - public Integer deserialize(ByteBuffer bytes) + public Integer deserialize(V value, ValueAccessor accessor) { - return bytes.remaining() == 0 ? null : ByteBufferUtil.toInt(bytes); + return accessor.isEmpty(value) ? null : accessor.toInt(value); } public ByteBuffer serialize(Integer value) @@ -36,10 +37,10 @@ public class Int32Serializer implements TypeSerializer return value == null ? ByteBufferUtil.EMPTY_BYTE_BUFFER : ByteBufferUtil.bytes(value); } - public void validate(ByteBuffer bytes) throws MarshalException + public void validate(V value, ValueAccessor accessor) throws MarshalException { - if (bytes.remaining() != 4 && bytes.remaining() != 0) - throw new MarshalException(String.format("Expected 4 or 0 byte int (%d)", bytes.remaining())); + if (accessor.size(value) != 4 && !accessor.isEmpty(value)) + throw new MarshalException(String.format("Expected 4 or 0 byte int (%d)", accessor.size(value))); } public String toString(Integer value) diff --git a/src/java/org/apache/cassandra/serializers/IntegerSerializer.java b/src/java/org/apache/cassandra/serializers/IntegerSerializer.java index 9d9505da35..c3538ffc2a 100644 --- a/src/java/org/apache/cassandra/serializers/IntegerSerializer.java +++ b/src/java/org/apache/cassandra/serializers/IntegerSerializer.java @@ -18,18 +18,19 @@ package org.apache.cassandra.serializers; +import org.apache.cassandra.db.marshal.ValueAccessor; import org.apache.cassandra.utils.ByteBufferUtil; import java.math.BigInteger; import java.nio.ByteBuffer; -public class IntegerSerializer implements TypeSerializer +public class IntegerSerializer extends TypeSerializer { public static final IntegerSerializer instance = new IntegerSerializer(); - public BigInteger deserialize(ByteBuffer bytes) + public BigInteger deserialize(V value, ValueAccessor accessor) { - return bytes.hasRemaining() ? new BigInteger(ByteBufferUtil.getArray(bytes)) : null; + return !accessor.isEmpty(value) ? new BigInteger(accessor.toArray(value)) : null; } public ByteBuffer serialize(BigInteger value) @@ -37,7 +38,7 @@ public class IntegerSerializer implements TypeSerializer return value == null ? ByteBufferUtil.EMPTY_BYTE_BUFFER : ByteBuffer.wrap(value.toByteArray()); } - public void validate(ByteBuffer bytes) throws MarshalException + public void validate(V value, ValueAccessor accessor) throws MarshalException { // no invalid integers. } diff --git a/src/java/org/apache/cassandra/serializers/ListSerializer.java b/src/java/org/apache/cassandra/serializers/ListSerializer.java index dd0bc9e8b7..240e0a62dc 100644 --- a/src/java/org/apache/cassandra/serializers/ListSerializer.java +++ b/src/java/org/apache/cassandra/serializers/ListSerializer.java @@ -24,7 +24,10 @@ import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import org.apache.cassandra.db.TypeSizes; import org.apache.cassandra.db.marshal.AbstractType; +import org.apache.cassandra.db.marshal.ByteBufferAccessor; +import org.apache.cassandra.db.marshal.ValueAccessor; import org.apache.cassandra.transport.ProtocolVersion; public class ListSerializer extends CollectionSerializer> @@ -47,12 +50,12 @@ public class ListSerializer extends CollectionSerializer> this.elements = elements; } - public List serializeValues(List values) + protected List serializeValues(List values) { - List buffers = new ArrayList<>(values.size()); - for (T value : values) - buffers.add(elements.serialize(value)); - return buffers; + List output = new ArrayList<>(values.size()); + for (T value: values) + output.add(elements.serialize(value)); + return output; } public int getElementCount(List value) @@ -60,30 +63,34 @@ public class ListSerializer extends CollectionSerializer> return value.size(); } - public void validateForNativeProtocol(ByteBuffer bytes, ProtocolVersion version) + public void validateForNativeProtocol(V input, ValueAccessor accessor, ProtocolVersion version) { try { - ByteBuffer input = bytes.duplicate(); - int n = readCollectionSize(input, version); + int n = readCollectionSize(input, accessor, version); + int offset = sizeOfCollectionSize(n, version); for (int i = 0; i < n; i++) - elements.validate(readValue(input, version)); + { + V value = readValue(input, accessor, offset, version); + offset += sizeOfValue(value, accessor, version); + elements.validate(value, accessor); + } - if (input.hasRemaining()) + if (!accessor.isEmptyFromOffset(input, offset)) throw new MarshalException("Unexpected extraneous bytes after list value"); } - catch (BufferUnderflowException e) + catch (BufferUnderflowException | IndexOutOfBoundsException e) { throw new MarshalException("Not enough bytes to read a list"); } } - public List deserializeForNativeProtocol(ByteBuffer bytes, ProtocolVersion version) + public List deserializeForNativeProtocol(V input, ValueAccessor accessor, ProtocolVersion version) { try { - ByteBuffer input = bytes.duplicate(); - int n = readCollectionSize(input, version); + int n = readCollectionSize(input, accessor, version); + int offset = sizeOfCollectionSize(n, version); if (n < 0) throw new MarshalException("The data cannot be deserialized as a list"); @@ -96,11 +103,12 @@ public class ListSerializer extends CollectionSerializer> for (int i = 0; i < n; i++) { // We can have nulls in lists that are used for IN values - ByteBuffer databb = readValue(input, version); + V databb = readValue(input, accessor, offset, version); + offset += sizeOfValue(databb, accessor, version); if (databb != null) { - elements.validate(databb); - l.add(elements.deserialize(databb)); + elements.validate(databb, accessor); + l.add(elements.deserialize(databb, accessor)); } else { @@ -108,12 +116,12 @@ public class ListSerializer extends CollectionSerializer> } } - if (input.hasRemaining()) + if (!accessor.isEmptyFromOffset(input, offset)) throw new MarshalException("Unexpected extraneous bytes after list value"); return l; } - catch (BufferUnderflowException e) + catch (BufferUnderflowException | IndexOutOfBoundsException e) { throw new MarshalException("Not enough bytes to read a list"); } @@ -121,32 +129,37 @@ public class ListSerializer extends CollectionSerializer> /** * Returns the element at the given index in a list. - * @param serializedList a serialized list + * @param input a serialized list * @param index the index to get * @return the serialized element at the given index, or null if the index exceeds the list size */ - public ByteBuffer getElement(ByteBuffer serializedList, int index) + public V getElement(V input, ValueAccessor accessor, int index) { try { - ByteBuffer input = serializedList.duplicate(); - int n = readCollectionSize(input, ProtocolVersion.V3); + int n = readCollectionSize(input, accessor, ProtocolVersion.V3); + int offset = sizeOfCollectionSize(n, ProtocolVersion.V3); if (n <= index) return null; for (int i = 0; i < index; i++) { - int length = input.getInt(); - input.position(input.position() + length); + int length = accessor.getInt(input, offset); + offset += TypeSizes.INT_SIZE + length; } - return readValue(input, ProtocolVersion.V3); + return readValue(input, accessor, offset, ProtocolVersion.V3); } - catch (BufferUnderflowException e) + catch (BufferUnderflowException | IndexOutOfBoundsException e) { throw new MarshalException("Not enough bytes to read a list"); } } + public ByteBuffer getElement(ByteBuffer input, int index) + { + return getElement(input, ByteBufferAccessor.instance, index); + } + public String toString(List value) { StringBuilder sb = new StringBuilder(); diff --git a/src/java/org/apache/cassandra/serializers/LongSerializer.java b/src/java/org/apache/cassandra/serializers/LongSerializer.java index e5ab43a631..1e33363368 100644 --- a/src/java/org/apache/cassandra/serializers/LongSerializer.java +++ b/src/java/org/apache/cassandra/serializers/LongSerializer.java @@ -18,17 +18,18 @@ package org.apache.cassandra.serializers; -import org.apache.cassandra.utils.ByteBufferUtil; - import java.nio.ByteBuffer; -public class LongSerializer implements TypeSerializer +import org.apache.cassandra.db.marshal.ValueAccessor; +import org.apache.cassandra.utils.ByteBufferUtil; + +public class LongSerializer extends TypeSerializer { public static final LongSerializer instance = new LongSerializer(); - public Long deserialize(ByteBuffer bytes) + public Long deserialize(V value, ValueAccessor accessor) { - return bytes.remaining() == 0 ? null : ByteBufferUtil.toLong(bytes); + return accessor.isEmpty(value) ? null : accessor.toLong(value); } public ByteBuffer serialize(Long value) @@ -36,10 +37,10 @@ public class LongSerializer implements TypeSerializer return value == null ? ByteBufferUtil.EMPTY_BYTE_BUFFER : ByteBufferUtil.bytes(value); } - public void validate(ByteBuffer bytes) throws MarshalException + public void validate(V value, ValueAccessor accessor) throws MarshalException { - if (bytes.remaining() != 8 && bytes.remaining() != 0) - throw new MarshalException(String.format("Expected 8 or 0 byte long (%d)", bytes.remaining())); + if (accessor.size(value) != 8 && !accessor.isEmpty(value)) + throw new MarshalException(String.format("Expected 8 or 0 byte long (%d)", accessor.size(value))); } public String toString(Long value) diff --git a/src/java/org/apache/cassandra/serializers/MapSerializer.java b/src/java/org/apache/cassandra/serializers/MapSerializer.java index 726d8a782c..9eae598003 100644 --- a/src/java/org/apache/cassandra/serializers/MapSerializer.java +++ b/src/java/org/apache/cassandra/serializers/MapSerializer.java @@ -24,7 +24,11 @@ import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import org.apache.cassandra.db.TypeSizes; import org.apache.cassandra.db.marshal.AbstractType; +import org.apache.cassandra.db.marshal.ByteBufferAccessor; +import org.apache.cassandra.db.marshal.ValueComparators; +import org.apache.cassandra.db.marshal.ValueAccessor; import org.apache.cassandra.transport.ProtocolVersion; import org.apache.cassandra.utils.ByteBufferUtil; import org.apache.cassandra.utils.Pair; @@ -32,26 +36,26 @@ import org.apache.cassandra.utils.Pair; public class MapSerializer extends CollectionSerializer> { // interning instances - private static final ConcurrentMap, TypeSerializer>, MapSerializer> instances = new ConcurrentHashMap, TypeSerializer>, MapSerializer>(); + private static final ConcurrentMap, TypeSerializer>, MapSerializer> instances = new ConcurrentHashMap<>(); public final TypeSerializer keys; public final TypeSerializer values; - private final Comparator> comparator; + private final ValueComparators comparators; - public static MapSerializer getInstance(TypeSerializer keys, TypeSerializer values, Comparator comparator) + public static MapSerializer getInstance(TypeSerializer keys, TypeSerializer values, ValueComparators comparators) { - Pair, TypeSerializer> p = Pair., TypeSerializer>create(keys, values); + Pair, TypeSerializer> p = Pair.create(keys, values); MapSerializer t = instances.get(p); if (t == null) - t = instances.computeIfAbsent(p, k -> new MapSerializer<>(k.left, k.right, comparator) ); + t = instances.computeIfAbsent(p, k -> new MapSerializer<>(k.left, k.right, comparators) ); return t; } - private MapSerializer(TypeSerializer keys, TypeSerializer values, Comparator comparator) + private MapSerializer(TypeSerializer keys, TypeSerializer values, ValueComparators comparators) { this.keys = keys; this.values = values; - this.comparator = (p1, p2) -> comparator.compare(p1.left, p2.left); + this.comparators = comparators; } public List serializeValues(Map map) @@ -59,7 +63,7 @@ public class MapSerializer extends CollectionSerializer> List> pairs = new ArrayList<>(map.size()); for (Map.Entry entry : map.entrySet()) pairs.add(Pair.create(keys.serialize(entry.getKey()), values.serialize(entry.getValue()))); - Collections.sort(pairs, comparator); + Collections.sort(pairs, (l, r) -> comparators.buffer.compare(l.left, r.left)); List buffers = new ArrayList<>(pairs.size() * 2); for (Pair p : pairs) { @@ -74,36 +78,40 @@ public class MapSerializer extends CollectionSerializer> return value.size(); } - public void validateForNativeProtocol(ByteBuffer bytes, ProtocolVersion version) + public void validateForNativeProtocol(T input, ValueAccessor accessor, ProtocolVersion version) { try { - if (bytes.remaining() == 0) - { - return; - } - ByteBuffer input = bytes.duplicate(); - int n = readCollectionSize(input, version); + // Empty values are still valid. + if (accessor.isEmpty(input)) return; + + int n = readCollectionSize(input, accessor, version); + int offset = sizeOfCollectionSize(n, version); for (int i = 0; i < n; i++) { - keys.validate(readValue(input, version)); - values.validate(readValue(input, version)); + T key = readValue(input, accessor, offset, version); + offset += sizeOfValue(key, accessor, version); + keys.validate(key, accessor); + + T value = readValue(input, accessor, offset, version); + offset += sizeOfValue(value, accessor, version); + values.validate(value, accessor); } - if (input.hasRemaining()) + if (!accessor.isEmptyFromOffset(input, offset)) throw new MarshalException("Unexpected extraneous bytes after map value"); } - catch (BufferUnderflowException e) + catch (BufferUnderflowException | IndexOutOfBoundsException e) { throw new MarshalException("Not enough bytes to read a map"); } } - public Map deserializeForNativeProtocol(ByteBuffer bytes, ProtocolVersion version) + public Map deserializeForNativeProtocol(I input, ValueAccessor accessor, ProtocolVersion version) { try { - ByteBuffer input = bytes.duplicate(); - int n = readCollectionSize(input, version); + int n = readCollectionSize(input, accessor, version); + int offset = sizeOfCollectionSize(n, version); if (n < 0) throw new MarshalException("The data cannot be deserialized as a map"); @@ -115,19 +123,21 @@ public class MapSerializer extends CollectionSerializer> Map m = new LinkedHashMap(Math.min(n, 256)); for (int i = 0; i < n; i++) { - ByteBuffer kbb = readValue(input, version); - keys.validate(kbb); + I key = readValue(input, accessor, offset, version); + offset += sizeOfValue(key, accessor, version); + keys.validate(key, accessor); - ByteBuffer vbb = readValue(input, version); - values.validate(vbb); + I value = readValue(input, accessor, offset, version); + offset += sizeOfValue(value, accessor, version); + values.validate(value, accessor); - m.put(keys.deserialize(kbb), values.deserialize(vbb)); + m.put(keys.deserialize(key, accessor), values.deserialize(value, accessor)); } - if (input.hasRemaining()) + if (!accessor.isEmptyFromOffset(input, offset)) throw new MarshalException("Unexpected extraneous bytes after map value"); return m; } - catch (BufferUnderflowException e) + catch (BufferUnderflowException | IndexOutOfBoundsException e) { throw new MarshalException("Not enough bytes to read a map"); } @@ -140,21 +150,23 @@ public class MapSerializer extends CollectionSerializer> { ByteBuffer input = collection.duplicate(); int n = readCollectionSize(input, ProtocolVersion.V3); + int offset = sizeOfCollectionSize(n, ProtocolVersion.V3); for (int i = 0; i < n; i++) { - ByteBuffer kbb = readValue(input, ProtocolVersion.V3); + ByteBuffer kbb = readValue(input, ByteBufferAccessor.instance, offset, ProtocolVersion.V3); + offset += sizeOfValue(kbb, ByteBufferAccessor.instance, ProtocolVersion.V3); int comparison = comparator.compareForCQL(kbb, key); if (comparison == 0) - return readValue(input, ProtocolVersion.V3); + return readValue(input, ByteBufferAccessor.instance, offset, ProtocolVersion.V3); else if (comparison > 0) // since the map is in sorted order, we know we've gone too far and the element doesn't exist return null; else // comparison < 0 - skipValue(input, ProtocolVersion.V3); + offset += skipValue(input, ByteBufferAccessor.instance, offset, ProtocolVersion.V3); } return null; } - catch (BufferUnderflowException e) + catch (BufferUnderflowException | IndexOutOfBoundsException e) { throw new MarshalException("Not enough bytes to read a map"); } @@ -174,6 +186,7 @@ public class MapSerializer extends CollectionSerializer> { ByteBuffer input = collection.duplicate(); int n = readCollectionSize(input, ProtocolVersion.V3); + input.position(input.position() + sizeOfCollectionSize(n, ProtocolVersion.V3)); int startPos = input.position(); int count = 0; boolean inSlice = from == ByteBufferUtil.UNSET_BYTE_BUFFER; @@ -181,7 +194,8 @@ public class MapSerializer extends CollectionSerializer> for (int i = 0; i < n; i++) { int pos = input.position(); - ByteBuffer kbb = readValue(input, ProtocolVersion.V3); // key + ByteBuffer kbb = readValue(input, ByteBufferAccessor.instance, 0, ProtocolVersion.V3); // key + input.position(input.position() + sizeOfValue(kbb, ByteBufferAccessor.instance, ProtocolVersion.V3)); // If we haven't passed the start already, check if we have now if (!inSlice) @@ -224,7 +238,7 @@ public class MapSerializer extends CollectionSerializer> return copyAsNewCollection(collection, count, startPos, input.position(), ProtocolVersion.V3); } - catch (BufferUnderflowException e) + catch (BufferUnderflowException | IndexOutOfBoundsException e) { throw new MarshalException("Not enough bytes to read a map"); } diff --git a/src/java/org/apache/cassandra/serializers/SetSerializer.java b/src/java/org/apache/cassandra/serializers/SetSerializer.java index 8a3ac158a5..0b7a2a5fa2 100644 --- a/src/java/org/apache/cassandra/serializers/SetSerializer.java +++ b/src/java/org/apache/cassandra/serializers/SetSerializer.java @@ -24,6 +24,10 @@ import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import org.apache.cassandra.db.TypeSizes; +import org.apache.cassandra.db.marshal.ByteBufferAccessor; +import org.apache.cassandra.db.marshal.ValueComparators; +import org.apache.cassandra.db.marshal.ValueAccessor; import org.apache.cassandra.transport.ProtocolVersion; import org.apache.cassandra.db.marshal.AbstractType; @@ -35,20 +39,20 @@ public class SetSerializer extends CollectionSerializer> private static final ConcurrentMap, SetSerializer> instances = new ConcurrentHashMap, SetSerializer>(); public final TypeSerializer elements; - private final Comparator comparator; + private final ValueComparators comparators; - public static SetSerializer getInstance(TypeSerializer elements, Comparator elementComparator) + public static SetSerializer getInstance(TypeSerializer elements, ValueComparators comparators) { SetSerializer t = instances.get(elements); if (t == null) - t = instances.computeIfAbsent(elements, k -> new SetSerializer<>(k, elementComparator) ); + t = instances.computeIfAbsent(elements, k -> new SetSerializer<>(k, comparators) ); return t; } - private SetSerializer(TypeSerializer elements, Comparator comparator) + public SetSerializer(TypeSerializer elements, ValueComparators comparators) { this.elements = elements; - this.comparator = comparator; + this.comparators = comparators; } public List serializeValues(Set values) @@ -56,7 +60,7 @@ public class SetSerializer extends CollectionSerializer> List buffers = new ArrayList<>(values.size()); for (T value : values) buffers.add(elements.serialize(value)); - Collections.sort(buffers, comparator); + Collections.sort(buffers, comparators.buffer); return buffers; } @@ -65,33 +69,36 @@ public class SetSerializer extends CollectionSerializer> return value.size(); } - public void validateForNativeProtocol(ByteBuffer bytes, ProtocolVersion version) + public void validateForNativeProtocol(V input, ValueAccessor accessor, ProtocolVersion version) { try { - if (bytes.remaining() == 0) - { - return; - } - ByteBuffer input = bytes.duplicate(); - int n = readCollectionSize(input, version); + // Empty values are still valid. + if (accessor.isEmpty(input)) return; + + int n = readCollectionSize(input, accessor, version); + int offset = sizeOfCollectionSize(n, version); for (int i = 0; i < n; i++) - elements.validate(readValue(input, version)); - if (input.hasRemaining()) + { + V value = readValue(input, accessor, offset, version); + offset += sizeOfValue(value, accessor, version); + elements.validate(value, accessor); + } + if (!accessor.isEmptyFromOffset(input, offset)) throw new MarshalException("Unexpected extraneous bytes after set value"); } - catch (BufferUnderflowException e) + catch (BufferUnderflowException | IndexOutOfBoundsException e) { throw new MarshalException("Not enough bytes to read a set"); } } - public Set deserializeForNativeProtocol(ByteBuffer bytes, ProtocolVersion version) + public Set deserializeForNativeProtocol(V input, ValueAccessor accessor, ProtocolVersion version) { try { - ByteBuffer input = bytes.duplicate(); - int n = readCollectionSize(input, version); + int n = readCollectionSize(input, accessor, version); + int offset = sizeOfCollectionSize(n, version); if (n < 0) throw new MarshalException("The data cannot be deserialized as a set"); @@ -104,15 +111,16 @@ public class SetSerializer extends CollectionSerializer> for (int i = 0; i < n; i++) { - ByteBuffer databb = readValue(input, version); - elements.validate(databb); - l.add(elements.deserialize(databb)); + V value = readValue(input, accessor, offset, version); + offset += sizeOfValue(value, accessor, version); + elements.validate(value, accessor); + l.add(elements.deserialize(value, accessor)); } - if (input.hasRemaining()) + if (!accessor.isEmptyFromOffset(input, offset)) throw new MarshalException("Unexpected extraneous bytes after set value"); return l; } - catch (BufferUnderflowException e) + catch (BufferUnderflowException | IndexOutOfBoundsException e) { throw new MarshalException("Not enough bytes to read a set"); } @@ -145,15 +153,17 @@ public class SetSerializer extends CollectionSerializer> } @Override - public ByteBuffer getSerializedValue(ByteBuffer collection, ByteBuffer key, AbstractType comparator) + public ByteBuffer getSerializedValue(ByteBuffer input, ByteBuffer key, AbstractType comparator) { try { - ByteBuffer input = collection.duplicate(); int n = readCollectionSize(input, ProtocolVersion.V3); + int offset = sizeOfCollectionSize(n, ProtocolVersion.V3); + for (int i = 0; i < n; i++) { - ByteBuffer value = readValue(input, ProtocolVersion.V3); + ByteBuffer value = readValue(input, ByteBufferAccessor.instance, offset, ProtocolVersion.V3); + offset += sizeOfValue(value, ByteBufferAccessor.instance, ProtocolVersion.V3); int comparison = comparator.compareForCQL(value, key); if (comparison == 0) return value; @@ -164,7 +174,7 @@ public class SetSerializer extends CollectionSerializer> } return null; } - catch (BufferUnderflowException e) + catch (BufferUnderflowException | IndexOutOfBoundsException e) { throw new MarshalException("Not enough bytes to read a set"); } @@ -184,6 +194,7 @@ public class SetSerializer extends CollectionSerializer> { ByteBuffer input = collection.duplicate(); int n = readCollectionSize(input, ProtocolVersion.V3); + input.position(input.position() + sizeOfCollectionSize(n, ProtocolVersion.V3)); int startPos = input.position(); int count = 0; boolean inSlice = from == ByteBufferUtil.UNSET_BYTE_BUFFER; @@ -191,7 +202,8 @@ public class SetSerializer extends CollectionSerializer> for (int i = 0; i < n; i++) { int pos = input.position(); - ByteBuffer value = readValue(input, ProtocolVersion.V3); + ByteBuffer value = readValue(input, ByteBufferAccessor.instance, 0, ProtocolVersion.V3); + input.position(input.position() + sizeOfValue(value, ByteBufferAccessor.instance, ProtocolVersion.V3)); // If we haven't passed the start already, check if we have now if (!inSlice) @@ -232,7 +244,7 @@ public class SetSerializer extends CollectionSerializer> return copyAsNewCollection(collection, count, startPos, input.position(), ProtocolVersion.V3); } - catch (BufferUnderflowException e) + catch (BufferUnderflowException | IndexOutOfBoundsException e) { throw new MarshalException("Not enough bytes to read a set"); } diff --git a/src/java/org/apache/cassandra/serializers/ShortSerializer.java b/src/java/org/apache/cassandra/serializers/ShortSerializer.java index f12affaeb6..039b3c1074 100644 --- a/src/java/org/apache/cassandra/serializers/ShortSerializer.java +++ b/src/java/org/apache/cassandra/serializers/ShortSerializer.java @@ -18,17 +18,18 @@ package org.apache.cassandra.serializers; -import org.apache.cassandra.utils.ByteBufferUtil; - import java.nio.ByteBuffer; -public class ShortSerializer implements TypeSerializer +import org.apache.cassandra.db.marshal.ValueAccessor; +import org.apache.cassandra.utils.ByteBufferUtil; + +public class ShortSerializer extends TypeSerializer { public static final ShortSerializer instance = new ShortSerializer(); - public Short deserialize(ByteBuffer bytes) + public Short deserialize(V value, ValueAccessor accessor) { - return bytes.remaining() == 0 ? null : ByteBufferUtil.toShort(bytes); + return accessor.isEmpty(value) ? null : accessor.toShort(value); } public ByteBuffer serialize(Short value) @@ -36,10 +37,10 @@ public class ShortSerializer implements TypeSerializer return value == null ? ByteBufferUtil.EMPTY_BYTE_BUFFER : ByteBufferUtil.bytes(value.shortValue()); } - public void validate(ByteBuffer bytes) throws MarshalException + public void validate(V value, ValueAccessor accessor) throws MarshalException { - if (bytes.remaining() != 2) - throw new MarshalException(String.format("Expected 2 bytes for a smallint (%d)", bytes.remaining())); + if (accessor.size(value) != 2) + throw new MarshalException(String.format("Expected 2 bytes for a smallint (%d)", accessor.size(value))); } public String toString(Short value) diff --git a/src/java/org/apache/cassandra/serializers/SimpleDateSerializer.java b/src/java/org/apache/cassandra/serializers/SimpleDateSerializer.java index fbb5087cf0..c367705fc7 100644 --- a/src/java/org/apache/cassandra/serializers/SimpleDateSerializer.java +++ b/src/java/org/apache/cassandra/serializers/SimpleDateSerializer.java @@ -27,6 +27,7 @@ import java.time.format.DateTimeParseException; import java.util.concurrent.TimeUnit; import java.util.regex.Pattern; +import org.apache.cassandra.db.marshal.ValueAccessor; import org.apache.cassandra.utils.ByteBufferUtil; import static java.time.ZoneOffset.UTC; @@ -34,7 +35,7 @@ import static java.time.format.ResolverStyle.STRICT; // For byte-order comparability, we shift by Integer.MIN_VALUE and treat the data as an unsigned integer ranging from // min date to max date w/epoch sitting in the center @ 2^31 -public class SimpleDateSerializer implements TypeSerializer +public class SimpleDateSerializer extends TypeSerializer { private static final DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE.withZone(UTC).withResolverStyle(STRICT); @@ -46,9 +47,9 @@ public class SimpleDateSerializer implements TypeSerializer private static final Pattern rawPattern = Pattern.compile("^-?\\d+$"); public static final SimpleDateSerializer instance = new SimpleDateSerializer(); - public Integer deserialize(ByteBuffer bytes) + public Integer deserialize(V value, ValueAccessor accessor) { - return bytes.remaining() == 0 ? null : ByteBufferUtil.toInt(bytes); + return accessor.isEmpty(value) ? null : accessor.toInt(value); } public ByteBuffer serialize(Integer value) @@ -114,10 +115,10 @@ public class SimpleDateSerializer implements TypeSerializer return Duration.ofDays(days + Integer.MIN_VALUE).toMillis(); } - public void validate(ByteBuffer bytes) throws MarshalException + public void validate(V value, ValueAccessor accessor) throws MarshalException { - if (bytes.remaining() != 4) - throw new MarshalException(String.format("Expected 4 byte long for date (%d)", bytes.remaining())); + if (accessor.size(value) != 4) + throw new MarshalException(String.format("Expected 4 byte long for date (%d)", accessor.size(value))); } public String toString(Integer value) diff --git a/src/java/org/apache/cassandra/serializers/TimeSerializer.java b/src/java/org/apache/cassandra/serializers/TimeSerializer.java index 1857be38a4..922c16c215 100644 --- a/src/java/org/apache/cassandra/serializers/TimeSerializer.java +++ b/src/java/org/apache/cassandra/serializers/TimeSerializer.java @@ -21,16 +21,17 @@ import java.nio.ByteBuffer; import java.util.concurrent.TimeUnit; import java.util.regex.Pattern; +import org.apache.cassandra.db.marshal.ValueAccessor; import org.apache.cassandra.utils.ByteBufferUtil; -public class TimeSerializer implements TypeSerializer +public class TimeSerializer extends TypeSerializer { public static final Pattern timePattern = Pattern.compile("^-?\\d+$"); public static final TimeSerializer instance = new TimeSerializer(); - public Long deserialize(ByteBuffer bytes) + public Long deserialize(V value, ValueAccessor accessor) { - return bytes.remaining() == 0 ? null : ByteBufferUtil.toLong(bytes); + return accessor.isEmpty(value) ? null : accessor.toLong(value); } public ByteBuffer serialize(Long value) @@ -67,10 +68,10 @@ public class TimeSerializer implements TypeSerializer } } - public void validate(ByteBuffer bytes) throws MarshalException + public void validate(V value, ValueAccessor accessor) throws MarshalException { - if (bytes.remaining() != 8) - throw new MarshalException(String.format("Expected 8 byte long for time (%d)", bytes.remaining())); + if (accessor.size(value) != 8) + throw new MarshalException(String.format("Expected 8 byte long for time (%d)", accessor.size(value))); } public String toString(Long value) diff --git a/src/java/org/apache/cassandra/serializers/TimeUUIDSerializer.java b/src/java/org/apache/cassandra/serializers/TimeUUIDSerializer.java index dc5dad0cc9..9cde1dd487 100644 --- a/src/java/org/apache/cassandra/serializers/TimeUUIDSerializer.java +++ b/src/java/org/apache/cassandra/serializers/TimeUUIDSerializer.java @@ -18,24 +18,20 @@ package org.apache.cassandra.serializers; -import java.nio.ByteBuffer; +import org.apache.cassandra.db.marshal.ValueAccessor; public class TimeUUIDSerializer extends UUIDSerializer { public static final TimeUUIDSerializer instance = new TimeUUIDSerializer(); - @Override - public void validate(ByteBuffer bytes) throws MarshalException + public void validate(V value, ValueAccessor accessor) throws MarshalException { - super.validate(bytes); - + super.validate(value, accessor); // Super class only validates the Time UUID - ByteBuffer slice = bytes.slice(); // version is bits 4-7 of byte 6. - if (bytes.remaining() > 0) + if (!accessor.isEmpty(value)) { - slice.position(6); - if ((slice.get() & 0xf0) != 0x10) + if ((accessor.getByte(value, 6) & 0xf0) != 0x10) throw new MarshalException("Invalid version for TimeUUID type."); } } diff --git a/src/java/org/apache/cassandra/serializers/TimestampSerializer.java b/src/java/org/apache/cassandra/serializers/TimestampSerializer.java index ba35f6498c..b6b712b262 100644 --- a/src/java/org/apache/cassandra/serializers/TimestampSerializer.java +++ b/src/java/org/apache/cassandra/serializers/TimestampSerializer.java @@ -18,6 +18,7 @@ package org.apache.cassandra.serializers; import io.netty.util.concurrent.FastThreadLocal; +import org.apache.cassandra.db.marshal.ValueAccessor; import org.apache.cassandra.utils.ByteBufferUtil; import java.nio.ByteBuffer; @@ -35,7 +36,7 @@ import java.util.TimeZone; import java.util.regex.Pattern; -public class TimestampSerializer implements TypeSerializer +public class TimestampSerializer extends TypeSerializer { private static final List dateFormatters = generateFormatters(); @@ -125,9 +126,9 @@ public class TimestampSerializer implements TypeSerializer public static final TimestampSerializer instance = new TimestampSerializer(); - public Date deserialize(ByteBuffer bytes) + public Date deserialize(V value, ValueAccessor accessor) { - return bytes.remaining() == 0 ? null : new Date(ByteBufferUtil.toLong(bytes)); + return accessor.isEmpty(value) ? null : new Date(accessor.toLong(value)); } public ByteBuffer serialize(Date value) @@ -172,10 +173,10 @@ public class TimestampSerializer implements TypeSerializer return FORMATTER_TO_JSON.get(); } - public void validate(ByteBuffer bytes) throws MarshalException + public void validate(V value, ValueAccessor accessor) throws MarshalException { - if (bytes.remaining() != 8 && bytes.remaining() != 0) - throw new MarshalException(String.format("Expected 8 or 0 byte long for date (%d)", bytes.remaining())); + if (accessor.size(value) != 8 && !accessor.isEmpty(value)) + throw new MarshalException(String.format("Expected 8 or 0 byte long for date (%d)", accessor.size(value))); } public String toString(Date value) @@ -201,7 +202,7 @@ public class TimestampSerializer implements TypeSerializer public String toCQLLiteral(ByteBuffer buffer) { return buffer == null || !buffer.hasRemaining() - ? "null" - : FORMATTER_UTC.get().format(deserialize(buffer)); + ? "null" + : FORMATTER_UTC.get().format(deserialize(buffer)); } } diff --git a/src/java/org/apache/cassandra/serializers/TupleSerializer.java b/src/java/org/apache/cassandra/serializers/TupleSerializer.java index 65e66545d0..afdf2484db 100644 --- a/src/java/org/apache/cassandra/serializers/TupleSerializer.java +++ b/src/java/org/apache/cassandra/serializers/TupleSerializer.java @@ -17,10 +17,10 @@ */ package org.apache.cassandra.serializers; -import java.nio.ByteBuffer; import java.util.List; -import org.apache.cassandra.utils.ByteBufferUtil; +import org.apache.cassandra.db.TypeSizes; +import org.apache.cassandra.db.marshal.ValueAccessor; public class TupleSerializer extends BytesSerializer { @@ -31,34 +31,35 @@ public class TupleSerializer extends BytesSerializer this.fields = fields; } - @Override - public void validate(ByteBuffer bytes) throws MarshalException + public void validate(V input, ValueAccessor accessor) throws MarshalException { - ByteBuffer input = bytes.duplicate(); + int offset = 0; for (int i = 0; i < fields.size(); i++) { // we allow the input to have less fields than declared so as to support field addition. - if (!input.hasRemaining()) + if (accessor.isEmptyFromOffset(input, offset)) return; - if (input.remaining() < Integer.BYTES) + if (accessor.sizeFromOffset(input, offset) < Integer.BYTES) throw new MarshalException(String.format("Not enough bytes to read size of %dth component", i)); - int size = input.getInt(); + int size = accessor.getInt(input, offset); + offset += TypeSizes.INT_SIZE; // size < 0 means null value if (size < 0) continue; - if (input.remaining() < size) + if (accessor.sizeFromOffset(input, offset) < size) throw new MarshalException(String.format("Not enough bytes to read %dth component", i)); - ByteBuffer field = ByteBufferUtil.readBytes(input, size); - fields.get(i).validate(field); + V field = accessor.slice(input, offset, size); + offset += size; + fields.get(i).validate(field, accessor); } // We're allowed to get less fields than declared, but not more - if (input.hasRemaining()) + if (!accessor.isEmptyFromOffset(input, offset)) throw new MarshalException("Invalid remaining data after end of tuple value"); } } diff --git a/src/java/org/apache/cassandra/serializers/TypeSerializer.java b/src/java/org/apache/cassandra/serializers/TypeSerializer.java index bf197cb598..595c360b68 100644 --- a/src/java/org/apache/cassandra/serializers/TypeSerializer.java +++ b/src/java/org/apache/cassandra/serializers/TypeSerializer.java @@ -20,32 +20,46 @@ package org.apache.cassandra.serializers; import java.nio.ByteBuffer; -public interface TypeSerializer +import org.apache.cassandra.db.marshal.ByteBufferAccessor; +import org.apache.cassandra.db.marshal.ValueAccessor; + +public abstract class TypeSerializer { - public ByteBuffer serialize(T value); + public abstract ByteBuffer serialize(T value); + + public abstract T deserialize(V value, ValueAccessor accessor); /* * Does not modify the position or limit of the buffer even temporarily. */ - public T deserialize(ByteBuffer bytes); + public final T deserialize(ByteBuffer bytes) + { + return deserialize(bytes, ByteBufferAccessor.instance); + } /* * Validate that the byte array is a valid sequence for the type this represents. * This guarantees deserialize() can be called without errors. - * - * Does not modify the position or limit of the buffer even temporarily */ - public void validate(ByteBuffer bytes) throws MarshalException; + public abstract void validate(V value, ValueAccessor accessor) throws MarshalException; - public String toString(T value); + /* + * Does not modify the position or limit of the buffer even temporarily. + */ + public final void validate(ByteBuffer bytes) throws MarshalException + { + validate(bytes, ByteBufferAccessor.instance); + } - public Class getType(); + public abstract String toString(T value); - public default String toCQLLiteral(ByteBuffer buffer) + public abstract Class getType(); + + public String toCQLLiteral(ByteBuffer buffer) { return buffer == null || !buffer.hasRemaining() - ? "null" - : toString(deserialize(buffer)); + ? "null" + : toString(deserialize(buffer)); } } diff --git a/src/java/org/apache/cassandra/serializers/UTF8Serializer.java b/src/java/org/apache/cassandra/serializers/UTF8Serializer.java index 444c06cfc3..38faf430b7 100644 --- a/src/java/org/apache/cassandra/serializers/UTF8Serializer.java +++ b/src/java/org/apache/cassandra/serializers/UTF8Serializer.java @@ -17,9 +17,10 @@ */ package org.apache.cassandra.serializers; -import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; +import org.apache.cassandra.db.marshal.ValueAccessor; + public class UTF8Serializer extends AbstractTextSerializer { public static final UTF8Serializer instance = new UTF8Serializer(); @@ -29,9 +30,9 @@ public class UTF8Serializer extends AbstractTextSerializer super(StandardCharsets.UTF_8); } - public void validate(ByteBuffer bytes) throws MarshalException + public void validate(V value, ValueAccessor accessor) throws MarshalException { - if (!UTF8Validator.validate(bytes)) + if (!UTF8Validator.validate(value, accessor)) throw new MarshalException("String didn't validate."); } @@ -51,17 +52,17 @@ public class UTF8Serializer extends AbstractTextSerializer // since we're not converting to java strings, we don't need to worry about converting to surrogates. // buf has already been sliced/duplicated. - static boolean validate(ByteBuffer buf) + static boolean validate(V value, ValueAccessor accessor) { - if (buf == null) + if (value == null) return false; - buf = buf.slice(); int b = 0; + int offset = 0; State state = State.START; - while (buf.remaining() > 0) + while (!accessor.isEmptyFromOffset(value, offset)) { - b = buf.get(); + b = accessor.getByte(value, offset++); switch (state) { case START: diff --git a/src/java/org/apache/cassandra/serializers/UUIDSerializer.java b/src/java/org/apache/cassandra/serializers/UUIDSerializer.java index 4501f34c77..944e6e43b8 100644 --- a/src/java/org/apache/cassandra/serializers/UUIDSerializer.java +++ b/src/java/org/apache/cassandra/serializers/UUIDSerializer.java @@ -20,16 +20,17 @@ package org.apache.cassandra.serializers; import java.nio.ByteBuffer; import java.util.UUID; +import org.apache.cassandra.db.marshal.ValueAccessor; import org.apache.cassandra.utils.ByteBufferUtil; import org.apache.cassandra.utils.UUIDGen; -public class UUIDSerializer implements TypeSerializer +public class UUIDSerializer extends TypeSerializer { public static final UUIDSerializer instance = new UUIDSerializer(); - public UUID deserialize(ByteBuffer bytes) + public UUID deserialize(V value, ValueAccessor accessor) { - return bytes.remaining() == 0 ? null : UUIDGen.getUUID(bytes); + return accessor.isEmpty(value) ? null : accessor.toUUID(value); } public ByteBuffer serialize(UUID value) @@ -37,10 +38,11 @@ public class UUIDSerializer implements TypeSerializer return value == null ? ByteBufferUtil.EMPTY_BYTE_BUFFER : UUIDGen.toByteBuffer(value); } - public void validate(ByteBuffer bytes) throws MarshalException + + public void validate(V value, ValueAccessor accessor) throws MarshalException { - if (bytes.remaining() != 16 && bytes.remaining() != 0) - throw new MarshalException(String.format("UUID should be 16 or 0 bytes (%d)", bytes.remaining())); + if (accessor.size(value) != 16 && !accessor.isEmpty(value)) + throw new MarshalException(String.format("UUID should be 16 or 0 bytes (%d)", accessor.size(value))); // not sure what the version should be for this. } diff --git a/src/java/org/apache/cassandra/serializers/UserTypeSerializer.java b/src/java/org/apache/cassandra/serializers/UserTypeSerializer.java index 7af6c4a781..685432177c 100644 --- a/src/java/org/apache/cassandra/serializers/UserTypeSerializer.java +++ b/src/java/org/apache/cassandra/serializers/UserTypeSerializer.java @@ -17,11 +17,11 @@ */ package org.apache.cassandra.serializers; -import java.nio.ByteBuffer; import java.util.LinkedHashMap; import java.util.Map.Entry; -import org.apache.cassandra.utils.ByteBufferUtil; +import org.apache.cassandra.db.TypeSizes; +import org.apache.cassandra.db.marshal.ValueAccessor; public class UserTypeSerializer extends BytesSerializer { @@ -33,33 +33,35 @@ public class UserTypeSerializer extends BytesSerializer } @Override - public void validate(ByteBuffer bytes) throws MarshalException + public void validate(V input, ValueAccessor accessor) throws MarshalException { - ByteBuffer input = bytes.duplicate(); - int i = -1; // first thing in the loop is to increment, so when starting this will get set to 0 and match the fields + int i = -1; + int offset = 0; for (Entry> entry : fields.entrySet()) { i++; // we allow the input to have less fields than declared so as to support field addition. - if (!input.hasRemaining()) + if (accessor.isEmptyFromOffset(input, offset)) return; - if (input.remaining() < 4) + if (accessor.sizeFromOffset(input, offset) < 4) throw new MarshalException(String.format("Not enough bytes to read size of %dth field %s", i, entry.getKey())); - int size = input.getInt(); + int size = accessor.getInt(input, offset); + offset += TypeSizes.INT_SIZE; // size < 0 means null value if (size < 0) continue; - if (input.remaining() < size) + if (accessor.sizeFromOffset(input, offset) < size) throw new MarshalException(String.format("Not enough bytes to read %dth field %s", i, entry.getKey())); - ByteBuffer field = ByteBufferUtil.readBytes(input, size); + V field = accessor.slice(input, offset, size); try { - entry.getValue().validate(field); + offset += size; + entry.getValue().validate(field, accessor); } catch (MarshalException e) { @@ -68,7 +70,7 @@ public class UserTypeSerializer extends BytesSerializer } // We're allowed to get less fields than declared, but not more - if (input.hasRemaining()) + if (!accessor.isEmptyFromOffset(input, offset)) throw new MarshalException("Invalid remaining data after end of UDT value"); } } diff --git a/src/java/org/apache/cassandra/service/CacheService.java b/src/java/org/apache/cassandra/service/CacheService.java index 4a2e3d53ce..a1225fb512 100644 --- a/src/java/org/apache/cassandra/service/CacheService.java +++ b/src/java/org/apache/cassandra/service/CacheService.java @@ -46,6 +46,7 @@ import org.apache.cassandra.io.sstable.format.SSTableReader; import org.apache.cassandra.io.util.DataInputPlus; import org.apache.cassandra.io.util.DataOutputPlus; import org.apache.cassandra.schema.TableMetadata; +import org.apache.cassandra.utils.ByteArrayUtil; import org.apache.cassandra.utils.ByteBufferUtil; import org.apache.cassandra.utils.FBUtilities; import org.apache.cassandra.utils.MBeanWrapper; @@ -380,7 +381,7 @@ public class CacheService implements CacheServiceMBean TableMetadata tableMetadata = cfs.metadata(); tableMetadata.id.serialize(out); out.writeUTF(tableMetadata.indexName().orElse("")); - ByteBufferUtil.writeWithLength(key.key, out); + ByteArrayUtil.writeWithLength(key.key, out); } public Future> deserialize(DataInputPlus in, final ColumnFamilyStore cfs) throws IOException @@ -421,7 +422,7 @@ public class CacheService implements CacheServiceMBean TableMetadata tableMetadata = cfs.metadata(); tableMetadata.id.serialize(out); out.writeUTF(tableMetadata.indexName().orElse("")); - ByteBufferUtil.writeWithLength(key.key, out); + ByteArrayUtil.writeWithLength(key.key, out); out.writeInt(key.desc.generation); out.writeBoolean(true); diff --git a/src/java/org/apache/cassandra/service/pager/AbstractQueryPager.java b/src/java/org/apache/cassandra/service/pager/AbstractQueryPager.java index 3faa253369..cc8f4340b4 100644 --- a/src/java/org/apache/cassandra/service/pager/AbstractQueryPager.java +++ b/src/java/org/apache/cassandra/service/pager/AbstractQueryPager.java @@ -188,7 +188,7 @@ abstract class AbstractQueryPager implements QueryPager // it means that there is only one row per partition. Therefore, in both cases there are no data remaining // within the partition. if (lastRow != null && (lastRow.clustering() == Clustering.STATIC_CLUSTERING - || lastRow.clustering() == Clustering.EMPTY)) + || lastRow.clustering().isEmpty())) { remainingInPartition = 0; } diff --git a/src/java/org/apache/cassandra/service/pager/AggregationQueryPager.java b/src/java/org/apache/cassandra/service/pager/AggregationQueryPager.java index 5ac01b2459..dbc4fc045a 100644 --- a/src/java/org/apache/cassandra/service/pager/AggregationQueryPager.java +++ b/src/java/org/apache/cassandra/service/pager/AggregationQueryPager.java @@ -146,7 +146,7 @@ public final class AggregationQueryPager implements QueryPager /** * The clustering of the last row processed */ - private Clustering lastClustering; + private Clustering lastClustering; /** * The initial amount of row remaining @@ -260,7 +260,7 @@ public final class AggregationQueryPager implements QueryPager protected QueryPager updatePagerLimit(QueryPager pager, DataLimits limits, ByteBuffer lastPartitionKey, - Clustering lastClustering) + Clustering lastClustering) { GroupingState state = new GroupingState(lastPartitionKey, lastClustering); DataLimits newLimits = limits.forGroupByInternalPaging(state); @@ -417,7 +417,7 @@ public final class AggregationQueryPager implements QueryPager protected QueryPager updatePagerLimit(QueryPager pager, DataLimits limits, ByteBuffer lastPartitionKey, - Clustering lastClustering) + Clustering lastClustering) { return pager; } diff --git a/src/java/org/apache/cassandra/service/pager/PagingState.java b/src/java/org/apache/cassandra/service/pager/PagingState.java index 6eba0ef5ac..1030debf08 100644 --- a/src/java/org/apache/cassandra/service/pager/PagingState.java +++ b/src/java/org/apache/cassandra/service/pager/PagingState.java @@ -26,6 +26,8 @@ import com.google.common.primitives.Ints; import org.apache.cassandra.db.Clustering; import org.apache.cassandra.db.marshal.AbstractType; +import org.apache.cassandra.db.marshal.ByteArrayAccessor; +import org.apache.cassandra.db.marshal.ByteBufferAccessor; import org.apache.cassandra.db.marshal.BytesType; import org.apache.cassandra.db.marshal.CompositeType; import org.apache.cassandra.db.rows.Cell; @@ -354,7 +356,7 @@ public class PagingState // We need to be backward compatible with 2.1/2.2 nodes paging states. Which means we have to send // the full cellname of the "last" cell in the row we get (since that's how 2.1/2.2 nodes will start after // that last row if they get that paging state). - Iterator cells = row.cellsInLegacyOrder(metadata, true).iterator(); + Iterator> cells = row.cellsInLegacyOrder(metadata, true).iterator(); if (!cells.hasNext()) { // If the last returned row has no cell, this means in 2.1/2.2 terms that we stopped on the row @@ -363,7 +365,7 @@ public class PagingState } else { - Cell cell = cells.next(); + Cell cell = cells.next(); mark = encodeCellName(metadata, row.clustering(), cell.column().name.bytes, cell.column().isComplex() ? cell.path().get(0) : null); } } @@ -376,7 +378,7 @@ public class PagingState return new RowMark(mark, protocolVersion); } - public Clustering clustering(TableMetadata metadata) + public Clustering clustering(TableMetadata metadata) { if (mark == null) return null; @@ -386,8 +388,8 @@ public class PagingState : Clustering.serializer.deserialize(mark, MessagingService.VERSION_30, makeClusteringTypes(metadata)); } - // Old (pre-3.0) encoding of cells. We need that for the protocol v3 as that is how things were encoded - private static ByteBuffer encodeCellName(TableMetadata metadata, Clustering clustering, ByteBuffer columnName, ByteBuffer collectionElement) + // Old (pre-3.0) encoding of cells. We need that for the protocol v3 as that is how things where encoded + private static ByteBuffer encodeCellName(TableMetadata metadata, Clustering clustering, ByteBuffer columnName, ByteBuffer collectionElement) { boolean isStatic = clustering == Clustering.STATIC_CLUSTERING; @@ -403,11 +405,11 @@ public class PagingState continue; } - ByteBuffer v = clustering.get(i); + ByteBuffer v = clustering.bufferAt(i); // we can have null (only for dense compound tables for backward compatibility reasons) but that // means we're done and should stop there as far as building the composite is concerned. if (v == null) - return CompositeType.build(Arrays.copyOfRange(values, 0, i)); + return CompositeType.build(ByteBufferAccessor.instance, Arrays.copyOfRange(values, 0, i)); values[i] = v; } @@ -416,19 +418,19 @@ public class PagingState if (collectionElement != null) values[clusteringSize + 1] = collectionElement; - return CompositeType.build(isStatic, values); + return CompositeType.build(ByteBufferAccessor.instance, isStatic, values); } - private static Clustering decodeClustering(TableMetadata metadata, ByteBuffer value) + private static Clustering decodeClustering(TableMetadata metadata, ByteBuffer value) { int csize = metadata.comparator.size(); if (csize == 0) return Clustering.EMPTY; - if (CompositeType.isStaticName(value)) + if (CompositeType.isStaticName(value, ByteBufferAccessor.instance)) return Clustering.STATIC_CLUSTERING; - List components = CompositeType.splitName(value); + List components = CompositeType.splitName(value, ByteBufferAccessor.instance); return Clustering.make(components.subList(0, Math.min(csize, components.size())).toArray(new ByteBuffer[csize])); } diff --git a/src/java/org/apache/cassandra/service/pager/SinglePartitionPager.java b/src/java/org/apache/cassandra/service/pager/SinglePartitionPager.java index 93a0265110..832526e5ce 100644 --- a/src/java/org/apache/cassandra/service/pager/SinglePartitionPager.java +++ b/src/java/org/apache/cassandra/service/pager/SinglePartitionPager.java @@ -85,7 +85,7 @@ public class SinglePartitionPager extends AbstractQueryPager clustering = lastReturned == null ? null : lastReturned.clustering(query.metadata()); DataLimits limits = lastReturned == null ? limits().forPaging(pageSize) : limits().forPaging(pageSize, key(), remainingInPartition()); diff --git a/src/java/org/apache/cassandra/service/reads/ReplicaFilteringProtection.java b/src/java/org/apache/cassandra/service/reads/ReplicaFilteringProtection.java index ed60deac27..e17fe0948c 100644 --- a/src/java/org/apache/cassandra/service/reads/ReplicaFilteringProtection.java +++ b/src/java/org/apache/cassandra/service/reads/ReplicaFilteringProtection.java @@ -364,7 +364,7 @@ public class ReplicaFilteringProtection> private DeletionTime deletionTime; private Row staticRow = Rows.EMPTY_STATIC_ROW; private final Queue contents = new ArrayDeque<>(); - private BTreeSet.Builder toFetch; + private BTreeSet.Builder> toFetch; private int partitionRowsCached; private PartitionBuilder(DecoratedKey key, Replica source, RegularAndStaticColumns columns, EncodingStats stats) @@ -507,7 +507,7 @@ public class ReplicaFilteringProtection> { assert toFetch != null; - NavigableSet clusterings = toFetch.build(); + NavigableSet> clusterings = toFetch.build(); tableMetrics.replicaFilteringProtectionRequests.mark(); if (logger.isTraceEnabled()) diff --git a/src/java/org/apache/cassandra/service/reads/ShortReadRowsProtection.java b/src/java/org/apache/cassandra/service/reads/ShortReadRowsProtection.java index f32502d2ce..9ba074dbff 100644 --- a/src/java/org/apache/cassandra/service/reads/ShortReadRowsProtection.java +++ b/src/java/org/apache/cassandra/service/reads/ShortReadRowsProtection.java @@ -47,7 +47,7 @@ class ShortReadRowsProtection extends Transformation implements MoreRows lastClustering; // clustering of the last observed row private int lastCounted = 0; // last seen recorded # before attempting to fetch more rows private int lastFetched = 0; // # rows returned by last attempt to get more (or by the original read command) @@ -118,7 +118,7 @@ class ShortReadRowsProtection extends Transformation implements MoreRows> // For each source, the time of the current deletion as known by the source. private final DeletionTime[] sourceDeletionTime; // For each source, record if there is an open range to send as repair, and from where. - private final ClusteringBound[] markerToRepair; + private final ClusteringBound[] markerToRepair; private final ReadRepair readRepair; @@ -111,37 +111,37 @@ public class RowIteratorMergeListener> this.repairs = new PartitionUpdate.Builder[size + (buildFullDiff ? 1 : 0)]; this.currentRows = new Row.Builder[size]; this.sourceDeletionTime = new DeletionTime[size]; - this.markerToRepair = new ClusteringBound[size]; + this.markerToRepair = new ClusteringBound[size]; this.command = command; this.readRepair = readRepair; this.diffListener = new RowDiffListener() { - public void onPrimaryKeyLivenessInfo(int i, Clustering clustering, LivenessInfo merged, LivenessInfo original) + public void onPrimaryKeyLivenessInfo(int i, Clustering clustering, LivenessInfo merged, LivenessInfo original) { if (merged != null && !merged.equals(original)) currentRow(i, clustering).addPrimaryKeyLivenessInfo(merged); } - public void onDeletion(int i, Clustering clustering, Row.Deletion merged, Row.Deletion original) + public void onDeletion(int i, Clustering clustering, Row.Deletion merged, Row.Deletion original) { if (merged != null && !merged.equals(original)) currentRow(i, clustering).addRowDeletion(merged); } - public void onComplexDeletion(int i, Clustering clustering, ColumnMetadata column, DeletionTime merged, DeletionTime original) + public void onComplexDeletion(int i, Clustering clustering, ColumnMetadata column, DeletionTime merged, DeletionTime original) { if (merged != null && !merged.equals(original)) currentRow(i, clustering).addComplexDeletion(column, merged); } - public void onCell(int i, Clustering clustering, Cell merged, Cell original) + public void onCell(int i, Clustering clustering, Cell merged, Cell original) { if (merged != null && !merged.equals(original) && isQueried(merged)) currentRow(i, clustering).addCell(merged); } - private boolean isQueried(Cell cell) + private boolean isQueried(Cell cell) { // When we read, we may have some cell that have been fetched but are not selected by the user. Those cells may // have empty values as optimization (see CASSANDRA-10655) and hence they should not be included in the read-repair. @@ -167,7 +167,7 @@ public class RowIteratorMergeListener> return repairs[i] == null ? DeletionTime.LIVE : repairs[i].partitionLevelDeletion(); } - private Row.Builder currentRow(int i, Clustering clustering) + private Row.Builder currentRow(int i, Clustering clustering) { if (currentRows[i] == null) { @@ -345,9 +345,9 @@ public class RowIteratorMergeListener> mergedDeletionTime = merged.isOpen(isReversed) ? merged.openDeletionTime(isReversed) : null; } - private void closeOpenMarker(int i, ClusteringBound close) + private void closeOpenMarker(int i, ClusteringBound close) { - ClusteringBound open = markerToRepair[i]; + ClusteringBound open = markerToRepair[i]; RangeTombstone rt = new RangeTombstone(Slice.make(isReversed ? close : open, isReversed ? open : close), currentDeletion()); applyToPartition(i, p -> p.add(rt)); markerToRepair[i] = null; diff --git a/src/java/org/apache/cassandra/tools/JsonTransformer.java b/src/java/org/apache/cassandra/tools/JsonTransformer.java index c53872274f..341512c27b 100644 --- a/src/java/org/apache/cassandra/tools/JsonTransformer.java +++ b/src/java/org/apache/cassandra/tools/JsonTransformer.java @@ -338,7 +338,7 @@ public final class JsonTransformer } } - private void serializeBound(ClusteringBound bound, DeletionTime deletionTime) throws IOException + private void serializeBound(ClusteringBound bound, DeletionTime deletionTime) throws IOException { json.writeFieldName(bound.isStart() ? "start" : "end"); json.writeStartObject(); @@ -349,7 +349,7 @@ public final class JsonTransformer json.writeEndObject(); } - private void serializeClustering(ClusteringPrefix clustering) throws IOException + private void serializeClustering(ClusteringPrefix clustering) throws IOException { if (clustering.size() > 0) { @@ -367,7 +367,7 @@ public final class JsonTransformer } else { - json.writeRawValue(column.cellValueType().toJSONString(clustering.get(i), ProtocolVersion.CURRENT)); + json.writeRawValue(column.cellValueType().toJSONString(clustering.get(i), clustering.accessor(), ProtocolVersion.CURRENT)); } } json.writeEndArray(); @@ -393,7 +393,7 @@ public final class JsonTransformer { if (cd.column().isSimple()) { - serializeCell((Cell) cd, liveInfo); + serializeCell((Cell) cd, liveInfo); } else { @@ -416,13 +416,13 @@ public final class JsonTransformer logger.error("Failure parsing ColumnData.", e); } } - for (Cell cell : complexData){ + for (Cell cell : complexData){ serializeCell(cell, liveInfo); } } } - private void serializeCell(Cell cell, LivenessInfo liveInfo) + private void serializeCell(Cell cell, LivenessInfo liveInfo) { try { @@ -483,7 +483,7 @@ public final class JsonTransformer else { json.writeFieldName("value"); - json.writeRawValue(cellType.toJSONString(cell.value(), ProtocolVersion.CURRENT)); + json.writeRawValue(cellType.toJSONString(cell.value(), cell.accessor(), ProtocolVersion.CURRENT)); } if (liveInfo.isEmpty() || cell.timestamp() != liveInfo.timestamp()) { diff --git a/src/java/org/apache/cassandra/tools/SSTableMetadataViewer.java b/src/java/org/apache/cassandra/tools/SSTableMetadataViewer.java index 6366fd5a6e..e99f4544e9 100755 --- a/src/java/org/apache/cassandra/tools/SSTableMetadataViewer.java +++ b/src/java/org/apache/cassandra/tools/SSTableMetadataViewer.java @@ -228,7 +228,7 @@ public class SSTableMetadataViewer Row row = (Row) unfiltered; psize += row.dataSize(); pcount++; - for (org.apache.cassandra.db.rows.Cell cell : row.cells()) + for (org.apache.cassandra.db.rows.Cell cell : row.cells()) { cellCount++; double percentComplete = Math.min(1.0, cellCount / totalCells); diff --git a/src/java/org/apache/cassandra/utils/ByteArrayUtil.java b/src/java/org/apache/cassandra/utils/ByteArrayUtil.java index b97a1c5e46..559607ccc5 100644 --- a/src/java/org/apache/cassandra/utils/ByteArrayUtil.java +++ b/src/java/org/apache/cassandra/utils/ByteArrayUtil.java @@ -4,7 +4,7 @@ * 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 + * "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 @@ -18,11 +18,78 @@ package org.apache.cassandra.utils; +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.charset.CharacterCodingException; +import java.nio.charset.Charset; + +import org.apache.cassandra.db.TypeSizes; + +// mostly copied from java.io.Bits public class ByteArrayUtil { - private ByteArrayUtil() - { + public static final byte[] EMPTY_BYTE_ARRAY = new byte[0]; + public static int compareUnsigned(byte[] o1, byte[] o2) + { + return FastByteOperations.compareUnsigned(o1, 0, o1.length, o2, 0, o2.length); + } + + public static int compareUnsigned(byte[] o1, int off1, byte[] o2, int off2, int len) + { + return FastByteOperations.compareUnsigned(o1, off1, len, o2, off2, len); + } + + public static byte[] bytes(byte b) + { + return new byte[] {b}; + } + + public static byte[] bytes(int v) + { + byte[] b = new byte[TypeSizes.sizeof(v)]; + putInt(b, 0, v); + return b; + } + + public static byte[] bytes(long v) + { + byte[] b = new byte[TypeSizes.sizeof(v)]; + putLong(b, 0, v); + return b; + } + + public static byte[] bytes(short v) + { + byte[] b = new byte[TypeSizes.sizeof(v)]; + putShort(b, 0, v); + return b; + } + + public static byte[] bytes(float v) + { + byte[] b = new byte[TypeSizes.sizeof(v)]; + putFloat(b, 0, v); + return b; + } + + public static byte[] bytes(double v) + { + byte[] b = new byte[TypeSizes.sizeof(v)]; + putDouble(b, 0, v); + return b; + } + + public static byte[] bytes(String v) + { + return v.getBytes(); + } + + public static byte[] bytes(String v, Charset charset) + { + return v.getBytes(charset); } /* @@ -30,104 +97,52 @@ public class ByteArrayUtil * given offsets. */ - public static boolean getBoolean(byte[] b) - { - return getBoolean(b, 0); - } - - public static boolean getBoolean(byte[] b, int off) - { + public static boolean getBoolean(byte[] b, int off) { return b[off] != 0; } - /** - * @return signed short encoded as big endian - */ - public static short getShort(byte[] b) - { - return getShort(b, 0); + public static char getChar(byte[] b, int off) { + return (char) ((b[off + 1] & 0xFF) + + (b[off] << 8)); } - /** - * @return signed short from the given offset encoded as big endian - */ - public static short getShort(byte[] b, int off) - { - return (short) (b[off ] << 8 | - b[off + 1] & 255); + public static short getShort(byte[] b, int off) { + return (short) ((b[off + 1] & 0xFF) + + (b[off] << 8)); } - /** - * @return signed int encoded as big endian - */ - public static int getInt(byte[] b) - { + public static int getInt(byte[] b, int off) { + return ((b[off + 3] & 0xFF) ) + + ((b[off + 2] & 0xFF) << 8) + + ((b[off + 1] & 0xFF) << 16) + + ((b[off ] ) << 24); + } + + public static int getInt(byte[] b) { return getInt(b, 0); } - /** - * @return signed int from the given offset encoded as big endian - */ - public static int getInt(byte[] b, int off) - { - return (b[off ] & 255) << 24 | - (b[off + 1] & 255) << 16 | - (b[off + 2] & 255) << 8 | - (b[off + 3] & 255); - } - - /** - * @return signed float encoded as big endian - */ - public static float getFloat(byte[] b) - { - return getFloat(b, 0); - } - - /** - * @return signed float from the given offset encoded as big endian - */ - public static float getFloat(byte[] b, int off) - { + public static float getFloat(byte[] b, int off) { return Float.intBitsToFloat(getInt(b, off)); } - /** - * @return signed long encoded as big endian - */ public static long getLong(byte[] b) { return getLong(b, 0); } - /** - * @return signed long from the given offset encoded as big endian - */ - public static long getLong(byte[] b, int off) - { - return ((long) b[off ] & 255L) << 56 | - ((long) b[off + 1] & 255L) << 48 | - ((long) b[off + 2] & 255L) << 40 | - ((long) b[off + 3] & 255L) << 32 | - ((long) b[off + 4] & 255L) << 24 | - ((long) b[off + 5] & 255L) << 16 | - ((long) b[off + 6] & 255L) << 8 | - ((long) b[off + 7] & 255L); + public static long getLong(byte[] b, int off) { + return ((b[off + 7] & 0xFFL) ) + + ((b[off + 6] & 0xFFL) << 8) + + ((b[off + 5] & 0xFFL) << 16) + + ((b[off + 4] & 0xFFL) << 24) + + ((b[off + 3] & 0xFFL) << 32) + + ((b[off + 2] & 0xFFL) << 40) + + ((b[off + 1] & 0xFFL) << 48) + + (((long) b[off]) << 56); } - /** - * @return signed double from the given offset encoded as big endian - */ - public static double getDouble(byte[] b) - { - return getDouble(b, 0); - } - - /** - * @return signed double from the given offset encoded as big endian - */ - public static double getDouble(byte[] b, int off) - { + public static double getDouble(byte[] b, int off) { return Double.longBitsToDouble(getLong(b, off)); } @@ -136,48 +151,32 @@ public class ByteArrayUtil * offsets. */ - public static void putBoolean(byte[] b, int off, boolean val) - { - ensureCapacity(b, off, 1); + public static void putBoolean(byte[] b, int off, boolean val) { b[off] = (byte) (val ? 1 : 0); } - /** - * Store a signed short at the given offset encoded as big endian - */ - public static void putShort(byte[] b, int off, short val) - { - ensureCapacity(b, off, Short.BYTES); + public static void putChar(byte[] b, int off, char val) { b[off + 1] = (byte) (val ); b[off ] = (byte) (val >>> 8); } - /** - * Store a signed int at the given offset encoded as big endian - */ - public static void putInt(byte[] b, int off, int val) - { - ensureCapacity(b, off, Integer.BYTES); + public static void putShort(byte[] b, int off, short val) { + b[off + 1] = (byte) (val ); + b[off ] = (byte) (val >>> 8); + } + + public static void putInt(byte[] b, int off, int val) { b[off + 3] = (byte) (val ); b[off + 2] = (byte) (val >>> 8); b[off + 1] = (byte) (val >>> 16); b[off ] = (byte) (val >>> 24); } - /** - * Store a signed float at the given offset encoded as big endian - */ - public static void putFloat(byte[] b, int off, float val) - { + public static void putFloat(byte[] b, int off, float val) { putInt(b, off, Float.floatToIntBits(val)); } - /** - * Store a signed long at the given offset encoded as big endian - */ - public static void putLong(byte[] b, int off, long val) - { - ensureCapacity(b, off, Long.BYTES); + public static void putLong(byte[] b, int off, long val) { b[off + 7] = (byte) (val ); b[off + 6] = (byte) (val >>> 8); b[off + 5] = (byte) (val >>> 16); @@ -188,22 +187,66 @@ public class ByteArrayUtil b[off ] = (byte) (val >>> 56); } - /** - * Store a signed double at the given offset encoded as big endian - */ - public static void putDouble(byte[] b, int off, double val) - { + public static void putDouble(byte[] b, int off, double val) { putLong(b, off, Double.doubleToLongBits(val)); } - private static void ensureCapacity(byte[] b, int off, int len) + public static String bytesToHex(byte[] bytes) { - int writable = b.length - off; - if (writable < len) - { - if (writable < 0) - throw new IndexOutOfBoundsException("Attempted to write to offset " + off + " but array length is " + b.length); - throw new IndexOutOfBoundsException("Attempted to write " + len + " bytes to array with remaining capacity of " + writable); - } + return Hex.bytesToHex(bytes, 0, bytes.length); } -} + + public static byte[] hexToBytes(String hex) + { + return Hex.hexToBytes(hex); + } + + public static String string(byte[] bytes) throws CharacterCodingException + { + return ByteBufferUtil.string(ByteBuffer.wrap(bytes)); + } + + public static String string(byte[] buffer, Charset charset) throws CharacterCodingException + { + return new String(buffer, charset); + } + + public static void writeWithLength(byte[] bytes, DataOutput out) throws IOException + { + out.writeInt(bytes.length); + out.write(bytes); + } + + public static void writeWithShortLength(byte[] buffer, DataOutput out) throws IOException + { + int length = buffer.length; + assert length <= FBUtilities.MAX_UNSIGNED_SHORT + : String.format("Attempted serializing to buffer exceeded maximum of %s bytes: %s", FBUtilities.MAX_UNSIGNED_SHORT, length); + out.writeShort(length); + out.write(buffer); + } + + public static byte[] readWithLength(DataInput in) throws IOException + { + byte[] b = new byte[in.readInt()]; + in.readFully(b); + return b; + } + + public static byte[] readWithShortLength(DataInput in) throws IOException + { + byte[] b = new byte[in.readUnsignedShort()]; + in.readFully(b); + return b; + } + + public static void copyBytes(byte[] src, int srcPos, byte[] dst, int dstPos, int length) + { + System.arraycopy(src, srcPos, dst, dstPos, length); + } + + public static void copyBytes(byte[] src, int srcPos, ByteBuffer dst, int dstPos, int length) + { + FastByteOperations.copy(src, srcPos, dst, dstPos, length); + } +} \ No newline at end of file diff --git a/src/java/org/apache/cassandra/utils/ByteBufferUtil.java b/src/java/org/apache/cassandra/utils/ByteBufferUtil.java index 5300d9de1f..fca989fb54 100644 --- a/src/java/org/apache/cassandra/utils/ByteBufferUtil.java +++ b/src/java/org/apache/cassandra/utils/ByteBufferUtil.java @@ -83,6 +83,8 @@ public class ByteBufferUtil /** Represents an unset value in bound variables */ public static final ByteBuffer UNSET_BYTE_BUFFER = ByteBuffer.wrap(new byte[]{}); + public static final ByteBuffer[] EMPTY_ARRAY = new ByteBuffer[0]; + @Inline public static int compareUnsigned(ByteBuffer o1, ByteBuffer o2) { @@ -340,12 +342,6 @@ public class ByteBufferUtil out.write(bytes); } - public static void writeWithLength(byte[] bytes, DataOutput out) throws IOException - { - out.writeInt(bytes.length); - out.write(bytes); - } - public static void writeWithShortLength(ByteBuffer buffer, DataOutputPlus out) throws IOException { int length = buffer.remaining(); @@ -355,15 +351,6 @@ public class ByteBufferUtil out.write(buffer); } - public static void writeWithShortLength(byte[] buffer, DataOutput out) throws IOException - { - int length = buffer.length; - assert 0 <= length && length <= FBUtilities.MAX_UNSIGNED_SHORT - : String.format("Attempted serializing to buffer exceeded maximum of %s bytes: %s", FBUtilities.MAX_UNSIGNED_SHORT, length); - out.writeShort(length); - out.write(buffer); - } - public static ByteBuffer readWithLength(DataInput in) throws IOException { int length = in.readInt(); diff --git a/src/java/org/apache/cassandra/utils/FastByteOperations.java b/src/java/org/apache/cassandra/utils/FastByteOperations.java index 060dee59ad..ffaee1f084 100644 --- a/src/java/org/apache/cassandra/utils/FastByteOperations.java +++ b/src/java/org/apache/cassandra/utils/FastByteOperations.java @@ -70,11 +70,21 @@ public class FastByteOperations return BestHolder.BEST.compare(b1, b2); } + public static void copy(byte[] src, int srcPosition, byte[] trg, int trgPosition, int length) + { + BestHolder.BEST.copy(src, srcPosition, trg, trgPosition, length); + } + public static void copy(ByteBuffer src, int srcPosition, byte[] trg, int trgPosition, int length) { BestHolder.BEST.copy(src, srcPosition, trg, trgPosition, length); } + public static void copy(byte[] src, int srcPosition, ByteBuffer trg, int trgPosition, int length) + { + BestHolder.BEST.copy(src, srcPosition, trg, trgPosition, length); + } + public static void copy(ByteBuffer src, int srcPosition, ByteBuffer trg, int trgPosition, int length) { BestHolder.BEST.copy(src, srcPosition, trg, trgPosition, length); @@ -91,8 +101,12 @@ public class FastByteOperations abstract public int compare(ByteBuffer buffer1, ByteBuffer buffer2); + abstract public void copy(byte[] src, int srcPosition, byte[] trg, int trgPosition, int length); + abstract public void copy(ByteBuffer src, int srcPosition, byte[] trg, int trgPosition, int length); + abstract public void copy(byte[] src, int srcPosition, ByteBuffer trg, int trgPosition, int length); + abstract public void copy(ByteBuffer src, int srcPosition, ByteBuffer trg, int trgPosition, int length); } @@ -225,6 +239,11 @@ public class FastByteOperations return compareTo(buffer1, buffer2); } + public void copy(byte[] src, int srcPosition, byte[] trg, int trgPosition, int length) + { + System.arraycopy(src, srcPosition, trg, trgPosition, length); + } + public void copy(ByteBuffer src, int srcPosition, byte[] trg, int trgPosition, int length) { if (src.hasArray()) @@ -233,6 +252,14 @@ public class FastByteOperations copy(null, srcPosition + theUnsafe.getLong(src, DIRECT_BUFFER_ADDRESS_OFFSET), trg, trgPosition, length); } + public void copy(byte[] src, int srcPosition, ByteBuffer trg, int trgPosition, int length) + { + if (trg.hasArray()) + System.arraycopy(src, srcPosition, trg.array(), trg.arrayOffset() + trgPosition, length); + else + copy(null, srcPosition + theUnsafe.getLong(src, Unsafe.ARRAY_BYTE_BASE_OFFSET), trg, trgPosition, length); + } + public void copy(ByteBuffer srcBuf, int srcPosition, ByteBuffer trgBuf, int trgPosition, int length) { Object src; @@ -449,6 +476,11 @@ public class FastByteOperations return buffer1.remaining() - buffer2.remaining(); } + public void copy(byte[] src, int srcPosition, byte[] trg, int trgPosition, int length) + { + System.arraycopy(src, srcPosition, trg, trgPosition, length); + } + public void copy(ByteBuffer src, int srcPosition, byte[] trg, int trgPosition, int length) { if (src.hasArray()) @@ -461,6 +493,16 @@ public class FastByteOperations src.get(trg, trgPosition, length); } + public void copy(byte[] src, int srcPosition, ByteBuffer trg, int trgPosition, int length) + { + if (trg.hasArray()) + { + System.arraycopy(src, srcPosition, trg.array(), trg.arrayOffset() + trgPosition, length); + return; + } + trg.duplicate().put(src, srcPosition, length); + } + public void copy(ByteBuffer src, int srcPosition, ByteBuffer trg, int trgPosition, int length) { if (src.hasArray() && trg.hasArray()) diff --git a/src/java/org/apache/cassandra/utils/NativeSSTableLoaderClient.java b/src/java/org/apache/cassandra/utils/NativeSSTableLoaderClient.java index 9763d7e8b6..004bc3450a 100644 --- a/src/java/org/apache/cassandra/utils/NativeSSTableLoaderClient.java +++ b/src/java/org/apache/cassandra/utils/NativeSSTableLoaderClient.java @@ -17,12 +17,10 @@ */ package org.apache.cassandra.utils; -import java.net.InetAddress; import java.nio.ByteBuffer; import java.net.InetSocketAddress; import java.net.UnknownHostException; import java.util.*; -import java.util.stream.Collectors; import com.datastax.driver.core.*; diff --git a/src/java/org/apache/cassandra/utils/memory/AbstractAllocator.java b/src/java/org/apache/cassandra/utils/memory/AbstractAllocator.java index c3cac2b7dd..310835543d 100644 --- a/src/java/org/apache/cassandra/utils/memory/AbstractAllocator.java +++ b/src/java/org/apache/cassandra/utils/memory/AbstractAllocator.java @@ -20,6 +20,9 @@ package org.apache.cassandra.utils.memory; import java.nio.ByteBuffer; import org.apache.cassandra.db.Clustering; +import org.apache.cassandra.db.marshal.ByteArrayAccessor; +import org.apache.cassandra.db.marshal.ByteBufferAccessor; +import org.apache.cassandra.db.marshal.ValueAccessor; import org.apache.cassandra.db.rows.BTreeRow; import org.apache.cassandra.db.rows.Cell; import org.apache.cassandra.db.rows.Row; @@ -32,13 +35,27 @@ public abstract class AbstractAllocator */ public ByteBuffer clone(ByteBuffer buffer) { - assert buffer != null; - if (buffer.remaining() == 0) + return clone(buffer, ByteBufferAccessor.instance); + } + + /** + * Allocate a slice of the given length. + */ + public ByteBuffer clone(byte[] bytes) + { + return clone(bytes, ByteArrayAccessor.instance); + } + + public ByteBuffer clone(V value, ValueAccessor accessor) + { + assert value != null; + int size = accessor.size(value); + if (size == 0) return ByteBufferUtil.EMPTY_BYTE_BUFFER; - ByteBuffer cloned = allocate(buffer.remaining()); + ByteBuffer cloned = allocate(size); cloned.mark(); - cloned.put(buffer.duplicate()); + accessor.write(value, cloned); cloned.reset(); return cloned; } @@ -61,13 +78,13 @@ public abstract class AbstractAllocator } @Override - public void newRow(Clustering clustering) + public void newRow(Clustering clustering) { super.newRow(clustering.copy(allocator)); } @Override - public void addCell(Cell cell) + public void addCell(Cell cell) { super.addCell(cell.copy(allocator)); } diff --git a/src/java/org/apache/cassandra/utils/memory/EnsureOnHeap.java b/src/java/org/apache/cassandra/utils/memory/EnsureOnHeap.java index 54ace5ea0f..71c17934cb 100644 --- a/src/java/org/apache/cassandra/utils/memory/EnsureOnHeap.java +++ b/src/java/org/apache/cassandra/utils/memory/EnsureOnHeap.java @@ -34,7 +34,7 @@ public abstract class EnsureOnHeap extends Transformation { public abstract DecoratedKey applyToPartitionKey(DecoratedKey key); public abstract UnfilteredRowIterator applyToPartition(UnfilteredRowIterator partition); - public abstract SearchIterator applyToPartition(SearchIterator partition); + public abstract SearchIterator, Row> applyToPartition(SearchIterator, Row> partition); public abstract Iterator applyToPartition(Iterator partition); public abstract DeletionInfo applyToDeletionInfo(DeletionInfo deletionInfo); public abstract Row applyToRow(Row row); @@ -79,11 +79,11 @@ public abstract class EnsureOnHeap extends Transformation return Transformation.apply(partition, this); } - public SearchIterator applyToPartition(SearchIterator partition) + public SearchIterator, Row> applyToPartition(SearchIterator, Row> partition) { - return new SearchIterator() + return new SearchIterator, Row>() { - public Row next(Clustering key) + public Row next(Clustering key) { return applyToRow(partition.next(key)); } @@ -147,7 +147,7 @@ public abstract class EnsureOnHeap extends Transformation return partition; } - public SearchIterator applyToPartition(SearchIterator partition) + public SearchIterator, Row> applyToPartition(SearchIterator, Row> partition) { return partition; } diff --git a/src/java/org/apache/cassandra/utils/memory/NativeAllocator.java b/src/java/org/apache/cassandra/utils/memory/NativeAllocator.java index af8b7507e0..9aecf85e45 100644 --- a/src/java/org/apache/cassandra/utils/memory/NativeAllocator.java +++ b/src/java/org/apache/cassandra/utils/memory/NativeAllocator.java @@ -74,7 +74,7 @@ public class NativeAllocator extends MemtableAllocator } @Override - public void newRow(Clustering clustering) + public void newRow(Clustering clustering) { if (clustering != Clustering.STATIC_CLUSTERING) clustering = new NativeClustering(allocator, writeOp, clustering); @@ -82,7 +82,7 @@ public class NativeAllocator extends MemtableAllocator } @Override - public void addCell(Cell cell) + public void addCell(Cell cell) { super.addCell(new NativeCell(allocator, writeOp, cell)); } diff --git a/test/distributed/org/apache/cassandra/distributed/Cluster.java b/test/distributed/org/apache/cassandra/distributed/Cluster.java index e8e6041721..5c5a954d4d 100644 --- a/test/distributed/org/apache/cassandra/distributed/Cluster.java +++ b/test/distributed/org/apache/cassandra/distributed/Cluster.java @@ -24,7 +24,6 @@ import java.util.function.Consumer; import org.apache.cassandra.distributed.api.IInstanceConfig; import org.apache.cassandra.distributed.impl.AbstractCluster; import org.apache.cassandra.distributed.api.IInvokableInstance; -import org.apache.cassandra.distributed.shared.AbstractBuilder; import org.apache.cassandra.distributed.shared.Versions; /** diff --git a/test/long/org/apache/cassandra/db/commitlog/CommitLogStressTest.java b/test/long/org/apache/cassandra/db/commitlog/CommitLogStressTest.java index 7fadac4382..a4f98e9945 100644 --- a/test/long/org/apache/cassandra/db/commitlog/CommitLogStressTest.java +++ b/test/long/org/apache/cassandra/db/commitlog/CommitLogStressTest.java @@ -464,12 +464,12 @@ public abstract class CommitLogStressTest while (rowIterator.hasNext()) { Row row = rowIterator.next(); - if (!(UTF8Type.instance.compose(row.clustering().get(0)).startsWith("name"))) + if (!(UTF8Type.instance.compose(row.clustering().bufferAt(0)).startsWith("name"))) continue; - for (Cell cell : row.cells()) + for (Cell cell : row.cells()) { - hash = hash(hash, cell.value()); + hash = hash(hash, cell.buffer()); ++cells; } } diff --git a/test/long/org/apache/cassandra/hints/HintsWriteThenReadTest.java b/test/long/org/apache/cassandra/hints/HintsWriteThenReadTest.java index a905f9a2cc..7970d59721 100644 --- a/test/long/org/apache/cassandra/hints/HintsWriteThenReadTest.java +++ b/test/long/org/apache/cassandra/hints/HintsWriteThenReadTest.java @@ -130,7 +130,7 @@ public class HintsWriteThenReadTest Row row = mutation.getPartitionUpdates().iterator().next().iterator().next(); assertEquals(1, Iterables.size(row.cells())); assertEquals(bytes(index), row.clustering().get(0)); - Cell cell = row.cells().iterator().next(); + Cell cell = row.cells().iterator().next(); assertNotNull(cell); assertEquals(bytes(index), cell.value()); assertEquals(timestamp * 1000, cell.timestamp()); diff --git a/test/unit/org/apache/cassandra/Util.java b/test/unit/org/apache/cassandra/Util.java index 4d6e2e8eb7..2c171e70ae 100644 --- a/test/unit/org/apache/cassandra/Util.java +++ b/test/unit/org/apache/cassandra/Util.java @@ -124,7 +124,7 @@ public class Util return PartitionPosition.ForKey.get(ByteBufferUtil.bytes(key), partitioner); } - public static Clustering clustering(ClusteringComparator comparator, Object... o) + public static Clustering clustering(ClusteringComparator comparator, Object... o) { return comparator.make(o); } @@ -433,7 +433,7 @@ public class Util return mutation.getPartitionUpdates().iterator().next().unfilteredIterator(); } - public static Cell cell(ColumnFamilyStore cfs, Row row, String columnName) + public static Cell cell(ColumnFamilyStore cfs, Row row, String columnName) { ColumnMetadata def = cfs.metadata().getColumn(ByteBufferUtil.bytes(columnName)); assert def != null; @@ -447,9 +447,9 @@ public class Util public static void assertCellValue(Object value, ColumnFamilyStore cfs, Row row, String columnName) { - Cell cell = cell(cfs, row, columnName); + Cell cell = cell(cfs, row, columnName); assert cell != null : "Row " + row.toString(cfs.metadata()) + " has no cell for " + columnName; - assertEquals(value, cell.column().type.compose(cell.value())); + assertEquals(value, Cells.composeValue(cell, cell.column().type)); } public static void consume(UnfilteredRowIterator iter) @@ -526,10 +526,10 @@ public class Util // moved & refactored from KeyspaceTest in < 3.0 public static void assertColumns(Row row, String... expectedColumnNames) { - Iterator cells = row == null ? Collections.emptyIterator() : row.cells().iterator(); - String[] actual = Iterators.toArray(Iterators.transform(cells, new Function() + Iterator> cells = row == null ? Collections.emptyIterator() : row.cells().iterator(); + String[] actual = Iterators.toArray(Iterators.transform(cells, new Function, String>() { - public String apply(Cell cell) + public String apply(Cell cell) { return cell.column().name.toString(); } @@ -543,14 +543,14 @@ public class Util public static void assertColumn(TableMetadata cfm, Row row, String name, String value, long timestamp) { - Cell cell = row.getCell(cfm.getColumn(new ColumnIdentifier(name, true))); + Cell cell = row.getCell(cfm.getColumn(new ColumnIdentifier(name, true))); assertColumn(cell, value, timestamp); } - public static void assertColumn(Cell cell, String value, long timestamp) + public static void assertColumn(Cell cell, String value, long timestamp) { assertNotNull(cell); - assertEquals(0, ByteBufferUtil.compareUnsigned(cell.value(), ByteBufferUtil.bytes(value))); + assertEquals(0, ByteBufferUtil.compareUnsigned(cell.buffer(), ByteBufferUtil.bytes(value))); assertEquals(timestamp, cell.timestamp()); } @@ -736,7 +736,7 @@ public class Util ByteBuffer pk = ByteBufferUtil.bytes("someKey"); ColumnMetadata def = metadata.getColumn(new ColumnIdentifier("myCol", false)); - Clustering c = Clustering.make(ByteBufferUtil.bytes("c1"), ByteBufferUtil.bytes(42)); + Clustering c = Clustering.make(ByteBufferUtil.bytes("c1"), ByteBufferUtil.bytes(42)); Row row = BTreeRow.singleCellRow(c, BufferCell.live(def, 0, ByteBufferUtil.EMPTY_BYTE_BUFFER)); PagingState.RowMark mark = PagingState.RowMark.create(metadata, row, protocolVersion); return new PagingState(pk, mark, 10, remainingInPartition); diff --git a/test/unit/org/apache/cassandra/cql3/CQL3TypeLiteralTest.java b/test/unit/org/apache/cassandra/cql3/CQL3TypeLiteralTest.java index 6728da2e26..8e6b76125d 100644 --- a/test/unit/org/apache/cassandra/cql3/CQL3TypeLiteralTest.java +++ b/test/unit/org/apache/cassandra/cql3/CQL3TypeLiteralTest.java @@ -24,7 +24,6 @@ import java.net.InetAddress; import java.net.UnknownHostException; import java.nio.ByteBuffer; import java.util.*; -import java.util.concurrent.ThreadLocalRandom; import java.util.regex.Pattern; import org.junit.Test; @@ -45,6 +44,7 @@ public class CQL3TypeLiteralTest { private static final Pattern QUOTE = Pattern.compile("'"); + private static final Random r = new Random(); /** * Container holding the expected CQL literal for a type and serialized value. * The CQL literal is generated independently from the code in {@link CQL3Type}. @@ -681,47 +681,47 @@ public class CQL3TypeLiteralTest static boolean randBool(double probability) { - return ThreadLocalRandom.current().nextDouble() < probability; + return r.nextDouble() < probability; } static long randLong() { - return ThreadLocalRandom.current().nextLong(); + return r.nextLong(); } static long randLong(long max) { - return ThreadLocalRandom.current().nextLong(max); + return r.nextLong() % max; } static int randInt() { - return ThreadLocalRandom.current().nextInt(); + return r.nextInt(); } static int randInt(int max) { - return ThreadLocalRandom.current().nextInt(max); + return r.nextInt(max); } static short randShort() { - return (short) ThreadLocalRandom.current().nextInt(); + return (short) r.nextInt(); } static byte randByte() { - return (byte) ThreadLocalRandom.current().nextInt(); + return (byte) r.nextInt(); } static double randDouble() { - return ThreadLocalRandom.current().nextDouble(); + return r.nextDouble(); } static float randFloat() { - return ThreadLocalRandom.current().nextFloat(); + return r.nextFloat(); } static String randString(boolean ascii) diff --git a/test/unit/org/apache/cassandra/cql3/ListsTest.java b/test/unit/org/apache/cassandra/cql3/ListsTest.java index 1155619442..92dcd96f35 100644 --- a/test/unit/org/apache/cassandra/cql3/ListsTest.java +++ b/test/unit/org/apache/cassandra/cql3/ListsTest.java @@ -143,7 +143,7 @@ public class ListsTest extends CQLTester DecoratedKey key = Murmur3Partitioner.instance.decorateKey(keyBuf); UpdateParameters parameters = new UpdateParameters(metaData, null, QueryOptions.DEFAULT, System.currentTimeMillis(), FBUtilities.nowInSeconds(), 1000, Collections.emptyMap()); - Clustering clustering = Clustering.make(ByteBufferUtil.bytes(1)); + Clustering clustering = Clustering.make(ByteBufferUtil.bytes(1)); parameters.newRow(clustering); prepender.execute(key, parameters); @@ -152,7 +152,7 @@ public class ListsTest extends CQLTester int idx = 0; UUID last = null; - for (Cell cell : row.cells()) + for (Cell cell : row.cells()) { UUID uuid = UUIDGen.getUUID(cell.path().get(0)); @@ -160,7 +160,7 @@ public class ListsTest extends CQLTester Assert.assertTrue(last.compareTo(uuid) < 0); last = uuid; - Assert.assertEquals(String.format("different values found: expected: '%d', found '%d'", ByteBufferUtil.toInt(terms.get(idx)), ByteBufferUtil.toInt(cell.value())), + Assert.assertEquals(String.format("different values found: expected: '%d', found '%d'", ByteBufferUtil.toInt(terms.get(idx)), ByteBufferUtil.toInt(cell.buffer())), terms.get(idx), cell.value()); idx++; } diff --git a/test/unit/org/apache/cassandra/cql3/TombstonesWithIndexedSSTableTest.java b/test/unit/org/apache/cassandra/cql3/TombstonesWithIndexedSSTableTest.java index 787c309b4e..f9ac8d16b0 100644 --- a/test/unit/org/apache/cassandra/cql3/TombstonesWithIndexedSSTableTest.java +++ b/test/unit/org/apache/cassandra/cql3/TombstonesWithIndexedSSTableTest.java @@ -82,10 +82,10 @@ public class TombstonesWithIndexedSSTableTest extends CQLTester try (FileDataInput reader = sstable.openIndexReader()) { RowIndexEntry.IndexInfoRetriever infoRetriever = indexEntry.openWithIndex(sstable.getIndexFile()); - ClusteringPrefix firstName = infoRetriever.columnsIndex(1).firstName; + ClusteringPrefix firstName = infoRetriever.columnsIndex(1).firstName; if (firstName.kind().isBoundary()) break deletionLoop; - indexedRow = Int32Type.instance.compose(firstName.get(0)); + indexedRow = Int32Type.instance.compose(firstName.bufferAt(0)); } } } diff --git a/test/unit/org/apache/cassandra/cql3/UDHelperTest.java b/test/unit/org/apache/cassandra/cql3/UDHelperTest.java index 288cd86f38..6e322e1738 100644 --- a/test/unit/org/apache/cassandra/cql3/UDHelperTest.java +++ b/test/unit/org/apache/cassandra/cql3/UDHelperTest.java @@ -46,6 +46,7 @@ import org.apache.cassandra.db.marshal.TimeUUIDType; import org.apache.cassandra.db.marshal.TimestampType; import org.apache.cassandra.db.marshal.UTF8Type; import org.apache.cassandra.db.marshal.UUIDType; +import org.apache.cassandra.db.marshal.ValueAccessor; import org.apache.cassandra.serializers.MarshalException; import org.apache.cassandra.serializers.TypeSerializer; import org.apache.cassandra.utils.ByteBufferUtil; @@ -74,9 +75,9 @@ public class UDHelperTest return UTF8Type.instance.getSerializer(); } - public int compareCustom(ByteBuffer o1, ByteBuffer o2) + public int compareCustom(VL left, ValueAccessor accessorL, VR right, ValueAccessor accessorR) { - return o1.compareTo(o2); + return ValueAccessor.compare(left, accessorL, right, accessorR); } } diff --git a/test/unit/org/apache/cassandra/cql3/restrictions/ClusteringColumnRestrictionsTest.java b/test/unit/org/apache/cassandra/cql3/restrictions/ClusteringColumnRestrictionsTest.java index 35adff3742..029729fe78 100644 --- a/test/unit/org/apache/cassandra/cql3/restrictions/ClusteringColumnRestrictionsTest.java +++ b/test/unit/org/apache/cassandra/cql3/restrictions/ClusteringColumnRestrictionsTest.java @@ -56,7 +56,7 @@ public class ClusteringColumnRestrictionsTest ClusteringColumnRestrictions restrictions = new ClusteringColumnRestrictions(tableMetadata); - SortedSet bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + SortedSet> bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); assertEquals(1, bounds.size()); assertEmptyStart(get(bounds, 0)); @@ -79,7 +79,7 @@ public class ClusteringColumnRestrictionsTest ClusteringColumnRestrictions restrictions = new ClusteringColumnRestrictions(tableMetadata); restrictions = restrictions.mergeWith(eq); - SortedSet bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + SortedSet> bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); assertEquals(1, bounds.size()); assertStartBound(get(bounds, 0), true, clustering_0); @@ -102,7 +102,7 @@ public class ClusteringColumnRestrictionsTest ClusteringColumnRestrictions restrictions = new ClusteringColumnRestrictions(tableMetadata); restrictions = restrictions.mergeWith(eq); - SortedSet bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + SortedSet> bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); assertEquals(1, bounds.size()); assertStartBound(get(bounds, 0), true, clustering_0); @@ -128,7 +128,7 @@ public class ClusteringColumnRestrictionsTest ClusteringColumnRestrictions restrictions = new ClusteringColumnRestrictions(tableMetadata); restrictions = restrictions.mergeWith(in); - SortedSet bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + SortedSet> bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); assertEquals(3, bounds.size()); assertStartBound(get(bounds, 0), true, value1); assertStartBound(get(bounds, 1), true, value2); @@ -156,7 +156,7 @@ public class ClusteringColumnRestrictionsTest ClusteringColumnRestrictions restrictions = new ClusteringColumnRestrictions(tableMetadata); restrictions = restrictions.mergeWith(slice); - SortedSet bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + SortedSet> bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); assertEquals(1, bounds.size()); assertStartBound(get(bounds, 0), false, value1); @@ -242,7 +242,7 @@ public class ClusteringColumnRestrictionsTest ClusteringColumnRestrictions restrictions = new ClusteringColumnRestrictions(tableMetadata); restrictions = restrictions.mergeWith(slice); - SortedSet bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + SortedSet> bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); assertEquals(1, bounds.size()); assertEmptyStart(get(bounds, 0)); @@ -329,7 +329,7 @@ public class ClusteringColumnRestrictionsTest ClusteringColumnRestrictions restrictions = new ClusteringColumnRestrictions(tableMetadata); restrictions = restrictions.mergeWith(eq).mergeWith(in); - SortedSet bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + SortedSet> bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); assertEquals(3, bounds.size()); assertStartBound(get(bounds, 0), true, value1, value1); assertStartBound(get(bounds, 1), true, value1, value2); @@ -360,7 +360,7 @@ public class ClusteringColumnRestrictionsTest ClusteringColumnRestrictions restrictions = new ClusteringColumnRestrictions(tableMetadata); restrictions = restrictions.mergeWith(eq).mergeWith(slice); - SortedSet bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + SortedSet> bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); assertEquals(1, bounds.size()); assertStartBound(get(bounds, 0), false, value3, value1); @@ -445,7 +445,7 @@ public class ClusteringColumnRestrictionsTest ClusteringColumnRestrictions restrictions = new ClusteringColumnRestrictions(tableMetadata); restrictions = restrictions.mergeWith(eq); - SortedSet bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + SortedSet> bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); assertEquals(1, bounds.size()); assertStartBound(get(bounds, 0), true, value1, value2); @@ -469,7 +469,7 @@ public class ClusteringColumnRestrictionsTest ClusteringColumnRestrictions restrictions = new ClusteringColumnRestrictions(tableMetadata); restrictions = restrictions.mergeWith(in); - SortedSet bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + SortedSet> bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); assertEquals(2, bounds.size()); assertStartBound(get(bounds, 0), true, value1, value2); assertStartBound(get(bounds, 1), true, value2, value3); @@ -496,7 +496,7 @@ public class ClusteringColumnRestrictionsTest ClusteringColumnRestrictions restrictions = new ClusteringColumnRestrictions(tableMetadata); restrictions = restrictions.mergeWith(slice); - SortedSet bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + SortedSet> bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); assertEquals(1, bounds.size()); assertStartBound(get(bounds, 0), false, value1); @@ -583,7 +583,7 @@ public class ClusteringColumnRestrictionsTest ClusteringColumnRestrictions restrictions = new ClusteringColumnRestrictions(tableMetadata); restrictions = restrictions.mergeWith(slice); - SortedSet bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + SortedSet> bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); assertEquals(1, bounds.size()); assertEmptyStart(get(bounds, 0)); @@ -670,7 +670,7 @@ public class ClusteringColumnRestrictionsTest ClusteringColumnRestrictions restrictions = new ClusteringColumnRestrictions(tableMetadata); restrictions = restrictions.mergeWith(slice); - SortedSet bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + SortedSet> bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); assertEquals(1, bounds.size()); assertStartBound(get(bounds, 0), false, value1, value2); @@ -762,7 +762,7 @@ public class ClusteringColumnRestrictionsTest ClusteringColumnRestrictions restrictions = new ClusteringColumnRestrictions(tableMetadata); restrictions = restrictions.mergeWith(slice); - SortedSet bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + SortedSet> bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); assertEquals(1, bounds.size()); assertEmptyStart(get(bounds, 0)); @@ -856,7 +856,7 @@ public class ClusteringColumnRestrictionsTest ClusteringColumnRestrictions restrictions = new ClusteringColumnRestrictions(tableMetadata); restrictions = restrictions.mergeWith(slice); - SortedSet bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + SortedSet> bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); assertEquals(2, bounds.size()); assertEmptyStart(get(bounds, 0)); assertStartBound(get(bounds, 1), false, value1, value2); @@ -979,7 +979,7 @@ public class ClusteringColumnRestrictionsTest ClusteringColumnRestrictions restrictions = new ClusteringColumnRestrictions(tableMetadata); restrictions = restrictions.mergeWith(slice); - SortedSet bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + SortedSet> bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); assertEquals(2, bounds.size()); assertStartBound(get(bounds, 0), true, value1); assertStartBound(get(bounds, 1), false, value1); @@ -1088,7 +1088,7 @@ public class ClusteringColumnRestrictionsTest ClusteringColumnRestrictions restrictions = new ClusteringColumnRestrictions(tableMetadata); restrictions = restrictions.mergeWith(slice); - SortedSet bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + SortedSet> bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); assertEquals(2, bounds.size()); assertStartBound(get(bounds, 0), true, value1, value2); assertStartBound(get(bounds, 1), false, value1, value2); @@ -1248,7 +1248,7 @@ public class ClusteringColumnRestrictionsTest ClusteringColumnRestrictions restrictions = new ClusteringColumnRestrictions(tableMetadata); restrictions = restrictions.mergeWith(slice); - SortedSet bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + SortedSet> bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); assertEquals(4, bounds.size()); assertStartBound(get(bounds, 0), true, value1); assertStartBound(get(bounds, 1), true, value1, value2, value3); @@ -1422,7 +1422,7 @@ public class ClusteringColumnRestrictionsTest ClusteringColumnRestrictions restrictions = new ClusteringColumnRestrictions(tableMetadata); restrictions = restrictions.mergeWith(singleEq).mergeWith(multiEq); - SortedSet bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + SortedSet> bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); assertEquals(1, bounds.size()); assertStartBound(get(bounds, 0), true, value1, value2, value3); @@ -1495,7 +1495,7 @@ public class ClusteringColumnRestrictionsTest ClusteringColumnRestrictions restrictions = new ClusteringColumnRestrictions(tableMetadata); restrictions = restrictions.mergeWith(singleEq).mergeWith(multiIN); - SortedSet bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + SortedSet> bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); assertEquals(2, bounds.size()); assertStartBound(get(bounds, 0), true, value1, value2, value3); assertStartBound(get(bounds, 1), true, value1, value4, value5); @@ -1558,7 +1558,7 @@ public class ClusteringColumnRestrictionsTest ClusteringColumnRestrictions restrictions = new ClusteringColumnRestrictions(tableMetadata); restrictions = restrictions.mergeWith(singleEq).mergeWith(multiSlice); - SortedSet bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + SortedSet> bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); assertEquals(1, bounds.size()); assertStartBound(get(bounds, 0), false, value1, value2, value3); @@ -1616,7 +1616,7 @@ public class ClusteringColumnRestrictionsTest ClusteringColumnRestrictions restrictions = new ClusteringColumnRestrictions(tableMetadata); restrictions = restrictions.mergeWith(multiEq).mergeWith(singleSlice); - SortedSet bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + SortedSet> bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); assertEquals(1, bounds.size()); assertStartBound(get(bounds, 0), false, value1, value2, value3); @@ -1642,7 +1642,7 @@ public class ClusteringColumnRestrictionsTest ClusteringColumnRestrictions restrictions = new ClusteringColumnRestrictions(tableMetadata); restrictions = restrictions.mergeWith(multiEq).mergeWith(multiSlice); - SortedSet bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); + SortedSet> bounds = restrictions.boundsAsClustering(Bound.START, QueryOptions.DEFAULT); assertEquals(1, bounds.size()); assertStartBound(get(bounds, 0), false, value1, value2, value3, value4); @@ -1686,9 +1686,9 @@ public class ClusteringColumnRestrictionsTest * * @param bound the bound to check */ - private static void assertEmptyStart(ClusteringBound bound) + private static void assertEmptyStart(ClusteringBound bound) { - assertEquals(ClusteringBound.BOTTOM, bound); + assertTrue(bound.isBottom()); } /** @@ -1696,9 +1696,9 @@ public class ClusteringColumnRestrictionsTest * * @param bound the bound to check */ - private static void assertEmptyEnd(ClusteringBound bound) + private static void assertEmptyEnd(ClusteringBound bound) { - assertEquals(ClusteringBound.TOP, bound); + assertTrue(bound.isTop()); } /** @@ -1708,7 +1708,7 @@ public class ClusteringColumnRestrictionsTest * @param isInclusive if the bound is expected to be inclusive * @param elements the expected elements of the clustering */ - private static void assertStartBound(ClusteringBound bound, boolean isInclusive, ByteBuffer... elements) + private static void assertStartBound(ClusteringBound bound, boolean isInclusive, ByteBuffer... elements) { assertBound(bound, true, isInclusive, elements); } @@ -1720,12 +1720,12 @@ public class ClusteringColumnRestrictionsTest * @param isInclusive if the bound is expected to be inclusive * @param elements the expected elements of the clustering */ - private static void assertEndBound(ClusteringBound bound, boolean isInclusive, ByteBuffer... elements) + private static void assertEndBound(ClusteringBound bound, boolean isInclusive, ByteBuffer... elements) { assertBound(bound, false, isInclusive, elements); } - private static void assertBound(ClusteringBound bound, boolean isStart, boolean isInclusive, ByteBuffer... elements) + private static void assertBound(ClusteringBound bound, boolean isStart, boolean isInclusive, ByteBuffer... elements) { assertEquals("the bound size is not the expected one:", elements.length, bound.size()); assertEquals("the bound should be a " + (isStart ? "start" : "end") + " but is a " + (bound.isStart() ? "start" : "end"), isStart, bound.isStart()); @@ -1736,8 +1736,8 @@ public class ClusteringColumnRestrictionsTest assertTrue(String.format("the element %s of the bound is not the expected one: expected %s but was %s", i, ByteBufferUtil.toInt(element), - ByteBufferUtil.toInt(bound.get(i))), - element.equals(bound.get(i))); + ByteBufferUtil.toInt(bound.bufferAt(i))), + bound.bufferAt(i).equals(element)); } } diff --git a/test/unit/org/apache/cassandra/cql3/validation/entities/SecondaryIndexTest.java b/test/unit/org/apache/cassandra/cql3/validation/entities/SecondaryIndexTest.java index 947e8b5e29..5ed1047d2a 100644 --- a/test/unit/org/apache/cassandra/cql3/validation/entities/SecondaryIndexTest.java +++ b/test/unit/org/apache/cassandra/cql3/validation/entities/SecondaryIndexTest.java @@ -1012,7 +1012,7 @@ public class SecondaryIndexTest extends CQLTester validateCell(oldRow.getCell(v1), v1, ByteBufferUtil.bytes(2), 2); newRow = index.rowsUpdated.get(0).right; assertEquals(1, newRow.columnCount()); - Cell newCell = newRow.getCell(v1); + Cell newCell = newRow.getCell(v1); assertTrue(newCell.isTombstone()); assertEquals(3, newCell.timestamp()); index.reset(); @@ -1599,10 +1599,10 @@ public class SecondaryIndexTest extends CQLTester ClientState.forInternalCalls()); } - private void validateCell(Cell cell, ColumnMetadata def, ByteBuffer val, long timestamp) + private void validateCell(Cell cell, ColumnMetadata def, ByteBuffer val, long timestamp) { assertNotNull(cell); - assertEquals(0, def.type.compare(cell.value(), val)); + assertEquals(0, def.type.compare(cell.buffer(), val)); assertEquals(timestamp, cell.timestamp()); } @@ -1610,7 +1610,7 @@ public class SecondaryIndexTest extends CQLTester { ColumnMetadata col = cfm.getColumn(new ColumnIdentifier(name, true)); AbstractType type = col.type; - assertEquals(expected, type.compose(row.getCell(col).value())); + assertEquals(expected, type.compose(row.getCell(col).buffer())); } /** diff --git a/test/unit/org/apache/cassandra/cql3/validation/entities/VirtualTableTest.java b/test/unit/org/apache/cassandra/cql3/validation/entities/VirtualTableTest.java index a503a60577..cd67cc9c86 100644 --- a/test/unit/org/apache/cassandra/cql3/validation/entities/VirtualTableTest.java +++ b/test/unit/org/apache/cassandra/cql3/validation/entities/VirtualTableTest.java @@ -81,7 +81,7 @@ public class VirtualTableTest extends CQLTester String key = (String) metadata().partitionKeyType.compose(update.partitionKey().getKey()); update.forEach(row -> { - Integer value = Int32Type.instance.compose(row.getCell(valueColumn).value()); + Integer value = Int32Type.instance.compose(row.getCell(valueColumn).buffer()); backingMap.put(key, value); }); } diff --git a/test/unit/org/apache/cassandra/db/CellTest.java b/test/unit/org/apache/cassandra/db/CellTest.java index 14d05c6c69..d6d03ffd00 100644 --- a/test/unit/org/apache/cassandra/db/CellTest.java +++ b/test/unit/org/apache/cassandra/db/CellTest.java @@ -91,8 +91,8 @@ public class CellTest // don't test equality for both sides native, as this is based on CellName resolution if (lhs && rhs) continue; - Cell a = expiring(cfm, "val", "a", 1, 1); - Cell b = regular(cfm, "val", "a", 1); + Cell a = expiring(cfm, "val", "a", 1, 1); + Cell b = regular(cfm, "val", "a", 1); Assert.assertNotSame(a, b); Assert.assertNotSame(b, a); @@ -103,7 +103,7 @@ public class CellTest } } - private void assertValid(Cell cell) + private void assertValid(Cell cell) { try { @@ -115,7 +115,7 @@ public class CellTest } } - private void assertInvalid(Cell cell) + private void assertInvalid(Cell cell) { try { @@ -275,8 +275,8 @@ public class CellTest public void testNonPurgableTombstone() { int now = 100; - Cell cell = deleted(cfm, "val", now, now); - Cell purged = cell.purge(new SimplePurger(now - 1), now + 1); + Cell cell = deleted(cfm, "val", now, now); + Cell purged = cell.purge(new SimplePurger(now - 1), now + 1); Assert.assertEquals(cell, purged); } @@ -284,8 +284,8 @@ public class CellTest public void testPurgeableTombstone() { int now = 100; - Cell cell = deleted(cfm, "val", now, now); - Cell purged = cell.purge(new SimplePurger(now + 1), now + 1); + Cell cell = deleted(cfm, "val", now, now); + Cell purged = cell.purge(new SimplePurger(now + 1), now + 1); Assert.assertNull(purged); } @@ -293,8 +293,8 @@ public class CellTest public void testLiveExpiringCell() { int now = 100; - Cell cell = expiring(cfm, "val", "a", now, now + 10); - Cell purged = cell.purge(new SimplePurger(now), now + 1); + Cell cell = expiring(cfm, "val", "a", now, now + 10); + Cell purged = cell.purge(new SimplePurger(now), now + 1); Assert.assertEquals(cell, purged); } @@ -306,8 +306,8 @@ public class CellTest public void testExpiredTombstoneConversion() { int now = 100; - Cell cell = expiring(cfm, "val", "a", now, 10, now + 10); - Cell purged = cell.purge(new SimplePurger(now), now + 11); + Cell cell = expiring(cfm, "val", "a", now, 10, now + 10); + Cell purged = cell.purge(new SimplePurger(now), now + 11); Assert.assertEquals(deleted(cfm, "val", now, now), purged); } @@ -319,8 +319,8 @@ public class CellTest public void testPurgeableExpiringCell() { int now = 100; - Cell cell = expiring(cfm, "val", "a", now, 10, now + 10); - Cell purged = cell.purge(new SimplePurger(now + 1), now + 11); + Cell cell = expiring(cfm, "val", "a", now, 10, now + 10); + Cell purged = cell.purge(new SimplePurger(now + 1), now + 11); Assert.assertNull(purged); } @@ -357,16 +357,16 @@ public class CellTest long ts1 = now1*1000000L; - Cell r1m1 = BufferCell.live(m, ts1, bb(1), CellPath.create(bb(1))); - Cell r1m2 = BufferCell.live(m, ts1, bb(2), CellPath.create(bb(2))); - List cells1 = Lists.newArrayList(r1m1, r1m2); + Cell r1m1 = BufferCell.live(m, ts1, bb(1), CellPath.create(bb(1))); + Cell r1m2 = BufferCell.live(m, ts1, bb(2), CellPath.create(bb(2))); + List> cells1 = Lists.newArrayList(r1m1, r1m2); int now2 = now1 + 1; long ts2 = now2*1000000L; - Cell r2m2 = BufferCell.live(m, ts2, bb(1), CellPath.create(bb(2))); - Cell r2m3 = BufferCell.live(m, ts2, bb(2), CellPath.create(bb(3))); - Cell r2m4 = BufferCell.live(m, ts2, bb(3), CellPath.create(bb(4))); - List cells2 = Lists.newArrayList(r2m2, r2m3, r2m4); + Cell r2m2 = BufferCell.live(m, ts2, bb(1), CellPath.create(bb(2))); + Cell r2m3 = BufferCell.live(m, ts2, bb(2), CellPath.create(bb(3))); + Cell r2m4 = BufferCell.live(m, ts2, bb(3), CellPath.create(bb(4))); + List> cells2 = Lists.newArrayList(r2m2, r2m3, r2m4); RowBuilder builder = new RowBuilder(); Cells.reconcileComplex(m, cells1.iterator(), cells2.iterator(), DeletionTime.LIVE, builder); @@ -383,32 +383,32 @@ public class CellTest t2 = t1; if (et2 == null) et2 = et1; - Cell c1 = expiring(cfm, n1, v1, t1, et1); - Cell c2 = expiring(cfm, n2, v2, t2, et2); + Cell c1 = expiring(cfm, n1, v1, t1, et1); + Cell c2 = expiring(cfm, n2, v2, t2, et2); if (Cells.reconcile(c1, c2) == c1) return Cells.reconcile(c2, c1) == c1 ? -1 : 0; return Cells.reconcile(c2, c1) == c2 ? 1 : 0; } - private Cell regular(TableMetadata cfm, String columnName, String value, long timestamp) + private Cell regular(TableMetadata cfm, String columnName, String value, long timestamp) { ColumnMetadata cdef = cfm.getColumn(ByteBufferUtil.bytes(columnName)); return BufferCell.live(cdef, timestamp, ByteBufferUtil.bytes(value)); } - private Cell expiring(TableMetadata cfm, String columnName, String value, long timestamp, int localExpirationTime) + private Cell expiring(TableMetadata cfm, String columnName, String value, long timestamp, int localExpirationTime) { return expiring(cfm, columnName, value, timestamp, 1, localExpirationTime); } - private Cell expiring(TableMetadata cfm, String columnName, String value, long timestamp, int ttl, int localExpirationTime) + private Cell expiring(TableMetadata cfm, String columnName, String value, long timestamp, int ttl, int localExpirationTime) { ColumnMetadata cdef = cfm.getColumn(ByteBufferUtil.bytes(columnName)); return new BufferCell(cdef, timestamp, ttl, localExpirationTime, ByteBufferUtil.bytes(value), null); } - private Cell deleted(TableMetadata cfm, String columnName, int localDeletionTime, long timestamp) + private Cell deleted(TableMetadata cfm, String columnName, int localDeletionTime, long timestamp) { ColumnMetadata cdef = cfm.getColumn(ByteBufferUtil.bytes(columnName)); return BufferCell.tombstone(cdef, timestamp, localDeletionTime); diff --git a/test/unit/org/apache/cassandra/db/ClusteringBoundTest.java b/test/unit/org/apache/cassandra/db/ClusteringBoundTest.java new file mode 100644 index 0000000000..20fcc2086c --- /dev/null +++ b/test/unit/org/apache/cassandra/db/ClusteringBoundTest.java @@ -0,0 +1,43 @@ +/* + * 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.db; + +import org.junit.Assert; +import org.junit.Test; + +public class ClusteringBoundTest +{ + @Test + public void arrayTopAndBottom() + { + Assert.assertTrue(ArrayClusteringBound.BOTTOM.isBottom()); + Assert.assertFalse(ArrayClusteringBound.BOTTOM.isTop()); + Assert.assertTrue(ArrayClusteringBound.TOP.isTop()); + Assert.assertFalse(ArrayClusteringBound.TOP.isBottom()); + } + + @Test + public void bufferTopAndBottom() + { + Assert.assertTrue(BufferClusteringBound.BOTTOM.isBottom()); + Assert.assertFalse(BufferClusteringBound.BOTTOM.isTop()); + Assert.assertTrue(BufferClusteringBound.TOP.isTop()); + Assert.assertFalse(BufferClusteringBound.TOP.isBottom()); + } +} diff --git a/test/unit/org/apache/cassandra/db/ColumnFamilyStoreTest.java b/test/unit/org/apache/cassandra/db/ColumnFamilyStoreTest.java index 54c2b35961..442072aa92 100644 --- a/test/unit/org/apache/cassandra/db/ColumnFamilyStoreTest.java +++ b/test/unit/org/apache/cassandra/db/ColumnFamilyStoreTest.java @@ -146,7 +146,7 @@ public class ColumnFamilyStoreTest public void runMayThrow() throws IOException { Row toCheck = Util.getOnlyRowUnfiltered(Util.cmd(cfs, "key1").build()); - Iterator iter = toCheck.cells().iterator(); + Iterator> iter = toCheck.cells().iterator(); assert(Iterators.size(iter) == 0); } }; @@ -417,7 +417,7 @@ public class ColumnFamilyStoreTest { for (Row r : partition) { - if (r.getCell(col).value().equals(val)) + if (r.getCell(col).buffer().equals(val)) ++found; } } diff --git a/test/unit/org/apache/cassandra/db/CounterCacheTest.java b/test/unit/org/apache/cassandra/db/CounterCacheTest.java index a913133254..62be22b110 100644 --- a/test/unit/org/apache/cassandra/db/CounterCacheTest.java +++ b/test/unit/org/apache/cassandra/db/CounterCacheTest.java @@ -75,8 +75,8 @@ public class CounterCacheTest cfs.truncateBlocking(); CacheService.instance.invalidateCounterCache(); - Clustering c1 = CBuilder.create(cfs.metadata().comparator).add(ByteBufferUtil.bytes(1)).build(); - Clustering c2 = CBuilder.create(cfs.metadata().comparator).add(ByteBufferUtil.bytes(2)).build(); + Clustering c1 = CBuilder.create(cfs.metadata().comparator).add(ByteBufferUtil.bytes(1)).build(); + Clustering c2 = CBuilder.create(cfs.metadata().comparator).add(ByteBufferUtil.bytes(2)).build(); ColumnMetadata cd = cfs.metadata().getColumn(ByteBufferUtil.bytes("c")); assertEquals(0, CacheService.instance.counterCache.size()); @@ -103,8 +103,8 @@ public class CounterCacheTest cfs.truncateBlocking(); CacheService.instance.invalidateCounterCache(); - Clustering c1 = CBuilder.create(cfs.metadata().comparator).add(ByteBufferUtil.bytes(1)).build(); - Clustering c2 = CBuilder.create(cfs.metadata().comparator).add(ByteBufferUtil.bytes(2)).build(); + Clustering c1 = CBuilder.create(cfs.metadata().comparator).add(ByteBufferUtil.bytes(1)).build(); + Clustering c2 = CBuilder.create(cfs.metadata().comparator).add(ByteBufferUtil.bytes(2)).build(); ColumnMetadata cd = cfs.metadata().getColumn(ByteBufferUtil.bytes("c")); assertEquals(0, CacheService.instance.counterCache.size()); @@ -164,8 +164,8 @@ public class CounterCacheTest CacheService.instance.counterCache.loadSaved(); assertEquals(4, CacheService.instance.counterCache.size()); - Clustering c1 = CBuilder.create(cfs.metadata().comparator).add(ByteBufferUtil.bytes(1)).build(); - Clustering c2 = CBuilder.create(cfs.metadata().comparator).add(ByteBufferUtil.bytes(2)).build(); + Clustering c1 = CBuilder.create(cfs.metadata().comparator).add(ByteBufferUtil.bytes(1)).build(); + Clustering c2 = CBuilder.create(cfs.metadata().comparator).add(ByteBufferUtil.bytes(2)).build(); ColumnMetadata cd = cfs.metadata().getColumn(ByteBufferUtil.bytes("c")); assertEquals(1L, cfs.getCachedCounter(bytes(1), c1, cd, null).count); diff --git a/test/unit/org/apache/cassandra/db/CounterCellTest.java b/test/unit/org/apache/cassandra/db/CounterCellTest.java index 4ce9802fe3..4acdc7620a 100644 --- a/test/unit/org/apache/cassandra/db/CounterCellTest.java +++ b/test/unit/org/apache/cassandra/db/CounterCellTest.java @@ -26,6 +26,7 @@ import org.junit.BeforeClass; import org.junit.Test; import org.apache.cassandra.SchemaLoader; +import org.apache.cassandra.db.marshal.ByteBufferAccessor; import org.apache.cassandra.schema.ColumnMetadata; import org.apache.cassandra.db.rows.BTreeRow; import org.apache.cassandra.db.rows.BufferCell; @@ -86,38 +87,38 @@ public class CounterCellTest ColumnFamilyStore cfs = Keyspace.open(KEYSPACE1).getColumnFamilyStore(COUNTER1); long delta = 3L; - Cell cell = createLegacyCounterCell(cfs, ByteBufferUtil.bytes("val"), delta, 1); + Cell cell = createLegacyCounterCell(cfs, ByteBufferUtil.bytes("val"), delta, 1); - assertEquals(delta, CounterContext.instance().total(cell.value())); - assertEquals(1, cell.value().getShort(0)); - assertEquals(0, cell.value().getShort(2)); - Assert.assertTrue(CounterId.wrap(cell.value(), 4).isLocalId()); - assertEquals(1L, cell.value().getLong(4 + idLength)); - assertEquals(delta, cell.value().getLong(4 + idLength + clockLength)); + assertEquals(delta, CounterContext.instance().total(cell)); + assertEquals(1, cell.buffer().getShort(0)); + assertEquals(0, cell.buffer().getShort(2)); + Assert.assertTrue(CounterId.wrap(cell.buffer(), 4).isLocalId()); + assertEquals(1L, cell.buffer().getLong(4 + idLength)); + assertEquals(delta, cell.buffer().getLong(4 + idLength + clockLength)); } - private Cell createLegacyCounterCell(ColumnFamilyStore cfs, ByteBuffer colName, long count, long ts) + private Cell createLegacyCounterCell(ColumnFamilyStore cfs, ByteBuffer colName, long count, long ts) { ColumnMetadata cDef = cfs.metadata().getColumn(colName); ByteBuffer val = CounterContext.instance().createLocal(count); return BufferCell.live(cDef, ts, val); } - private Cell createCounterCell(ColumnFamilyStore cfs, ByteBuffer colName, CounterId id, long count, long ts) + private Cell createCounterCell(ColumnFamilyStore cfs, ByteBuffer colName, CounterId id, long count, long ts) { ColumnMetadata cDef = cfs.metadata().getColumn(colName); ByteBuffer val = CounterContext.instance().createGlobal(id, ts, count); return BufferCell.live(cDef, ts, val); } - private Cell createCounterCellFromContext(ColumnFamilyStore cfs, ByteBuffer colName, ContextState context, long ts) + private Cell createCounterCellFromContext(ColumnFamilyStore cfs, ByteBuffer colName, ContextState context, long ts) { ColumnMetadata cDef = cfs.metadata().getColumn(colName); return BufferCell.live(cDef, ts, context.context); } - private Cell createDeleted(ColumnFamilyStore cfs, ByteBuffer colName, long ts, int localDeletionTime) + private Cell createDeleted(ColumnFamilyStore cfs, ByteBuffer colName, long ts, int localDeletionTime) { ColumnMetadata cDef = cfs.metadata().getColumn(colName); return BufferCell.tombstone(cDef, ts, localDeletionTime); @@ -129,8 +130,8 @@ public class CounterCellTest ColumnFamilyStore cfs = Keyspace.open(KEYSPACE1).getColumnFamilyStore(COUNTER1); ByteBuffer col = ByteBufferUtil.bytes("val"); - Cell left; - Cell right; + Cell left; + Cell right; // both deleted, diff deletion time, same ts left = createDeleted(cfs, col, 2, 5); @@ -159,26 +160,26 @@ public class CounterCellTest // live + live left = createLegacyCounterCell(cfs, col, 1, 2); right = createLegacyCounterCell(cfs, col, 3, 5); - Cell reconciled = Cells.reconcile(left, right); - assertEquals(CounterContext.instance().total(reconciled.value()), 4); + Cell reconciled = Cells.reconcile(left, right); + assertEquals(CounterContext.instance().total(reconciled), 4); assertEquals(reconciled.timestamp(), 5L); // Add, don't change TS - Cell addTen = createLegacyCounterCell(cfs, col, 10, 4); + Cell addTen = createLegacyCounterCell(cfs, col, 10, 4); reconciled = Cells.reconcile(reconciled, addTen); - assertEquals(CounterContext.instance().total(reconciled.value()), 14); + assertEquals(CounterContext.instance().total(reconciled), 14); assertEquals(reconciled.timestamp(), 5L); // Add w/new TS - Cell addThree = createLegacyCounterCell(cfs, col, 3, 7); + Cell addThree = createLegacyCounterCell(cfs, col, 3, 7); reconciled = Cells.reconcile(reconciled, addThree); - assertEquals(CounterContext.instance().total(reconciled.value()), 17); + assertEquals(CounterContext.instance().total(reconciled), 17); assertEquals(reconciled.timestamp(), 7L); // Confirm no deletion time assert reconciled.localDeletionTime() == Integer.MAX_VALUE; - Cell deleted = createDeleted(cfs, col, 8, 8); + Cell deleted = createDeleted(cfs, col, 8, 8); reconciled = Cells.reconcile(reconciled, deleted); assert reconciled.localDeletionTime() == 8; } @@ -189,24 +190,24 @@ public class CounterCellTest ColumnFamilyStore cfs = Keyspace.open(KEYSPACE1).getColumnFamilyStore(COUNTER1); ByteBuffer col = ByteBufferUtil.bytes("val"); - Cell leftCell; - Cell rightCell; + Cell leftCell; + Cell rightCell; // Equal count leftCell = createLegacyCounterCell(cfs, col, 2, 2); rightCell = createLegacyCounterCell(cfs, col, 2, 1); - assertEquals(CounterContext.Relationship.EQUAL, CounterContext.instance().diff(leftCell.value(), rightCell.value())); + assertEquals(CounterContext.Relationship.EQUAL, CounterContext.instance().diff(leftCell.buffer(), rightCell.buffer())); // Non-equal count leftCell = createLegacyCounterCell(cfs, col, 1, 2); rightCell = createLegacyCounterCell(cfs, col, 2, 1); - assertEquals(CounterContext.Relationship.DISJOINT, CounterContext.instance().diff(leftCell.value(), rightCell.value())); + assertEquals(CounterContext.Relationship.DISJOINT, CounterContext.instance().diff(leftCell.buffer(), rightCell.buffer())); // timestamp CounterId id = CounterId.generate(); leftCell = createCounterCell(cfs, col, id, 2, 2); rightCell = createCounterCell(cfs, col, id, 2, 1); - assertEquals(CounterContext.Relationship.GREATER_THAN, CounterContext.instance().diff(leftCell.value(), rightCell.value())); + assertEquals(CounterContext.Relationship.GREATER_THAN, CounterContext.instance().diff(leftCell.buffer(), rightCell.buffer())); ContextState leftContext; ContextState rightContext; @@ -220,7 +221,7 @@ public class CounterCellTest leftCell = createCounterCellFromContext(cfs, col, leftContext, 1); rightCell = createCounterCellFromContext(cfs, col, rightContext, 1); - assertEquals(CounterContext.Relationship.EQUAL, CounterContext.instance().diff(leftCell.value(), rightCell.value())); + assertEquals(CounterContext.Relationship.EQUAL, CounterContext.instance().diff(leftCell.buffer(), rightCell.buffer())); // greater than: left has superset of nodes (counts equal) leftContext = ContextState.allocate(0, 0, 4); @@ -236,8 +237,8 @@ public class CounterCellTest leftCell = createCounterCellFromContext(cfs, col, leftContext, 1); rightCell = createCounterCellFromContext(cfs, col, rightContext, 1); - assertEquals(CounterContext.Relationship.GREATER_THAN, CounterContext.instance().diff(leftCell.value(), rightCell.value())); - assertEquals(CounterContext.Relationship.LESS_THAN, CounterContext.instance().diff(rightCell.value(), leftCell.value())); + assertEquals(CounterContext.Relationship.GREATER_THAN, CounterContext.instance().diff(leftCell.buffer(), rightCell.buffer())); + assertEquals(CounterContext.Relationship.LESS_THAN, CounterContext.instance().diff(rightCell.buffer(), leftCell.buffer())); // disjoint: right and left have disjoint node sets leftContext = ContextState.allocate(0, 0, 3); @@ -252,8 +253,8 @@ public class CounterCellTest leftCell = createCounterCellFromContext(cfs, col, leftContext, 1); rightCell = createCounterCellFromContext(cfs, col, rightContext, 1); - assertEquals(CounterContext.Relationship.DISJOINT, CounterContext.instance().diff(leftCell.value(), rightCell.value())); - assertEquals(CounterContext.Relationship.DISJOINT, CounterContext.instance().diff(rightCell.value(), leftCell.value())); + assertEquals(CounterContext.Relationship.DISJOINT, CounterContext.instance().diff(leftCell.buffer(), rightCell.buffer())); + assertEquals(CounterContext.Relationship.DISJOINT, CounterContext.instance().diff(rightCell.buffer(), leftCell.buffer())); } @Test @@ -271,10 +272,10 @@ public class CounterCellTest state.writeRemote(CounterId.fromInt(3), 4L, 4L); state.writeLocal(CounterId.fromInt(4), 4L, 4L); - Cell original = createCounterCellFromContext(cfs, col, state, 5); + Cell original = createCounterCellFromContext(cfs, col, state, 5); ColumnMetadata cDef = cfs.metadata().getColumn(col); - Cell cleared = BufferCell.live(cDef, 5, CounterContext.instance().clearAllLocal(state.context)); + Cell cleared = BufferCell.live(cDef, 5, CounterContext.instance().clearAllLocal(state.context, ByteBufferAccessor.instance)); original.digest(digest1); cleared.digest(digest2); diff --git a/test/unit/org/apache/cassandra/db/CounterMutationTest.java b/test/unit/org/apache/cassandra/db/CounterMutationTest.java index 9be0960f7a..5f25c72185 100644 --- a/test/unit/org/apache/cassandra/db/CounterMutationTest.java +++ b/test/unit/org/apache/cassandra/db/CounterMutationTest.java @@ -72,7 +72,7 @@ public class CounterMutationTest new CounterMutation(m, ConsistencyLevel.ONE).apply(); Row row = Util.getOnlyRow(Util.cmd(cfs).includeRow("cc").columns("val").build()); - assertEquals(expected, CounterContext.instance().total(row.getCell(cDef).value())); + assertEquals(expected, CounterContext.instance().total(row.getCell(cDef))); } @Test @@ -104,8 +104,8 @@ public class CounterMutationTest new CounterMutation(m, ConsistencyLevel.ONE).apply(); Row row = Util.getOnlyRow(Util.cmd(cfs).includeRow("cc").columns("val", "val2").build()); - assertEquals(expectedOne, CounterContext.instance().total(row.getCell(cDefOne).value())); - assertEquals(expectedTwo, CounterContext.instance().total(row.getCell(cDefTwo).value())); + assertEquals(expectedOne, CounterContext.instance().total(row.getCell(cDefOne))); + assertEquals(expectedTwo, CounterContext.instance().total(row.getCell(cDefTwo))); } @Test @@ -137,14 +137,14 @@ public class CounterMutationTest ColumnMetadata c2cfs1 = cfsOne.metadata().getColumn(ByteBufferUtil.bytes("val2")); Row row = Util.getOnlyRow(Util.cmd(cfsOne).includeRow("cc").columns("val", "val2").build()); - assertEquals(1L, CounterContext.instance().total(row.getCell(c1cfs1).value())); - assertEquals(-1L, CounterContext.instance().total(row.getCell(c2cfs1).value())); + assertEquals(1L, CounterContext.instance().total(row.getCell(c1cfs1))); + assertEquals(-1L, CounterContext.instance().total(row.getCell(c2cfs1))); ColumnMetadata c1cfs2 = cfsTwo.metadata().getColumn(ByteBufferUtil.bytes("val")); ColumnMetadata c2cfs2 = cfsTwo.metadata().getColumn(ByteBufferUtil.bytes("val2")); row = Util.getOnlyRow(Util.cmd(cfsTwo).includeRow("cc").columns("val", "val2").build()); - assertEquals(2L, CounterContext.instance().total(row.getCell(c1cfs2).value())); - assertEquals(-2L, CounterContext.instance().total(row.getCell(c2cfs2).value())); + assertEquals(2L, CounterContext.instance().total(row.getCell(c1cfs2))); + assertEquals(-2L, CounterContext.instance().total(row.getCell(c2cfs2))); // Check the caches, separately CBuilder cb = CBuilder.create(cfsOne.metadata().comparator); @@ -175,8 +175,8 @@ public class CounterMutationTest ConsistencyLevel.ONE).apply(); Row row = Util.getOnlyRow(Util.cmd(cfs).includeRow("cc").columns("val", "val2").build()); - assertEquals(1L, CounterContext.instance().total(row.getCell(cOne).value())); - assertEquals(-1L, CounterContext.instance().total(row.getCell(cTwo).value())); + assertEquals(1L, CounterContext.instance().total(row.getCell(cOne))); + assertEquals(-1L, CounterContext.instance().total(row.getCell(cTwo))); // Remove the first counter, increment the second counter new CounterMutation( @@ -189,7 +189,7 @@ public class CounterMutationTest row = Util.getOnlyRow(Util.cmd(cfs).includeRow("cc").columns("val", "val2").build()); assertEquals(null, row.getCell(cOne)); - assertEquals(-6L, CounterContext.instance().total(row.getCell(cTwo).value())); + assertEquals(-6L, CounterContext.instance().total(row.getCell(cTwo))); // Increment the first counter, make sure it's still shadowed by the tombstone new CounterMutation( diff --git a/test/unit/org/apache/cassandra/db/KeyspaceTest.java b/test/unit/org/apache/cassandra/db/KeyspaceTest.java index e7d7814f42..c549b8539f 100644 --- a/test/unit/org/apache/cassandra/db/KeyspaceTest.java +++ b/test/unit/org/apache/cassandra/db/KeyspaceTest.java @@ -101,20 +101,20 @@ public class KeyspaceTest extends CQLTester { // slice with limit 1 Row row = Util.getOnlyRow(Util.cmd(cfs, "0").columns("c").withLimit(1).build()); - assertEquals(ByteBufferUtil.bytes(0), row.getCell(cfs.metadata().getColumn(new ColumnIdentifier("c", false))).value()); + assertEquals(ByteBufferUtil.bytes(0), row.getCell(cfs.metadata().getColumn(new ColumnIdentifier("c", false))).buffer()); // fetch each row by name for (int i = 0; i < 2; i++) { row = Util.getOnlyRow(Util.cmd(cfs, "0").columns("c").includeRow(i).build()); - assertEquals(ByteBufferUtil.bytes(i), row.getCell(cfs.metadata().getColumn(new ColumnIdentifier("c", false))).value()); + assertEquals(ByteBufferUtil.bytes(i), row.getCell(cfs.metadata().getColumn(new ColumnIdentifier("c", false))).buffer()); } // fetch each row by slice for (int i = 0; i < 2; i++) { row = Util.getOnlyRow(Util.cmd(cfs, "0").columns("c").fromIncl(i).toIncl(i).build()); - assertEquals(ByteBufferUtil.bytes(i), row.getCell(cfs.metadata().getColumn(new ColumnIdentifier("c", false))).value()); + assertEquals(ByteBufferUtil.bytes(i), row.getCell(cfs.metadata().getColumn(new ColumnIdentifier("c", false))).buffer()); } if (round == 0) @@ -150,8 +150,8 @@ public class KeyspaceTest extends CQLTester private static void assertRowsInSlice(ColumnFamilyStore cfs, String key, int sliceStart, int sliceEnd, int limit, boolean reversed, String columnValuePrefix) { - Clustering startClustering = Clustering.make(ByteBufferUtil.bytes(sliceStart)); - Clustering endClustering = Clustering.make(ByteBufferUtil.bytes(sliceEnd)); + Clustering startClustering = Clustering.make(ByteBufferUtil.bytes(sliceStart)); + Clustering endClustering = Clustering.make(ByteBufferUtil.bytes(sliceEnd)); Slices slices = Slices.with(cfs.getComparator(), Slice.make(startClustering, endClustering)); ClusteringIndexSliceFilter filter = new ClusteringIndexSliceFilter(slices, reversed); SinglePartitionReadCommand command = singlePartitionSlice(cfs, key, filter, limit); @@ -166,8 +166,8 @@ public class KeyspaceTest extends CQLTester for (int i = sliceEnd; i >= sliceStart; i--) { Row row = rowIterator.next(); - Cell cell = row.getCell(cfs.metadata().getColumn(new ColumnIdentifier("c", false))); - assertEquals(ByteBufferUtil.bytes(columnValuePrefix + i), cell.value()); + Cell cell = row.getCell(cfs.metadata().getColumn(new ColumnIdentifier("c", false))); + assertEquals(ByteBufferUtil.bytes(columnValuePrefix + i), cell.buffer()); } } else @@ -175,8 +175,8 @@ public class KeyspaceTest extends CQLTester for (int i = sliceStart; i <= sliceEnd; i++) { Row row = rowIterator.next(); - Cell cell = row.getCell(cfs.metadata().getColumn(new ColumnIdentifier("c", false))); - assertEquals(ByteBufferUtil.bytes(columnValuePrefix + i), cell.value()); + Cell cell = row.getCell(cfs.metadata().getColumn(new ColumnIdentifier("c", false))); + assertEquals(ByteBufferUtil.bytes(columnValuePrefix + i), cell.buffer()); } } assertFalse(rowIterator.hasNext()); @@ -235,8 +235,8 @@ public class KeyspaceTest extends CQLTester try (RowIterator rowIterator = iterator.next()) { Row row = rowIterator.next(); - Cell cell = row.getCell(cfs.metadata().getColumn(new ColumnIdentifier("c", false))); - assertEquals(ByteBufferUtil.bytes(i), cell.value()); + Cell cell = row.getCell(cfs.metadata().getColumn(new ColumnIdentifier("c", false))); + assertEquals(ByteBufferUtil.bytes(i), cell.buffer()); } } } @@ -259,10 +259,10 @@ public class KeyspaceTest extends CQLTester for (int expected : columnValues) { Row row = rowIterator.next(); - Cell cell = row.getCell(cfs.metadata().getColumn(new ColumnIdentifier("c", false))); + Cell cell = row.getCell(cfs.metadata().getColumn(new ColumnIdentifier("c", false))); assertEquals( - String.format("Expected %s, but got %s", ByteBufferUtil.bytesToHex(ByteBufferUtil.bytes(expected)), ByteBufferUtil.bytesToHex(cell.value())), - ByteBufferUtil.bytes(expected), cell.value()); + String.format("Expected %s, but got %s", ByteBufferUtil.bytesToHex(ByteBufferUtil.bytes(expected)), ByteBufferUtil.bytesToHex(cell.buffer())), + ByteBufferUtil.bytes(expected), cell.buffer()); } assertFalse(rowIterator.hasNext()); } @@ -271,12 +271,12 @@ public class KeyspaceTest extends CQLTester private static ClusteringIndexSliceFilter slices(ColumnFamilyStore cfs, Integer sliceStart, Integer sliceEnd, boolean reversed) { - ClusteringBound startBound = sliceStart == null - ? ClusteringBound.BOTTOM - : ClusteringBound.create(ClusteringPrefix.Kind.INCL_START_BOUND, new ByteBuffer[]{ByteBufferUtil.bytes(sliceStart)}); - ClusteringBound endBound = sliceEnd == null - ? ClusteringBound.TOP - : ClusteringBound.create(ClusteringPrefix.Kind.INCL_END_BOUND, new ByteBuffer[]{ByteBufferUtil.bytes(sliceEnd)}); + ClusteringBound startBound = sliceStart == null + ? BufferClusteringBound.create(ClusteringPrefix.Kind.INCL_START_BOUND, ByteBufferUtil.EMPTY_ARRAY) + : BufferClusteringBound.create(ClusteringPrefix.Kind.INCL_START_BOUND, new ByteBuffer[]{ByteBufferUtil.bytes(sliceStart)}); + ClusteringBound endBound = sliceEnd == null + ? BufferClusteringBound.create(ClusteringPrefix.Kind.INCL_END_BOUND, ByteBufferUtil.EMPTY_ARRAY) + : BufferClusteringBound.create(ClusteringPrefix.Kind.INCL_END_BOUND, new ByteBuffer[]{ByteBufferUtil.bytes(sliceEnd)}); Slices slices = Slices.with(cfs.getComparator(), Slice.make(startBound, endBound)); return new ClusteringIndexSliceFilter(slices, reversed); } diff --git a/test/unit/org/apache/cassandra/db/NameSortTest.java b/test/unit/org/apache/cassandra/db/NameSortTest.java index 0b00f40ea2..0d7b09c8fc 100644 --- a/test/unit/org/apache/cassandra/db/NameSortTest.java +++ b/test/unit/org/apache/cassandra/db/NameSortTest.java @@ -100,7 +100,7 @@ public class NameSortTest continue; int cellVal = Integer.valueOf(cd.name.toString().substring(cd.name.toString().length() - 1)); String expected = cellVal % 2 == 0 ? "a" : "b"; - assertEquals(expected, ByteBufferUtil.string(r.getCell(cd).value())); + assertEquals(expected, ByteBufferUtil.string(r.getCell(cd).buffer())); } } } diff --git a/test/unit/org/apache/cassandra/db/NativeCellTest.java b/test/unit/org/apache/cassandra/db/NativeCellTest.java index a63fb32de1..d54461d526 100644 --- a/test/unit/org/apache/cassandra/db/NativeCellTest.java +++ b/test/unit/org/apache/cassandra/db/NativeCellTest.java @@ -70,7 +70,7 @@ public class NativeCellTest } } - private static Clustering rndclustering() + private static Clustering rndclustering() { int count = 1 + rand.nextInt(100); ByteBuffer[] values = new ByteBuffer[count]; @@ -117,7 +117,7 @@ public class NativeCellTest ColumnMetadata.Kind.REGULAR); } - private static Cell rndcell(ColumnMetadata col) + private static Cell rndcell(ColumnMetadata col) { long timestamp = rand.nextLong(); int ttl = rand.nextInt(); diff --git a/test/unit/org/apache/cassandra/db/PartitionRangeReadTest.java b/test/unit/org/apache/cassandra/db/PartitionRangeReadTest.java index 9918229aa3..56d7ae1a12 100644 --- a/test/unit/org/apache/cassandra/db/PartitionRangeReadTest.java +++ b/test/unit/org/apache/cassandra/db/PartitionRangeReadTest.java @@ -127,11 +127,11 @@ public class PartitionRangeReadTest // fetch by the first column name; we should get the second version of the column value Row row = Util.getOnlyRow(Util.cmd(cfs, "k1").includeRow(new BigInteger(new byte[]{1})).build()); - assertTrue(row.getCell(cDef).value().equals(ByteBufferUtil.bytes("val2"))); + assertTrue(row.getCell(cDef).buffer().equals(ByteBufferUtil.bytes("val2"))); // fetch by the second column name; we should get the second version of the column value row = Util.getOnlyRow(Util.cmd(cfs, "k1").includeRow(new BigInteger(new byte[]{0, 0, 1})).build()); - assertTrue(row.getCell(cDef).value().equals(ByteBufferUtil.bytes("val2"))); + assertTrue(row.getCell(cDef).buffer().equals(ByteBufferUtil.bytes("val2"))); } @Test @@ -184,26 +184,26 @@ public class PartitionRangeReadTest // Start and end inclusive partitions = Util.getAll(Util.cmd(cfs).fromKeyIncl("2").toKeyIncl("7").build()); assertEquals(6, partitions.size()); - assertTrue(partitions.get(0).iterator().next().getCell(cDef).value().equals(ByteBufferUtil.bytes("2"))); - assertTrue(partitions.get(partitions.size() - 1).iterator().next().getCell(cDef).value().equals(ByteBufferUtil.bytes("7"))); + assertTrue(partitions.get(0).iterator().next().getCell(cDef).buffer().equals(ByteBufferUtil.bytes("2"))); + assertTrue(partitions.get(partitions.size() - 1).iterator().next().getCell(cDef).buffer().equals(ByteBufferUtil.bytes("7"))); // Start and end excluded partitions = Util.getAll(Util.cmd(cfs).fromKeyExcl("2").toKeyExcl("7").build()); assertEquals(4, partitions.size()); - assertTrue(partitions.get(0).iterator().next().getCell(cDef).value().equals(ByteBufferUtil.bytes("3"))); - assertTrue(partitions.get(partitions.size() - 1).iterator().next().getCell(cDef).value().equals(ByteBufferUtil.bytes("6"))); + assertTrue(partitions.get(0).iterator().next().getCell(cDef).buffer().equals(ByteBufferUtil.bytes("3"))); + assertTrue(partitions.get(partitions.size() - 1).iterator().next().getCell(cDef).buffer().equals(ByteBufferUtil.bytes("6"))); // Start excluded, end included partitions = Util.getAll(Util.cmd(cfs).fromKeyExcl("2").toKeyIncl("7").build()); assertEquals(5, partitions.size()); - assertTrue(partitions.get(0).iterator().next().getCell(cDef).value().equals(ByteBufferUtil.bytes("3"))); - assertTrue(partitions.get(partitions.size() - 1).iterator().next().getCell(cDef).value().equals(ByteBufferUtil.bytes("7"))); + assertTrue(partitions.get(0).iterator().next().getCell(cDef).buffer().equals(ByteBufferUtil.bytes("3"))); + assertTrue(partitions.get(partitions.size() - 1).iterator().next().getCell(cDef).buffer().equals(ByteBufferUtil.bytes("7"))); // Start included, end excluded partitions = Util.getAll(Util.cmd(cfs).fromKeyIncl("2").toKeyExcl("7").build()); assertEquals(5, partitions.size()); - assertTrue(partitions.get(0).iterator().next().getCell(cDef).value().equals(ByteBufferUtil.bytes("2"))); - assertTrue(partitions.get(partitions.size() - 1).iterator().next().getCell(cDef).value().equals(ByteBufferUtil.bytes("6"))); + assertTrue(partitions.get(0).iterator().next().getCell(cDef).buffer().equals(ByteBufferUtil.bytes("2"))); + assertTrue(partitions.get(partitions.size() - 1).iterator().next().getCell(cDef).buffer().equals(ByteBufferUtil.bytes("6"))); } @Test diff --git a/test/unit/org/apache/cassandra/db/PartitionTest.java b/test/unit/org/apache/cassandra/db/PartitionTest.java index 5f67580ae9..170083553a 100644 --- a/test/unit/org/apache/cassandra/db/PartitionTest.java +++ b/test/unit/org/apache/cassandra/db/PartitionTest.java @@ -110,7 +110,7 @@ public class PartitionTest assertTrue(deserialized.columns().regulars.getSimple(5).equals(partition.columns().regulars.getSimple(5))); ColumnMetadata cDef = cfs.metadata().getColumn(ByteBufferUtil.bytes("val8")); - assertTrue(partition.lastRow().getCell(cDef).value().equals(deserialized.lastRow().getCell(cDef).value())); + assertTrue(partition.lastRow().getCell(cDef).buffer().equals(deserialized.lastRow().getCell(cDef).buffer())); assert deserialized.partitionKey().equals(partition.partitionKey()); } diff --git a/test/unit/org/apache/cassandra/db/RangeTombstoneListTest.java b/test/unit/org/apache/cassandra/db/RangeTombstoneListTest.java index d4f7e59b40..8f61a0562d 100644 --- a/test/unit/org/apache/cassandra/db/RangeTombstoneListTest.java +++ b/test/unit/org/apache/cassandra/db/RangeTombstoneListTest.java @@ -686,7 +686,7 @@ public class RangeTombstoneListTest } - private static Clustering clustering(int i) + private static Clustering clustering(int i) { return Clustering.make(bb(i)); } @@ -708,7 +708,7 @@ public class RangeTombstoneListTest private static RangeTombstone rt(int start, int end, long tstamp, int delTime) { - return new RangeTombstone(Slice.make(ClusteringBound.inclusiveStartOf(bb(start)), ClusteringBound.inclusiveEndOf(bb(end))), new DeletionTime(tstamp, delTime)); + return new RangeTombstone(Slice.make(BufferClusteringBound.inclusiveStartOf(bb(start)), BufferClusteringBound.inclusiveEndOf(bb(end))), new DeletionTime(tstamp, delTime)); } private static RangeTombstone rtei(int start, int end, long tstamp) @@ -718,7 +718,7 @@ public class RangeTombstoneListTest private static RangeTombstone rtei(int start, int end, long tstamp, int delTime) { - return new RangeTombstone(Slice.make(ClusteringBound.exclusiveStartOf(bb(start)), ClusteringBound.inclusiveEndOf(bb(end))), new DeletionTime(tstamp, delTime)); + return new RangeTombstone(Slice.make(BufferClusteringBound.exclusiveStartOf(bb(start)), BufferClusteringBound.inclusiveEndOf(bb(end))), new DeletionTime(tstamp, delTime)); } private static RangeTombstone rtie(int start, int end, long tstamp) @@ -728,26 +728,26 @@ public class RangeTombstoneListTest private static RangeTombstone rtie(int start, int end, long tstamp, int delTime) { - return new RangeTombstone(Slice.make(ClusteringBound.inclusiveStartOf(bb(start)), ClusteringBound.exclusiveEndOf(bb(end))), new DeletionTime(tstamp, delTime)); + return new RangeTombstone(Slice.make(BufferClusteringBound.inclusiveStartOf(bb(start)), BufferClusteringBound.exclusiveEndOf(bb(end))), new DeletionTime(tstamp, delTime)); } private static RangeTombstone atLeast(int start, long tstamp, int delTime) { - return new RangeTombstone(Slice.make(ClusteringBound.inclusiveStartOf(bb(start)), ClusteringBound.TOP), new DeletionTime(tstamp, delTime)); + return new RangeTombstone(Slice.make(BufferClusteringBound.inclusiveStartOf(bb(start)), BufferClusteringBound.TOP), new DeletionTime(tstamp, delTime)); } private static RangeTombstone atMost(int end, long tstamp, int delTime) { - return new RangeTombstone(Slice.make(ClusteringBound.BOTTOM, ClusteringBound.inclusiveEndOf(bb(end))), new DeletionTime(tstamp, delTime)); + return new RangeTombstone(Slice.make(BufferClusteringBound.BOTTOM, BufferClusteringBound.inclusiveEndOf(bb(end))), new DeletionTime(tstamp, delTime)); } private static RangeTombstone lessThan(int end, long tstamp, int delTime) { - return new RangeTombstone(Slice.make(ClusteringBound.BOTTOM, ClusteringBound.exclusiveEndOf(bb(end))), new DeletionTime(tstamp, delTime)); + return new RangeTombstone(Slice.make(BufferClusteringBound.BOTTOM, BufferClusteringBound.exclusiveEndOf(bb(end))), new DeletionTime(tstamp, delTime)); } private static RangeTombstone greaterThan(int start, long tstamp, int delTime) { - return new RangeTombstone(Slice.make(ClusteringBound.exclusiveStartOf(bb(start)), ClusteringBound.TOP), new DeletionTime(tstamp, delTime)); + return new RangeTombstone(Slice.make(BufferClusteringBound.exclusiveStartOf(bb(start)), BufferClusteringBound.TOP), new DeletionTime(tstamp, delTime)); } } diff --git a/test/unit/org/apache/cassandra/db/RangeTombstoneTest.java b/test/unit/org/apache/cassandra/db/RangeTombstoneTest.java index 3d1d00322d..755302d1bd 100644 --- a/test/unit/org/apache/cassandra/db/RangeTombstoneTest.java +++ b/test/unit/org/apache/cassandra/db/RangeTombstoneTest.java @@ -457,7 +457,7 @@ public class RangeTombstoneTest FilteredPartition partition = Util.getOnlyPartition(Util.cmd(cfs, key).build()); assertTrue(partition.rowCount() > 0); - int last = i(partition.unfilteredIterator(ColumnFilter.all(cfs.metadata()), Slices.ALL, true).next().clustering().get(0)); + int last = i(partition.unfilteredIterator(ColumnFilter.all(cfs.metadata()), Slices.ALL, true).next().clustering().bufferAt(0)); assertEquals("Last column should be column 1 since column 2 has been deleted", 1, last); } diff --git a/test/unit/org/apache/cassandra/db/ReadCommandTest.java b/test/unit/org/apache/cassandra/db/ReadCommandTest.java index 990f675f08..fc2520ada2 100644 --- a/test/unit/org/apache/cassandra/db/ReadCommandTest.java +++ b/test/unit/org/apache/cassandra/db/ReadCommandTest.java @@ -330,7 +330,7 @@ public class ReadCommandTest int nowInSeconds = FBUtilities.nowInSeconds(); ColumnFilter columnFilter = ColumnFilter.allRegularColumnsBuilder(cfs.metadata()).build(); RowFilter rowFilter = RowFilter.create(); - Slice slice = Slice.make(ClusteringBound.BOTTOM, ClusteringBound.TOP); + Slice slice = Slice.make(BufferClusteringBound.BOTTOM, BufferClusteringBound.TOP); ClusteringIndexSliceFilter sliceFilter = new ClusteringIndexSliceFilter(Slices.with(cfs.metadata().comparator, slice), false); for (String[][] group : groups) @@ -497,7 +497,7 @@ public class ReadCommandTest int nowInSeconds = FBUtilities.nowInSeconds(); ColumnFilter columnFilter = ColumnFilter.allRegularColumnsBuilder(cfs.metadata()).build(); RowFilter rowFilter = RowFilter.create(); - Slice slice = Slice.make(ClusteringBound.BOTTOM, ClusteringBound.TOP); + Slice slice = Slice.make(BufferClusteringBound.BOTTOM, BufferClusteringBound.TOP); ClusteringIndexSliceFilter sliceFilter = new ClusteringIndexSliceFilter( Slices.with(cfs.metadata().comparator, slice), false); @@ -573,7 +573,7 @@ public class ReadCommandTest int nowInSeconds = FBUtilities.nowInSeconds(); ColumnFilter columnFilter = ColumnFilter.allRegularColumnsBuilder(cfs.metadata()).build(); RowFilter rowFilter = RowFilter.create(); - Slice slice = Slice.make(ClusteringBound.BOTTOM, ClusteringBound.TOP); + Slice slice = Slice.make(BufferClusteringBound.BOTTOM, BufferClusteringBound.TOP); ClusteringIndexSliceFilter sliceFilter = new ClusteringIndexSliceFilter( Slices.with(cfs.metadata().comparator, slice), false); @@ -825,7 +825,7 @@ public class ReadCommandTest Row r = (Row)u; assertTrue(!r.hasDeletion(cmd.nowInSec()) || (key.equals(keys[2]) && r.clustering() - .get(0) + .bufferAt(0) .equals(AsciiType.instance.fromString("cc")))); }); diff --git a/test/unit/org/apache/cassandra/db/RecoveryManagerTest.java b/test/unit/org/apache/cassandra/db/RecoveryManagerTest.java index 527c6a7d09..013f30b14a 100644 --- a/test/unit/org/apache/cassandra/db/RecoveryManagerTest.java +++ b/test/unit/org/apache/cassandra/db/RecoveryManagerTest.java @@ -245,7 +245,7 @@ public class RecoveryManagerTest ColumnMetadata counterCol = cfs.metadata().getColumn(ByteBufferUtil.bytes("val")); Row row = Util.getOnlyRow(Util.cmd(cfs).includeRow("cc").columns("val").build()); - assertEquals(10L, CounterContext.instance().total(row.getCell(counterCol).value())); + assertEquals(10L, CounterContext.instance().total(row.getCell(counterCol))); } @Test diff --git a/test/unit/org/apache/cassandra/db/RepairedDataInfoTest.java b/test/unit/org/apache/cassandra/db/RepairedDataInfoTest.java index c43be988db..45b80a55d3 100644 --- a/test/unit/org/apache/cassandra/db/RepairedDataInfoTest.java +++ b/test/unit/org/apache/cassandra/db/RepairedDataInfoTest.java @@ -243,7 +243,7 @@ public class RepairedDataInfoTest return getArray(info.getDigest()); } - public static Cell cell(ColumnMetadata def, Object value) + public static Cell cell(ColumnMetadata def, Object value) { ByteBuffer bb = value instanceof ByteBuffer ? (ByteBuffer)value : ((AbstractType)def.type).decompose(value); return new BufferCell(def, 1L, BufferCell.NO_TTL, BufferCell.NO_DELETION_TIME, bb, null); @@ -292,7 +292,7 @@ public class RepairedDataInfoTest { return new RangeTombstoneBoundMarker( ClusteringBound.create(ClusteringBound.boundKind(true, true), - new ByteBuffer[] { Clustering.make(Int32Type.instance.decompose(start)).get(0)}), + Clustering.make(Int32Type.instance.decompose(start))), new DeletionTime(FBUtilities.timestampMicros(), FBUtilities.nowInSeconds())); } @@ -300,7 +300,7 @@ public class RepairedDataInfoTest { return new RangeTombstoneBoundMarker( ClusteringBound.create(ClusteringBound.boundKind(false, true), - new ByteBuffer[] { Clustering.make(Int32Type.instance.decompose(close)).get(0)}), + Clustering.make(Int32Type.instance.decompose(close))), new DeletionTime(FBUtilities.timestampMicros(), FBUtilities.nowInSeconds())); } diff --git a/test/unit/org/apache/cassandra/db/RepairedDataTombstonesTest.java b/test/unit/org/apache/cassandra/db/RepairedDataTombstonesTest.java index a864786dbc..bb272afe9f 100644 --- a/test/unit/org/apache/cassandra/db/RepairedDataTombstonesTest.java +++ b/test/unit/org/apache/cassandra/db/RepairedDataTombstonesTest.java @@ -256,7 +256,7 @@ public class RepairedDataTombstonesTest extends CQLTester for (int i = 0; i < row.clustering().size(); i++) { foundRows++; - int val = ByteBufferUtil.toInt(row.clustering().get(i)); + int val = ByteBufferUtil.toInt(row.clustering().bufferAt(i)); assertTrue("val=" + val, val >= minVal && val < maxVal); } } @@ -296,7 +296,7 @@ public class RepairedDataTombstonesTest extends CQLTester for (int i = 0; i < row.clustering().size(); i++) { foundRows++; - int val = ByteBufferUtil.toInt(row.clustering().get(i)); + int val = ByteBufferUtil.toInt(row.clustering().bufferAt(i)); assertTrue("val=" + val, val >= minVal && val < maxVal); } } diff --git a/test/unit/org/apache/cassandra/db/RowCacheTest.java b/test/unit/org/apache/cassandra/db/RowCacheTest.java index 5ca1eefb85..59ce213454 100644 --- a/test/unit/org/apache/cassandra/db/RowCacheTest.java +++ b/test/unit/org/apache/cassandra/db/RowCacheTest.java @@ -31,6 +31,7 @@ import org.junit.Test; import org.apache.cassandra.SchemaLoader; import org.apache.cassandra.Util; import org.apache.cassandra.cache.RowCacheKey; +import org.apache.cassandra.db.marshal.ValueAccessors; import org.apache.cassandra.locator.InetAddressAndPort; import org.apache.cassandra.schema.Schema; import org.apache.cassandra.db.marshal.AsciiType; @@ -121,7 +122,7 @@ public class RowCacheTest Row r = (Row) unfiltered; for (ColumnData c : r) { - assertEquals(((Cell)c).value(), ByteBufferUtil.bytes("val" + 0)); + assertEquals(((Cell)c).buffer(), ByteBufferUtil.bytes("val" + 0)); } } cachedStore.truncateBlocking(); @@ -161,12 +162,12 @@ public class RowCacheTest Row r = (Row)ai.next(); assertFalse(ai.hasNext()); - Iterator ci = r.cells().iterator(); + Iterator> ci = r.cells().iterator(); assert(ci.hasNext()); - Cell cell = ci.next(); + Cell cell = ci.next(); assert cell.column().name.bytes.equals(ByteBufferUtil.bytes("val")); - assert cell.value().equals(ByteBufferUtil.bytes("val" + i)); + assert cell.buffer().equals(ByteBufferUtil.bytes("val" + i)); } } @@ -188,12 +189,12 @@ public class RowCacheTest Row r = (Row)ai.next(); assertFalse(ai.hasNext()); - Iterator ci = r.cells().iterator(); + Iterator> ci = r.cells().iterator(); assert(ci.hasNext()); - Cell cell = ci.next(); + Cell cell = ci.next(); assert cell.column().name.bytes.equals(ByteBufferUtil.bytes("val")); - assert cell.value().equals(ByteBufferUtil.bytes("val" + i)); + assert cell.buffer().equals(ByteBufferUtil.bytes("val" + i)); } } @@ -255,12 +256,12 @@ public class RowCacheTest Row r = (Row)ai.next(); assertFalse(ai.hasNext()); - Iterator ci = r.cells().iterator(); + Iterator> ci = r.cells().iterator(); assert(ci.hasNext()); - Cell cell = ci.next(); + Cell cell = ci.next(); assert cell.column().name.bytes.equals(ByteBufferUtil.bytes("val")); - assert cell.value().equals(ByteBufferUtil.bytes("val" + i)); + assert cell.buffer().equals(ByteBufferUtil.bytes("val" + i)); } } @@ -460,11 +461,11 @@ public class RowCacheTest { Row r = (Row) unfiltered; - assertEquals(r.clustering().get(0), ByteBufferUtil.bytes(values[i].substring(3))); + ValueAccessors.assertDataEquals(r.clustering().get(0), ByteBufferUtil.bytes(values[i].substring(3))); for (ColumnData c : r) { - assertEquals(((Cell)c).value(), ByteBufferUtil.bytes(values[i])); + assertEquals(((Cell)c).buffer(), ByteBufferUtil.bytes(values[i])); } i++; } diff --git a/test/unit/org/apache/cassandra/db/RowIndexEntryTest.java b/test/unit/org/apache/cassandra/db/RowIndexEntryTest.java index 392a1a041d..7b774eb037 100644 --- a/test/unit/org/apache/cassandra/db/RowIndexEntryTest.java +++ b/test/unit/org/apache/cassandra/db/RowIndexEntryTest.java @@ -34,8 +34,6 @@ import org.junit.Test; import org.apache.cassandra.Util; import org.apache.cassandra.cache.IMeasurableMemory; import org.apache.cassandra.cql3.statements.schema.CreateTableStatement; -import org.apache.cassandra.db.rows.SerializationHelper; -import org.apache.cassandra.schema.TableMetadata; import org.apache.cassandra.config.DatabaseDescriptor; import org.apache.cassandra.cql3.CQLTester; import org.apache.cassandra.db.columniterator.AbstractSSTableIterator; @@ -49,6 +47,7 @@ import org.apache.cassandra.db.rows.ColumnData; import org.apache.cassandra.db.rows.EncodingStats; import org.apache.cassandra.db.rows.RangeTombstoneMarker; import org.apache.cassandra.db.rows.Row; +import org.apache.cassandra.db.rows.SerializationHelper; import org.apache.cassandra.db.rows.Unfiltered; import org.apache.cassandra.db.rows.UnfilteredRowIterator; import org.apache.cassandra.db.rows.UnfilteredSerializer; @@ -59,6 +58,7 @@ import org.apache.cassandra.io.sstable.format.SSTableFlushObserver; import org.apache.cassandra.io.sstable.format.Version; import org.apache.cassandra.io.sstable.format.big.BigFormat; import org.apache.cassandra.io.util.*; +import org.apache.cassandra.schema.TableMetadata; import org.apache.cassandra.serializers.LongSerializer; import org.apache.cassandra.utils.ByteBufferUtil; import org.apache.cassandra.utils.FBUtilities; @@ -75,7 +75,7 @@ public class RowIndexEntryTest extends CQLTester private static final byte[] dummy_100k = new byte[100000]; - private static Clustering cn(long l) + private static Clustering cn(long l) { return Util.clustering(comp, l); } @@ -182,10 +182,10 @@ public class RowIndexEntryTest extends CQLTester } void build(Row staticRow, DecoratedKey partitionKey, - Collection clusterings, long startPosition) throws IOException + Collection> clusterings, long startPosition) throws IOException { - Iterator clusteringIter = clusterings.iterator(); + Iterator> clusteringIter = clusterings.iterator(); columnIndex.buildRowIndex(makeRowIter(staticRow, partitionKey, clusteringIter, dataWriterNew)); rieNew = RowIndexEntry.create(startPosition, 0L, deletionInfo, columnIndex.headerLength, columnIndex.columnIndexCount, @@ -195,7 +195,7 @@ public class RowIndexEntryTest extends CQLTester rieSerializer.serialize(rieNew, rieOutput, columnIndex.buffer()); rieNewSerialized = rieOutput.buffer().duplicate(); - Iterator clusteringIter2 = clusterings.iterator(); + Iterator> clusteringIter2 = clusterings.iterator(); ColumnIndex columnIndex = RowIndexEntryTest.ColumnIndex.writeAndBuildIndex(makeRowIter(staticRow, partitionKey, clusteringIter2, dataWriterOld), dataWriterOld, header, Collections.emptySet(), BigFormat.latestVersion); rieOld = Pre_C_11206_RowIndexEntry.create(startPosition, deletionInfo, columnIndex); @@ -204,7 +204,7 @@ public class RowIndexEntryTest extends CQLTester } private AbstractUnfilteredRowIterator makeRowIter(Row staticRow, DecoratedKey partitionKey, - Iterator clusteringIter, SequentialWriter dataWriter) + Iterator> clusteringIter, SequentialWriter dataWriter) { return new AbstractUnfilteredRowIterator(metadata, partitionKey, deletionInfo, metadata.regularAndStaticColumns(), staticRow, false, new EncodingStats(0, 0, 0)) @@ -227,7 +227,7 @@ public class RowIndexEntryTest extends CQLTester }; } - private Unfiltered buildRow(Clustering clustering) + private Unfiltered buildRow(Clustering clustering) { BTree.Builder builder = BTree.builder(ColumnData.comparator); builder.add(BufferCell.live(metadata.regularAndStaticColumns().iterator().next(), @@ -293,8 +293,8 @@ public class RowIndexEntryTest extends CQLTester private int written; private long previousRowStart; - private ClusteringPrefix firstClustering; - private ClusteringPrefix lastClustering; + private ClusteringPrefix firstClustering; + private ClusteringPrefix lastClustering; private DeletionTime openMarker; diff --git a/test/unit/org/apache/cassandra/db/RowTest.java b/test/unit/org/apache/cassandra/db/RowTest.java index fe5429945c..411eecb476 100644 --- a/test/unit/org/apache/cassandra/db/RowTest.java +++ b/test/unit/org/apache/cassandra/db/RowTest.java @@ -111,12 +111,12 @@ public class RowTest while (merged.hasNext()) { RangeTombstoneBoundMarker openMarker = (RangeTombstoneBoundMarker)merged.next(); - ClusteringBound openBound = openMarker.clustering(); + ClusteringBound openBound = openMarker.clustering(); DeletionTime openDeletion = new DeletionTime(openMarker.deletionTime().markedForDeleteAt(), openMarker.deletionTime().localDeletionTime()); RangeTombstoneBoundMarker closeMarker = (RangeTombstoneBoundMarker)merged.next(); - ClusteringBound closeBound = closeMarker.clustering(); + ClusteringBound closeBound = closeMarker.clustering(); DeletionTime closeDeletion = new DeletionTime(closeMarker.deletionTime().markedForDeleteAt(), closeMarker.deletionTime().localDeletionTime()); @@ -144,8 +144,8 @@ public class RowTest Unfiltered unfiltered = update.unfilteredIterator().next(); assertTrue(unfiltered.kind() == Unfiltered.Kind.ROW); row = (Row) unfiltered; - assertEquals("a2", defA.cellValueType().getString(row.getCell(defA).value())); - assertEquals("b1", defB.cellValueType().getString(row.getCell(defB).value())); + assertEquals("a2", defA.cellValueType().getString(row.getCell(defA).buffer())); + assertEquals("b1", defB.cellValueType().getString(row.getCell(defB).buffer())); assertEquals(2, row.columns().size()); } @@ -155,7 +155,7 @@ public class RowTest int ttl = 1; ColumnMetadata def = metadata.getColumn(new ColumnIdentifier("a", true)); - Cell cell = BufferCell.expiring(def, 0, ttl, nowInSeconds, ((AbstractType) def.cellValueType()).decompose("a1")); + Cell cell = BufferCell.expiring(def, 0, ttl, nowInSeconds, ((AbstractType) def.cellValueType()).decompose("a1")); PartitionUpdate update = PartitionUpdate.singleRowUpdate(metadata, dk, BTreeRow.singleCellRow(metadata.comparator.make("c1"), cell)); new Mutation(update).applyUnsafe(); @@ -163,7 +163,7 @@ public class RowTest // when we read with a nowInSeconds before the cell has expired, // the PartitionIterator includes the row we just wrote Row row = Util.getOnlyRow(Util.cmd(cfs, dk).includeRow("c1").withNowInSeconds(nowInSeconds).build()); - assertEquals("a1", ByteBufferUtil.string(row.getCell(def).value())); + assertEquals("a1", ByteBufferUtil.string(row.getCell(def).buffer())); // when we read with a nowInSeconds after the cell has expired, the row is filtered // so the PartitionIterator is empty @@ -188,17 +188,17 @@ public class RowTest assertEquals(Integer.valueOf(1), map.get(row)); } - private void assertRangeTombstoneMarkers(ClusteringBound start, ClusteringBound end, DeletionTime deletionTime, Object[] expected) + private void assertRangeTombstoneMarkers(ClusteringBound start, ClusteringBound end, DeletionTime deletionTime, Object[] expected) { AbstractType clusteringType = (AbstractType) metadata.comparator.subtype(0); assertEquals(1, start.size()); assertEquals(start.kind(), ClusteringPrefix.Kind.INCL_START_BOUND); - assertEquals(expected[0], clusteringType.getString(start.get(0))); + assertEquals(expected[0], clusteringType.getString(start.bufferAt(0))); assertEquals(1, end.size()); assertEquals(end.kind(), ClusteringPrefix.Kind.INCL_END_BOUND); - assertEquals(expected[1], clusteringType.getString(end.get(0))); + assertEquals(expected[1], clusteringType.getString(end.bufferAt(0))); assertEquals(expected[2], deletionTime.markedForDeleteAt()); assertEquals(expected[3], deletionTime.localDeletionTime()); diff --git a/test/unit/org/apache/cassandra/db/SecondaryIndexTest.java b/test/unit/org/apache/cassandra/db/SecondaryIndexTest.java index bfe1c6d908..e7bfb120bd 100644 --- a/test/unit/org/apache/cassandra/db/SecondaryIndexTest.java +++ b/test/unit/org/apache/cassandra/db/SecondaryIndexTest.java @@ -136,7 +136,7 @@ public class SecondaryIndexTest for (Row row : partition) { ++rowCount; - assert ByteBufferUtil.toLong(Util.cell(cfs, row, "birthdate").value()) > 1L; + assert ByteBufferUtil.toLong(Util.cell(cfs, row, "birthdate").buffer()) > 1L; } } assertEquals(2, rowCount); diff --git a/test/unit/org/apache/cassandra/db/SerializationHeaderTest.java b/test/unit/org/apache/cassandra/db/SerializationHeaderTest.java index 1092a90643..c9649b15a7 100644 --- a/test/unit/org/apache/cassandra/db/SerializationHeaderTest.java +++ b/test/unit/org/apache/cassandra/db/SerializationHeaderTest.java @@ -88,7 +88,7 @@ public class SerializationHeaderTest File dir = Files.createTempDir(); try { - BiFunction, Callable> writer = (schema, clusteringFunction) -> () -> { + BiFunction>, Callable> writer = (schema, clusteringFunction) -> () -> { Descriptor descriptor = new Descriptor(BigFormat.latestVersion, dir, schema.keyspace, schema.name, generation.incrementAndGet(), SSTableFormat.Type.BIG); SerializationHeader header = SerializationHeader.makeWithoutStats(schema); @@ -98,8 +98,8 @@ public class SerializationHeaderTest ColumnMetadata cd = schema.getColumn(v); for (int i = 0 ; i < 5 ; ++i) { final ByteBuffer value = Int32Type.instance.decompose(i); - Cell cell = BufferCell.live(cd, 1L, value); - Clustering clustering = clusteringFunction.apply(value); + Cell cell = BufferCell.live(cd, 1L, value); + Clustering clustering = clusteringFunction.apply(value); Row row = BTreeRow.singleCellRow(clustering, cell); sstableWriter.append(PartitionUpdate.singleRowUpdate(schema, value, row).unfilteredIterator()); } @@ -119,7 +119,7 @@ public class SerializationHeaderTest { UnfilteredRowIterator partition = partitions.next(); Assert.assertFalse(partition.hasNext()); - long value = Int32Type.instance.compose(partition.staticRow().getCell(columnStatic).value()); + long value = Int32Type.instance.compose(partition.staticRow().getCell(columnStatic).buffer()); Assert.assertEquals(value, (long)i); } Assert.assertFalse(partitions.hasNext()); @@ -128,7 +128,7 @@ public class SerializationHeaderTest for (int i = 0 ; i < 5 ; ++i) { UnfilteredRowIterator partition = partitions.next(); - long value = Int32Type.instance.compose(((Row)partition.next()).getCell(columnRegular).value()); + long value = Int32Type.instance.compose(((Row)partition.next()).getCell(columnRegular).buffer()); Assert.assertEquals(value, (long)i); Assert.assertTrue(partition.staticRow().isEmpty()); Assert.assertFalse(partition.hasNext()); diff --git a/test/unit/org/apache/cassandra/db/SinglePartitionSliceCommandTest.java b/test/unit/org/apache/cassandra/db/SinglePartitionSliceCommandTest.java index 67fd314a06..05f0883ca9 100644 --- a/test/unit/org/apache/cassandra/db/SinglePartitionSliceCommandTest.java +++ b/test/unit/org/apache/cassandra/db/SinglePartitionSliceCommandTest.java @@ -40,6 +40,7 @@ import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.apache.cassandra.SchemaLoader; +import org.apache.cassandra.db.marshal.ByteBufferAccessor; import org.apache.cassandra.schema.ColumnMetadata; import org.apache.cassandra.schema.TableMetadata; import org.apache.cassandra.config.DatabaseDescriptor; @@ -151,7 +152,7 @@ public class SinglePartitionSliceCommandTest private AbstractClusteringIndexFilter createClusteringFilter(int uniqueCk1, int uniqueCk2, boolean isSlice) { Slices.Builder slicesBuilder = new Slices.Builder(CFM_SLICES.comparator); - BTreeSet.Builder namesBuilder = BTreeSet.builder(CFM_SLICES.comparator); + BTreeSet.Builder> namesBuilder = BTreeSet.builder(CFM_SLICES.comparator); for (int ck1 = 0; ck1 < uniqueCk1; ck1++) { @@ -216,12 +217,10 @@ public class SinglePartitionSliceCommandTest assertEquals(deletionTime, marker.closeDeletionTime(false).markedForDeleteAt()); // check clustering values - Clustering clustering = Util.clustering(CFM_SLICES.comparator, ck1, count / 2); + Clustering clustering = Util.clustering(CFM_SLICES.comparator, ck1, count / 2); for (int i = 0; i < CFM_SLICES.comparator.size(); i++) { - int cmp = CFM_SLICES.comparator.compareComponent(i, - clustering.getRawValues()[i], - marker.clustering().values[i]); + int cmp = CFM_SLICES.comparator.compareComponent(i, clustering, marker.clustering()); assertEquals(0, cmp); } open = !open; @@ -248,11 +247,11 @@ public class SinglePartitionSliceCommandTest UnfilteredRowIterator ri = pi.next(); Assert.assertTrue(ri.columns().contains(s)); Row staticRow = ri.staticRow(); - Iterator cellIterator = staticRow.cells().iterator(); + Iterator> cellIterator = staticRow.cells().iterator(); Assert.assertTrue(staticRow.toString(metadata, true), cellIterator.hasNext()); - Cell cell = cellIterator.next(); + Cell cell = cellIterator.next(); Assert.assertEquals(s, cell.column()); - Assert.assertEquals(ByteBufferUtil.bytesToHex(cell.value()), ByteBufferUtil.bytes("s"), cell.value()); + Assert.assertEquals(ByteBufferUtil.bytesToHex(cell.buffer()), ByteBufferUtil.bytes("s"), cell.buffer()); Assert.assertFalse(cellIterator.hasNext()); } @@ -322,7 +321,7 @@ public class SinglePartitionSliceCommandTest DecoratedKey key = metadata.partitioner.decorateKey(ByteBufferUtil.bytes("k1")); ColumnFilter columnFilter = ColumnFilter.selection(RegularAndStaticColumns.of(s)); - Slice slice = Slice.make(ClusteringBound.BOTTOM, ClusteringBound.inclusiveEndOf(ByteBufferUtil.bytes("i1"))); + Slice slice = Slice.make(BufferClusteringBound.BOTTOM, BufferClusteringBound.inclusiveEndOf(ByteBufferUtil.bytes("i1"))); ClusteringIndexSliceFilter sliceFilter = new ClusteringIndexSliceFilter(Slices.with(metadata.comparator, slice), false); ReadCommand cmd = SinglePartitionReadCommand.create(metadata, FBUtilities.nowInSeconds(), diff --git a/test/unit/org/apache/cassandra/db/TransformerTest.java b/test/unit/org/apache/cassandra/db/TransformerTest.java index 9c2ed9161d..41e47a2515 100644 --- a/test/unit/org/apache/cassandra/db/TransformerTest.java +++ b/test/unit/org/apache/cassandra/db/TransformerTest.java @@ -182,7 +182,7 @@ public class TransformerTest public Row applyToRow(Row row) { - Assert.assertEquals(cur++, ByteBufferUtil.toInt(row.clustering().get(0))); + Assert.assertEquals(cur++, ByteBufferUtil.toInt(row.clustering().bufferAt(0))); return row; } @@ -319,7 +319,7 @@ public class TransformerTest { Unfiltered u = iter.next(); assert u instanceof Row; - Assert.assertEquals(i, ByteBufferUtil.toInt(u.clustering().get(0))); + Assert.assertEquals(i, ByteBufferUtil.toInt(u.clustering().bufferAt(0))); } iter.close(); diff --git a/test/unit/org/apache/cassandra/db/aggregation/GroupMakerTest.java b/test/unit/org/apache/cassandra/db/aggregation/GroupMakerTest.java index 563a70935e..8ff262d5e0 100644 --- a/test/unit/org/apache/cassandra/db/aggregation/GroupMakerTest.java +++ b/test/unit/org/apache/cassandra/db/aggregation/GroupMakerTest.java @@ -157,7 +157,7 @@ public class GroupMakerTest return DatabaseDescriptor.getPartitioner().decorateKey(buffer); } - private static Clustering clustering(int... components) + private static Clustering clustering(int... components) { return Clustering.make(toByteBufferArray(components)); } diff --git a/test/unit/org/apache/cassandra/db/commitlog/CommitLogReaderTest.java b/test/unit/org/apache/cassandra/db/commitlog/CommitLogReaderTest.java index ca76e45ac8..794f99f47b 100644 --- a/test/unit/org/apache/cassandra/db/commitlog/CommitLogReaderTest.java +++ b/test/unit/org/apache/cassandra/db/commitlog/CommitLogReaderTest.java @@ -180,7 +180,7 @@ public class CommitLogReaderTest extends CQLTester for (Row r : pu) { String expected = Integer.toString(i + offset); - String seen = new String(r.getCell(cd).value().array()); + String seen = new String(r.getCell(cd).buffer().array()); if (!expected.equals(seen)) Assert.fail("Mismatch at index: " + i + ". Offset: " + offset + " Expected: " + expected + " Seen: " + seen); } diff --git a/test/unit/org/apache/cassandra/db/commitlog/CommitLogUpgradeTest.java b/test/unit/org/apache/cassandra/db/commitlog/CommitLogUpgradeTest.java index 1db0f1634b..47059193bd 100644 --- a/test/unit/org/apache/cassandra/db/commitlog/CommitLogUpgradeTest.java +++ b/test/unit/org/apache/cassandra/db/commitlog/CommitLogUpgradeTest.java @@ -160,11 +160,11 @@ public class CommitLogUpgradeTest { for (Row row : update) if (row.clustering().size() > 0 && - AsciiType.instance.compose(row.clustering().get(0)).startsWith(CELLNAME)) + AsciiType.instance.compose(row.clustering().bufferAt(0)).startsWith(CELLNAME)) { - for (Cell cell : row.cells()) + for (Cell cell : row.cells()) { - hash = hash(hash, cell.value()); + hash = hash(hash, cell.buffer()); ++cells; } } diff --git a/test/unit/org/apache/cassandra/db/compaction/CompactionsCQLTest.java b/test/unit/org/apache/cassandra/db/compaction/CompactionsCQLTest.java index 14b3d6da5d..fa42ab063a 100644 --- a/test/unit/org/apache/cassandra/db/compaction/CompactionsCQLTest.java +++ b/test/unit/org/apache/cassandra/db/compaction/CompactionsCQLTest.java @@ -586,7 +586,7 @@ public class CompactionsCQLTest extends CQLTester { Unfiltered unfiltered = iter.next(); assertTrue(unfiltered instanceof Row); - for (Cell c : ((Row)unfiltered).cells()) + for (Cell c : ((Row)unfiltered).cells()) { if (c.isTombstone()) foundTombstone = true; diff --git a/test/unit/org/apache/cassandra/db/compaction/CompactionsTest.java b/test/unit/org/apache/cassandra/db/compaction/CompactionsTest.java index 4bf9cdde32..3bdb158459 100644 --- a/test/unit/org/apache/cassandra/db/compaction/CompactionsTest.java +++ b/test/unit/org/apache/cassandra/db/compaction/CompactionsTest.java @@ -53,6 +53,7 @@ import org.apache.cassandra.db.filter.ClusteringIndexSliceFilter; import org.apache.cassandra.db.filter.ColumnFilter; import org.apache.cassandra.db.filter.DataLimits; import org.apache.cassandra.db.filter.RowFilter; +import org.apache.cassandra.db.marshal.ValueAccessors; import org.apache.cassandra.db.marshal.AsciiType; import org.apache.cassandra.db.partitions.FilteredPartition; import org.apache.cassandra.db.partitions.ImmutableBTreePartition; @@ -298,8 +299,8 @@ public class CompactionsTest { RowUpdateBuilder deletedRowUpdateBuilder = new RowUpdateBuilder(table, 1, Util.dk(Integer.toString(dk))); deletedRowUpdateBuilder.clustering("01").add("val", "a"); //Range tombstone covers this (timestamp 2 > 1) - Clustering startClustering = Clustering.make(ByteBufferUtil.bytes("0")); - Clustering endClustering = Clustering.make(ByteBufferUtil.bytes("b")); + Clustering startClustering = Clustering.make(ByteBufferUtil.bytes("0")); + Clustering endClustering = Clustering.make(ByteBufferUtil.bytes("b")); deletedRowUpdateBuilder.addRangeTombstone(new RangeTombstone(Slice.make(startClustering, endClustering), new DeletionTime(2, (int) (System.currentTimeMillis() / 1000)))); deletedRowUpdateBuilder.build().applyUnsafe(); @@ -357,11 +358,11 @@ public class CompactionsTest try (RowIterator rowIterator = iterator.next()) { Row row = rowIterator.next(); - Cell cell = row.getCell(cfs.metadata().getColumn(new ColumnIdentifier("val", false))); - assertEquals(ByteBufferUtil.bytes("a"), cell.value()); + Cell cell = row.getCell(cfs.metadata().getColumn(new ColumnIdentifier("val", false))); + assertEquals(ByteBufferUtil.bytes("a"), cell.buffer()); assertEquals(3, cell.timestamp()); - assertNotEquals(ByteBufferUtil.bytes("01"), row.clustering().getRawValues()[0]); - assertEquals(ByteBufferUtil.bytes("02"), row.clustering().getRawValues()[0]); + ValueAccessors.assertDataNotEquals(ByteBufferUtil.bytes("01"), row.clustering().getRawValues()[0]); + ValueAccessors.assertDataEquals(ByteBufferUtil.bytes("02"), row.clustering().getRawValues()[0]); } } } diff --git a/test/unit/org/apache/cassandra/db/compaction/NeverPurgeTest.java b/test/unit/org/apache/cassandra/db/compaction/NeverPurgeTest.java index 0d5bc81b02..241003ad55 100644 --- a/test/unit/org/apache/cassandra/db/compaction/NeverPurgeTest.java +++ b/test/unit/org/apache/cassandra/db/compaction/NeverPurgeTest.java @@ -119,7 +119,7 @@ public class NeverPurgeTest extends CQLTester Row r = (Row)atom; if (!r.deletion().isLive()) tombstoneCount++; - for (Cell c : r.cells()) + for (Cell c : r.cells()) if (c.isTombstone()) tombstoneCount++; } diff --git a/test/unit/org/apache/cassandra/db/composites/CTypeTest.java b/test/unit/org/apache/cassandra/db/composites/CTypeTest.java index 999417e6ba..fc06d4321f 100644 --- a/test/unit/org/apache/cassandra/db/composites/CTypeTest.java +++ b/test/unit/org/apache/cassandra/db/composites/CTypeTest.java @@ -31,38 +31,47 @@ public class CTypeTest CompositeType baseType = CompositeType.getInstance(AsciiType.instance, UUIDType.instance, LongType.instance); ByteBuffer a1 = CompositeType.build( + ByteBufferAccessor.instance, ByteBufferUtil.bytes("a"), UUIDType.instance.fromString("00000000-0000-0000-0000-000000000000"), ByteBufferUtil.bytes(1)); ByteBuffer a2 = CompositeType.build( + ByteBufferAccessor.instance, ByteBufferUtil.bytes("a"), UUIDType.instance.fromString("00000000-0000-0000-0000-000000000000"), ByteBufferUtil.bytes(100)); ByteBuffer b1 = CompositeType.build( + ByteBufferAccessor.instance, ByteBufferUtil.bytes("a"), UUIDType.instance.fromString("ffffffff-ffff-ffff-ffff-ffffffffffff"), ByteBufferUtil.bytes(1)); ByteBuffer b2 = CompositeType.build( + ByteBufferAccessor.instance, ByteBufferUtil.bytes("a"), UUIDType.instance.fromString("ffffffff-ffff-ffff-ffff-ffffffffffff"), ByteBufferUtil.bytes(100)); ByteBuffer c1 = CompositeType.build( + ByteBufferAccessor.instance, ByteBufferUtil.bytes("z"), UUIDType.instance.fromString("00000000-0000-0000-0000-000000000000"), ByteBufferUtil.bytes(1)); ByteBuffer c2 = CompositeType.build( + ByteBufferAccessor.instance, ByteBufferUtil.bytes("z"), UUIDType.instance.fromString("00000000-0000-0000-0000-000000000000"), ByteBufferUtil.bytes(100)); ByteBuffer d1 = CompositeType.build( + ByteBufferAccessor.instance, ByteBufferUtil.bytes("z"), UUIDType.instance.fromString("ffffffff-ffff-ffff-ffff-ffffffffffff"), ByteBufferUtil.bytes(1)); ByteBuffer d2 = CompositeType.build( + ByteBufferAccessor.instance, ByteBufferUtil.bytes("z"), UUIDType.instance.fromString("ffffffff-ffff-ffff-ffff-ffffffffffff"), ByteBufferUtil.bytes(100)); ByteBuffer z1 = CompositeType.build( + ByteBufferAccessor.instance, ByteBufferUtil.EMPTY_BYTE_BUFFER, UUIDType.instance.fromString("ffffffff-ffff-ffff-ffff-ffffffffffff"), ByteBufferUtil.bytes(100)); @@ -105,8 +114,8 @@ public class CTypeTest public void testSimpleType2() { CompositeType baseType = CompositeType.getInstance(UUIDType.instance); - ByteBuffer a = CompositeType.build(UUIDType.instance.fromString("00000000-0000-0000-0000-000000000000")); - ByteBuffer z = CompositeType.build(UUIDType.instance.fromString("ffffffff-ffff-ffff-ffff-ffffffffffff")); + ByteBuffer a = CompositeType.build(ByteBufferAccessor.instance, UUIDType.instance.fromString("00000000-0000-0000-0000-000000000000")); + ByteBuffer z = CompositeType.build(ByteBufferAccessor.instance, UUIDType.instance.fromString("ffffffff-ffff-ffff-ffff-ffffffffffff")); assert baseType.compare(a,z) < 0; assert baseType.compare(z,a) > 0; @@ -118,8 +127,8 @@ public class CTypeTest public void testSimpleType1() { CompositeType baseType = CompositeType.getInstance(BytesType.instance); - ByteBuffer a = CompositeType.build(ByteBufferUtil.bytes("a")); - ByteBuffer z = CompositeType.build(ByteBufferUtil.bytes("z")); + ByteBuffer a = CompositeType.build(ByteBufferAccessor.instance, ByteBufferUtil.bytes("a")); + ByteBuffer z = CompositeType.build(ByteBufferAccessor.instance, ByteBufferUtil.bytes("z")); assert baseType.compare(a,z) < 0; assert baseType.compare(z,a) > 0; diff --git a/test/unit/org/apache/cassandra/db/context/CounterContextTest.java b/test/unit/org/apache/cassandra/db/context/CounterContextTest.java index 44373655bd..5eda484744 100644 --- a/test/unit/org/apache/cassandra/db/context/CounterContextTest.java +++ b/test/unit/org/apache/cassandra/db/context/CounterContextTest.java @@ -30,6 +30,7 @@ import org.apache.cassandra.config.DatabaseDescriptor; import org.apache.cassandra.db.ClockAndCount; import org.apache.cassandra.db.commitlog.CommitLog; import org.apache.cassandra.db.context.CounterContext.Relationship; +import org.apache.cassandra.db.marshal.ByteBufferAccessor; import org.apache.cassandra.utils.ByteBufferUtil; import org.apache.cassandra.utils.CounterId; @@ -306,7 +307,7 @@ public class CounterContextTest merged = cc.merge(left.context, right.context); assertEquals(headerSizeLength + 5 * headerEltLength + 5 * stepLength, merged.remaining()); - assertEquals(18L, cc.total(merged)); + assertEquals(18L, cc.total(merged, ByteBufferAccessor.instance)); assertEquals(5, merged.getShort(merged.position())); int headerLength = headerSizeLength + 5 * headerEltLength; @@ -339,7 +340,7 @@ public class CounterContextTest merged = cc.merge(left.context, right.context); headerLength = headerSizeLength + headerEltLength; assertEquals(headerLength + stepLength, merged.remaining()); - assertEquals(30L, cc.total(merged)); + assertEquals(30L, cc.total(merged, ByteBufferAccessor.instance)); assertEquals(1, merged.getShort(merged.position())); assertTrue(Util.equalsCounterId(CounterId.fromInt(1), merged, headerLength)); assertEquals(10L, merged.getLong(merged.position() + headerLength + idLength)); @@ -361,7 +362,7 @@ public class CounterContextTest merged = cc.merge(left.context, right.context); headerLength = headerSizeLength + 2 * headerEltLength; assertEquals(headerLength + 2 * stepLength, merged.remaining()); - assertEquals(2L, cc.total(merged)); + assertEquals(2L, cc.total(merged, ByteBufferAccessor.instance)); assertEquals(2, merged.getShort(merged.position())); assertTrue(Util.equalsCounterId(CounterId.fromInt(1), merged, headerLength)); assertEquals(1L, merged.getLong(merged.position() + headerLength + idLength)); @@ -380,13 +381,13 @@ public class CounterContextTest mixed.writeRemote(CounterId.fromInt(4), 4L, 4L); mixed.writeRemote(CounterId.fromInt(5), 5L, 5L); mixed.writeLocal(CounterId.getLocalId(), 12L, 12L); - assertEquals(24L, cc.total(mixed.context)); + assertEquals(24L, cc.total(mixed.context, ByteBufferAccessor.instance)); ContextState global = ContextState.allocate(3, 0, 0); global.writeGlobal(CounterId.fromInt(1), 1L, 1L); global.writeGlobal(CounterId.fromInt(2), 2L, 2L); global.writeGlobal(CounterId.fromInt(3), 3L, 3L); - assertEquals(6L, cc.total(global.context)); + assertEquals(6L, cc.total(global.context, ByteBufferAccessor.instance)); } @Test @@ -400,26 +401,26 @@ public class CounterContextTest state = ContextState.allocate(0, 0, 1); state.writeRemote(CounterId.fromInt(1), 1L, 1L); - assertFalse(cc.shouldClearLocal(state.context)); + assertFalse(cc.shouldClearLocal(state.context, ByteBufferAccessor.instance)); marked = cc.markLocalToBeCleared(state.context); assertEquals(0, marked.getShort(marked.position())); assertSame(state.context, marked); // should return the original context - cleared = cc.clearAllLocal(marked); + cleared = cc.clearAllLocal(marked, ByteBufferAccessor.instance); assertSame(cleared, marked); // shouldn't alter anything either // a single local shard state = ContextState.allocate(0, 1, 0); state.writeLocal(CounterId.fromInt(1), 1L, 1L); - assertFalse(cc.shouldClearLocal(state.context)); + assertFalse(cc.shouldClearLocal(state.context, ByteBufferAccessor.instance)); marked = cc.markLocalToBeCleared(state.context); - assertTrue(cc.shouldClearLocal(marked)); + assertTrue(cc.shouldClearLocal(marked, ByteBufferAccessor.instance)); assertEquals(-1, marked.getShort(marked.position())); assertNotSame(state.context, marked); // shouldn't alter in place, as it used to do - cleared = cc.clearAllLocal(marked); - assertFalse(cc.shouldClearLocal(cleared)); + cleared = cc.clearAllLocal(marked, ByteBufferAccessor.instance); + assertFalse(cc.shouldClearLocal(cleared, ByteBufferAccessor.instance)); assertEquals(0, cleared.getShort(cleared.position())); // 2 global + 1 local shard @@ -428,9 +429,9 @@ public class CounterContextTest state.writeGlobal(CounterId.fromInt(2), 2L, 2L); state.writeGlobal(CounterId.fromInt(3), 3L, 3L); - assertFalse(cc.shouldClearLocal(state.context)); + assertFalse(cc.shouldClearLocal(state.context, ByteBufferAccessor.instance)); marked = cc.markLocalToBeCleared(state.context); - assertTrue(cc.shouldClearLocal(marked)); + assertTrue(cc.shouldClearLocal(marked, ByteBufferAccessor.instance)); assertEquals(-3, marked.getShort(marked.position())); assertEquals(0, marked.getShort(marked.position() + headerSizeLength)); @@ -450,8 +451,8 @@ public class CounterContextTest assertEquals(3L, marked.getLong(marked.position() + headerLength + 2 * stepLength + idLength)); assertEquals(3L, marked.getLong(marked.position() + headerLength + 2 * stepLength + idLength + clockLength)); - cleared = cc.clearAllLocal(marked); - assertFalse(cc.shouldClearLocal(cleared)); + cleared = cc.clearAllLocal(marked, ByteBufferAccessor.instance); + assertFalse(cc.shouldClearLocal(cleared, ByteBufferAccessor.instance)); assertEquals(2, cleared.getShort(cleared.position())); // 2 global shards assertEquals(Short.MIN_VALUE + 1, cleared.getShort(marked.position() + headerEltLength)); @@ -474,12 +475,12 @@ public class CounterContextTest state = ContextState.allocate(1, 0, 0); state.writeGlobal(CounterId.fromInt(1), 1L, 1L); - assertFalse(cc.shouldClearLocal(state.context)); + assertFalse(cc.shouldClearLocal(state.context, ByteBufferAccessor.instance)); marked = cc.markLocalToBeCleared(state.context); assertEquals(1, marked.getShort(marked.position())); assertSame(state.context, marked); - cleared = cc.clearAllLocal(marked); + cleared = cc.clearAllLocal(marked, ByteBufferAccessor.instance); assertSame(cleared, marked); } diff --git a/test/unit/org/apache/cassandra/db/filter/SliceTest.java b/test/unit/org/apache/cassandra/db/filter/SliceTest.java index 6c0450007a..77c0ec2cbf 100644 --- a/test/unit/org/apache/cassandra/db/filter/SliceTest.java +++ b/test/unit/org/apache/cassandra/db/filter/SliceTest.java @@ -344,14 +344,14 @@ public class SliceTest assertTrue(Slice.isEmpty(cc, makeBound(INCL_START_BOUND, 5, 0), makeBound(EXCL_END_BOUND, 3, 0))); } - private static ClusteringBound makeBound(ClusteringPrefix.Kind kind, Integer... components) + private static ClusteringBound makeBound(ClusteringPrefix.Kind kind, Integer... components) { ByteBuffer[] values = new ByteBuffer[components.length]; for (int i = 0; i < components.length; i++) { values[i] = ByteBufferUtil.bytes(components[i]); } - return ClusteringBound.create(kind, values); + return BufferClusteringBound.create(kind, values); } private static List columnNames(Integer ... components) diff --git a/test/unit/org/apache/cassandra/db/marshal/ByteBufferAccessorTest.java b/test/unit/org/apache/cassandra/db/marshal/ByteBufferAccessorTest.java new file mode 100644 index 0000000000..0314d8fb7a --- /dev/null +++ b/test/unit/org/apache/cassandra/db/marshal/ByteBufferAccessorTest.java @@ -0,0 +1,85 @@ +/* + * 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.db.marshal; + +import java.nio.ByteBuffer; + +import org.junit.Assert; +import org.junit.Test; + +public class ByteBufferAccessorTest +{ + private static final ValueAccessor bbAccessor = ByteBufferAccessor.instance; + private static final ValueAccessor baAccessor = ByteArrayAccessor.instance; + + private static byte[] array(int start, int size) + { + assert Byte.MIN_VALUE <= start && start <= Byte.MAX_VALUE; + assert (start + size) <= Byte.MAX_VALUE; + byte[] a = new byte[size]; + for (int i=0; i void testCopyFromOffsets(ValueAccessor dstAccessor) + { + ByteBuffer src = ByteBuffer.wrap(array(0, 10)); + src.position(5); + Assert.assertEquals(5, src.remaining()); + + V dst = dstAccessor.allocate(5); + bbAccessor.copyTo(src, 0, dst, dstAccessor, 0, 5); + Assert.assertArrayEquals(dstAccessor.getClass().getSimpleName(), + array(5, 5), dstAccessor.toArray(dst)); + } + + /** + * Test byte buffers with position > 0 are copied correctly + */ + @Test + public void testCopyFromOffets() + { + for (ValueAccessor accessor : ValueAccessors.ACCESSORS) + testCopyFromOffsets(accessor); + } + + private void testCopyToOffsets(ValueAccessor srcAccessor) + { + byte[] value = array(5, 5); + V src = srcAccessor.allocate(5); + baAccessor.copyTo(value, 0, src, srcAccessor, 0, value.length); + + byte[] actual = new byte[10]; + ByteBuffer bb = ByteBuffer.wrap(actual); + bb.position(5); + srcAccessor.copyTo(src, 0, bb, bbAccessor, 0, value.length); + + byte[] expected = new byte[10]; + System.arraycopy(value, 0, expected, 5, 5); + Assert.assertArrayEquals(srcAccessor.getClass().getSimpleName(), expected, actual); + } + + @Test + public void testCopyToOffsets() + { + for (ValueAccessor accessor : ValueAccessors.ACCESSORS) + testCopyToOffsets(accessor); + } +} diff --git a/test/unit/org/apache/cassandra/db/marshal/CollectionTypesTest.java b/test/unit/org/apache/cassandra/db/marshal/CollectionTypesTest.java new file mode 100644 index 0000000000..971af76ec8 --- /dev/null +++ b/test/unit/org/apache/cassandra/db/marshal/CollectionTypesTest.java @@ -0,0 +1,124 @@ +/* + * 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.db.marshal; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.Set; + +import org.junit.Assert; +import org.junit.Test; + +import org.apache.cassandra.cql3.CQL3Type; +import org.apache.cassandra.transport.ProtocolVersion; + +import static org.apache.cassandra.db.marshal.ValueAccessors.ACCESSORS; + +public class CollectionTypesTest +{ + interface TypeFactory { T createType(AbstractType keyType, AbstractType valType); } + interface ValueFactory { T createValue(ValueGenerator keyGen, ValueGenerator valGen, int size, Random random); } + + static void testSerializationDeserialization(TypeFactory typeFactory, ValueFactory valueFactory, ValueGenerator keyType) + { + for (ValueGenerator valueType : ValueGenerator.GENERATORS) + { + CT type = typeFactory.createType(keyType != null ? keyType.getType() : null, valueType.getType()); + CQL3Type.Collection cql3Type = new CQL3Type.Collection(type); + + for (int i=0; i<500; i++) + { + Random random = new Random(i); + int size = random.nextInt(1000); + T expected = valueFactory.createValue(keyType, valueType, size, random); + + for (ValueAccessor srcAccessor : ACCESSORS) + { + ByteBuffer srcBuffer = type.decompose(expected); + Object srcBytes = srcAccessor.convert(srcBuffer, ByteBufferAccessor.instance); + String srcString = type.getString(srcBytes, srcAccessor); + + for (ValueAccessor dstAccessor : ACCESSORS) + { + Object dstBytes = dstAccessor.convert(srcBytes, srcAccessor); + String dstString = type.getString(dstBytes, dstAccessor); + T composed = (T) type.compose(dstBytes, dstAccessor); + Assert.assertEquals(expected, composed); + ValueAccessors.assertDataEquals(srcBytes, srcAccessor, dstBytes, dstAccessor); + Assert.assertEquals(srcString, dstString); + } + } + } + } + } + + static void testSerializationDeserialization(TypeFactory typeFactory, ValueFactory valueFactory) + { + for (ValueGenerator keyType : ValueGenerator.GENERATORS) + testSerializationDeserialization(typeFactory, valueFactory, keyType); + + } + + private static List randomList(ValueGenerator keyGen, ValueGenerator valGen, int size, Random random) + { + List list = new ArrayList<>(); + for (int k=0; k ListType.getInstance(v, false), CollectionTypesTest::randomList, null); + } + + private static Map randomMap(ValueGenerator keyGen, ValueGenerator valGen, int size, Random random) + { + Map map = new HashMap<>(); + for (int k=0; k MapType.getInstance(k, v, false), CollectionTypesTest::randomMap); + } + + private static Set randomSet(ValueGenerator keyGen, ValueGenerator valGen, int size, Random random) + { + Set set = new HashSet<>(); + for (int k=0; k SetType.getInstance(v, false), CollectionTypesTest::randomSet, null); + } +} diff --git a/test/unit/org/apache/cassandra/db/marshal/CompositeAndTupleTypesTest.java b/test/unit/org/apache/cassandra/db/marshal/CompositeAndTupleTypesTest.java new file mode 100644 index 0000000000..178c291019 --- /dev/null +++ b/test/unit/org/apache/cassandra/db/marshal/CompositeAndTupleTypesTest.java @@ -0,0 +1,138 @@ +/* + * 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.db.marshal; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import org.junit.Assert; +import org.junit.Test; + +import org.apache.cassandra.cql3.FieldIdentifier; +import org.apache.cassandra.utils.ByteBufferUtil; + +import static org.apache.cassandra.db.marshal.ValueAccessors.ACCESSORS; + +public class CompositeAndTupleTypesTest +{ + interface TypeFactory { T createType(List> types); } + interface ValueCombiner { V combine(ValueAccessor accessor, V[] values); } + + public static Object[] createValues(ValueGenerator[] generators, Random random) + { + Object[] values = new Object[generators.length]; + for (int i=0; i) generators[i].getType()).decompose(values[i]); + } + return decomposed; + } + + public static D[] convert(S[] src, ValueAccessor srcAccessor, ValueAccessor dstAccessor) + { + D[] dst = dstAccessor.createArray(src.length); + for (int i=0; i Object[] compose(ValueGenerator[] generators, V[] values, ValueAccessor accessor) + { + assert generators.length == values.length; + + Object[] composed = new Object[generators.length]; + for (int i=0; i) generators[i].getType()).compose(values[i], accessor); + } + return composed; + } + + public void testSerializationDeserialization(TypeFactory typeFactory, ValueCombiner combiner) + { + for (int i=0; i<100; i++) + { + Random random = new Random(i); + ValueGenerator[] generators = ValueGenerator.randomGenerators(random, 100); + AT type = typeFactory.createType(ValueGenerator.toTypes(generators)); + + for (int j=0; j<100; j++) + { + Object[] expected = createValues(generators, random); + for (ValueAccessor srcAccessor : ACCESSORS) + { + ByteBuffer[] srcBuffers = decompose(generators, expected); + Object[] srcValues = convert(srcBuffers, ByteBufferAccessor.instance, srcAccessor); + Object srcJoined = combiner.combine(srcAccessor, srcValues); + String srcString = type.getString(srcJoined, srcAccessor); + + for (ValueAccessor dstAccessor : ACCESSORS) + { + // convert data types and deserialize with + Object[] dstValues = convert(srcValues, srcAccessor, dstAccessor); + Object dstJoined = combiner.combine(dstAccessor, dstValues); + String dstString = type.getString(dstJoined, dstAccessor); + + Object[] composed = compose(generators, dstValues, dstAccessor); + Assert.assertArrayEquals(expected, composed); + ValueAccessors.assertDataEquals(srcJoined, srcAccessor, dstJoined, dstAccessor); + Assert.assertEquals(srcString, dstString); + } + } + } + } + } + + @Test + public void tuple() + { + testSerializationDeserialization(TupleType::new, TupleType::buildValue); + } + + @Test + public void userType() + { + TypeFactory factory = types -> { + List names = new ArrayList<>(types.size()); + for (int i=0; i c, String r) throws CharacterCodingException { - assert ByteBufferUtil.string(c.value()).equals(r) : "Expected: {" + ByteBufferUtil.string(c.value()) + "} got: {" + r + "}"; + assert ByteBufferUtil.string(c.buffer()).equals(r) : "Expected: {" + ByteBufferUtil.string(c.buffer()) + "} got: {" + r + "}"; } @Test @@ -272,7 +272,7 @@ public class CompositeTypeTest for (int i = 0; i < input.length; i++) bbs[i] = UTF8Type.instance.fromString(input[i]); - ByteBuffer value = comp.fromString(comp.getString(CompositeType.build(bbs))); + ByteBuffer value = comp.fromString(comp.getString(CompositeType.build(ByteBufferAccessor.instance, bbs))); ByteBuffer[] splitted = comp.split(value); for (int i = 0; i < splitted.length; i++) assertEquals(input[i], UTF8Type.instance.getString(splitted[i])); diff --git a/test/unit/org/apache/cassandra/db/marshal/DynamicCompositeTypeTest.java b/test/unit/org/apache/cassandra/db/marshal/DynamicCompositeTypeTest.java index 32187eda9c..9f8eec3c21 100644 --- a/test/unit/org/apache/cassandra/db/marshal/DynamicCompositeTypeTest.java +++ b/test/unit/org/apache/cassandra/db/marshal/DynamicCompositeTypeTest.java @@ -214,9 +214,9 @@ public class DynamicCompositeTypeTest compareValues(iter.next().getCell(cdef), "cname4"); compareValues(iter.next().getCell(cdef), "cname5"); } - private void compareValues(Cell c, String r) throws CharacterCodingException + private void compareValues(Cell c, String r) throws CharacterCodingException { - assert ByteBufferUtil.string(c.value()).equals(r) : "Expected: {" + ByteBufferUtil.string(c.value()) + "} got: {" + r + "}"; + assert ByteBufferUtil.string(c.buffer()).equals(r) : "Expected: {" + ByteBufferUtil.string(c.buffer()) + "} got: {" + r + "}"; } @Test diff --git a/test/unit/org/apache/cassandra/db/marshal/EmptyTypeTest.java b/test/unit/org/apache/cassandra/db/marshal/EmptyTypeTest.java index b3626668e2..fd72c92b28 100644 --- a/test/unit/org/apache/cassandra/db/marshal/EmptyTypeTest.java +++ b/test/unit/org/apache/cassandra/db/marshal/EmptyTypeTest.java @@ -46,12 +46,12 @@ public class EmptyTypeTest { DataInputPlus input = Mockito.mock(DataInputPlus.class); - ByteBuffer buffer = EmptyType.instance.readValue(input); + ByteBuffer buffer = EmptyType.instance.readBuffer(input); assertThat(buffer) .isNotNull() .matches(b -> !b.hasRemaining()); - buffer = EmptyType.instance.readValue(input, 42); + buffer = EmptyType.instance.readBuffer(input, 42); assertThat(buffer) .isNotNull() .matches(b -> !b.hasRemaining()); diff --git a/test/unit/org/apache/cassandra/db/marshal/ValueAccessorTest.java b/test/unit/org/apache/cassandra/db/marshal/ValueAccessorTest.java new file mode 100644 index 0000000000..49851e93bb --- /dev/null +++ b/test/unit/org/apache/cassandra/db/marshal/ValueAccessorTest.java @@ -0,0 +1,132 @@ +/* + * 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.db.marshal; + +import java.nio.ByteBuffer; +import java.util.Arrays; +import java.util.Random; + +import com.google.common.primitives.Shorts; +import org.junit.Assert; +import org.junit.Test; + +import org.apache.cassandra.utils.ByteArrayUtil; +import org.apache.cassandra.utils.ByteBufferUtil; + +import static org.apache.cassandra.db.marshal.ValueAccessors.ACCESSORS; + +public class ValueAccessorTest +{ + private static byte[] randomBytes(int minSize, int maxSize, Random random) + { + int size = random.nextInt(maxSize - minSize + 1) + minSize; + byte[] bytes = new byte[size]; + random.nextBytes(bytes); + return bytes; + } + + private static ValueAccessor nextAccessor(Random random) + { + return ACCESSORS[random.nextInt(ACCESSORS.length)]; + } + + private static void testHashCodeAndEquals(int seed, ValueAccessor accessor1, ValueAccessor accessor2, Random random) + { + byte[] rawBytes = randomBytes(2, 200, random); + int sliceOffset = random.nextInt(rawBytes.length); + int sliceSize = random.nextInt(rawBytes.length - sliceOffset); + V1 value1 = accessor1.slice(accessor1.valueOf(rawBytes), sliceOffset, sliceSize); + V2 value2 = accessor2.slice(accessor2.valueOf(rawBytes), sliceOffset, sliceSize); + + Assert.assertTrue(ValueAccessor.equals(value1, accessor1, value2, accessor2)); + + int hash1 = accessor1.hashCode(value1); + int hash2 = accessor2.hashCode(value2); + if (hash1 != hash2) + throw new AssertionError(String.format("%s and %s produced inconsistency hash codes for seed %s (%s != %s)", + accessor1.getClass().getSimpleName(), accessor2.getClass().getSimpleName(), + seed, hash1, hash2)); + + byte[] array1 = accessor1.toArray(value1); + byte[] array2 = accessor2.toArray(value2); + if (!Arrays.equals(array1, array2)) + throw new AssertionError(String.format("%s and %s produced inconsistent byte arrays for seed %s (%s != %s)", + accessor1.getClass().getSimpleName(), accessor2.getClass().getSimpleName(), + seed, ByteArrayUtil.bytesToHex(array1), ByteArrayUtil.bytesToHex(array2))); + + ByteBuffer buffer1 = accessor1.toBuffer(value1); + ByteBuffer buffer2 = accessor2.toBuffer(value2); + if (!buffer1.equals(buffer2)) + throw new AssertionError(String.format("%s and %s produced inconsistent byte buffers for seed %s (%s != %s)", + accessor1.getClass().getSimpleName(), accessor2.getClass().getSimpleName(), + seed, ByteBufferUtil.bytesToHex(buffer1), ByteBufferUtil.bytesToHex(buffer1))); + + } + + private static void testHashCodeAndEquals(int seed) + { + Random random = new Random(seed); + testHashCodeAndEquals(seed, nextAccessor(random), nextAccessor(random), random); + } + + /** + * Identical data should yield identical hashcodes even if the underlying format is different + */ + @Test + public void testHashCodeAndEquals() + { + for (int i=0; i<10000; i++) + testHashCodeAndEquals(i); + } + + private static void testTypeConversion(int seed, ValueAccessor accessor, Random random) + { + String msg = accessor.getClass().getSimpleName() + " seed: " + seed; + byte[] b = new byte[2]; + random.nextBytes(b); + Assert.assertEquals(msg, b[0], accessor.toByte(accessor.valueOf(b[0]))); + Assert.assertArrayEquals(msg, b, accessor.toArray(accessor.valueOf(b))); + + short s = Shorts.fromBytes(b[0], b[1]); + Assert.assertEquals(msg, s, accessor.toShort(accessor.valueOf(s))); + + int i = random.nextInt(); + Assert.assertEquals(msg, i, accessor.toInt(accessor.valueOf(i))); + + long l = random.nextLong(); + Assert.assertEquals(msg, l, accessor.toLong(accessor.valueOf(l))); + + float f = random.nextFloat(); + Assert.assertEquals(msg, f, accessor.toFloat(accessor.valueOf(f)), 0.000002); + + double d = random.nextDouble(); + Assert.assertEquals(msg, d, accessor.toDouble(accessor.valueOf(d)), 0.0000002); + } + + @Test + public void testTypeConversion() + { + for (int i=0; i<10000; i++) + { + Random random = new Random(i); + for (ValueAccessor accessor: ACCESSORS) + testTypeConversion(i, accessor, random); + } + } +} diff --git a/test/unit/org/apache/cassandra/db/marshal/ValueAccessors.java b/test/unit/org/apache/cassandra/db/marshal/ValueAccessors.java new file mode 100644 index 0000000000..e04de761e8 --- /dev/null +++ b/test/unit/org/apache/cassandra/db/marshal/ValueAccessors.java @@ -0,0 +1,62 @@ +/* + * 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.db.marshal; + +import java.nio.ByteBuffer; + +public class ValueAccessors +{ + public static final ValueAccessor[] ACCESSORS = new ValueAccessor[]{ ByteBufferAccessor.instance, ByteArrayAccessor.instance }; + + public static void assertDataEquals(V1 expected, ValueAccessor expectedAccessor, V2 actual, ValueAccessor actualAccessor) + { + if (expectedAccessor.compare(expected, actual, actualAccessor) != 0) + { + throw new AssertionError(String.format("%s != %s", expectedAccessor.toHex(expected), actualAccessor.toHex(actual))); + } + } + + public static void assertDataNotEquals(V1 expected, ValueAccessor expectedAccessor, V2 actual, ValueAccessor actualAccessor) + { + if (expectedAccessor.compare(expected, actual, actualAccessor) == 0) + { + throw new AssertionError(String.format("unexpected data equality: %s", expectedAccessor.toHex(expected))); + } + } + + private static ValueAccessor getAccessor(Object o) + { + if (o instanceof ByteBuffer) + return ByteBufferAccessor.instance; + if (o instanceof byte[]) + return ByteArrayAccessor.instance; + + throw new AssertionError("Unhandled type " + o.getClass().getName()); + } + + public static void assertDataEquals(Object expected, Object actual) + { + assertDataEquals(expected, getAccessor(expected), actual, getAccessor(actual)); + } + + public static void assertDataNotEquals(Object expected, Object actual) + { + assertDataNotEquals(expected, getAccessor(expected), actual, getAccessor(actual)); + } +} diff --git a/test/unit/org/apache/cassandra/db/marshal/ValueGenerator.java b/test/unit/org/apache/cassandra/db/marshal/ValueGenerator.java new file mode 100644 index 0000000000..79f6fdfacd --- /dev/null +++ b/test/unit/org/apache/cassandra/db/marshal/ValueGenerator.java @@ -0,0 +1,95 @@ +/* + * 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.db.marshal; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; +import java.util.function.Function; + +import com.google.common.collect.ImmutableList; + +public class ValueGenerator +{ + public static final ValueGenerator INTEGER = new ValueGenerator(Int32Type.instance, Random::nextInt); + public static final ValueGenerator BLOB = new ValueGenerator(BytesType.instance, ValueGenerator::randomBytes); + public static final ValueGenerator TEXT = new ValueGenerator(UTF8Type.instance, ValueGenerator::randomString); + public static final List GENERATORS = ImmutableList.of(INTEGER, BLOB); + + private final AbstractType type; + private final Function generator; + + public static ByteBuffer randomBytes(Random random) + { + byte[] bytes = new byte[random.nextInt(100)]; + random.nextBytes(bytes); + return ByteBuffer.wrap(bytes); + } + + private static final char[] CHARS = "abcdefghijklmnopqrstuvwxyz0123456789".toCharArray(); + + public static String randomString(Random random) + { + char[] chars = new char[random.nextInt(100)]; + for (int i=0; i type, Function generator) + { + this.type = type; + this.generator = generator; + } + + public AbstractType getType() + { + return type; + } + + public Object nextValue(Random random) + { + return generator.apply(random); + } + + public static ValueGenerator randomGenerator(Random random) + { + return GENERATORS.get(random.nextInt(GENERATORS.size())); + } + + public static List> toTypes(ValueGenerator[] generators) + { + List> types = new ArrayList<>(generators.length); + for (ValueGenerator generator : generators) + types.add(generator.getType()); + return types; + } + + public static ValueGenerator[] randomGenerators(Random random, int maxSize) + { + int size = random.nextInt(maxSize); + ValueGenerator[] generators = new ValueGenerator[size]; + for (int i=0; i prefix) + { + ByteBuffer[] values = new ByteBuffer[prefix.size()]; + for (int i = 0; i < prefix.size(); i++) + values[i] = prefix.get(i); + return BufferClusteringBound.inclusiveStartOf(values); + } + + public static BufferClusteringBound exclusiveStartOf(ClusteringPrefix prefix) + { + ByteBuffer[] values = new ByteBuffer[prefix.size()]; + for (int i = 0; i < prefix.size(); i++) + values[i] = prefix.get(i); + return BufferClusteringBound.exclusiveStartOf(values); + } + + public static BufferClusteringBound inclusiveEndOf(ClusteringPrefix prefix) + { + ByteBuffer[] values = new ByteBuffer[prefix.size()]; + for (int i = 0; i < prefix.size(); i++) + values[i] = prefix.get(i); + return BufferClusteringBound.inclusiveEndOf(values); + } + private List generateRows() { List content = new ArrayList<>(); @@ -98,7 +123,7 @@ public class PartitionImplementationTest return content; // not sorted } - Row makeRow(Clustering clustering, String colValue) + Row makeRow(Clustering clustering, String colValue) { ColumnMetadata defCol = metadata.getColumn(new ColumnIdentifier("col", true)); Row.Builder row = BTreeRow.unsortedBuilder(); @@ -142,9 +167,9 @@ public class PartitionImplementationTest int start = rand.nextInt(KEY_RANGE); DeletionTime dt = new DeletionTime(delTime, delTime); - RangeTombstoneMarker open = RangeTombstoneBoundMarker.inclusiveOpen(false, clustering(start).getRawValues(), dt); + RangeTombstoneMarker open = RangeTombstoneBoundMarker.inclusiveOpen(false, clustering(start), dt); int end = start + rand.nextInt((KEY_RANGE - start) / 4 + 1); - RangeTombstoneMarker close = RangeTombstoneBoundMarker.inclusiveClose(false, clustering(end).getRawValues(), dt); + RangeTombstoneMarker close = RangeTombstoneBoundMarker.inclusiveClose(false, clustering(end), dt); markers.add(open); markers.add(close); } @@ -210,9 +235,9 @@ public class PartitionImplementationTest return content; } - private Clustering clustering(int i) + private Clustering clustering(int i) { - return metadata.comparator.make(String.format("Row%06d", i)); + return (Clustering) metadata.comparator.make(String.format("Row%06d", i)); } private void test(Supplier> content, Row staticRow) @@ -257,7 +282,7 @@ public class PartitionImplementationTest // get for (int i=0; i < KEY_RANGE; ++i) { - Clustering cl = clustering(i); + Clustering cl = clustering(i); assertRowsEqual(getRow(sortedContent, cl), partition.getRow(cl)); } @@ -321,7 +346,7 @@ public class PartitionImplementationTest void testSearchIterator(NavigableSet sortedContent, Partition partition, ColumnFilter cf, boolean reversed) { - SearchIterator searchIter = partition.searchIterator(cf, reversed); + SearchIterator, Row> searchIter = partition.searchIterator(cf, reversed); int pos = reversed ? KEY_RANGE : 0; int mul = reversed ? -1 : 1; boolean started = false; @@ -329,7 +354,7 @@ public class PartitionImplementationTest { int skip = rand.nextInt(KEY_RANGE / 10); pos += skip * mul; - Clustering cl = clustering(pos); + Clustering cl = clustering(pos); Row row = searchIter.next(cl); // returns row with deletion, incl. empty row with deletion if (row == null && skip == 0 && started) // allowed to return null if already reported row continue; @@ -351,10 +376,10 @@ public class PartitionImplementationTest int skip = rand.nextInt(KEY_RANGE / 10) * (rand.nextInt(3) + 2 / 3); // increased chance of getting 0 pos += skip; int sz = rand.nextInt(KEY_RANGE / 10) + (skip == 0 ? 1 : 0); // if start is exclusive need at least sz 1 - Clustering start = clustering(pos); + Clustering start = clustering(pos); pos += sz; - Clustering end = clustering(pos); - Slice slice = Slice.make(skip == 0 ? ClusteringBound.exclusiveStartOf(start) : ClusteringBound.inclusiveStartOf(start), ClusteringBound.inclusiveEndOf(end)); + Clustering end = clustering(pos); + Slice slice = Slice.make(skip == 0 ? exclusiveStartOf(start) : inclusiveStartOf(start), inclusiveEndOf(end)); builder.add(slice); } return builder.build(); @@ -446,7 +471,7 @@ public class PartitionImplementationTest assertArrayEquals("Arrays differ. Expected " + a1s + " was " + a2s, a1, a2); } - private Row getRow(NavigableSet sortedContent, Clustering cl) + private Row getRow(NavigableSet sortedContent, Clustering cl) { NavigableSet nexts = sortedContent.tailSet(cl, true); if (nexts.isEmpty()) diff --git a/test/unit/org/apache/cassandra/db/partitions/PurgeFunctionTest.java b/test/unit/org/apache/cassandra/db/partitions/PurgeFunctionTest.java index ce569b5453..ba6a9dba0d 100644 --- a/test/unit/org/apache/cassandra/db/partitions/PurgeFunctionTest.java +++ b/test/unit/org/apache/cassandra/db/partitions/PurgeFunctionTest.java @@ -240,7 +240,7 @@ public final class PurgeFunctionTest ByteBuffer[] clusteringByteBuffers = new ByteBuffer[] { decompose(metadata.clusteringColumns().get(0).type, clusteringValue) }; - return new RangeTombstoneBoundMarker(ClusteringBound.create(kind, clusteringByteBuffers), + return new RangeTombstoneBoundMarker(BufferClusteringBound.create(kind, clusteringByteBuffers), new DeletionTime(timestamp, localDeletionTime)); } @@ -254,7 +254,7 @@ public final class PurgeFunctionTest ByteBuffer[] clusteringByteBuffers = new ByteBuffer[] { decompose(metadata.clusteringColumns().get(0).type, clusteringValue) }; - return new RangeTombstoneBoundaryMarker(ClusteringBoundary.create(kind, clusteringByteBuffers), + return new RangeTombstoneBoundaryMarker(BufferClusteringBoundary.create(kind, clusteringByteBuffers), new DeletionTime(closeTimestamp, closeLocalDeletionTime), new DeletionTime(openTimestamp, openDeletionTime)); } diff --git a/test/unit/org/apache/cassandra/db/rows/RowAndDeletionMergeIteratorTest.java b/test/unit/org/apache/cassandra/db/rows/RowAndDeletionMergeIteratorTest.java index f590d36a31..c90694d444 100644 --- a/test/unit/org/apache/cassandra/db/rows/RowAndDeletionMergeIteratorTest.java +++ b/test/unit/org/apache/cassandra/db/rows/RowAndDeletionMergeIteratorTest.java @@ -128,7 +128,7 @@ public class RowAndDeletionMergeIteratorTest assertRtMarker(iterator.next(), ClusteringPrefix.Kind.INCL_START_BOUND, 4); assertTrue(iterator.hasNext()); - assertRtMarker(iterator.next(), ClusteringBound.TOP); + assertRtMarker(iterator.next(), BufferClusteringBound.TOP); assertFalse(iterator.hasNext()); } @@ -146,7 +146,7 @@ public class RowAndDeletionMergeIteratorTest UnfilteredRowIterator iterator = createMergeIterator(rowIterator, rangeTombstoneIterator, false); assertTrue(iterator.hasNext()); - assertRtMarker(iterator.next(), ClusteringBound.BOTTOM); + assertRtMarker(iterator.next(), BufferClusteringBound.BOTTOM); assertTrue(iterator.hasNext()); assertRtMarker(iterator.next(), ClusteringPrefix.Kind.INCL_END_BOUND, 0); @@ -191,7 +191,7 @@ public class RowAndDeletionMergeIteratorTest assertRtMarker(iterator.next(), ClusteringPrefix.Kind.EXCL_START_BOUND, 2); assertTrue(iterator.hasNext()); - assertRtMarker(iterator.next(), ClusteringBound.TOP); + assertRtMarker(iterator.next(), BufferClusteringBound.TOP); assertFalse(iterator.hasNext()); } @@ -210,7 +210,7 @@ public class RowAndDeletionMergeIteratorTest UnfilteredRowIterator iterator = createMergeIterator(rowIterator, rangeTombstoneIterator, false); assertTrue(iterator.hasNext()); - assertRtMarker(iterator.next(), ClusteringBound.BOTTOM); + assertRtMarker(iterator.next(), BufferClusteringBound.BOTTOM); assertTrue(iterator.hasNext()); assertRtMarker(iterator.next(), ClusteringPrefix.Kind.INCL_END_BOUND, 0); @@ -225,7 +225,7 @@ public class RowAndDeletionMergeIteratorTest assertRtMarker(iterator.next(), ClusteringPrefix.Kind.EXCL_START_BOUND, 2); assertTrue(iterator.hasNext()); - assertRtMarker(iterator.next(), ClusteringBound.TOP); + assertRtMarker(iterator.next(), BufferClusteringBound.TOP); assertFalse(iterator.hasNext()); } @@ -253,13 +253,13 @@ public class RowAndDeletionMergeIteratorTest UnfilteredRowIterator iterator = createMergeIterator(rowIterator, rangeTombstoneIterator, false); assertTrue(iterator.hasNext()); - assertRtMarker(iterator.next(), ClusteringBound.BOTTOM); + assertRtMarker(iterator.next(), BufferClusteringBound.BOTTOM); assertTrue(iterator.hasNext()); assertRtMarker(iterator.next(), ClusteringPrefix.Kind.INCL_END_EXCL_START_BOUNDARY, 2); assertTrue(iterator.hasNext()); - assertRtMarker(iterator.next(), ClusteringBound.TOP); + assertRtMarker(iterator.next(), BufferClusteringBound.TOP); assertFalse(iterator.hasNext()); } @@ -280,13 +280,13 @@ public class RowAndDeletionMergeIteratorTest UnfilteredRowIterator iterator = createMergeIterator(rowIterator, rangeTombstoneIterator, false); assertTrue(iterator.hasNext()); - assertRtMarker(iterator.next(), ClusteringBound.BOTTOM); + assertRtMarker(iterator.next(), BufferClusteringBound.BOTTOM); assertTrue(iterator.hasNext()); assertRtMarker(iterator.next(), ClusteringPrefix.Kind.EXCL_END_INCL_START_BOUNDARY, 2); assertTrue(iterator.hasNext()); - assertRtMarker(iterator.next(), ClusteringBound.TOP); + assertRtMarker(iterator.next(), BufferClusteringBound.TOP); assertFalse(iterator.hasNext()); } @@ -301,7 +301,7 @@ public class RowAndDeletionMergeIteratorTest UnfilteredRowIterator iterator = createMergeIterator(rowIterator, rangeTombstoneIterator, false); assertTrue(iterator.hasNext()); - assertRtMarker(iterator.next(), ClusteringBound.BOTTOM); + assertRtMarker(iterator.next(), BufferClusteringBound.BOTTOM); assertTrue(iterator.hasNext()); assertRow(iterator.next(), 0); @@ -369,7 +369,7 @@ public class RowAndDeletionMergeIteratorTest } } - private void assertRtMarker(Unfiltered unfiltered, ClusteringBoundOrBoundary bound) + private void assertRtMarker(Unfiltered unfiltered, ClusteringBoundOrBoundary bound) { assertEquals(Unfiltered.Kind.RANGE_TOMBSTONE_MARKER, unfiltered.kind()); assertEquals(bound, unfiltered.clustering()); @@ -427,35 +427,35 @@ public class RowAndDeletionMergeIteratorTest update.add(BTreeRow.singleCellRow(update.metadata().comparator.make(col1), makeCell(defA, a, 0))); } - private Cell makeCell(ColumnMetadata columnMetadata, int value, long timestamp) + private Cell makeCell(ColumnMetadata columnMetadata, int value, long timestamp) { return BufferCell.live(columnMetadata, timestamp, ((AbstractType) columnMetadata.cellValueType()).decompose(value)); } private static RangeTombstone atLeast(int start, long tstamp, int delTime) { - return new RangeTombstone(Slice.make(ClusteringBound.inclusiveStartOf(bb(start)), ClusteringBound.TOP), new DeletionTime(tstamp, delTime)); + return new RangeTombstone(Slice.make(BufferClusteringBound.inclusiveStartOf(bb(start)), BufferClusteringBound.TOP), new DeletionTime(tstamp, delTime)); } private static RangeTombstone atMost(int end, long tstamp, int delTime) { - return new RangeTombstone(Slice.make(ClusteringBound.BOTTOM, ClusteringBound.inclusiveEndOf(bb(end))), new DeletionTime(tstamp, delTime)); + return new RangeTombstone(Slice.make(BufferClusteringBound.BOTTOM, BufferClusteringBound.inclusiveEndOf(bb(end))), new DeletionTime(tstamp, delTime)); } private static RangeTombstone lessThan(int end, long tstamp, int delTime) { - return new RangeTombstone(Slice.make(ClusteringBound.BOTTOM, ClusteringBound.exclusiveEndOf(bb(end))), new DeletionTime(tstamp, delTime)); + return new RangeTombstone(Slice.make(BufferClusteringBound.BOTTOM, BufferClusteringBound.exclusiveEndOf(bb(end))), new DeletionTime(tstamp, delTime)); } private static RangeTombstone greaterThan(int start, long tstamp, int delTime) { - return new RangeTombstone(Slice.make(ClusteringBound.exclusiveStartOf(bb(start)), ClusteringBound.TOP), new DeletionTime(tstamp, delTime)); + return new RangeTombstone(Slice.make(BufferClusteringBound.exclusiveStartOf(bb(start)), BufferClusteringBound.TOP), new DeletionTime(tstamp, delTime)); } private static RangeTombstone rt(int start, boolean startInclusive, int end, boolean endInclusive, long tstamp, int delTime) { - ClusteringBound startBound = startInclusive ? ClusteringBound.inclusiveStartOf(bb(start)) : ClusteringBound.exclusiveStartOf(bb(start)); - ClusteringBound endBound = endInclusive ? ClusteringBound.inclusiveEndOf(bb(end)) : ClusteringBound.exclusiveEndOf(bb(end)); + ClusteringBound startBound = startInclusive ? BufferClusteringBound.inclusiveStartOf(bb(start)) : BufferClusteringBound.exclusiveStartOf(bb(start)); + ClusteringBound endBound = endInclusive ? BufferClusteringBound.inclusiveEndOf(bb(end)) : BufferClusteringBound.exclusiveEndOf(bb(end)); return new RangeTombstone(Slice.make(startBound, endBound), new DeletionTime(tstamp, delTime)); } diff --git a/test/unit/org/apache/cassandra/db/rows/RowBuilder.java b/test/unit/org/apache/cassandra/db/rows/RowBuilder.java index 21522a509b..aa2c5a738b 100644 --- a/test/unit/org/apache/cassandra/db/rows/RowBuilder.java +++ b/test/unit/org/apache/cassandra/db/rows/RowBuilder.java @@ -34,8 +34,8 @@ import org.apache.cassandra.utils.Pair; */ public class RowBuilder implements Row.Builder { - public List cells = new LinkedList<>(); - public Clustering clustering = null; + public List> cells = new LinkedList<>(); + public Clustering clustering = null; public LivenessInfo livenessInfo = null; public Row.Deletion deletionTime = null; public List> complexDeletions = new LinkedList<>(); @@ -46,7 +46,7 @@ public class RowBuilder implements Row.Builder throw new UnsupportedOperationException(); } - public void addCell(Cell cell) + public void addCell(Cell cell) { cells.add(cell); } @@ -56,13 +56,13 @@ public class RowBuilder implements Row.Builder throw new UnsupportedOperationException(); } - public void newRow(Clustering clustering) + public void newRow(Clustering clustering) { assert this.clustering == null; this.clustering = clustering; } - public Clustering clustering() + public Clustering clustering() { return clustering; } diff --git a/test/unit/org/apache/cassandra/db/rows/RowsTest.java b/test/unit/org/apache/cassandra/db/rows/RowsTest.java index 00a9af4522..13045da382 100644 --- a/test/unit/org/apache/cassandra/db/rows/RowsTest.java +++ b/test/unit/org/apache/cassandra/db/rows/RowsTest.java @@ -53,7 +53,7 @@ public class RowsTest private static final TableMetadata kcvm; private static final ColumnMetadata v; private static final ColumnMetadata m; - private static final Clustering c1; + private static final Clustering c1; static { @@ -127,16 +127,16 @@ public class RowsTest private static class DiffListener implements RowDiffListener { int updates = 0; - Clustering clustering = null; + Clustering clustering = null; - private void updateClustering(Clustering c) + private void updateClustering(Clustering c) { assert clustering == null || clustering == c; clustering = c; } - List> cells = new LinkedList<>(); - public void onCell(int i, Clustering clustering, Cell merged, Cell original) + List>> cells = new LinkedList<>(); + public void onCell(int i, Clustering clustering, Cell merged, Cell original) { updateClustering(clustering); cells.add(MergedPair.create(i, merged, original)); @@ -144,7 +144,7 @@ public class RowsTest } List> liveness = new LinkedList<>(); - public void onPrimaryKeyLivenessInfo(int i, Clustering clustering, LivenessInfo merged, LivenessInfo original) + public void onPrimaryKeyLivenessInfo(int i, Clustering clustering, LivenessInfo merged, LivenessInfo original) { updateClustering(clustering); liveness.add(MergedPair.create(i, merged, original)); @@ -152,7 +152,7 @@ public class RowsTest } List> deletions = new LinkedList<>(); - public void onDeletion(int i, Clustering clustering, Row.Deletion merged, Row.Deletion original) + public void onDeletion(int i, Clustering clustering, Row.Deletion merged, Row.Deletion original) { updateClustering(clustering); deletions.add(MergedPair.create(i, merged, original)); @@ -160,7 +160,7 @@ public class RowsTest } Map>> complexDeletions = new HashMap<>(); - public void onComplexDeletion(int i, Clustering clustering, ColumnMetadata column, DeletionTime merged, DeletionTime original) + public void onComplexDeletion(int i, Clustering clustering, ColumnMetadata column, DeletionTime merged, DeletionTime original) { updateClustering(clustering); if (!complexDeletions.containsKey(column)) complexDeletions.put(column, new LinkedList<>()); @@ -171,8 +171,8 @@ public class RowsTest public static class StatsCollector implements PartitionStatisticsCollector { - List cells = new LinkedList<>(); - public void update(Cell cell) + List> cells = new LinkedList<>(); + public void update(Cell cell) { cells.add(cell); } @@ -208,7 +208,7 @@ public class RowsTest return now * 1000000L; } - private static Row.Builder createBuilder(Clustering c, int now, ByteBuffer vVal, ByteBuffer mKey, ByteBuffer mVal) + private static Row.Builder createBuilder(Clustering c, int now, ByteBuffer vVal, ByteBuffer mKey, ByteBuffer mVal) { long ts = secondToTs(now); Row.Builder builder = BTreeRow.unsortedBuilder(); @@ -238,7 +238,7 @@ public class RowsTest originalBuilder.addPrimaryKeyLivenessInfo(liveness); DeletionTime complexDeletion = new DeletionTime(ts-1, now); originalBuilder.addComplexDeletion(m, complexDeletion); - List expectedCells = Lists.newArrayList(BufferCell.live(v, secondToTs(now), BB1), + List> expectedCells = Lists.newArrayList(BufferCell.live(v, secondToTs(now), BB1), BufferCell.live(m, secondToTs(now), BB1, CellPath.create(BB1)), BufferCell.live(m, secondToTs(now), BB2, CellPath.create(BB2))); expectedCells.forEach(originalBuilder::addCell); @@ -267,7 +267,7 @@ public class RowsTest builder.addPrimaryKeyLivenessInfo(liveness); DeletionTime complexDeletion = new DeletionTime(ts-1, now); builder.addComplexDeletion(m, complexDeletion); - List expectedCells = Lists.newArrayList(BufferCell.live(v, ts, BB1), + List> expectedCells = Lists.newArrayList(BufferCell.live(v, ts, BB1), BufferCell.live(m, ts, BB1, CellPath.create(BB1)), BufferCell.live(m, ts, BB2, CellPath.create(BB2))); expectedCells.forEach(builder::addCell); @@ -286,7 +286,7 @@ public class RowsTest } - public static void addExpectedCells(Set> dst, Cell merged, Cell... inputs) + public static void addExpectedCells(Set>> dst, Cell merged, Cell... inputs) { for (int i=0; i r1ExpectedCells = Lists.newArrayList(r1v, r1m1, r1m2); + Cell r1v = BufferCell.live(v, ts1, BB1); + Cell r1m1 = BufferCell.live(m, ts1, BB1, CellPath.create(BB1)); + Cell r1m2 = BufferCell.live(m, ts1, BB2, CellPath.create(BB2)); + List> r1ExpectedCells = Lists.newArrayList(r1v, r1m1, r1m2); r1ExpectedCells.forEach(r1Builder::addCell); @@ -319,11 +319,11 @@ public class RowsTest r2Builder.newRow(c1); LivenessInfo r2Liveness = LivenessInfo.create(ts2, now2); r2Builder.addPrimaryKeyLivenessInfo(r2Liveness); - Cell r2v = BufferCell.live(v, ts2, BB2); - Cell r2m2 = BufferCell.live(m, ts2, BB1, CellPath.create(BB2)); - Cell r2m3 = BufferCell.live(m, ts2, BB2, CellPath.create(BB3)); - Cell r2m4 = BufferCell.live(m, ts2, BB3, CellPath.create(BB4)); - List r2ExpectedCells = Lists.newArrayList(r2v, r2m2, r2m3, r2m4); + Cell r2v = BufferCell.live(v, ts2, BB2); + Cell r2m2 = BufferCell.live(m, ts2, BB1, CellPath.create(BB2)); + Cell r2m3 = BufferCell.live(m, ts2, BB2, CellPath.create(BB3)); + Cell r2m4 = BufferCell.live(m, ts2, BB3, CellPath.create(BB4)); + List> r2ExpectedCells = Lists.newArrayList(r2v, r2m2, r2m3, r2m4); r2ExpectedCells.forEach(r2Builder::addCell); Row.Deletion r2RowDeletion = new Row.Deletion(new DeletionTime(ts1 - 2, now2), false); @@ -341,7 +341,7 @@ public class RowsTest Assert.assertEquals(c1, listener.clustering); // check cells - Set> expectedCells = Sets.newHashSet(); + Set>> expectedCells = Sets.newHashSet(); addExpectedCells(expectedCells, r2v, r1v, r2v); // v addExpectedCells(expectedCells, r1m1, r1m1, null); // m[1] addExpectedCells(expectedCells, r2m2, r1m2, r2m2); // m[2] @@ -389,11 +389,11 @@ public class RowsTest r2Builder.addPrimaryKeyLivenessInfo(r2Liveness); DeletionTime r2ComplexDeletion = new DeletionTime(ts2-1, now2); r2Builder.addComplexDeletion(m, r2ComplexDeletion); - Cell r2v = BufferCell.live(v, ts2, BB2); - Cell r2m2 = BufferCell.live(m, ts2, BB1, CellPath.create(BB2)); - Cell r2m3 = BufferCell.live(m, ts2, BB2, CellPath.create(BB3)); - Cell r2m4 = BufferCell.live(m, ts2, BB3, CellPath.create(BB4)); - List r2ExpectedCells = Lists.newArrayList(r2v, r2m2, r2m3, r2m4); + Cell r2v = BufferCell.live(v, ts2, BB2); + Cell r2m2 = BufferCell.live(m, ts2, BB1, CellPath.create(BB2)); + Cell r2m3 = BufferCell.live(m, ts2, BB2, CellPath.create(BB3)); + Cell r2m4 = BufferCell.live(m, ts2, BB3, CellPath.create(BB4)); + List> r2ExpectedCells = Lists.newArrayList(r2v, r2m2, r2m3, r2m4); r2ExpectedCells.forEach(r2Builder::addCell); Row.Deletion r2RowDeletion = new Row.Deletion(new DeletionTime(ts1 - 1, now2), false); @@ -408,7 +408,7 @@ public class RowsTest Assert.assertEquals(c1, listener.clustering); // check cells - Set> expectedCells = Sets.newHashSet(MergedPair.create(0, null, r2v), // v + Set>> expectedCells = Sets.newHashSet(MergedPair.create(0, null, r2v), // v MergedPair.create(0, null, r2m2), // m[2] MergedPair.create(0, null, r2m3), // m[3] MergedPair.create(0, null, r2m4)); // m[4] @@ -443,11 +443,11 @@ public class RowsTest r2Builder.addPrimaryKeyLivenessInfo(r2Liveness); DeletionTime r2ComplexDeletion = new DeletionTime(ts2-1, now2); r2Builder.addComplexDeletion(m, r2ComplexDeletion); - Cell r2v = BufferCell.live(v, ts2, BB2); - Cell r2m2 = BufferCell.live(m, ts2, BB1, CellPath.create(BB2)); - Cell r2m3 = BufferCell.live(m, ts2, BB2, CellPath.create(BB3)); - Cell r2m4 = BufferCell.live(m, ts2, BB3, CellPath.create(BB4)); - List r2ExpectedCells = Lists.newArrayList(r2v, r2m2, r2m3, r2m4); + Cell r2v = BufferCell.live(v, ts2, BB2); + Cell r2m2 = BufferCell.live(m, ts2, BB1, CellPath.create(BB2)); + Cell r2m3 = BufferCell.live(m, ts2, BB2, CellPath.create(BB3)); + Cell r2m4 = BufferCell.live(m, ts2, BB3, CellPath.create(BB4)); + List> r2ExpectedCells = Lists.newArrayList(r2v, r2m2, r2m3, r2m4); r2ExpectedCells.forEach(r2Builder::addCell); Row.Deletion r2RowDeletion = new Row.Deletion(new DeletionTime(ts1 - 1, now2), false); @@ -462,7 +462,7 @@ public class RowsTest Assert.assertEquals(c1, listener.clustering); // check cells - Set> expectedCells = Sets.newHashSet(MergedPair.create(0, r2v, null), // v + Set>> expectedCells = Sets.newHashSet(MergedPair.create(0, r2v, null), // v MergedPair.create(0, r2m2, null), // m[2] MergedPair.create(0, r2m3, null), // m[3] MergedPair.create(0, r2m4, null)); // m[4] @@ -484,8 +484,8 @@ public class RowsTest int now2 = now1 + 1; long ts2 = secondToTs(now2); - Cell expectedVCell = BufferCell.live(v, ts2, BB2); - Cell expectedMCell = BufferCell.live(m, ts2, BB2, CellPath.create(BB1)); + Cell expectedVCell = BufferCell.live(v, ts2, BB2); + Cell expectedMCell = BufferCell.live(m, ts2, BB2, CellPath.create(BB1)); DeletionTime expectedComplexDeletionTime = new DeletionTime(ts2 - 1, now2); Row.Builder updateBuilder = createBuilder(c1, now2, null, null, null); @@ -551,14 +551,14 @@ public class RowsTest } // Creates a dummy cell for a (regular) column for the provided name and without a cellPath. - private static Cell liveCell(ColumnMetadata name) + private static Cell liveCell(ColumnMetadata name) { return liveCell(name, -1); } // Creates a dummy cell for a (regular) column for the provided name. // If path >= 0, the cell will have a CellPath containing path as an Int32Type. - private static Cell liveCell(ColumnMetadata name, int path) + private static Cell liveCell(ColumnMetadata name, int path) { CellPath cp = path < 0 ? null : CellPath.create(ByteBufferUtil.bytes(path)); return new BufferCell(name, 0L, Cell.NO_TTL, Cell.NO_DELETION_TIME, ByteBuffer.allocate(1), cp); @@ -566,10 +566,10 @@ public class RowsTest // Assert that the cells generated by iterating iterable are the cell of cells (in the same order // and with neither more nor less cells). - private static void assertCellOrder(Iterable iterable, Cell... cells) + private static void assertCellOrder(Iterable> iterable, Cell... cells) { int i = 0; - for (Cell actual : iterable) + for (Cell actual : iterable) { Assert.assertFalse(String.format("Got more rows than expected (expecting %d). First unexpected cell is %s", cells.length, actual), i >= cells.length); Assert.assertEquals(cells[i++], actual); @@ -578,11 +578,11 @@ public class RowsTest } // Make a dummy row (empty clustering) with the provided cells, that are assumed to be in order - private static Row makeDummyRow(Cell ... cells) + private static Row makeDummyRow(Cell ... cells) { Row.Builder builder = BTreeRow.sortedBuilder(); builder.newRow(Clustering.EMPTY); - for (Cell cell : cells) + for (Cell cell : cells) builder.addCell(cell); return builder.build(); diff --git a/test/unit/org/apache/cassandra/db/rows/ThrottledUnfilteredIteratorTest.java b/test/unit/org/apache/cassandra/db/rows/ThrottledUnfilteredIteratorTest.java index cc886f1c24..d5e6348d3b 100644 --- a/test/unit/org/apache/cassandra/db/rows/ThrottledUnfilteredIteratorTest.java +++ b/test/unit/org/apache/cassandra/db/rows/ThrottledUnfilteredIteratorTest.java @@ -50,6 +50,7 @@ import org.apache.cassandra.db.ReadCommand; import org.apache.cassandra.db.ReadExecutionController; import org.apache.cassandra.db.RegularAndStaticColumns; import org.apache.cassandra.db.RowUpdateBuilder; +import org.apache.cassandra.db.marshal.ByteBufferAccessor; import org.apache.cassandra.db.marshal.Int32Type; import org.apache.cassandra.db.marshal.UTF8Type; import org.apache.cassandra.db.partitions.AbstractUnfilteredPartitionIterator; @@ -160,7 +161,7 @@ public class ThrottledUnfilteredIteratorTest extends CQLTester UnfilteredRowIterator iterator = throttled.next(); assertFalse(throttled.hasNext()); assertFalse(iterator.hasNext()); - assertEquals(Int32Type.instance.getSerializer().deserialize(iterator.staticRow().cells().iterator().next().value()), new Integer(160)); + assertEquals(Int32Type.instance.getSerializer().deserialize(iterator.staticRow().cells().iterator().next().buffer()), new Integer(160)); } // test opt out @@ -319,13 +320,12 @@ public class ThrottledUnfilteredIteratorTest extends CQLTester } else { - ByteBuffer[] byteBuffers = expected.clustering().getRawValues(); RangeTombstoneBoundMarker closeMarker = RangeTombstoneBoundMarker.exclusiveClose(isRevered, - byteBuffers, + expected.clustering(), openDeletionTime); RangeTombstoneBoundMarker nextOpenMarker = RangeTombstoneBoundMarker.inclusiveOpen(isRevered, - byteBuffers, + expected.clustering(), openDeletionTime); assertEquals(closeMarker, data); assertEquals(nextOpenMarker, output.get(index + 1)); @@ -567,35 +567,35 @@ public class ThrottledUnfilteredIteratorTest extends CQLTester } - private static Row createRow(int ck, Cell... columns) + private static Row createRow(int ck, Cell... columns) { return createRow(ck, ck, columns); } - private static Row createRow(int ck1, int ck2, Cell... columns) + private static Row createRow(int ck1, int ck2, Cell... columns) { BTreeRow.Builder builder = new BTreeRow.Builder(true); builder.newRow(Util.clustering(metadata.comparator, ck1, ck2)); - for (Cell cell : columns) + for (Cell cell : columns) builder.addCell(cell); return builder.build(); } - private static Row createStaticRow(Cell... columns) + private static Row createStaticRow(Cell... columns) { Row.Builder builder = new BTreeRow.Builder(true); builder.newRow(Clustering.STATIC_CLUSTERING); - for (Cell cell : columns) + for (Cell cell : columns) builder.addCell(cell); return builder.build(); } - private static Cell createCell(ColumnMetadata metadata, int v) + private static Cell createCell(ColumnMetadata metadata, int v) { return createCell(metadata, v, 100L, BufferCell.NO_DELETION_TIME); } - private static Cell createCell(ColumnMetadata metadata, int v, long timestamp, int localDeletionTime) + private static Cell createCell(ColumnMetadata metadata, int v, long timestamp, int localDeletionTime) { return new BufferCell(metadata, timestamp, diff --git a/test/unit/org/apache/cassandra/db/rows/UnfilteredRowIteratorsMergeTest.java b/test/unit/org/apache/cassandra/db/rows/UnfilteredRowIteratorsMergeTest.java index 7f1b7350ae..ed8e2944dd 100644 --- a/test/unit/org/apache/cassandra/db/rows/UnfilteredRowIteratorsMergeTest.java +++ b/test/unit/org/apache/cassandra/db/rows/UnfilteredRowIteratorsMergeTest.java @@ -239,11 +239,11 @@ public class UnfilteredRowIteratorsMergeTest if (prev != null && curr != null && prev.isClose(false) && curr.isOpen(false) && prev.clustering().invert().equals(curr.clustering())) { // Join. Prefer not to use merger to check its correctness. - ClusteringBound b = ((RangeTombstoneBoundMarker) prev).clustering(); + ClusteringBound b = ((RangeTombstoneBoundMarker) prev).clustering(); ClusteringBoundary boundary = ClusteringBoundary.create(b.isInclusive() - ? ClusteringPrefix.Kind.INCL_END_EXCL_START_BOUNDARY - : ClusteringPrefix.Kind.EXCL_END_INCL_START_BOUNDARY, - b.getRawValues()); + ? ClusteringPrefix.Kind.INCL_END_EXCL_START_BOUNDARY + : ClusteringPrefix.Kind.EXCL_END_INCL_START_BOUNDARY, + b); prev = new RangeTombstoneBoundaryMarker(boundary, prev.closeDeletionTime(false), curr.openDeletionTime(false)); currUnfiltered = prev; --di; @@ -331,7 +331,7 @@ public class UnfilteredRowIteratorsMergeTest { if (curr == null) return "null"; - return Int32Type.instance.getString(curr.clustering().get(0)); + return Int32Type.instance.getString(curr.clustering().bufferAt(0)); } private Unfiltered rowFor(Clusterable pointer, List list) @@ -376,19 +376,19 @@ public class UnfilteredRowIteratorsMergeTest return def; } - private static ClusteringBound boundFor(int pos, boolean start, boolean inclusive) + private static ClusteringBound boundFor(int pos, boolean start, boolean inclusive) { - return ClusteringBound.create(ClusteringBound.boundKind(start, inclusive), new ByteBuffer[] {Int32Type.instance.decompose(pos)}); + return BufferClusteringBound.create(ClusteringBound.boundKind(start, inclusive), new ByteBuffer[] {Int32Type.instance.decompose(pos)}); } - private static Clustering clusteringFor(int i) + private static Clustering clusteringFor(int i) { return Clustering.make(Int32Type.instance.decompose(i)); } static Row emptyRowAt(int pos, IntUnaryOperator timeGenerator) { - final Clustering clustering = clusteringFor(pos); + final Clustering clustering = clusteringFor(pos); final LivenessInfo live = LivenessInfo.create(timeGenerator.applyAsInt(pos), nowInSec); return BTreeRow.noCellLiveRow(clustering, live); } @@ -404,7 +404,7 @@ public class UnfilteredRowIteratorsMergeTest { if (curr == null) return "null"; - String val = Int32Type.instance.getString(curr.clustering().get(0)); + String val = Int32Type.instance.getString(curr.clustering().bufferAt(0)); if (curr instanceof RangeTombstoneMarker) { RangeTombstoneMarker marker = (RangeTombstoneMarker) curr; @@ -506,8 +506,8 @@ public class UnfilteredRowIteratorsMergeTest private RangeTombstoneMarker marker(int pos, int delTime, boolean isStart, boolean inclusive) { - return new RangeTombstoneBoundMarker(ClusteringBound.create(ClusteringBound.boundKind(isStart, inclusive), - new ByteBuffer[] {clusteringFor(pos).get(0)}), + return new RangeTombstoneBoundMarker(BufferClusteringBound.create(ClusteringBound.boundKind(isStart, inclusive), + new ByteBuffer[] {clusteringFor(pos).bufferAt(0)}), new DeletionTime(delTime, delTime)); } } diff --git a/test/unit/org/apache/cassandra/db/rows/UnfilteredRowIteratorsTest.java b/test/unit/org/apache/cassandra/db/rows/UnfilteredRowIteratorsTest.java index a936504d12..9a40823db9 100644 --- a/test/unit/org/apache/cassandra/db/rows/UnfilteredRowIteratorsTest.java +++ b/test/unit/org/apache/cassandra/db/rows/UnfilteredRowIteratorsTest.java @@ -168,16 +168,16 @@ public class UnfilteredRowIteratorsTest }; } - public Row row(int ck, Cell... columns) + public Row row(int ck, Cell... columns) { BTreeRow.Builder builder = new BTreeRow.Builder(true); builder.newRow(Util.clustering(metadata.comparator, ck)); - for (Cell cell : columns) + for (Cell cell : columns) builder.addCell(cell); return builder.build(); } - public Cell cell(ColumnMetadata metadata, int v) + public Cell cell(ColumnMetadata metadata, int v) { return new BufferCell(metadata, 1L, BufferCell.NO_TTL, BufferCell.NO_DELETION_TIME, ByteBufferUtil.bytes(v), null); diff --git a/test/unit/org/apache/cassandra/db/rows/UnfilteredRowsGenerator.java b/test/unit/org/apache/cassandra/db/rows/UnfilteredRowsGenerator.java index 71b28e8c21..2804733e3f 100644 --- a/test/unit/org/apache/cassandra/db/rows/UnfilteredRowsGenerator.java +++ b/test/unit/org/apache/cassandra/db/rows/UnfilteredRowsGenerator.java @@ -46,7 +46,7 @@ public class UnfilteredRowsGenerator { if (curr == null) return "null"; - String val = Int32Type.instance.getString(curr.clustering().get(0)); + String val = Int32Type.instance.getString(curr.clustering().bufferAt(0)); if (curr instanceof RangeTombstoneMarker) { RangeTombstoneMarker marker = (RangeTombstoneMarker) curr; @@ -221,27 +221,27 @@ public class UnfilteredRowsGenerator static Row emptyRowAt(int pos, IntUnaryOperator timeGenerator) { - final Clustering clustering = clusteringFor(pos); + final Clustering clustering = clusteringFor(pos); final LivenessInfo live = LivenessInfo.create(timeGenerator.applyAsInt(pos), UnfilteredRowIteratorsMergeTest.nowInSec); return BTreeRow.noCellLiveRow(clustering, live); } static Row emptyRowAt(int pos, int time, int deletionTime) { - final Clustering clustering = clusteringFor(pos); + final Clustering clustering = clusteringFor(pos); final LivenessInfo live = LivenessInfo.create(time, UnfilteredRowIteratorsMergeTest.nowInSec); final DeletionTime delTime = deletionTime == -1 ? DeletionTime.LIVE : new DeletionTime(deletionTime, deletionTime); return BTreeRow.create(clustering, live, Row.Deletion.regular(delTime), BTree.empty()); } - static Clustering clusteringFor(int i) + static Clustering clusteringFor(int i) { return Clustering.make(Int32Type.instance.decompose(i)); } - static ClusteringBound boundFor(int pos, boolean start, boolean inclusive) + static ClusteringBound boundFor(int pos, boolean start, boolean inclusive) { - return ClusteringBound.create(ClusteringBound.boundKind(start, inclusive), new ByteBuffer[] {Int32Type.instance.decompose(pos)}); + return BufferClusteringBound.create(ClusteringBound.boundKind(start, inclusive), new ByteBuffer[] {Int32Type.instance.decompose(pos)}); } static void attachBoundaries(List content) @@ -257,10 +257,10 @@ public class UnfilteredRowsGenerator if (prev != null && curr != null && prev.isClose(false) && curr.isOpen(false) && prev.clustering().invert().equals(curr.clustering())) { // Join. Prefer not to use merger to check its correctness. - ClusteringBound b = (ClusteringBound) prev.clustering(); + ClusteringBound b = (ClusteringBound) prev.clustering(); ClusteringBoundary boundary = ClusteringBoundary.create( b.isInclusive() ? ClusteringBound.Kind.INCL_END_EXCL_START_BOUNDARY : ClusteringBound.Kind.EXCL_END_INCL_START_BOUNDARY, - b.getRawValues()); + b); prev = new RangeTombstoneBoundaryMarker(boundary, prev.closeDeletionTime(false), curr.openDeletionTime(false)); currUnfiltered = prev; --di; @@ -284,8 +284,8 @@ public class UnfilteredRowsGenerator private static RangeTombstoneMarker marker(int pos, int delTime, boolean isStart, boolean inclusive) { - return new RangeTombstoneBoundMarker(ClusteringBound.create(ClusteringBound.boundKind(isStart, inclusive), - new ByteBuffer[] {clusteringFor(pos).get(0)}), + return new RangeTombstoneBoundMarker(BufferClusteringBound.create(ClusteringBound.boundKind(isStart, inclusive), + new ByteBuffer[] {clusteringFor(pos).bufferAt(0)}), new DeletionTime(delTime, delTime)); } diff --git a/test/unit/org/apache/cassandra/db/transform/RTTransformationsTest.java b/test/unit/org/apache/cassandra/db/transform/RTTransformationsTest.java index e400f3a08d..95d79a0c78 100644 --- a/test/unit/org/apache/cassandra/db/transform/RTTransformationsTest.java +++ b/test/unit/org/apache/cassandra/db/transform/RTTransformationsTest.java @@ -375,7 +375,7 @@ public final class RTTransformationsTest for (int i = 0; i < clusteringValues.length; i++) clusteringByteBuffers[i] = decompose(metadata.clusteringColumns().get(i).type, clusteringValues[i]); - return new RangeTombstoneBoundMarker(ClusteringBound.create(kind, clusteringByteBuffers), new DeletionTime(timestamp, nowInSec)); + return new RangeTombstoneBoundMarker(BufferClusteringBound.create(kind, clusteringByteBuffers), new DeletionTime(timestamp, nowInSec)); } private RangeTombstoneBoundaryMarker boundary(ClusteringPrefix.Kind kind, long closeTimestamp, long openTimestamp, Object... clusteringValues) @@ -384,7 +384,7 @@ public final class RTTransformationsTest for (int i = 0; i < clusteringValues.length; i++) clusteringByteBuffers[i] = decompose(metadata.clusteringColumns().get(i).type, clusteringValues[i]); - return new RangeTombstoneBoundaryMarker(ClusteringBoundary.create(kind, clusteringByteBuffers), + return new RangeTombstoneBoundaryMarker(BufferClusteringBoundary.create(kind, clusteringByteBuffers), new DeletionTime(closeTimestamp, nowInSec), new DeletionTime(openTimestamp, nowInSec)); } diff --git a/test/unit/org/apache/cassandra/hints/HintsBufferTest.java b/test/unit/org/apache/cassandra/hints/HintsBufferTest.java index a4cb651dd1..0dcf74752a 100644 --- a/test/unit/org/apache/cassandra/hints/HintsBufferTest.java +++ b/test/unit/org/apache/cassandra/hints/HintsBufferTest.java @@ -31,6 +31,7 @@ import org.apache.cassandra.SchemaLoader; import org.apache.cassandra.concurrent.NamedThreadFactory; import org.apache.cassandra.db.Mutation; import org.apache.cassandra.db.RowUpdateBuilder; +import org.apache.cassandra.db.marshal.ValueAccessors; import org.apache.cassandra.db.rows.Cell; import org.apache.cassandra.db.rows.Row; import org.apache.cassandra.io.util.DataInputBuffer; @@ -181,10 +182,10 @@ public class HintsBufferTest Row row = hint.mutation.getPartitionUpdates().iterator().next().iterator().next(); assertEquals(1, Iterables.size(row.cells())); - assertEquals(bytes(idx), row.clustering().get(0)); - Cell cell = row.cells().iterator().next(); + ValueAccessors.assertDataEquals(bytes(idx), row.clustering().get(0)); + Cell cell = row.cells().iterator().next(); assertEquals(TimeUnit.MILLISECONDS.toMicros(baseTimestamp + idx), cell.timestamp()); - assertEquals(bytes(idx), cell.value()); + ValueAccessors.assertDataEquals(bytes(idx), cell.buffer()); return idx; } diff --git a/test/unit/org/apache/cassandra/hints/HintsReaderTest.java b/test/unit/org/apache/cassandra/hints/HintsReaderTest.java index d95bd56047..871b796f75 100644 --- a/test/unit/org/apache/cassandra/hints/HintsReaderTest.java +++ b/test/unit/org/apache/cassandra/hints/HintsReaderTest.java @@ -33,6 +33,7 @@ import org.junit.Test; import org.apache.cassandra.SchemaLoader; import org.apache.cassandra.db.Mutation; import org.apache.cassandra.db.RowUpdateBuilder; +import org.apache.cassandra.db.marshal.ValueAccessors; import org.apache.cassandra.db.rows.Cell; import org.apache.cassandra.db.rows.Row; import org.apache.cassandra.io.util.FileUtils; @@ -115,10 +116,10 @@ public class HintsReaderTest Row row = mutation.getPartitionUpdates().iterator().next().iterator().next(); assertEquals(1, Iterables.size(row.cells())); - assertEquals(bytes(i), row.clustering().get(0)); - Cell cell = row.cells().iterator().next(); + ValueAccessors.assertDataEquals(bytes(i), row.clustering().get(0)); + Cell cell = row.cells().iterator().next(); assertNotNull(cell); - assertEquals(bytes(i), cell.value()); + ValueAccessors.assertDataEquals(bytes(i), cell.buffer()); assertEquals(timestamp * 1000, cell.timestamp()); index++; diff --git a/test/unit/org/apache/cassandra/index/CustomIndexTest.java b/test/unit/org/apache/cassandra/index/CustomIndexTest.java index 2b2bb87411..84a36dfc8e 100644 --- a/test/unit/org/apache/cassandra/index/CustomIndexTest.java +++ b/test/unit/org/apache/cassandra/index/CustomIndexTest.java @@ -602,7 +602,7 @@ public class CustomIndexTest extends CQLTester // the index should have been notified of the expired row assertEquals(1, index.rowsDeleted.size()); - Integer deletedClustering = Int32Type.instance.compose(index.rowsDeleted.get(0).clustering().get(0)); + Integer deletedClustering = Int32Type.instance.compose(index.rowsDeleted.get(0).clustering().bufferAt(0)); assertEquals(0, deletedClustering.intValue()); } diff --git a/test/unit/org/apache/cassandra/index/internal/CustomCassandraIndex.java b/test/unit/org/apache/cassandra/index/internal/CustomCassandraIndex.java index 04db7f6f90..51bb6bbf6a 100644 --- a/test/unit/org/apache/cassandra/index/internal/CustomCassandraIndex.java +++ b/test/unit/org/apache/cassandra/index/internal/CustomCassandraIndex.java @@ -253,7 +253,7 @@ public class CustomCassandraIndex implements Index } protected CBuilder buildIndexClusteringPrefix(ByteBuffer partitionKey, - ClusteringPrefix prefix, + ClusteringPrefix prefix, CellPath path) { CBuilder builder = CBuilder.create(getIndexComparator()); @@ -262,7 +262,7 @@ public class CustomCassandraIndex implements Index } protected ByteBuffer getIndexedValue(ByteBuffer partitionKey, - Clustering clustering, + Clustering clustering, CellPath path, ByteBuffer cellValue) { return cellValue; @@ -278,11 +278,11 @@ public class CustomCassandraIndex implements Index if (row == null) return true; - Cell cell = row.getCell(indexedColumn); + Cell cell = row.getCell(indexedColumn); return (cell == null || !cell.isLive(nowInSec) - || indexedColumn.type.compare(indexValue, cell.value()) != 0); + || indexedColumn.type.compare(indexValue, cell.buffer()) != 0); } public Indexer indexerFor(final DecoratedKey key, @@ -360,16 +360,16 @@ public class CustomCassandraIndex implements Index { } - private void indexCells(Clustering clustering, Iterable cells) + private void indexCells(Clustering clustering, Iterable> cells) { if (cells == null) return; - for (Cell cell : cells) + for (Cell cell : cells) indexCell(clustering, cell); } - private void indexCell(Clustering clustering, Cell cell) + private void indexCell(Clustering clustering, Cell cell) { if (cell == null || !cell.isLive(nowInSec)) return; @@ -381,16 +381,16 @@ public class CustomCassandraIndex implements Index ctx); } - private void removeCells(Clustering clustering, Iterable cells) + private void removeCells(Clustering clustering, Iterable> cells) { if (cells == null) return; - for (Cell cell : cells) + for (Cell cell : cells) removeCell(clustering, cell); } - private void removeCell(Clustering clustering, Cell cell) + private void removeCell(Clustering clustering, Cell cell) { if (cell == null || !cell.isLive(nowInSec)) return; @@ -398,7 +398,7 @@ public class CustomCassandraIndex implements Index delete(key.getKey(), clustering, cell, ctx, nowInSec); } - private void indexPrimaryKey(final Clustering clustering, + private void indexPrimaryKey(final Clustering clustering, final LivenessInfo liveness, final Row.Deletion deletion) { @@ -413,7 +413,7 @@ public class CustomCassandraIndex implements Index { long timestamp = row.primaryKeyLivenessInfo().timestamp(); int ttl = row.primaryKeyLivenessInfo().ttl(); - for (Cell cell : row.cells()) + for (Cell cell : row.cells()) { long cellTimestamp = cell.timestamp(); if (cell.isLive(nowInSec)) @@ -439,7 +439,7 @@ public class CustomCassandraIndex implements Index * @param ctx the context under which to perform the deletion */ public void deleteStaleEntry(DecoratedKey indexKey, - Clustering indexClustering, + Clustering indexClustering, DeletionTime deletion, WriteContext ctx) { @@ -451,8 +451,8 @@ public class CustomCassandraIndex implements Index * Called when adding a new entry to the index */ private void insert(ByteBuffer rowKey, - Clustering clustering, - Cell cell, + Clustering clustering, + Cell cell, LivenessInfo info, WriteContext ctx) { @@ -469,8 +469,8 @@ public class CustomCassandraIndex implements Index * Called when deleting entries on non-primary key columns */ private void delete(ByteBuffer rowKey, - Clustering clustering, - Cell cell, + Clustering clustering, + Cell cell, WriteContext ctx, int nowInSec) { @@ -487,7 +487,7 @@ public class CustomCassandraIndex implements Index * Called when deleting entries from indexes on primary key columns */ private void delete(ByteBuffer rowKey, - Clustering clustering, + Clustering clustering, DeletionTime deletion, WriteContext ctx) { @@ -501,7 +501,7 @@ public class CustomCassandraIndex implements Index } private void doDelete(DecoratedKey indexKey, - Clustering indexClustering, + Clustering indexClustering, DeletionTime deletion, WriteContext ctx) { @@ -534,9 +534,9 @@ public class CustomCassandraIndex implements Index ComplexColumnData data = row.getComplexColumnData(indexedColumn); if (data != null) { - for (Cell cell : data) + for (Cell cell : data) { - validateIndexedValue(getIndexedValue(null, null, cell.path(), cell.value())); + validateIndexedValue(getIndexedValue(null, null, cell.path(), cell.buffer())); } } } @@ -561,19 +561,19 @@ public class CustomCassandraIndex implements Index } private ByteBuffer getIndexedValue(ByteBuffer rowKey, - Clustering clustering, - Cell cell) + Clustering clustering, + Cell cell) { return getIndexedValue(rowKey, clustering, cell == null ? null : cell.path(), - cell == null ? null : cell.value() + cell == null ? null : cell.buffer() ); } - private Clustering buildIndexClustering(ByteBuffer rowKey, - Clustering clustering, - Cell cell) + private Clustering buildIndexClustering(ByteBuffer rowKey, + Clustering clustering, + Cell cell) { return buildIndexClusteringPrefix(rowKey, clustering, diff --git a/test/unit/org/apache/cassandra/index/sasi/SASIIndexTest.java b/test/unit/org/apache/cassandra/index/sasi/SASIIndexTest.java index 3508d76ad1..7619bd21b9 100644 --- a/test/unit/org/apache/cassandra/index/sasi/SASIIndexTest.java +++ b/test/unit/org/apache/cassandra/index/sasi/SASIIndexTest.java @@ -1187,7 +1187,7 @@ public class SASIIndexTest final ByteBuffer age = UTF8Type.instance.decompose("age"); Mutation.PartitionUpdateCollector rm = new Mutation.PartitionUpdateCollector(KS_NAME, decoratedKey(AsciiType.instance.decompose("key1"))); - update(rm, new ArrayList() + update(rm, new ArrayList>() {{ add(buildCell(age, LongType.instance.decompose(26L), System.currentTimeMillis())); add(buildCell(firstName, AsciiType.instance.decompose("pavel"), System.currentTimeMillis())); @@ -1682,9 +1682,9 @@ public class SASIIndexTest return UTF8Type.instance.getSerializer(); } - public int compareCustom(ByteBuffer a, ByteBuffer b) + public int compareCustom(VL left, ValueAccessor accessorL, VR right, ValueAccessor accessorR) { - return UTF8Type.instance.compare(a, b); + return UTF8Type.instance.compare(left, accessorL, right, accessorR); } }; @@ -2584,7 +2584,7 @@ public class SASIIndexTest private static Mutation newMutation(String key, String firstName, String lastName, int age, long timestamp) { Mutation.PartitionUpdateCollector rm = new Mutation.PartitionUpdateCollector(KS_NAME, decoratedKey(AsciiType.instance.decompose(key))); - List cells = new ArrayList<>(3); + List> cells = new ArrayList<>(3); if (age >= 0) cells.add(buildCell(ByteBufferUtil.bytes("age"), Int32Type.instance.decompose(age), timestamp)); @@ -2655,27 +2655,27 @@ public class SASIIndexTest return decoratedKey(AsciiType.instance.fromString(key)); } - private static Row buildRow(Collection cells) + private static Row buildRow(Collection> cells) { - return buildRow(cells.toArray(new Cell[cells.size()])); + return buildRow(cells.toArray(new Cell[cells.size()])); } - private static Row buildRow(Cell... cells) + private static Row buildRow(Cell... cells) { Row.Builder rowBuilder = BTreeRow.sortedBuilder(); rowBuilder.newRow(Clustering.EMPTY); - for (Cell c : cells) + for (Cell c : cells) rowBuilder.addCell(c); return rowBuilder.build(); } - private static Cell buildCell(ByteBuffer name, ByteBuffer value, long timestamp) + private static Cell buildCell(ByteBuffer name, ByteBuffer value, long timestamp) { TableMetadata cfm = Keyspace.open(KS_NAME).getColumnFamilyStore(CF_NAME).metadata(); return BufferCell.live(cfm.getColumn(name), timestamp, value); } - private static Cell buildCell(TableMetadata cfm, ByteBuffer name, ByteBuffer value, long timestamp) + private static Cell buildCell(TableMetadata cfm, ByteBuffer name, ByteBuffer value, long timestamp) { ColumnMetadata column = cfm.getColumn(name); assert column != null; @@ -2694,7 +2694,7 @@ public class SASIIndexTest } - private static void update(Mutation.PartitionUpdateCollector rm, List cells) + private static void update(Mutation.PartitionUpdateCollector rm, List> cells) { TableMetadata metadata = Keyspace.open(KS_NAME).getColumnFamilyStore(CF_NAME).metadata(); rm.add(PartitionUpdate.singleRowUpdate(metadata, rm.key(), buildRow(cells))); diff --git a/test/unit/org/apache/cassandra/index/sasi/plan/OperationTest.java b/test/unit/org/apache/cassandra/index/sasi/plan/OperationTest.java index 8273dec2f4..4468f2c219 100644 --- a/test/unit/org/apache/cassandra/index/sasi/plan/OperationTest.java +++ b/test/unit/org/apache/cassandra/index/sasi/plan/OperationTest.java @@ -653,26 +653,26 @@ public class OperationTest extends SchemaLoader } } - private static Unfiltered buildRow(Cell... cells) + private static Unfiltered buildRow(Cell... cells) { return buildRow(Clustering.EMPTY, null, cells); } - private static Row buildRow(Row.Deletion deletion, Cell... cells) + private static Row buildRow(Row.Deletion deletion, Cell... cells) { return buildRow(Clustering.EMPTY, deletion, cells); } - private static Row buildRow(Clustering clustering, Cell... cells) + private static Row buildRow(Clustering clustering, Cell... cells) { return buildRow(clustering, null, cells); } - private static Row buildRow(Clustering clustering, Row.Deletion deletion, Cell... cells) + private static Row buildRow(Clustering clustering, Row.Deletion deletion, Cell... cells) { Row.Builder rowBuilder = BTreeRow.sortedBuilder(); rowBuilder.newRow(clustering); - for (Cell c : cells) + for (Cell c : cells) rowBuilder.addCell(c); if (deletion != null) @@ -681,12 +681,12 @@ public class OperationTest extends SchemaLoader return rowBuilder.build(); } - private static Cell buildCell(ColumnMetadata column, ByteBuffer value, long timestamp) + private static Cell buildCell(ColumnMetadata column, ByteBuffer value, long timestamp) { return BufferCell.live(column, timestamp, value); } - private static Cell deletedCell(ColumnMetadata column, long timestamp, int nowInSeconds) + private static Cell deletedCell(ColumnMetadata column, long timestamp, int nowInSeconds) { return BufferCell.tombstone(column, timestamp, nowInSeconds); } diff --git a/test/unit/org/apache/cassandra/io/sstable/IndexSummaryManagerTest.java b/test/unit/org/apache/cassandra/io/sstable/IndexSummaryManagerTest.java index d383e886b2..9bae92386e 100644 --- a/test/unit/org/apache/cassandra/io/sstable/IndexSummaryManagerTest.java +++ b/test/unit/org/apache/cassandra/io/sstable/IndexSummaryManagerTest.java @@ -160,9 +160,9 @@ public class IndexSummaryManagerTest for (int i = 0; i < numPartition; i++) { Row row = Util.getOnlyRowUnfiltered(Util.cmd(cfs, String.format("%3d", i)).build()); - Cell cell = row.getCell(cfs.metadata().getColumn(ByteBufferUtil.bytes("val"))); + Cell cell = row.getCell(cfs.metadata().getColumn(ByteBufferUtil.bytes("val"))); assertNotNull(cell); - assertEquals(100, cell.value().array().length); + assertEquals(100, cell.buffer().array().length); } } diff --git a/test/unit/org/apache/cassandra/io/sstable/SSTableLoaderTest.java b/test/unit/org/apache/cassandra/io/sstable/SSTableLoaderTest.java index 5d40f8cc62..334e47696d 100644 --- a/test/unit/org/apache/cassandra/io/sstable/SSTableLoaderTest.java +++ b/test/unit/org/apache/cassandra/io/sstable/SSTableLoaderTest.java @@ -150,7 +150,7 @@ public class SSTableLoaderTest assertEquals("key1", AsciiType.instance.getString(partitions.get(0).partitionKey().getKey())); assertEquals(ByteBufferUtil.bytes("100"), partitions.get(0).getRow(Clustering.make(ByteBufferUtil.bytes("col1"))) .getCell(metadata.getColumn(ByteBufferUtil.bytes("val"))) - .value()); + .buffer()); // The stream future is signalled when the work is complete but before releasing references. Wait for release // before cleanup (CASSANDRA-10118). @@ -248,7 +248,7 @@ public class SSTableLoaderTest assertEquals("key1", AsciiType.instance.getString(partitions.get(0).partitionKey().getKey())); assertEquals(ByteBufferUtil.bytes("100"), partitions.get(0).getRow(Clustering.make(ByteBufferUtil.bytes("col1"))) .getCell(metadata.getColumn(ByteBufferUtil.bytes("val"))) - .value()); + .buffer()); // The stream future is signalled when the work is complete but before releasing references. Wait for release // before cleanup (CASSANDRA-10118). diff --git a/test/unit/org/apache/cassandra/io/sstable/SSTableMetadataTest.java b/test/unit/org/apache/cassandra/io/sstable/SSTableMetadataTest.java index ae63fc3331..e70f72f7eb 100644 --- a/test/unit/org/apache/cassandra/io/sstable/SSTableMetadataTest.java +++ b/test/unit/org/apache/cassandra/io/sstable/SSTableMetadataTest.java @@ -38,7 +38,6 @@ import org.apache.cassandra.io.sstable.format.SSTableReader; import org.apache.cassandra.schema.KeyspaceParams; import org.apache.cassandra.utils.ByteBufferUtil; -import static org.apache.cassandra.Util.getBytes; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -52,7 +51,7 @@ public class SSTableMetadataTest public static final String CF_COUNTER1 = "Counter1"; @BeforeClass - public static void defineSchema() throws Exception + public static void defineSchema() { SchemaLoader.prepareServer(); SchemaLoader.createKeyspace(KEYSPACE1, diff --git a/test/unit/org/apache/cassandra/io/sstable/SSTableReaderTest.java b/test/unit/org/apache/cassandra/io/sstable/SSTableReaderTest.java index bfb3e034b1..c8bdd09c66 100644 --- a/test/unit/org/apache/cassandra/io/sstable/SSTableReaderTest.java +++ b/test/unit/org/apache/cassandra/io/sstable/SSTableReaderTest.java @@ -591,7 +591,7 @@ public class SSTableReaderTest public void run() { Row row = Util.getOnlyRowUnfiltered(Util.cmd(store, key).build()); - assertEquals(0, ByteBufferUtil.compare(String.format("%3d", index).getBytes(), row.cells().iterator().next().value())); + assertEquals(0, ByteBufferUtil.compare(String.format("%3d", index).getBytes(), row.cells().iterator().next().buffer())); } })); diff --git a/test/unit/org/apache/cassandra/io/sstable/format/SSTableFlushObserverTest.java b/test/unit/org/apache/cassandra/io/sstable/format/SSTableFlushObserverTest.java index 2b787ca4ee..5f1920639b 100644 --- a/test/unit/org/apache/cassandra/io/sstable/format/SSTableFlushObserverTest.java +++ b/test/unit/org/apache/cassandra/io/sstable/format/SSTableFlushObserverTest.java @@ -105,7 +105,7 @@ public class SSTableFlushObserverTest transaction); SSTableReader reader = null; - Multimap expected = ArrayListMultimap.create(); + Multimap> expected = ArrayListMultimap.create(); try { @@ -187,7 +187,7 @@ public class SSTableFlushObserverTest private static class FlushObserver implements SSTableFlushObserver { - private final Multimap, Cell> rows = ArrayListMultimap.create(); + private final Multimap, Cell> rows = ArrayListMultimap.create(); private Pair currentKey; private boolean isComplete; @@ -205,7 +205,7 @@ public class SSTableFlushObserverTest public void nextUnfilteredCluster(Unfiltered row) { if (row.isRow()) - ((Row) row).forEach((c) -> rows.put(currentKey, (Cell) c)); + ((Row) row).forEach((c) -> rows.put(currentKey, (Cell) c)); } @Override @@ -215,7 +215,7 @@ public class SSTableFlushObserverTest } } - private static Row buildRow(Collection cells) + private static Row buildRow(Collection> cells) { Row.Builder rowBuilder = BTreeRow.sortedBuilder(); rowBuilder.newRow(Clustering.EMPTY); diff --git a/test/unit/org/apache/cassandra/io/util/DataOutputTest.java b/test/unit/org/apache/cassandra/io/util/DataOutputTest.java index c8f0087997..68700719bd 100644 --- a/test/unit/org/apache/cassandra/io/util/DataOutputTest.java +++ b/test/unit/org/apache/cassandra/io/util/DataOutputTest.java @@ -42,6 +42,7 @@ import org.junit.BeforeClass; import org.junit.Test; import org.apache.cassandra.config.DatabaseDescriptor; +import org.apache.cassandra.utils.ByteArrayUtil; import org.apache.cassandra.utils.ByteBufferUtil; public class DataOutputTest @@ -408,33 +409,33 @@ public class DataOutputTest int size = 50; byte[] bytes = new byte[size]; rnd.nextBytes(bytes); - ByteBufferUtil.writeWithLength(bytes, test); - ByteBufferUtil.writeWithLength(bytes, canon); + ByteArrayUtil.writeWithLength(bytes, test); + ByteArrayUtil.writeWithLength(bytes, canon); bytes = new byte[size]; rnd.nextBytes(bytes); ByteBufferUtil.writeWithLength(wrap(bytes, false), test); - ByteBufferUtil.writeWithLength(bytes, canon); + ByteArrayUtil.writeWithLength(bytes, canon); bytes = new byte[size]; rnd.nextBytes(bytes); ByteBufferUtil.writeWithLength(wrap(bytes, true), test); - ByteBufferUtil.writeWithLength(bytes, canon); + ByteArrayUtil.writeWithLength(bytes, canon); bytes = new byte[size]; rnd.nextBytes(bytes); - ByteBufferUtil.writeWithShortLength(bytes, test); - ByteBufferUtil.writeWithShortLength(bytes, canon); + ByteArrayUtil.writeWithShortLength(bytes, test); + ByteArrayUtil.writeWithShortLength(bytes, canon); bytes = new byte[size]; rnd.nextBytes(bytes); ByteBufferUtil.writeWithShortLength(wrap(bytes, false), test); - ByteBufferUtil.writeWithShortLength(bytes, canon); + ByteArrayUtil.writeWithShortLength(bytes, canon); bytes = new byte[size]; rnd.nextBytes(bytes); ByteBufferUtil.writeWithShortLength(wrap(bytes, true), test); - ByteBufferUtil.writeWithShortLength(bytes, canon); + ByteArrayUtil.writeWithShortLength(bytes, canon); // 318 { diff --git a/test/unit/org/apache/cassandra/service/PaxosStateTest.java b/test/unit/org/apache/cassandra/service/PaxosStateTest.java index bd7a85f130..7d69223d98 100644 --- a/test/unit/org/apache/cassandra/service/PaxosStateTest.java +++ b/test/unit/org/apache/cassandra/service/PaxosStateTest.java @@ -96,7 +96,7 @@ public class PaxosStateTest { Row row = Util.getOnlyRowUnfiltered(Util.cmd(cfs, key).build()); assertEquals(0, ByteBufferUtil.compareUnsigned(value, - row.getCell(cfs.metadata().getColumn(ByteBufferUtil.bytes(name))).value())); + row.getCell(cfs.metadata().getColumn(ByteBufferUtil.bytes(name))).buffer())); } private void assertNoDataPresent(ColumnFamilyStore cfs, DecoratedKey key) diff --git a/test/unit/org/apache/cassandra/service/QueryPagerTest.java b/test/unit/org/apache/cassandra/service/QueryPagerTest.java index 0b8248a319..87478abeb8 100644 --- a/test/unit/org/apache/cassandra/service/QueryPagerTest.java +++ b/test/unit/org/apache/cassandra/service/QueryPagerTest.java @@ -217,7 +217,7 @@ public class QueryPagerTest for (Row row : Util.once(partition.iterator())) { ByteBuffer expected = names[i++]; - assertEquals("column " + i + " doesn't match "+string(expected)+" vs "+string(row.clustering().get(0)), expected, row.clustering().get(0)); + assertEquals("column " + i + " doesn't match "+string(expected)+" vs "+string(row.clustering().bufferAt(0)), expected, row.clustering().bufferAt(0)); } } @@ -496,7 +496,7 @@ public class QueryPagerTest Row row = partition.next(); int cellIndex = !reversed ? i : 4 - i; - assertEquals(row.clustering().get(0), ByteBufferUtil.bytes(cellIndex)); + assertEquals(row.clustering().bufferAt(0), ByteBufferUtil.bytes(cellIndex)); assertCell(row, table.getColumn(new ColumnIdentifier("v1", false)), cellIndex); assertCell(row, table.getColumn(new ColumnIdentifier("v2", false)), cellIndex); @@ -516,8 +516,8 @@ public class QueryPagerTest private void assertCell(Row row, ColumnMetadata column, int value) { - Cell cell = row.getCell(column); + Cell cell = row.getCell(column); assertNotNull(cell); - assertEquals(value, ByteBufferUtil.toInt(cell.value())); + assertEquals(value, ByteBufferUtil.toInt(cell.buffer())); } } diff --git a/test/unit/org/apache/cassandra/service/reads/AbstractReadResponseTest.java b/test/unit/org/apache/cassandra/service/reads/AbstractReadResponseTest.java index 884baa14c5..ae1c59a989 100644 --- a/test/unit/org/apache/cassandra/service/reads/AbstractReadResponseTest.java +++ b/test/unit/org/apache/cassandra/service/reads/AbstractReadResponseTest.java @@ -34,6 +34,8 @@ import org.apache.cassandra.SchemaLoader; import org.apache.cassandra.Util; import org.apache.cassandra.config.DatabaseDescriptor; import org.apache.cassandra.cql3.ColumnIdentifier; +import org.apache.cassandra.db.BufferClusteringBound; +import org.apache.cassandra.db.BufferClusteringBoundary; import org.apache.cassandra.db.ClusteringBound; import org.apache.cassandra.db.ClusteringBoundary; import org.apache.cassandra.db.ClusteringPrefix; @@ -277,18 +279,18 @@ public abstract class AbstractReadResponseTest public RangeTombstone tombstone(Object start, boolean inclusiveStart, Object end, boolean inclusiveEnd, long markedForDeleteAt, int localDeletionTime) { - ClusteringBound startBound = rtBound(start, true, inclusiveStart); - ClusteringBound endBound = rtBound(end, false, inclusiveEnd); + ClusteringBound startBound = rtBound(start, true, inclusiveStart); + ClusteringBound endBound = rtBound(end, false, inclusiveEnd); return new RangeTombstone(Slice.make(startBound, endBound), new DeletionTime(markedForDeleteAt, localDeletionTime)); } - public ClusteringBound rtBound(Object value, boolean isStart, boolean inclusive) + public ClusteringBound rtBound(Object value, boolean isStart, boolean inclusive) { ClusteringBound.Kind kind = isStart ? (inclusive ? ClusteringPrefix.Kind.INCL_START_BOUND : ClusteringPrefix.Kind.EXCL_START_BOUND) : (inclusive ? ClusteringPrefix.Kind.INCL_END_BOUND : ClusteringPrefix.Kind.EXCL_END_BOUND); - return ClusteringBound.create(kind, cfm.comparator.make(value).getRawValues()); + return BufferClusteringBound.create(kind, cfm.comparator.make(value).getBufferArray()); } public ClusteringBoundary rtBoundary(Object value, boolean inclusiveOnEnd) @@ -296,7 +298,7 @@ public abstract class AbstractReadResponseTest ClusteringBound.Kind kind = inclusiveOnEnd ? ClusteringPrefix.Kind.INCL_END_EXCL_START_BOUNDARY : ClusteringPrefix.Kind.EXCL_END_INCL_START_BOUNDARY; - return ClusteringBoundary.create(kind, cfm.comparator.make(value).getRawValues()); + return BufferClusteringBoundary.create(kind, cfm.comparator.make(value).getBufferArray()); } public RangeTombstoneBoundMarker marker(Object value, boolean isStart, boolean inclusive, long markedForDeleteAt, int localDeletionTime) diff --git a/test/unit/org/apache/cassandra/service/reads/DataResolverTest.java b/test/unit/org/apache/cassandra/service/reads/DataResolverTest.java index 5d71f4d3fa..36d792e105 100644 --- a/test/unit/org/apache/cassandra/service/reads/DataResolverTest.java +++ b/test/unit/org/apache/cassandra/service/reads/DataResolverTest.java @@ -26,12 +26,6 @@ import java.util.UUID; import com.google.common.collect.Iterators; import com.google.common.collect.Sets; -import org.apache.cassandra.db.ColumnFamilyStore; -import org.apache.cassandra.db.Keyspace; -import org.apache.cassandra.dht.Murmur3Partitioner; -import org.apache.cassandra.dht.Token; -import org.apache.cassandra.gms.Gossiper; -import org.apache.cassandra.locator.ReplicaPlan; import org.junit.Assert; import org.junit.Test; @@ -60,9 +54,15 @@ import org.apache.cassandra.db.rows.RangeTombstoneBoundMarker; import org.apache.cassandra.db.rows.RangeTombstoneBoundaryMarker; import org.apache.cassandra.db.rows.Row; import org.apache.cassandra.db.rows.RowIterator; +import org.apache.cassandra.db.ColumnFamilyStore; +import org.apache.cassandra.db.Keyspace; +import org.apache.cassandra.dht.Murmur3Partitioner; +import org.apache.cassandra.dht.Token; +import org.apache.cassandra.gms.Gossiper; import org.apache.cassandra.locator.EndpointsForRange; import org.apache.cassandra.locator.InetAddressAndPort; import org.apache.cassandra.locator.Replica; +import org.apache.cassandra.locator.ReplicaPlan; import org.apache.cassandra.locator.ReplicaUtils; import org.apache.cassandra.net.*; import org.apache.cassandra.service.StorageService; @@ -702,7 +702,7 @@ public class DataResolverTest extends AbstractReadResponseTest return rt; Slice slice = rt.deletedSlice(); - ClusteringBound newStart = ClusteringBound.create(Kind.EXCL_START_BOUND, slice.start().getRawValues()); + ClusteringBound newStart = ClusteringBound.create(Kind.EXCL_START_BOUND, slice.start()); return condition ? new RangeTombstone(Slice.make(newStart, slice.end()), rt.deletionTime()) : rt; @@ -715,7 +715,7 @@ public class DataResolverTest extends AbstractReadResponseTest return rt; Slice slice = rt.deletedSlice(); - ClusteringBound newEnd = ClusteringBound.create(Kind.EXCL_END_BOUND, slice.end().getRawValues()); + ClusteringBound newEnd = ClusteringBound.create(Kind.EXCL_END_BOUND, slice.end()); return condition ? new RangeTombstone(Slice.make(slice.start(), newEnd), rt.deletionTime()) : rt; @@ -726,7 +726,7 @@ public class DataResolverTest extends AbstractReadResponseTest return ByteBufferUtil.bytes(b); } - private Cell mapCell(int k, int v, long ts) + private Cell mapCell(int k, int v, long ts) { return BufferCell.live(m, ts, bb(v), CellPath.create(bb(k))); } @@ -752,7 +752,7 @@ public class DataResolverTest extends AbstractReadResponseTest builder.newRow(Clustering.EMPTY); DeletionTime expectedCmplxDelete = new DeletionTime(ts[1] - 1, nowInSec); builder.addComplexDeletion(m, expectedCmplxDelete); - Cell expectedCell = mapCell(1, 1, ts[1]); + Cell expectedCell = mapCell(1, 1, ts[1]); builder.addCell(expectedCell); InetAddressAndPort peer2 = replicas.get(1).endpoint(); @@ -842,7 +842,7 @@ public class DataResolverTest extends AbstractReadResponseTest builder.newRow(Clustering.EMPTY); DeletionTime expectedCmplxDelete = new DeletionTime(ts[0] - 1, nowInSec); builder.addComplexDeletion(m, expectedCmplxDelete); - Cell expectedCell = mapCell(0, 0, ts[0]); + Cell expectedCell = mapCell(0, 0, ts[0]); builder.addCell(expectedCell); // empty map column @@ -899,7 +899,7 @@ public class DataResolverTest extends AbstractReadResponseTest builder.newRow(Clustering.EMPTY); DeletionTime expectedCmplxDelete = new DeletionTime(ts[1] - 1, nowInSec); builder.addComplexDeletion(m, expectedCmplxDelete); - Cell expectedCell = mapCell(1, 1, ts[1]); + Cell expectedCell = mapCell(1, 1, ts[1]); builder.addCell(expectedCell); InetAddressAndPort peer2 = replicas.get(1).endpoint(); diff --git a/test/unit/org/apache/cassandra/service/reads/repair/AbstractReadRepairTest.java b/test/unit/org/apache/cassandra/service/reads/repair/AbstractReadRepairTest.java index 14074edbbe..765e1fac8e 100644 --- a/test/unit/org/apache/cassandra/service/reads/repair/AbstractReadRepairTest.java +++ b/test/unit/org/apache/cassandra/service/reads/repair/AbstractReadRepairTest.java @@ -85,9 +85,9 @@ public abstract class AbstractReadRepairTest static long now = TimeUnit.NANOSECONDS.toMicros(System.nanoTime()); static DecoratedKey key; - static Cell cell1; - static Cell cell2; - static Cell cell3; + static Cell cell1; + static Cell cell2; + static Cell cell3; static Mutation resolved; static ReadCommand command; @@ -145,35 +145,35 @@ public abstract class AbstractReadRepairTest return DatabaseDescriptor.getPartitioner().decorateKey(ByteBufferUtil.bytes(v)); } - static Cell cell(String name, String value, long timestamp) + static Cell cell(String name, String value, long timestamp) { return BufferCell.live(cfm.getColumn(ColumnIdentifier.getInterned(name, false)), timestamp, ByteBufferUtil.bytes(value)); } - static PartitionUpdate update(Cell... cells) + static PartitionUpdate update(Cell... cells) { Row.Builder builder = BTreeRow.unsortedBuilder(); builder.newRow(Clustering.EMPTY); - for (Cell cell: cells) + for (Cell cell: cells) { builder.addCell(cell); } return PartitionUpdate.singleRowUpdate(cfm, key, builder.build()); } - static PartitionIterator partition(Cell... cells) + static PartitionIterator partition(Cell... cells) { UnfilteredPartitionIterator iter = new SingletonUnfilteredPartitionIterator(update(cells).unfilteredIterator()); return UnfilteredPartitionIterators.filter(iter, Ints.checkedCast(TimeUnit.MICROSECONDS.toSeconds(now))); } - static Mutation mutation(Cell... cells) + static Mutation mutation(Cell... cells) { return new Mutation(update(cells)); } @SuppressWarnings("resource") - static Message msg(InetAddressAndPort from, Cell... cells) + static Message msg(InetAddressAndPort from, Cell... cells) { UnfilteredPartitionIterator iter = new SingletonUnfilteredPartitionIterator(update(cells).unfilteredIterator()); return Message.builder(INTERNAL_RSP, ReadResponse.createDataResponse(iter, command)) diff --git a/test/unit/org/apache/cassandra/service/reads/repair/ReadRepairTest.java b/test/unit/org/apache/cassandra/service/reads/repair/ReadRepairTest.java index 7458e9b801..11b057f583 100644 --- a/test/unit/org/apache/cassandra/service/reads/repair/ReadRepairTest.java +++ b/test/unit/org/apache/cassandra/service/reads/repair/ReadRepairTest.java @@ -87,9 +87,9 @@ public class ReadRepairTest static long now = TimeUnit.NANOSECONDS.toMicros(System.nanoTime()); static DecoratedKey key; - static Cell cell1; - static Cell cell2; - static Cell cell3; + static Cell cell1; + static Cell cell2; + static Cell cell3; static Mutation resolved; private static void assertRowsEqual(Row expected, Row actual) @@ -142,16 +142,16 @@ public class ReadRepairTest return DatabaseDescriptor.getPartitioner().decorateKey(ByteBufferUtil.bytes(v)); } - private static Cell cell(String name, String value, long timestamp) + private static Cell cell(String name, String value, long timestamp) { return BufferCell.live(cfm.getColumn(ColumnIdentifier.getInterned(name, false)), timestamp, ByteBufferUtil.bytes(value)); } - private static Mutation mutation(Cell... cells) + private static Mutation mutation(Cell... cells) { Row.Builder builder = BTreeRow.unsortedBuilder(); builder.newRow(Clustering.EMPTY); - for (Cell cell: cells) + for (Cell cell: cells) { builder.addCell(cell); } diff --git a/test/unit/org/apache/cassandra/streaming/StreamingTransferTest.java b/test/unit/org/apache/cassandra/streaming/StreamingTransferTest.java index d88f379fec..d99d35f904 100644 --- a/test/unit/org/apache/cassandra/streaming/StreamingTransferTest.java +++ b/test/unit/org/apache/cassandra/streaming/StreamingTransferTest.java @@ -212,7 +212,7 @@ public class StreamingTransferTest assert !Util.getAll(Util.cmd(cfs, key).build()).isEmpty(); ImmutableBTreePartition partition = partitions.get(i); assert ByteBufferUtil.compareUnsigned(partition.partitionKey().getKey(), ByteBufferUtil.bytes(key)) == 0; - assert ByteBufferUtil.compareUnsigned(partition.iterator().next().clustering().get(0), ByteBufferUtil.bytes(col)) == 0; + assert ByteBufferUtil.compareUnsigned(partition.iterator().next().clustering().bufferAt(0), ByteBufferUtil.bytes(col)) == 0; } // and that the max timestamp for the file was rediscovered @@ -375,7 +375,7 @@ public class StreamingTransferTest Row r = Util.getOnlyRow(Util.cmd(cfs).build()); Assert.assertFalse(r.isEmpty()); - Assert.assertTrue(1 == Int32Type.instance.compose(r.clustering().get(0))); + Assert.assertTrue(1 == Int32Type.instance.compose(r.clustering().bufferAt(0))); } @Test diff --git a/test/unit/org/apache/cassandra/triggers/TriggerExecutorTest.java b/test/unit/org/apache/cassandra/triggers/TriggerExecutorTest.java index 7e9f62670e..199e6372a1 100644 --- a/test/unit/org/apache/cassandra/triggers/TriggerExecutorTest.java +++ b/test/unit/org/apache/cassandra/triggers/TriggerExecutorTest.java @@ -67,7 +67,7 @@ public class TriggerExecutorTest // only 1 row assertEquals(1, rows.size()); - List cells = new ArrayList<>(); + List> cells = new ArrayList<>(); rows.get(0).cells().forEach(cells::add); // 2 columns diff --git a/test/unit/org/apache/cassandra/utils/ByteArrayUtilTest.java b/test/unit/org/apache/cassandra/utils/ByteArrayUtilTest.java index fe965feaf7..1feaab122e 100644 --- a/test/unit/org/apache/cassandra/utils/ByteArrayUtilTest.java +++ b/test/unit/org/apache/cassandra/utils/ByteArrayUtilTest.java @@ -44,7 +44,7 @@ public class ByteArrayUtilTest { byte[] bytes = new byte[16]; assertThatThrownBy(() -> ByteArrayUtil.putBoolean(bytes, bytes.length + 10, true)) - .hasMessageContaining("Attempted to write to offset 26 but array length is 16"); + .isInstanceOf(IndexOutOfBoundsException.class); } @Test @@ -74,7 +74,7 @@ public class ByteArrayUtilTest { byte[] bytes = new byte[16]; assertThatThrownBy(() -> ByteArrayUtil.putInt(bytes, bytes.length + 10, (short) 42)) - .hasMessageContaining("Attempted to write to offset 26 but array length is 16"); + .isInstanceOf(IndexOutOfBoundsException.class); } @Test @@ -104,7 +104,7 @@ public class ByteArrayUtilTest { byte[] bytes = new byte[16]; assertThatThrownBy(() -> ByteArrayUtil.putInt(bytes, bytes.length + 10, 42)) - .hasMessageContaining("Attempted to write to offset 26 but array length is 16"); + .isInstanceOf(IndexOutOfBoundsException.class); } @Test @@ -134,7 +134,7 @@ public class ByteArrayUtilTest { byte[] bytes = new byte[16]; assertThatThrownBy(() -> ByteArrayUtil.putLong(bytes, bytes.length + 10, 42)) - .hasMessageContaining("Attempted to write to offset 26 but array length is 16"); + .isInstanceOf(IndexOutOfBoundsException.class); } @Test @@ -164,7 +164,7 @@ public class ByteArrayUtilTest { byte[] bytes = new byte[16]; assertThatThrownBy(() -> ByteArrayUtil.putFloat(bytes, bytes.length + 10, 42.0f)) - .hasMessageContaining("Attempted to write to offset 26 but array length is 16"); + .isInstanceOf(IndexOutOfBoundsException.class); } @Test @@ -194,7 +194,7 @@ public class ByteArrayUtilTest { byte[] bytes = new byte[16]; assertThatThrownBy(() -> ByteArrayUtil.putDouble(bytes, bytes.length + 10, 42.0)) - .hasMessageContaining("Attempted to write to offset 26 but array length is 16"); + .isInstanceOf(IndexOutOfBoundsException.class); } private static void putArrayToSmall(int targetBytes, FailingConsumer fn) @@ -202,10 +202,8 @@ public class ByteArrayUtilTest for (int i = 0; i < targetBytes - 1; i++) { byte[] bytes = new byte[i]; - assertThatThrownBy(() -> fn.doAccept(bytes)).isInstanceOf(IndexOutOfBoundsException.class) - .hasMessageContaining("Attempted to write " + targetBytes + " bytes") - .hasMessageContaining("remaining capacity of " + i); + assertThatThrownBy(() -> fn.doAccept(bytes)).isInstanceOf(IndexOutOfBoundsException.class); assertThat(bytes).isEqualTo(new byte[i]); } } -} \ No newline at end of file +} diff --git a/test/unit/org/apache/cassandra/utils/CassandraGenerators.java b/test/unit/org/apache/cassandra/utils/CassandraGenerators.java index 575dcf2178..9e71e6279a 100644 --- a/test/unit/org/apache/cassandra/utils/CassandraGenerators.java +++ b/test/unit/org/apache/cassandra/utils/CassandraGenerators.java @@ -38,6 +38,7 @@ import org.apache.cassandra.db.SchemaCQLHelper; import org.apache.cassandra.db.SinglePartitionReadCommand; import org.apache.cassandra.db.Slices; import org.apache.cassandra.db.marshal.AbstractType; +import org.apache.cassandra.db.marshal.ByteBufferAccessor; import org.apache.cassandra.db.marshal.CompositeType; import org.apache.cassandra.db.marshal.EmptyType; import org.apache.cassandra.db.marshal.TimeUUIDType; @@ -185,7 +186,7 @@ public final class CassandraGenerators ByteBuffer[] buffers = new ByteBuffer[columnGens.size()]; for (int i = 0; i < columnGens.size(); i++) buffers[i] = columnGens.get(i).generate(rnd); - return CompositeType.build(buffers); + return CompositeType.build(ByteBufferAccessor.instance, buffers); }; } diff --git a/tools/stress/src/org/apache/cassandra/io/sstable/StressCQLSSTableWriter.java b/tools/stress/src/org/apache/cassandra/io/sstable/StressCQLSSTableWriter.java index 7c012e4731..bc6756b498 100644 --- a/tools/stress/src/org/apache/cassandra/io/sstable/StressCQLSSTableWriter.java +++ b/tools/stress/src/org/apache/cassandra/io/sstable/StressCQLSSTableWriter.java @@ -243,7 +243,7 @@ public class StressCQLSSTableWriter implements Closeable QueryOptions options = QueryOptions.forInternalCalls(null, values); List keys = insert.buildPartitionKeyNames(options); - SortedSet clusterings = insert.createClustering(options); + SortedSet> clusterings = insert.createClustering(options); long now = System.currentTimeMillis(); // Note that we asks indexes to not validate values (the last 'false' arg below) because that triggers a 'Keyspace.open' @@ -260,7 +260,7 @@ public class StressCQLSSTableWriter implements Closeable { for (ByteBuffer key : keys) { - for (Clustering clustering : clusterings) + for (Clustering clustering : clusterings) insert.addUpdateForKey(writer.getUpdateFor(key), clustering, params); } return this;