[ https://issues.apache.org/jira/browse/CASSANDRA-20374?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18003634#comment-18003634 ]
Caleb Rackliffe commented on CASSANDRA-20374: --------------------------------------------- Here are my notes from a first pass at review... *Documentation* - I made a pass at letting Claude generate some JavaDoc for the new {{MultiStepSearcher}} interface and the {{PartialTrackedRead}} -> {{AbstractPartialTrackedRead}} -> {{PartialTrackedIndexRead}} hierarchy. My impression is that some of it could be useful, but I'm also open to waiting until more of the overall CEP implementation stabilizes. Either way, let me know if you want to collaborate on this. *Testing* - We might be able to parameterize {{PartialUpdateHandlingTest}} with replication type in a similar fashion to what this patch already does in {{{}StrictFilteringTest{}}}. - The refactoring to the existing SAI logic will be covered well enough as it is, although some longer runs than what we have in CI for {{{}MultiNodeSAITest{}}}, {{{}MultiNodeTableWalkWithoutReadRepairTest{}}}, and {{MultiNodeTableWalkWithReadRepairTest}} are warranted. The more important point is that we need to expand those (or at least the {{MultiNodeTableWalkBase}} stuff) to cover tables with mutation tracking enabled. (CC [~dcapwell]) - Should {{ReadRepairEmptyRangeTombstonesTestBase}} cover tables w/ mutation tracking? - I'm wondering how necessary the {{AbstractTester#queryColumns()}} logic for overwriting rows when {{replicationType.isTracked()}} is. It seems like the tests (ex. {{{}ReadRepairIndexTest#rangeReadTest(){}}}) already account for this by supplying the full set of rows. Also, in the "tracked" case, {{verifyQuery()}} doesn't look like it really does much? (i.e. Everything is already in sync when we call {{{}verifyQuery(){}}}?) - Similar thing in {{AbstractTester#tearDown()}} where we make adjustments. I played w/ just throwing this (in addition to removing the row reassignments in there and in {{{}queryColumns(){}}}) at the start of {{verifyQuery()}} and it seems to work: {noformat} if (replicationType.isTracked()) { assertRows(cluster.get(1).executeInternal(query), allRows); assertRows(cluster.get(2).executeInternal(query), allRows); return self(); } {noformat} - In {{ReadRepairIndexTest$Tester#createIndex()}} you might eventually have a situation where {{default_secondary_index}} gets set to "sai". If that happens, {{SECONDARY}} will duplicate {{{}SAI{}}}. You can use {{CassandraIndex.NAME}} and force it to use the legacy 2i, etc. *{{RowFilter}}* - This class needs a rebase, as a few important fixes have been made recently, like CASSANDRA-20566 and CASSANDRA-20541. *{{Memtable}}* - {{snapshotPartition()}} is just exposing/wrapping getPartition() in all implementations outside tests. Wondering why we didn't just make {{getPartition()}} public? Also, is what we get back actually a snapshot? Aren't we just getting an {{AtomicBTreePartition}} from {{{}SkipListMemtable{}}}, but the {{ref}} could be updated in {{{}AtomicBTreePartition{}}}? *{{CassandraIndexSearcher}}* - Looks like {{queryDataFromIndex()}} and its implementations are unused now? *{{{}RegularColumnIndex{}}}, {{{}ClusteringColumnIndex{}}}, et al* - {{decodeEntry()}} looks like it involves having to create a DK object it didn't before, but it's probably small enough not to be too visible in a profile. *{{ShardReplicatedOffsets}}* - No love for the TRACE logging for {{{}verbHandler{}}}? *{{Index}}* - Is {{supportsMutationTracking()}} unused? *{{ReadCommand}}* - In {{{}ReadCompleter.TRACKED#complete(){}}}, the {{IllegalStateException}} feels more like an assertion/programming error than a state that we shouldn't see. *{{{}StorageAttachedIndexSearcher{}}}, {{QueryController}}* - Using the natural order means {{{}PrimaryKey#compareTo(){}}}, which is "strict", and will treat static column index matches differently than normal column index matches. (i.e. STATIC will sort at the start of the partition.) Make sure that's what we want. There are lots of existing examples of static/wide intersection testing. ({{{}StaticColumnIndexTest{}}} locally and then {{MultiNodeTableWalkWithoutReadRepairTest}} for multi-node, etc.) - All of this work was done before the enhancements in CASSANDRA-20191 for skipping within a partition, so we'll have to rebase on that and make sure things still work. - We appear to have moved the post-filtering row read batching to the second step of the searcher process now, which should still be fine...just want to confirm. - In {{{}MatchIterator#computeNext(){}}}, I think we can move the {{null}} check for {{resultKeyIterator}} of of the loop and the skipping as well, as they don't actually matter after the first call to {{{}computeNext(){}}}. - I'm not 100% sure that leaving {{hasUnrepairedMatches}} alone in the tracked reads case is the best way to manage what kind of filtering happens at different steps of the multi-step read. It doesn't matter for the first stage, where we're just getting the initial local index matches, as no row filtering occurs there anyway. When we get to the step that uses {{{}MatchIndexer{}}}, we should assess incoming mutations based on whether the original {{ReadCommand}} decides on strict filtering. In other words, we could actually always set {{hasUnrepairedMatches = true}} to preserve that intent, and the {{FilterTree}} you're already building in the searcher constructor would do what it should. We shouldn't force strict filtering on the {{MatchIndexer}} when we don't need to, which is what looks to be happening now. There are a couple other things in {{PartialTrackedIndexRead}} to discuss around what kind of filtering we're applying as well... *{{PartialTrackedIndexRead}}* - Claude is worried (anthropomorphizing, I know) about {{prepareInternal()}} holding a large {{TreeSet}} of {{IndexMatch}} objects on the heap for individual queries. There is a guardrail we have in RFP to limit this kind of thing w/ warning and failure thresholds. (see {{{}replica_filtering_protection.cached_rows_warn_threshold{}}}) The other thing I'm curious about is the {{TreeSet}} doing extra sorting work when the SAI match iterator should already produce a sorted stream of {{{}PrimaryKey{}}}. It looks like this set is later directly added to during augmentation, so I'm guessing that's the point, but if there is minimal augmentation, perhaps it would be cheaper to zip that smaller sorted set into the primary match iterator. - In {{{}prepareInternal(){}}}, there's this: {{{}// TODO (now): make decorated key part of IndexEntry interface{}}}. Did it mean {{{}IndexMatch{}}}? is it already done? - In {{{}FollowUpRead{}}}, {{{}promise{}}}, {{{}consistencyLevel{}}}, and {{expiresAtNanos}} are either unused or can be local - {{Preconditions.checkArgument(minIdx >= 0);}} in {{MergingMatchIterator#computeNext()}} could probably just be an assertion, given it's guaranteed to be true. - nit: {{SnapshotView}} and {{IndexpartitionRead}} assume a single DK, but they also have methods that take arbitrary partition updates. There are defensive checks in place to make sure those things don't get mixed up, but I wonder if there's a better way... - nit: {{prepareInternal()}} in the indexed case doesn't use {{{}initialData{}}}. I guess we could codify that expectation and throw IAE otherwise. - nit: General naming ambiguities, things like {{IndexCompletedRead}} and {{CompletedIndexRead}} were there is only one implementation of the interface. - {{IndexCompletedRead.UnfilteredResultIterator}} can't be static because of type args, so should we just use the {{followUpReads}} from the enclosing class? - {{IndexPreComplete#preComplete()}} and it's abstract version in the super don't do anything. - Let's return to our conversation around post-filtering and {{{}hasUnrepairedMatches{}}}. In {{PTIR}} we filter in three places I can see, and all of them look to be over completed/augmented data. This means that we should be using strict filtering for all of them. Right now, this actually might work, because we leave {{hasUnrepairedMatches = false}} for the tracked case and the existing {{filterTree}} respects it, but if we correct this (see the comment above), we would have make sure the {{FilterTree}} we use here is explicitly made strict, just as we force it in RFP at the coordinator (see {{{}filterReplicaFilteringProtection(){}}}). - We post-filter with {{readHit()}} in {{{}UnfilteredResultIterator{}}}, but then again in {{filter()}} via {{{}filterCompletedRead(){}}}. Has any of the underlying data changed there? If not, are we filtering twice? (Again, if the data is completed in both cases, the filtering should be explicitly strict.) [~bdeggleston] Let's discuss when you're back from your break if you have some time. > CEP-45: Index read support for mutation tracking > ------------------------------------------------ > > Key: CASSANDRA-20374 > URL: https://issues.apache.org/jira/browse/CASSANDRA-20374 > Project: Apache Cassandra > Issue Type: Improvement > Components: Consistency/Coordination > Reporter: Blake Eggleston > Assignee: Blake Eggleston > Priority: Normal > > Index reads are disabled for mutation tracking and we need to add support for > them. A big part of this will be adapting the ReplicaFilteringProtection to > work with the logged read classes. -- This message was sent by Atlassian Jira (v8.20.10#820010) --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@cassandra.apache.org For additional commands, e-mail: commits-h...@cassandra.apache.org