Repository navigation
Description
Search before asking
- I had searched in the issues and found no similar issues.
Version
4.0.5-rc01 (commit 59de8c4c524). The same code paths are present on branch-4.0 HEAD and master HEAD as of today.
What's Wrong?
DynamicPartitionScheduler.runtimeInfos (Map<Long, Map<String,String>> keyed by tableId) accumulates entries indefinitely.
Entries are added by createOrUpdateRuntimeInfo() on every scheduler tick for tables with dynamic_partition.enable=true or partitionRetentionCount > 0.
The only place removeRuntimeInfo() is called in production code is ShowDynamicPartitionCommand.doRun() (fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ShowDynamicPartitionCommand.java:107). That cleanup is opportunistic. It only runs when:
- a user explicitly issues
SHOW DYNAMIC PARTITIONagainst a database; - the table is still present in
db.getTables()(so DROP TABLE never reaches it — the table is already gone from the catalog); - the table no longer satisfies
olapTable.dynamicPartitionExists().
No catalog mutation path calls it. Three scenarios leave stale entries behind:
InternalCatalog.unprotectDropTable()— table is gone from the catalog, theruntimeInfosentry stays.DynamicPartitionScheduler.executeDynamicPartition()whendb == null— the scheduler removes the pair fromdynamicPartitionTableInfoviaiterator.remove()and leavesruntimeInfosuntouched.- Same method when
olapTableis null, anMTMV, or has lost both itsdynamic_partition.enableflag andpartitionRetentionCount— same story.
In a cluster where users don't run SHOW DYNAMIC PARTITION regularly (most automated ETL workloads), the map grows unbounded.
In our production cluster (4.0.5-rc01, ETL workload with frequent CREATE/DROP on dynamic_partition tables, ~24K DDL/hour), the FE OOMed after a few weeks of uptime. Heap dump:
runtimeInfosbacked by aConcurrentHashMap$Node[]of 2,097,152 buckets, roughly 1M–1.5M leaked entries.- 554 MB retained on
DynamicPartitionScheduler(17% of live heap post-GC walk). - Dump file: 52 GiB, live heap 3.23 GB after reachability walk, the rest is the leak path holding old
Database/Tablegraphs alive transitively through these stale entries.
What You Expected?
runtimeInfos.remove(tableId) should run when:
- A table is dropped — inside
InternalCatalog.unprotectDropTable(), alongsidedb.unregisterTable(). - The scheduler removes a table from its working set in
executeDynamicPartition(), in each of theiterator.remove(); continue;branches.
How to Reproduce?
Run a CREATE/DROP loop against a table with dynamic_partition.enable=true for long enough and watch FE heap. The leak is fastest under high-DDL-churn ETL workloads, but slow churn hits it eventually because nothing ever clears the map.
A self-contained repro:
CREATE DATABASE leak_repro;
USE leak_repro;
-- in a shell loop, repeat for N=10000 cycles:
CREATE TABLE t (
k INT, dt DATE
) DUPLICATE KEY(k) PARTITION BY RANGE(dt) ()
DISTRIBUTED BY HASH(k) BUCKETS 1
PROPERTIES (
"dynamic_partition.enable"="true",
"dynamic_partition.time_unit"="DAY",
"dynamic_partition.start"="-3",
"dynamic_partition.end"="3",
"dynamic_partition.prefix"="p",
"replication_num"="1"
);
DROP TABLE t;Take a heap dump, open in Eclipse MAT, look at retained heap on DynamicPartitionScheduler. Bucket count on runtimeInfos will track the iteration count.
Anything Else?
Suggested patch (4 lines added across two files):
diff --git a/fe/fe-core/src/main/java/org/apache/doris/clone/DynamicPartitionScheduler.java b/fe/fe-core/src/main/java/org/apache/doris/clone/DynamicPartitionScheduler.java
@@ -671,6 +671,7 @@ public class DynamicPartitionScheduler extends MasterDaemon {
Database db = Env.getCurrentInternalCatalog().getDbNullable(dbId);
if (db == null) {
iterator.remove();
+ removeRuntimeInfo(tableId);
continue;
}
@@ -688,6 +689,7 @@ public class DynamicPartitionScheduler extends MasterDaemon {
|| !olapTable.getTableProperty().getDynamicPartitionProperty().getEnable())
&& olapTable.getPartitionRetentionCount() <= 0) {
iterator.remove();
+ removeRuntimeInfo(tableId);
continue;
} else if (olapTable.isBeingSynced()) {
diff --git a/fe/fe-core/src/main/java/org/apache/doris/datasource/InternalCatalog.java b/fe/fe-core/src/main/java/org/apache/doris/datasource/InternalCatalog.java
@@ -1027,6 +1027,8 @@ public class InternalCatalog implements CatalogIf<Database> {
Env.getCurrentEnv().getQueryStats().clear(...);
table.removeTableIdentifierFromPrimaryTable();
db.unregisterTable(table.getId());
+ // Fix DynamicPartitionScheduler.runtimeInfos leak on DROP TABLE.
+ Env.getCurrentEnv().getDynamicPartitionScheduler().removeRuntimeInfo(table.getId());
StopWatch watch = StopWatch.createStarted();
Env.getCurrentRecycleBin().recycleTable(...);A patched build is running in our production cluster since 2026-04-27. Same workload that previously grew runtimeInfos past 500 MB now keeps it flat.
Two analogous leaks fixed in the past by similar remove() calls on the cleanup path:
- [fix](Export) fix a memory leak in the FE because of the ExportJob #44019 — ExportMgr leak
- [fix](cloud)(bulk load) fix memory leak in FE observer node #47074 — CallBackFactory leak
Are you willing to submit PR?
- Yes I am willing to submit a PR!
Code of Conduct
- I agree to follow this project's Code of Conduct
Activity
github-actions commentedon Oct 25, 2026
We're closing this issue because it hasn't been updated in a while.
If you'd like to revive this issue, please reopen it and feel free a maintainer to remove the Stale tag!