This is an automated email from the ASF dual-hosted git repository.

JackieTien97 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/iotdb.git


The following commit(s) were added to refs/heads/master by this push:
     new e3ad5350ec8 Avoid heap exhaustion in batch activate template 
permission check (#19024)
e3ad5350ec8 is described below

commit e3ad5350ec8445f5a36e34eb3626aa07835c903d
Author: alpass163 <[email protected]>
AuthorDate: Tue Oct 27 14:01:53 2026 +0800

    Avoid heap exhaustion in batch activate template permission check (#19024)
---
 .../security/TreeAccessCheckVisitor.java           |  20 +++-
 .../InternalBatchActivateTemplateStatement.java    |  15 ++-
 .../template/BatchActivateTemplateStatement.java   |  15 ++-
 .../BatchActivateTemplateStatementTest.java        | 127 +++++++++++++++++++++
 4 files changed, 158 insertions(+), 19 deletions(-)

diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/TreeAccessCheckVisitor.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/TreeAccessCheckVisitor.java
index c1945f9d728..1797f94a548 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/TreeAccessCheckVisitor.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/TreeAccessCheckVisitor.java
@@ -312,7 +312,9 @@ public class TreeAccessCheckVisitor extends 
StatementVisitor<TSStatus, TreeAcces
     return checkTimeSeriesPermission(
         context.setAuditLogOperation(AuditLogOperation.DDL),
         statement::getPaths,
-        PrivilegeType.WRITE_SCHEMA);
+        PrivilegeType.WRITE_SCHEMA,
+        statement::getDevicePathList,
+        Object::toString);
   }
 
   @Override
