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


##########
fe/fe-core/src/main/java/org/apache/doris/job/extensions/mtmv/MTMVTask.java:
##########
@@ -510,9 +565,46 @@ && hasUnusableIvmStream()) {
                     mtmv.getName(), getTaskId());
             return Lists.newArrayList(RefreshAttemptType.COMPLETE);
         }
+        // Every partition either needs a rebuild or was never filled, and at 
least one needs a rebuild:
+        // COMPLETE then does nothing the per-partition routing would not, in 
one read of the MV.
+        if (!request.explicitPartitions && 
attempts.contains(RefreshAttemptType.IVM)

Review Comment:
   Fixed, and confirmed as the substantive one of the four. The requirement is 
durable and per partition, and only the requests that reach the incremental 
attempt were reading it: `planPartitionRefresh` asked `isMTMVSync` -- the 
snapshots -- and returned an empty plan, so a `PARTITIONS` request over the 
failed-whole-MV-refresh state reported NOT_REFRESH and repaired nothing, while 
a strict request that may not fall back got that same silent success instead of 
the failure its own contract promises. The plan reads the requirement as well 
now (`MTMV#getPartitionsNeedingRebuild`), both `PARTITIONS` forms rebuild the 
partitions it names, and the incremental refresh after them reports nothing 
left to rebuild -- the requirement cleared rather than deferred.
   
   Of your two options I took the first (plan by the requirement) rather than 
refuse or force: a partition refresh of one of those partitions is exactly the 
rebuild the requirement asks for -- it is what the incremental attempt's own 
rebuild phase calls -- so refusing would leave a job whose refresh method is 
PARTITIONS unable to recover the MV at all, which is the worse end of the same 
defect.
   
   Covered end to end by a new nonConcurrent suite, 
`test_ivm_partitions_after_failed_complete`: it produces the state by injecting 
the failure into a real whole-MV refresh (a debug point on the IVM insert, so 
the mark is journaled and the snapshots are never written), then runs both 
`PARTITIONS` forms and pins the whole-MV scope, the row that was pending, and 
the following incremental refresh reporting nothing to rebuild. Reverting just 
this change makes it fail with the snapshot-only scope (`PARTIAL`), as the 
positive control.



##########
fe/fe-core/src/main/java/org/apache/doris/job/extensions/mtmv/MTMVTask.java:
##########
@@ -510,9 +565,46 @@ && hasUnusableIvmStream()) {
                     mtmv.getName(), getTaskId());
             return Lists.newArrayList(RefreshAttemptType.COMPLETE);
         }
+        // Every partition either needs a rebuild or was never filled, and at 
least one needs a rebuild:
+        // COMPLETE then does nothing the per-partition routing would not, in 
one read of the MV.
+        if (!request.explicitPartitions && 
attempts.contains(RefreshAttemptType.IVM)
+                && shouldEscalateToComplete()) {
+            LOG.info("Every MV partition needs a rebuild or has no data yet, 
mv={}, taskId={}. "
+                    + "Continuing with COMPLETE refresh.", mtmv.getName(), 
getTaskId());
+            return Lists.newArrayList(RefreshAttemptType.COMPLETE);
+        }
         return attempts;
     }
 
+    /**
+     * Notes that this refresh rebuilds partitions the request did not ask to 
rebuild, which is what a
+     * strict INCREMENTAL request cannot tell from its result otherwise: it 
reports the count, and a request
+     * that asked for a complete refresh reports nothing because rebuilding 
everything is what it asked for.
+     */
+    private void recordRebuiltPartitions(RefreshRequest request, int 
rebuiltPartitions) {
+        // Only an IVM MV has a baseline to rebuild: a plain MV's COMPLETE is 
the only way it refreshes at
+        // all, so reporting it there would put a rebuild count on every 
ordinary refresh.
+        if (!mtmv.isIvm() || request.refreshMode == RefreshMode.COMPLETE) {
+            return;
+        }
+        ivmRebuiltPartitions = rebuiltPartitions;

Review Comment:
   Fixed. Where I agree, and where I read the consequence more narrowly.
   
   Agreed, and this is what changed: the two columns were reassigned per phase, 
so a refresh that rebuilt a partition and then fell back reported only what the 
fallback covered, while the MV published the rebuilt partition's snapshots and 
its epochs. They are task-wide accumulators now -- sets, because a later 
attempt's scope can cover an earlier one's (a whole-MV attempt after a 
per-partition one) and a partition counted twice would report more work than 
the MV has partitions -- and `IvmRebuiltPartitions` is the largest count the 
attempts reported rather than the last one's, for the same reason. That also 
let the round-3 merge block go: the union is at the source now, so a phase 
cannot narrow what an earlier one reported.
   
   Where I did not follow the finding's conclusion: "SHOW loses work the task 
actually committed" holds for the two columns, but I could not construct a case 
where a *successful* task reports a wrong rebuilt count. The 
overwrite-with-zero needs the whole-MV arm to be last and the task still to 
succeed, and that arm returns: if the attempt throws, the task fails and 
nothing is published, and its early `NOT_REFRESH` return is unreachable as long 
as the arm sets its scope to the MV's partition names. So what I fixed there is 
the fragility of "last writer wins" rather than a wrong value today. The record 
keeps its shape in one more respect: both columns are still JSON arrays of 
names -- a task written by an earlier FE reads into the sets and the sets write 
the same JSON, which a test pins.



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