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


##########
fe/fe-core/src/main/java/org/apache/doris/mtmv/MTMVRelatedPartitionDescTransferGenerator.java:
##########
@@ -65,6 +75,38 @@ public void apply(MTMVPartitionInfo mvPartitionInfo, 
Map<String, String> mvPrope
         lastResult.setRes(res);
     }
 
+    /**
+     * One MV partition per set of keys that meet, whichever table wrote them 
down: a partition of a list
+     * partitioned base table can hold several keys of the MV's partition 
column, so two partitions -- of one
+     * table or of two -- can describe keys that meet, and an MV's own 
partitions cannot overlap. The one
+     * partition that holds a group's keys names every table's partitions of 
them, which is what a refresh
+     * reads and records for those keys (see {@link 
MTMVPartitionUtil#mergedListDescs}).
+     *
+     * <p>Merging across tables, not within each of them, is what keeps the MV 
buildable: two tables of a
+     * multi-table MV have to come out with the same descs, or one table's 
merged desc repeats a key another
+     * table's desc holds and `checkIntersect` (or the partition creation 
itself) rejects the MV.
+     */
+    private Map<PartitionKeyDesc, Map<MTMVRelatedTableIf, Set<String>>> 
mergeOverlappingListDescs(
+            Map<MTMVRelatedTableIf, Map<PartitionKeyDesc, Set<String>>> descs) 
{
+        Set<PartitionKeyDesc> allDescs = Sets.newHashSet();
+        for (Map<PartitionKeyDesc, Set<String>> onePctDescs : descs.values()) {
+            allDescs.addAll(onePctDescs.keySet());
+        }
+        Map<PartitionKeyDesc, PartitionKeyDesc> mergedOfDesc = 
MTMVPartitionUtil.mergedListDescs(allDescs);
+        Map<PartitionKeyDesc, Map<MTMVRelatedTableIf, Set<String>>> res = 
Maps.newHashMap();
+        for (Entry<MTMVRelatedTableIf, Map<PartitionKeyDesc, Set<String>>> 
entry : descs.entrySet()) {
+            for (Entry<PartitionKeyDesc, Set<String>> onePctEntry : 
entry.getValue().entrySet()) {
+                PartitionKeyDesc desc = 
mergedOfDesc.getOrDefault(onePctEntry.getKey(), onePctEntry.getKey());

Review Comment:
   Closed here rather than in a follow-up: d880803e06d scopes external PCT 
reads to their recorded partitions.
   
   - `MTMVPartitionUtil#mappedBasePartitions` now names every PCT table, olap 
or external, with an empty set before filling in the names the mapping holds, 
so an external table the mapping does not name for this batch is read as no 
rows instead of through the MV partition's key range.
   - `UpdateMvByPartitionCommand` resolves a scoped table's partitions through 
`MTMVRelatedTableIf#getAndCopyPartitionItems`/`getPartitionColumns` at the 
snapshot pinned in the statement context -- the one the mapping was built from 
-- and refuses a recorded partition that snapshot lacks, instead of casting the 
table to `OlapTable`.
   
   The regression is `mtmv_p0/test_mtmv_external_pct_read_scope`, on your 
fixture: OLAP A `LIST(d,k)` with `p_kept={(2020-01-01,1),(2038-01-01,1)}`, 
Paimon E `LIST(d)` with one populated partition per date, a non-IVM `PARTITION 
BY(d)` view of `SELECT a.d,a.k,e.v FROM A a JOIN E e ON a.d=e.d`, 
`partition_sync_limit=2`, `partition_sync_time_unit=YEAR`. The COMPLETE refresh 
now reads E only at its mapped `2038` partition, so the view partition holds 
only the 2038 row although its own keys include 2020. After `ALTER TABLE ... 
DROP PARTITION (d = '2020-01-01')` on the Paimon side and `REFRESH CATALOG`, 
the view partition is still reported synchronized -- and holds no row from the 
dropped partition. With the read left at the MV key range the COMPLETE refresh 
materializes both rows and the D0 row stays after the remote drop, which is 
what the golden records against.
   



##########
fe/fe-core/src/main/java/org/apache/doris/job/extensions/mtmv/MTMVTask.java:
##########
@@ -1290,6 +1290,13 @@ private void 
executePartitionBasedRefresh(MTMVRefreshContext context, RefreshMod
             int end = start + refreshPartitionNum;
             Set<String> execPartitionNames = Sets.newHashSet(partitions
                     .subList(start, Math.min(end, partitions.size())));
+            // What this batch reads and what it records are the same set, 
both decided here from the one
+            // mapping the snapshots below are generated from; see 
MTMVPartitionUtil#mappedBasePartitions.
+            Map<BaseTableInfo, Set<String>> readableBasePartitions = 
mtmv.isIvm()
+                    ? null : 
MTMVPartitionUtil.mappedBasePartitions(tableWithPartKey, context, 
execPartitionNames);

Review Comment:
   Closed here rather than in a follow-up: 8d1ab2b90f4 preserves an explicit 
empty reset set for every absent PCT input.
   
   - `MTMVTask#collectPctResetPartitionIds` pre-seeds every OLAP PCT input with 
an empty set, the same way `generateRelatedBasePartitionIds` seeds the delta's 
scope, so a table absent from the batch's mapping is a stated empty read rather 
than an unscoped one.
   - `IvmFullRefreshMTMV` answers an empty reset set with a 
`LogicalEmptyRelation` before any stream lookup: the table feeds the batch with 
no partitions, so it is read as no rows -- and a table read as nothing needs no 
usable stream.
   
   The regression is `mtmv_p0/ivm/test_ivm_absent_pct_input_read_scope`, on the 
same merged-component shape: A.kept={2020,2038}, C.kept={2020,2038,2039}, 
B.old={2020}, B.future={2040}, one 2020 row in each, plus a 2045 component all 
three tables name so the MV is proven built rather than trivially empty; 
`PARTITION BY(d)`, `partition_sync_limit=2 YEAR`, `refresh_partition_num=1`. 
COMPLETE on M records B={} and reads B as no rows, so the 2020 join row is not 
materialized (with the old code it is), while M still holds the 2045 component 
every input feeds. After `DELETE FROM B WHERE d='2020-01-01'`, `REFRESH ... 
INCREMENTAL` exits at the all-synchronized check with the 2020 row still 
absent, where the old code preserved it.
   
   So the fork I described earlier is settled on the read side: the batch's 
scope is the mapping, and a table the mapping does not name is read as nothing 
-- the MV loses no row the batch's keys produce, because the regression's other 
component is still built with all three inputs read.
   



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