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


##########
fe/fe-core/src/main/java/org/apache/doris/datasource/iceberg/source/IcebergScanNode.java:
##########
@@ -1367,9 +1461,11 @@ private List<Split> doGetSystemTableSplits() throws 
UserException {
         List<Split> splits = new ArrayList<>();
         TableScan scan = createTableScan();
         long startTime = System.currentTimeMillis();
-        try (CloseableIterable<FileScanTask> fileScanTasks = scan.planFiles()) 
{
+        try {
+            List<FileScanTask> fileScanTasks = getOrLoadExternalScanTasks(

Review Comment:
   [P1] Keep metadata-table task planning streaming
   
   This changes the metadata-table path from consuming `scan.planFiles()` one 
task at a time to materializing every native task in the statement cache before 
any are serialized into Doris splits. System tables are hard-excluded from 
batch mode, so large `$files`/`$entries` scans—and especially 
`$all_files`/`$all_entries`, which traverse manifests across snapshots—now 
retain both the full native task graph and every Base64-serialized 
`IcebergSplit` until statement end. In Iceberg 1.10.1 these tables create one 
`ManifestReadTask` per manifest and each task copies the table's spec map, so 
long table histories can exhaust FE heap even though the previous loop let each 
native task become collectible after conversion. Please keep this system-table 
conversion on the streaming `planFiles()` iterable, or otherwise bypass 
statement caching here.



##########
fe/fe-core/src/main/java/org/apache/doris/datasource/hudi/source/HudiScanNode.java:
##########
@@ -380,29 +384,80 @@ private List<HivePartition> 
getPrunedPartitions(HoodieTableMetaClient metaClient
 
     private List<Split> getIncrementalSplits() {
         long startTime = System.currentTimeMillis();
-        if (canUseNativeReader()) {
-            List<Split> splits = incrementalRelation.collectSplits();
-            noLogsSplitNum.addAndGet(splits.size());
+        try {
+            HudiIncrementalScanTaskCacheKey cacheKey = new 
HudiIncrementalScanTaskCacheKey(
+                    hmsTable.getCatalog().getId(), hmsTable.getId(),
+                    incrementalRelation.getStartTs(), 
incrementalRelation.getEndTs(),
+                    canUseNativeReader(), 
incrementalRelation.getHoodieParams());
+            List<HudiSplit> plannedSplits = 
getOrLoadExternalScanTasks(cacheKey, () -> {
+                if (canUseNativeReader()) {
+                    return incrementalRelation.collectSplits().stream()
+                            .map(split -> {
+                                Preconditions.checkState(split instanceof 
HudiSplit,
+                                        "Hudi COW incremental relation must 
produce HudiSplit");
+                                return (HudiSplit) split;
+                            })
+                            .collect(Collectors.toList());
+                }
+                Option<String[]> partitionColumns = 
hudiClient.getTableConfig().getPartitionFields();
+                List<String> partitionNames = partitionColumns.isPresent()
+                        ? Arrays.asList(partitionColumns.get()) : 
Collections.emptyList();
+                return incrementalRelation.collectFileSlices().stream()
+                        .map(fileSlice -> generateHudiSplit(fileSlice,
+                                HudiPartitionUtils.parsePartitionValues(
+                                        partitionNames, 
fileSlice.getPartitionPath()),
+                                incrementalRelation.getEndTs()))
+                        .collect(Collectors.toList());
+            });
+            List<Split> splits = plannedSplits.stream()

Review Comment:
   [P1] Avoid duplicating every incremental Hudi split
   
   `getIncrementalSplits()` is hard-excluded from batch mode, but this now 
retains the complete `plannedSplits` list in the statement cache and 
deep-copies every element into the scan's output. For MOR/JNI reads, 
`generateHudiSplit()` shares the node's column-name/type lists across source 
splits, while `copyHudiSplit()` allocates a fresh copy of both lists for every 
file, so a wide incremental range holds an O(files * columns) copy in addition 
to the original split graph until statement close. COW ranges also retain two 
complete split graphs. Previously the one planned list could be released after 
range conversion. Please bypass statement caching for incremental scans, or 
cache an immutable compact representation that doesn't require retaining and 
copying the full graph.



##########
fe/fe-core/src/main/java/org/apache/doris/datasource/hudi/source/HudiScanNode.java:
##########
@@ -380,29 +384,80 @@ private List<HivePartition> 
getPrunedPartitions(HoodieTableMetaClient metaClient
 
     private List<Split> getIncrementalSplits() {
         long startTime = System.currentTimeMillis();
-        if (canUseNativeReader()) {
-            List<Split> splits = incrementalRelation.collectSplits();
-            noLogsSplitNum.addAndGet(splits.size());
+        try {
+            HudiIncrementalScanTaskCacheKey cacheKey = new 
HudiIncrementalScanTaskCacheKey(

Review Comment:
   [P1] Key incremental tasks by the relation snapshot
   
   `HudiIncrementalScanTaskCacheKey` omits this node's resolved `queryInstant`, 
even though the relation grammar permits `table@incr(...) FOR TIME AS OF ...` 
and each alias carries its own `HudiMvccSnapshot`. For MOR/JNI planning, 
`doInitialize()` loads `columnNames`/`columnTypes` from that historical instant 
and `generateHudiSplit()` embeds them in every cached split. Two aliases with 
the same incremental begin/end/options but different `FOR TIME AS OF` instants 
therefore compare equal, so the second skips its loader and sends the first 
alias's historical schema vectors to BE. With schema evolution between the 
instants this can decode the second scan against the wrong schema. Please 
include `queryInstant` (or an equivalent snapshot/schema identity) in this key 
and cover two historical MOR aliases in one statement.



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