github-actions[bot] commented on code in PR #66247:
URL: https://github.com/apache/doris/pull/66247#discussion_r3688450289


##########
fe/fe-core/src/main/java/org/apache/doris/nereids/StatementContext.java:
##########
@@ -1047,8 +1049,28 @@ public void loadSnapshots(TableIf specificTable, 
Optional<TableSnapshot> tableSn
             MvccTableInfo mvccTableInfo = new MvccTableInfo(specificTable,
                     versionKeyOf(tableSnapshot, scanParams));
             if (!snapshots.containsKey(mvccTableInfo)) {
-                snapshots.put(mvccTableInfo,
-                        ((MvccTable) 
specificTable).loadSnapshot(tableSnapshot, scanParams));
+                MvccTable mvccTable = (MvccTable) specificTable;
+                MvccSnapshot snapshot;
+                if (mvccTable.requiresLatestSnapshotFence(tableSnapshot, 
scanParams)) {
+                    MvccTableInfo latestKey = new MvccTableInfo(specificTable);
+                    MvccSnapshot latestFence = 
latestSnapshots.computeIfAbsent(latestKey,

Review Comment:
   [P1] Reuse an explicitly seeded statement snapshot for this fence. MTMV 
refresh captures snapshot S before planning and injects it with 
`setSnapshot(defaultKey, S)`, but that setter populates only `snapshots`, not 
`latestSnapshots`. A reader/planning-only `@options` relation has a non-default 
projection key, misses `snapshots`, and reaches this `computeIfAbsent`, 
performing a live latest lookup S+1. If a commit lands after MTMV's capture, 
the option alias scans S+1 while a plain alias in the same refresh still reads 
seeded S. Please seed `latestSnapshots` when a default snapshot is supplied (or 
prefer the existing default entry here), and add an MTMV-style seeded-fence 
alias-order test.



##########
fe/be-java-extensions/paimon-scanner/src/main/java/org/apache/doris/paimon/PaimonJniScanner.java:
##########
@@ -575,12 +676,98 @@ static Optional<Long> parseDataSizeBytes(String value) {
     private void initTable() {
         Preconditions.checkState(params.containsKey("serialized_table"));
         table = PaimonUtils.deserialize(params.get("serialized_table"));
+        table = applyBackendManifestParallelism(table,
+                params.get(PAIMON_OPTION_PREFIX + 
DORIS_MANIFEST_PARALLELISM_CAP),
+                Runtime.getRuntime().availableProcessors());
+        validateSerializedReaderOptions(table);
         paimonAllFieldNames = PaimonUtils.getFieldNames(this.table.rowType());
         if (LOG.isDebugEnabled()) {
             LOG.debug("paimonAllFieldNames:{}", paimonAllFieldNames);
         }
     }
 
+    static Table applyBackendManifestParallelism(
+            Table table, String feParallelismCap, int localCapacity) {
+        int safeParallelism;
+        if (feParallelismCap != null) {
+            safeParallelism = 
parsePositiveManifestParallelism(feParallelismCap);
+            if (safeParallelism <= localCapacity) {
+                return table;
+            }
+            safeParallelism = localCapacity;
+        } else {
+            List<Integer> configuredValues = new ArrayList<>();
+            collectManifestParallelism(table, configuredValues);
+            if (configuredValues.isEmpty()
+                    || configuredValues.stream().noneMatch(value -> value > 
localCapacity)) {
+                return table;
+            }
+            safeParallelism = Math.min(
+                    
configuredValues.stream().mapToInt(Integer::intValue).min().getAsInt(),
+                    localCapacity);
+        }
+        Map<String, String> cap = Collections.singletonMap(
+                CoreOptions.SCAN_MANIFEST_PARALLELISM.key(), 
String.valueOf(safeParallelism));
+        // File-store copies must retain the FE-selected schema while only 
lowering an execution
+        // bound; ordinary copy can re-resolve time travel and undo schema 
pinning.
+        return table instanceof FileStoreTable
+                ? ((FileStoreTable) table).copyWithoutTimeTravel(cap)
+                : table.copy(cap);

Review Comment:
   [P1] Preserve the schema fence when capping system wrappers. For a deferred 
`$files`/`$partitions` object this arm receives a system wrapper, so Paimon 
delegates `table.copy(cap)` to the hidden `storeTable.copy`. Because 
`tableForBackend` retained `scan.snapshot-id` with `copyWithoutTimeTravel`, 
this ordinary copy re-runs time travel and rewinds the hidden base schema, 
undoing that deliberate fence. After a schema-only ALTER with no new snapshot, 
a smaller BE can therefore return `$files` stats maps keyed by the old fields 
(`FilesRead` seeds them from `storeTable.schema().id()`) while the FE has bound 
the current schema. Please cap the hidden base with `copyWithoutTimeTravel` and 
rebuild the same wrapper, and cover a real deferred system wrapper at lower BE 
capacity.



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