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;
+ }
+}