lukasz-antoniak commented on code in PR #254:
URL: 
https://github.com/apache/cassandra-analytics/pull/254#discussion_r4351328349


##########
cassandra-six-zero-bridge/src/main/java/org/apache/cassandra/bridge/CassandraBridgeImplementation.java:
##########
@@ -227,6 +232,186 @@ public StreamScanner<RowData> 
getCompactionScanner(@NotNull CqlTable table,
         }));
     }
 
+    @Override
+    public StreamScanner<RowData> getCompactionScanner(@NotNull CqlTable table,
+                                                       @NotNull Partitioner 
partitioner,
+                                                       @NotNull 
SSTablesSupplier ssTables,
+                                                       @Nullable 
SparkRangeFilter sparkRangeFilter,
+                                                       @NotNull 
Collection<PartitionKeyFilter> partitionKeyFilters,
+                                                       @NotNull 
SSTableTimeRangeFilter sstableTimeRangeFilter,
+                                                       @Nullable 
PruneColumnFilter columnFilter,
+                                                       @NotNull TimeProvider 
timeProvider,
+                                                       boolean readIndexOffset,
+                                                       boolean 
useIncrementalRepair,
+                                                       @NotNull Stats stats,
+                                                       @NotNull 
List<SaiFilter> saiFilters,
+                                                       int 
saiMaxCandidateTokens)
+    {
+        // A complete partition-key lookup is already more selective and 
cheaper than consulting SAI.
+        if (!partitionKeyFilters.isEmpty() || saiFilters.isEmpty())
+        {
+            return getCompactionScanner(table, partitioner, ssTables, 
sparkRangeFilter, partitionKeyFilters,
+                                        sstableTimeRangeFilter, columnFilter, 
timeProvider, readIndexOffset,
+                                        useIncrementalRepair, stats);
+        }
+
+        // NOTE: Need to use SchemaBuilder to init keyspace if not already set 
in Cassandra Schema instance
+        SchemaBuilder schemaBuilder = new SchemaBuilder(table, partitioner);
+        TableMetadata metadata = schemaBuilder.tableMetaData();
+
+        // Resolve each sstable token span before opening any SAI resources so 
data files outside this
+        // Spark worker's token range are ignored.
+        Set<SaiSSTableReference> references = ssTables.openAll((sstable, 
isRepairPrimary) -> {
+            if (sparkRangeFilter == null)
+            {
+                return new SaiSSTableReference(sstable, isRepairPrimary);
+            }
+            Pair<BigInteger, BigInteger> tokens = null;
+            if (sstable.isBigFormat())
+            {
+                SSTableSummary summary = 
getSSTableSummary(metadata.partitioner,
+                                                           sstable,
+                                                           
metadata.params.minIndexInterval,
+                                                           
metadata.params.maxIndexInterval);
+                tokens = Pair.of(summary.firstToken, summary.lastToken);
+            }
+            else
+            {
+                Pair<DecoratedKey, DecoratedKey> keys = 
ReaderUtils.keysFromIndex(metadata.partitioner, sstable);
+                if (keys != null)
+                {
+                    tokens = 
Pair.of(ReaderUtils.tokenToBigInteger(keys.left.getToken()),
+                                     
ReaderUtils.tokenToBigInteger(keys.right.getToken()));
+                }
+            }
+            if (tokens == null)
+            {
+                return new SaiSSTableReference(sstable, isRepairPrimary);
+            }
+            return new SaiSSTableReference(sstable,
+                                           isRepairPrimary,
+                                           tokens.left,
+                                           tokens.right,
+                                           sparkRangeFilter);
+        });
+        if (references.isEmpty())
+        {
+            return EmptyStreamScanner.INSTANCE;
+        }
+
+        Set<SSTable> sstables = references.stream()
+                                          .filter(p -> !p.ignore)
+                                          .map(reference -> reference.sstable)
+                                          .collect(Collectors.toSet());
+        Optional<CandidateTokens> candidates = 
SaiIndexReader.findCandidateTokens(metadata,
+                                                                               
   sstables,
+                                                                               
   saiFilters,
+                                                                               
   sparkRangeFilter,
+                                                                               
   saiMaxCandidateTokens);
+        if (candidates.isEmpty())
+        {
+            // No candidate token ranges selected form SAI filter, use 
standard full-table scan.
+            return openCompactionScanner(metadata, partitioner, timeProvider, 
references, sparkRangeFilter,
+                                         Collections.emptyList(), null, 
sstableTimeRangeFilter, columnFilter,
+                                         readIndexOffset, 
useIncrementalRepair, stats);
+        }
+
+        CandidateTokens candidateTokens = candidates.get();
+        if (candidateTokens.isEmpty())
+        {
+            return EmptyStreamScanner.INSTANCE;
+        }
+
+        return openCompactionScanner(metadata, partitioner, timeProvider, 
references, sparkRangeFilter,
+                                     Collections.emptyList(), candidateTokens, 
sstableTimeRangeFilter,
+                                     columnFilter, readIndexOffset, 
useIncrementalRepair, stats);
+    }
+
+    @NotNull
+    private static StreamScanner<RowData> openCompactionScanner(@NotNull 
TableMetadata metadata,
+                                                                @NotNull 
Partitioner partitioner,
+                                                                @NotNull 
TimeProvider timeProvider,
+                                                                @NotNull 
Set<SaiSSTableReference> references,
+                                                                @Nullable 
SparkRangeFilter sparkRangeFilter,
+                                                                @NotNull 
Collection<PartitionKeyFilter> partitionKeyFilters,
+                                                                @Nullable 
CandidateTokens candidateTokens,
+                                                                @NotNull 
SSTableTimeRangeFilter sstableTimeRangeFilter,
+                                                                @Nullable 
PruneColumnFilter columnFilter,
+                                                                boolean 
readIndexOffset,
+                                                                boolean 
useIncrementalRepair,
+                                                                @NotNull Stats 
stats)
+    {
+        Set<org.apache.cassandra.spark.reader.SSTableReader> readers = 
references.stream()
+                .map(reference -> {
+                    try
+                    {
+                        return 
org.apache.cassandra.spark.reader.SSTableReader.builder(metadata, 
reference.sstable)

Review Comment:
   This is a very good finding. SAI opens SSTables is a two-step process:
   
   1. First we list SSTables and process their SAI indexes to compute candidate 
token ranges.
   2. Second step involves opening actual SSTables and running compaction.
   
   For SAI-search correctness, both stages have to use same SSTables. I have 
tried to refactor the code and introduce "planning" and "opening" stages in 
`SSTablesSupplier`, but code was quite complicated. In the end, I settled on 
passing executor service (like we already do in `getPartitionSizeIterator()`) 
and use it to build `SSTableReader` in parallel.
   
   I will push my changes tomorrow.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to