From 6a7bef12ecdf59e3a67c81b89c13e3c2bf7e19d8 Mon Sep 17 00:00:00 2001 From: Mike Adamson Date: Tue, 28 Nov 2023 10:48:23 +0000 Subject: [PATCH] Fix SAI intersection queries - Fix comparison in PostingListRangeIterator for updating skip token - Fix binary search in KeyLookup.clusteredSeekToKey - Added new on-disk component for storing partition sizes by partition ID patch by Mike Adamson; reviewed by Caleb Rackliffe, Mick Semb Wever for CASSANDRA-19011 --- .../index/sai/disk/format/IndexComponent.java | 13 +- .../sai/disk/v1/SSTableComponentsWriter.java | 18 +- .../sai/disk/v1/SkinnyPrimaryKeyMap.java | 62 +++-- .../index/sai/disk/v1/V1OnDiskFormat.java | 11 +- .../index/sai/disk/v1/WidePrimaryKeyMap.java | 40 +-- .../bitpack/MonotonicBlockPackedReader.java | 6 + .../index/sai/disk/v1/keystore/KeyLookup.java | 109 ++++----- .../v1/postings/PostingListRangeIterator.java | 25 +- .../index/sai/cql/RandomIntersectionTest.java | 227 ++++++++++++++++++ .../sai/cql/StorageAttachedIndexDDLTest.java | 11 +- .../disk/v1/bitpack/NumericValuesTest.java | 10 +- 11 files changed, 388 insertions(+), 144 deletions(-) create mode 100644 test/unit/org/apache/cassandra/index/sai/cql/RandomIntersectionTest.java diff --git a/src/java/org/apache/cassandra/index/sai/disk/format/IndexComponent.java b/src/java/org/apache/cassandra/index/sai/disk/format/IndexComponent.java index a0c5b24e2e..21cd5cf455 100644 --- a/src/java/org/apache/cassandra/index/sai/disk/format/IndexComponent.java +++ b/src/java/org/apache/cassandra/index/sai/disk/format/IndexComponent.java @@ -68,14 +68,19 @@ public enum IndexComponent // per-sstable components /** - * Partition key token value for rows including row tombstone and static row. (access key is rowId) + * An on-disk block packed index mapping rowIds to token values. */ - TOKEN_VALUES("TokenValues"), + ROW_TO_TOKEN("RowToToken"), /** - * An on-disk block packed index containing the starting and ending rowIds for each partition. + * An on-disk block packed index mapping rowIds to partitionIds. */ - PARTITION_SIZES("PartitionSizes"), + ROW_TO_PARTITION("RowToPartition"), + + /** + * An on-disk block packed index mapping partitionIds to the number of rows for the partition. + */ + PARTITION_TO_SIZE("PartitionToSize"), /** * Prefix-compressed blocks of partition keys used for rowId to partition key lookups diff --git a/src/java/org/apache/cassandra/index/sai/disk/v1/SSTableComponentsWriter.java b/src/java/org/apache/cassandra/index/sai/disk/v1/SSTableComponentsWriter.java index 63670c8f17..b6e006584a 100644 --- a/src/java/org/apache/cassandra/index/sai/disk/v1/SSTableComponentsWriter.java +++ b/src/java/org/apache/cassandra/index/sai/disk/v1/SSTableComponentsWriter.java @@ -42,18 +42,22 @@ public class SSTableComponentsWriter implements PerSSTableIndexWriter private final IndexDescriptor indexDescriptor; private final MetadataWriter metadataWriter; private final NumericValuesWriter partitionSizeWriter; + private final NumericValuesWriter partitionRowsWriter; private final NumericValuesWriter tokenWriter; private final KeyStoreWriter partitionKeysWriter; private final KeyStoreWriter clusteringKeysWriter; private long partitionId = -1; + // This is used to record the number of rows in each partition + private long partitionRowCount = 0; public SSTableComponentsWriter(IndexDescriptor indexDescriptor) throws IOException { this.indexDescriptor = indexDescriptor; this.metadataWriter = new MetadataWriter(indexDescriptor.openPerSSTableOutput(IndexComponent.GROUP_META)); - this.tokenWriter = new NumericValuesWriter(indexDescriptor, IndexComponent.TOKEN_VALUES, metadataWriter, false); - this.partitionSizeWriter = new NumericValuesWriter(indexDescriptor, IndexComponent.PARTITION_SIZES, metadataWriter, true); + this.tokenWriter = new NumericValuesWriter(indexDescriptor, IndexComponent.ROW_TO_TOKEN, metadataWriter, false); + this.partitionRowsWriter = new NumericValuesWriter(indexDescriptor, IndexComponent.ROW_TO_PARTITION, metadataWriter, true); + this.partitionSizeWriter = new NumericValuesWriter(indexDescriptor, IndexComponent.PARTITION_TO_SIZE, metadataWriter, false); IndexOutputWriter partitionKeyBlocksWriter = indexDescriptor.openPerSSTableOutput(IndexComponent.PARTITION_KEY_BLOCKS); NumericValuesWriter partitionKeyBlockOffsetWriter = new NumericValuesWriter(indexDescriptor, IndexComponent.PARTITION_KEY_BLOCK_OFFSETS, metadataWriter, true); this.partitionKeysWriter = new KeyStoreWriter(indexDescriptor.componentName(IndexComponent.PARTITION_KEY_BLOCKS), @@ -82,7 +86,11 @@ public class SSTableComponentsWriter implements PerSSTableIndexWriter @Override public void startPartition(DecoratedKey partitionKey) throws IOException { + if (partitionId >= 0) + partitionSizeWriter.add(partitionRowCount); + partitionId++; + partitionRowCount = 0; partitionKeysWriter.add(v -> ByteSource.of(partitionKey.getKey(), v)); if (indexDescriptor.hasClustering()) clusteringKeysWriter.startPartition(); @@ -92,7 +100,8 @@ public class SSTableComponentsWriter implements PerSSTableIndexWriter public void nextRow(PrimaryKey primaryKey) throws IOException { tokenWriter.add(primaryKey.token().getLongValue()); - partitionSizeWriter.add(partitionId); + partitionRowsWriter.add(partitionId); + partitionRowCount++; if (indexDescriptor.hasClustering()) clusteringKeysWriter.add(indexDescriptor.clusteringComparator.asByteComparable(primaryKey.clustering())); } @@ -102,11 +111,12 @@ public class SSTableComponentsWriter implements PerSSTableIndexWriter { try { + partitionSizeWriter.add(partitionRowCount); indexDescriptor.createComponentOnDisk(IndexComponent.GROUP_COMPLETION_MARKER); } finally { - FileUtils.close(tokenWriter, partitionSizeWriter, partitionKeysWriter, clusteringKeysWriter, metadataWriter); + FileUtils.close(tokenWriter, partitionSizeWriter, partitionRowsWriter, partitionKeysWriter, clusteringKeysWriter, metadataWriter); } } diff --git a/src/java/org/apache/cassandra/index/sai/disk/v1/SkinnyPrimaryKeyMap.java b/src/java/org/apache/cassandra/index/sai/disk/v1/SkinnyPrimaryKeyMap.java index 35c9f2f9f8..a764eb6c8e 100644 --- a/src/java/org/apache/cassandra/index/sai/disk/v1/SkinnyPrimaryKeyMap.java +++ b/src/java/org/apache/cassandra/index/sai/disk/v1/SkinnyPrimaryKeyMap.java @@ -34,7 +34,6 @@ import org.apache.cassandra.index.sai.disk.v1.bitpack.NumericValuesMeta; import org.apache.cassandra.index.sai.disk.v1.keystore.KeyLookupMeta; import org.apache.cassandra.index.sai.disk.v1.keystore.KeyLookup; import org.apache.cassandra.index.sai.utils.PrimaryKey; -import org.apache.cassandra.io.sstable.format.SSTableReader; import org.apache.cassandra.io.util.FileHandle; import org.apache.cassandra.io.util.FileUtils; import org.apache.cassandra.utils.Throwables; @@ -44,10 +43,10 @@ import org.apache.cassandra.utils.Throwables; *

* This uses the following on-disk structures: *