yujun777 commented on code in PR #68390:
URL: https://github.com/apache/doris/pull/68390#discussion_r4128484606


##########
fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/NormalizeOlapTableStreamScan.java:
##########
@@ -262,6 +263,15 @@ private Plan makeSnapshotScan(LogicalOlapTableStreamScan 
scan, CascadesContext c
         OlapTable baseTable = streamWrapper.getBaseTable();
         List<Slot> originSlots = scan.getOutput();
         selectedPartitionIds = 
streamWrapper.filterConsumedPartitionIds(selectedPartitionIds);
+        // What this read is about to answer with is recorded here, where the 
plan is final and the read states
+        // are in place, and before the read is built: the refresh that reads 
it back may not record a
+        // partition it replaced through an image of the table as of the 
offset as caught up -- what it wrote
+        // is that image, and the delta that would bring the table up to date 
does not apply to it. See
+        // MTMVTask#executePartitionBasedRefresh.
+        if (streamWrapper.readsSnapshotOfAnOlderImage(selectedPartitionIds)) {

Review Comment:
   Right, and the reason it kept applying is that the branch I pointed at was 
unreachable from where it runs. `answersWithTheCurrentTable` asks about a 
partition the read dropped that holds rows, and the caller handed it the list 
`filterConsumedPartitionIds` had already filtered -- so the partitions that 
branch is about were not in it, and the judgement answered "yes, the table as 
it is now" about a read that had just left rows out. Handing it the filtered 
list asked a different question than its own contract states.
   
   `e952c29714d` asks it before the filter, with the partitions the scan 
selected: the filtering that has to be visible to the question is the wrapper's 
own, which sees what it dropped. Nothing else moves -- every read below still 
uses the filtered list.
   
   What it costs, measured rather than reasoned, is in the suite added here: a 
dimension that is empty when the MV's baseline is built, so its partition is 
never given an offset; rows inserted into it afterwards; one fact partition 
invalidated; and the strict refresh whose delta fails, which is the case you 
asked to have covered. Reverted, that suite fails on the task row of the 
refresh after it -- `NONE` with the untouched partition's scope and no rebuild, 
because the failed refresh had recorded the rebuilt partition as caught up and 
the refresh that follows sees nothing to do. In place, the rebuild is still 
owed, its delta reads the dimension without the snapshot's offset and joins its 
rows in, and the records the rebuild held back are published with it -- the 
third refresh then reports nothing left.
   
   Two things I checked before committing, since the change widens what is 
withheld. The direction is one extra rebuild, never a missing row. The other 
route it can reach is a whole-MV refresh, whose first batch reads the tables 
through RESET rather than the snapshot: measured on a cluster, a `REFRESH 
COMPLETE` in the same state lands the joined rows, and the `INCREMENTAL` 
refreshes after it report no scope and no rebuild. And the suite carries 
`nonConcurrent` (it drives a debug point), which the cloud pipeline skips, so 
the sentinel-offset variant of this case is covered by inspection here rather 
than end to end.
   



-- 
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