@@ -321,7 +323,9 @@ public class TreeAccessCheckVisitor extends 
StatementVisitor<TSStatus, TreeAcces
     return checkTimeSeriesPermission(
         context.setAuditLogOperation(AuditLogOperation.DDL),
         statement::getPaths,
-        PrivilegeType.WRITE_SCHEMA);
+        PrivilegeType.WRITE_SCHEMA,
+        () -> statement.getDeviceMap().keySet(),
+        Object::toString);
   }
 
   private TSStatus checkTemplateShowRelated(
@@ -1422,10 +1426,20 @@ public class TreeAccessCheckVisitor extends 
StatementVisitor<TSStatus, TreeAcces
       Supplier<List<? extends PartialPath>> checkedPathsSupplier,
       PrivilegeType permission,
       Function<List<? extends PartialPath>, String> auditObjectFormatter) {
+    return checkTimeSeriesPermission(
+        context, checkedPathsSupplier, permission, checkedPathsSupplier, 
auditObjectFormatter);
+  }
+
+  private static TSStatus checkTimeSeriesPermission(
+      IAuditEntity context,
+      Supplier<List<? extends PartialPath>> checkedPathsSupplier,
+      PrivilegeType permission,
+      Supplier<? extends Collection<? extends PartialPath>> 
systemDatabaseCheckPathsSupplier,
+      Function<List<? extends PartialPath>, String> auditObjectFormatter) {
     context.setPrivilegeType(permission);
     if (permission == PrivilegeType.WRITE_SCHEMA || permission == 
PrivilegeType.WRITE_DATA) {
       final TSStatus systemDatabaseStatus =
-          checkSystemDatabaseWrite(context, checkedPathsSupplier.get());
+          checkSystemDatabaseWrite(context, 
systemDatabaseCheckPathsSupplier.get());
       if (systemDatabaseStatus != null) {
         return systemDatabaseStatus;
       }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/internal/InternalBatchActivateTemplateStatement.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/internal/InternalBatchActivateTemplateStatement.java
index 48f3bf16b8b..f3a01278921 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/internal/InternalBatchActivateTemplateStatement.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/internal/InternalBatchActivateTemplateStatement.java
@@ -31,7 +31,6 @@ import org.apache.tsfile.utils.Pair;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
-import java.util.stream.Collectors;
 
 // This is only used for auto activate template on multi devices while 
inserting data
 public class InternalBatchActivateTemplateStatement extends Statement {
@@ -53,18 +52,18 @@ public class InternalBatchActivateTemplateStatement extends 
Statement {
   @Override
   public List<PartialPath> getPaths() {
     ClusterTemplateManager clusterTemplateManager = 
ClusterTemplateManager.getInstance();
-    List<String> templatePaths = new ArrayList<>();
-    for (PartialPath path : deviceMap.keySet()) {
+    List<PartialPath> paths = new ArrayList<>();
+    for (PartialPath devicePath : deviceMap.keySet()) {
       Pair<Template, PartialPath> templateSetInfo =
-          clusterTemplateManager.checkTemplateSetInfo(path);
+          clusterTemplateManager.checkTemplateSetInfo(devicePath);
       if (templateSetInfo == null) {
         continue;
       }
-      templatePaths.addAll(templateSetInfo.left.getSchemaMap().keySet());
+      for (String measurement : templateSetInfo.left.getSchemaMap().keySet()) {
+        paths.add(devicePath.concatAsMeasurementPath(measurement));
+      }
     }
-    return deviceMap.keySet().stream()
-        .flatMap(path -> 
templatePaths.stream().map(path::concatAsMeasurementPath))
-        .collect(Collectors.toList());
+    return paths;
   }
 
   @Override
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/template/BatchActivateTemplateStatement.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/template/BatchActivateTemplateStatement.java
index b92bc13abc8..40b0faf6b47 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/template/BatchActivateTemplateStatement.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/template/BatchActivateTemplateStatement.java
@@ -30,7 +30,6 @@ import org.apache.tsfile.utils.Pair;
 
 import java.util.ArrayList;
 import java.util.List;
-import java.util.stream.Collectors;
 
 public class BatchActivateTemplateStatement extends Statement {
 
@@ -45,18 +44,18 @@ public class BatchActivateTemplateStatement extends 
Statement {
   @Override
   public List<PartialPath> getPaths() {
     ClusterTemplateManager clusterTemplateManager = 
ClusterTemplateManager.getInstance();
-    List<String> templatePaths = new ArrayList<>();
-    for (PartialPath path : devicePathList) {
+    List<PartialPath> paths = new ArrayList<>();
+    for (PartialPath devicePath : devicePathList) {
       Pair<Template, PartialPath> templateSetInfo =
-          clusterTemplateManager.checkTemplateSetInfo(path);
+          clusterTemplateManager.checkTemplateSetInfo(devicePath);
       if (templateSetInfo == null) {
         continue;
       }
-      templatePaths.addAll(templateSetInfo.left.getSchemaMap().keySet());
+      for (String measurement : templateSetInfo.left.getSchemaMap().keySet()) {
+        paths.add(devicePath.concatAsMeasurementPath(measurement));
+      }
     }
-    return devicePathList.stream()
-        .flatMap(path -> 
templatePaths.stream().map(path::concatAsMeasurementPath))
-        .collect(Collectors.toList());
+    return paths;
   }
 
   public List<PartialPath> getDevicePathList() {
diff --git 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/template/BatchActivateTemplateStatementTest.java
 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/template/BatchActivateTemplateStatementTest.java
new file mode 100644
index 00000000000..8ffc5f8691f
--- /dev/null
+++ 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/template/BatchActivateTemplateStatementTest.java
@@ -0,0 +1,127 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.db.queryengine.plan.statement.metadata.template;
+
+import org.apache.iotdb.commons.exception.IllegalPathException;
+import org.apache.iotdb.commons.path.PartialPath;
+import org.apache.iotdb.commons.schema.template.Template;
+import 
org.apache.iotdb.db.queryengine.plan.statement.internal.InternalBatchActivateTemplateStatement;
+import org.apache.iotdb.db.schemaengine.template.ClusterTemplateManager;
+import org.apache.iotdb.db.schemaengine.template.TemplateInternalRPCUtil;
+
+import org.apache.tsfile.enums.TSDataType;
+import org.apache.tsfile.file.metadata.enums.CompressionType;
+import org.apache.tsfile.file.metadata.enums.TSEncoding;
+import org.apache.tsfile.utils.Pair;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+
+public class BatchActivateTemplateStatementTest {
+
+  private Template template1;
+  private Template template2;
+
+  @Before
+  public void setUp() throws Exception {
+    final ClusterTemplateManager templateManager = 
ClusterTemplateManager.getInstance();
+    templateManager.clear();
+
+    template1 = createTemplate("t1", 1, Arrays.asList("s1", "s2"));
+    templateManager.addTemplateSetInfo(
+        TemplateInternalRPCUtil.generateAddTemplateSetInfoBytes(template1, 
"root.sg.v1"));
+
+    template2 = createTemplate("t2", 2, Collections.singletonList("s3"));
+    templateManager.addTemplateSetInfo(
+        TemplateInternalRPCUtil.generateAddTemplateSetInfoBytes(template2, 
"root.sg.v2"));
+  }
+
+  @After
+  public void tearDown() {
+    ClusterTemplateManager.getInstance().clear();
+  }
+
+  @Test
+  public void testGetPathsUsesTheTemplateOfEachDevice() throws 
IllegalPathException {
+    final BatchActivateTemplateStatement statement =
+        new BatchActivateTemplateStatement(
+            Arrays.asList(
+                new PartialPath("root.sg.v1.d1"),
+                new PartialPath("root.sg.v2.d1"),
+                // no template is set on this path, so it contributes no path
+                new PartialPath("root.sg.v3.d1")));
+
+    final List<PartialPath> paths = statement.getPaths();
+
+    // s1 and s2 belong to template1, s3 belongs to template2; each path 
appears exactly once
+    Assert.assertEquals(3, paths.size());
+    Assert.assertEquals(
+        new HashSet<>(
+            Arrays.asList(
+                new PartialPath("root.sg.v1.d1.s1"),
+                new PartialPath("root.sg.v1.d1.s2"),
+                new PartialPath("root.sg.v2.d1.s3"))),
+        new HashSet<>(paths));
+  }
+
+  @Test
+  public void testInternalGetPathsUsesTheTemplateOfEachDevice() throws 
IllegalPathException {
+    final Map<PartialPath, Pair<Template, PartialPath>> deviceMap = new 
HashMap<>();
+    deviceMap.put(
+        new PartialPath("root.sg.v1.d1"), new Pair<>(template1, new 
PartialPath("root.sg.v1")));
+    deviceMap.put(
+        new PartialPath("root.sg.v2.d1"), new Pair<>(template2, new 
PartialPath("root.sg.v2")));
+
+    final InternalBatchActivateTemplateStatement statement =
+        new InternalBatchActivateTemplateStatement(deviceMap);
+
+    final List<PartialPath> paths = statement.getPaths();
+
+    Assert.assertEquals(3, paths.size());
+    Assert.assertEquals(
+        new HashSet<>(
+            Arrays.asList(
+                new PartialPath("root.sg.v1.d1.s1"),
+                new PartialPath("root.sg.v1.d1.s2"),
+                new PartialPath("root.sg.v2.d1.s3"))),
+        new HashSet<>(paths));
+  }
+
+  private static Template createTemplate(
+      final String name, final int id, final List<String> measurements) throws 
Exception {
+    final Template template =
+        new Template(
+            name,
+            measurements,
+            Collections.nCopies(measurements.size(), TSDataType.DOUBLE),
+            Collections.nCopies(measurements.size(), TSEncoding.RLE),
+            Collections.nCopies(measurements.size(), CompressionType.SNAPPY));
+    template.setId(id);
+    return template;
+  }
+}

Reply via email to