This is an automated email from the ASF dual-hosted git repository. JackieTien97 pushed a commit to branch codex/backport-pr-18149-dev-1.3 in repository https://gitbox.apache.org/repos/asf/iotdb.git
commit 3c20c256a3933130c74c2472bd75432084a5dbdd Author: JackieTien97 <[email protected]> AuthorDate: Wed Jul 8 15:36:26 2026 +0800 Remap non-positive REST row limit config to default and add regression tests A non-positive rest_query_default_row_size_limit used to mean "unlimited"; the hard-cap handling clamped it down to 1, silently capping every REST response to a single row. Remap non-positive values to the built-in default (10000) so existing deployments are not degraded, while still guaranteeing a finite cap. Add regression coverage: - QueryRowLimitUtilsTest: an oversized caller-provided rowLimit is clamped to the configured hard limit. - FastLastHandlerTest: the fastLastQuery cache-hit path caps the number of materialized entries. The cache-hit loop is extracted into FastLastHandler.fillLastValueDataSet so it is unit-testable. --- .../protocol/rest/handler/QueryRowLimitUtils.java | 12 ++- .../rest/v1/handler/QueryDataSetHandler.java | 2 +- .../protocol/rest/v2/handler/FastLastHandler.java | 59 ++++++++++- .../rest/v2/handler/QueryDataSetHandler.java | 2 +- .../protocol/rest/v2/impl/RestApiServiceImpl.java | 41 +------- .../rest/handler/QueryRowLimitUtilsTest.java | 17 +++- .../rest/v1/handler/QueryDataSetHandlerTest.java | 1 - .../rest/v2/handler/FastLastHandlerTest.java | 108 +++++++++++++++++++++ .../conf/iotdb-system.properties.template | 1 + 9 files changed, 191 insertions(+), 52 deletions(-) diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/rest/handler/QueryRowLimitUtils.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/rest/handler/QueryRowLimitUtils.java index ae3ceb7e61e..00f8a993ae8 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/rest/handler/QueryRowLimitUtils.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/rest/handler/QueryRowLimitUtils.java @@ -26,7 +26,12 @@ import javax.ws.rs.core.Response; public final class QueryRowLimitUtils { - private static final int MIN_ROW_SIZE_LIMIT = 1; + /** + * Fallback used when {@code rest_query_default_row_size_limit} is missing or non-positive. + * Matches the built-in default in {@code IoTDBRestServiceConfig}; a non-positive configured value + * used to mean "unlimited" and is now treated as this cap instead of being clamped down to 1. + */ + private static final int DEFAULT_ROW_SIZE_LIMIT = 10000; private QueryRowLimitUtils() {} @@ -40,7 +45,7 @@ public final class QueryRowLimitUtils { } public static int normalizeRowSizeLimit(int rowSizeLimit) { - return Math.max(MIN_ROW_SIZE_LIMIT, rowSizeLimit); + return rowSizeLimit > 0 ? rowSizeLimit : DEFAULT_ROW_SIZE_LIMIT; } public static boolean exceedsLimit( @@ -57,8 +62,7 @@ public final class QueryRowLimitUtils { .code(TSStatusCode.QUERY_PROCESS_ERROR.getStatusCode()) .message( String.format( - "Dataset row size exceeded the given max row size (%d)", - rowSizeLimit))) + "Dataset row size exceeded the given max row size (%d)", rowSizeLimit))) .build(); } } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/rest/v1/handler/QueryDataSetHandler.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/rest/v1/handler/QueryDataSetHandler.java index e774cdde00b..b87ace54df4 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/rest/v1/handler/QueryDataSetHandler.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/rest/v1/handler/QueryDataSetHandler.java @@ -18,6 +18,7 @@ package org.apache.iotdb.db.protocol.rest.v1.handler; import org.apache.iotdb.commons.exception.IoTDBException; +import org.apache.iotdb.db.protocol.rest.handler.QueryRowLimitUtils; import org.apache.iotdb.db.protocol.rest.v1.model.ExecutionStatus; import org.apache.iotdb.db.queryengine.common.header.DatasetHeader; import org.apache.iotdb.db.queryengine.plan.execution.IQueryExecution; @@ -28,7 +29,6 @@ import org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowChildPathsSta import org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowStatement; import org.apache.iotdb.db.queryengine.plan.statement.metadata.model.ShowModelsStatement; import org.apache.iotdb.db.queryengine.plan.statement.sys.AuthorStatement; -import org.apache.iotdb.db.protocol.rest.handler.QueryRowLimitUtils; import org.apache.iotdb.rpc.TSStatusCode; import org.apache.tsfile.block.column.Column; diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/rest/v2/handler/FastLastHandler.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/rest/v2/handler/FastLastHandler.java index 5d1c3d0109c..af1657a8b13 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/rest/v2/handler/FastLastHandler.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/rest/v2/handler/FastLastHandler.java @@ -20,16 +20,25 @@ package org.apache.iotdb.db.protocol.rest.v2.handler; import org.apache.iotdb.common.rpc.thrift.TSStatus; +import org.apache.iotdb.commons.path.PartialPath; +import org.apache.iotdb.db.protocol.rest.handler.QueryRowLimitUtils; import org.apache.iotdb.db.protocol.rest.v2.model.ExecutionStatus; import org.apache.iotdb.db.protocol.rest.v2.model.PrefixPathList; +import org.apache.iotdb.db.protocol.rest.v2.model.QueryDataSet; import org.apache.iotdb.db.protocol.session.IClientSession; +import org.apache.iotdb.db.queryengine.plan.analyze.cache.schema.DeviceLastCache; import org.apache.iotdb.rpc.TSStatusCode; import org.apache.iotdb.service.rpc.thrift.TSLastDataQueryReq; +import org.apache.tsfile.common.constant.TsFileConstant; +import org.apache.tsfile.read.TimeValuePair; + import javax.ws.rs.core.Response; import java.util.ArrayList; import java.util.Collections; +import java.util.List; +import java.util.Map; public class FastLastHandler { @@ -59,8 +68,7 @@ public class FastLastHandler { .build(); } - public static void setupTargetDataSet( - org.apache.iotdb.db.protocol.rest.v2.model.QueryDataSet dataSet) { + public static void setupTargetDataSet(QueryDataSet dataSet) { dataSet.addExpressionsItem("Timeseries"); dataSet.addExpressionsItem("Value"); dataSet.addExpressionsItem("DataType"); @@ -70,4 +78,51 @@ public class FastLastHandler { dataSet.setValues(new ArrayList<>()); dataSet.setTimestamps(new ArrayList<>()); } + + /** + * Builds the fastLastQuery response directly from cached last values. The number of materialized + * entries is capped by {@code actualRowSizeLimit}; once exceeded an "exceeded max row size" + * response is returned instead of materializing the whole cache into heap. + * + * @param resultMap last values keyed by device/measurement, as filled by the schema cache + * @param actualRowSizeLimit hard cap on the number of returned rows + */ + public static Response fillLastValueDataSet( + Map<PartialPath, Map<String, TimeValuePair>> resultMap, int actualRowSizeLimit) { + QueryDataSet targetDataSet = new QueryDataSet(); + setupTargetDataSet(targetDataSet); + List<Object> timeseries = new ArrayList<>(); + List<Object> valueList = new ArrayList<>(); + List<Object> dataTypeList = new ArrayList<>(); + int fetched = 0; + + for (final Map.Entry<PartialPath, Map<String, TimeValuePair>> device2MeasurementLastEntry : + resultMap.entrySet()) { + final String deviceWithSeparator = + device2MeasurementLastEntry.getKey() + TsFileConstant.PATH_SEPARATOR; + for (Map.Entry<String, TimeValuePair> measurementEntry : + device2MeasurementLastEntry.getValue().entrySet()) { + final TimeValuePair tvPair = measurementEntry.getValue(); + if (tvPair == null + || tvPair == DeviceLastCache.EMPTY_TIME_VALUE_PAIR + || tvPair.getValue() == null) { + continue; + } + if (QueryRowLimitUtils.exceedsLimit(fetched, 1, actualRowSizeLimit)) { + return QueryRowLimitUtils.buildRowSizeLimitExceededResponse(actualRowSizeLimit); + } + valueList.add(tvPair.getValue().getStringValue()); + dataTypeList.add(tvPair.getValue().getDataType().name()); + targetDataSet.addTimestampsItem(tvPair.getTimestamp()); + timeseries.add(deviceWithSeparator + measurementEntry.getKey()); + fetched++; + } + } + if (!timeseries.isEmpty()) { + targetDataSet.addValuesItem(timeseries); + targetDataSet.addValuesItem(valueList); + targetDataSet.addValuesItem(dataTypeList); + } + return Response.ok().entity(targetDataSet).build(); + } } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/rest/v2/handler/QueryDataSetHandler.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/rest/v2/handler/QueryDataSetHandler.java index e423dc2539a..e77265abe1d 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/rest/v2/handler/QueryDataSetHandler.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/rest/v2/handler/QueryDataSetHandler.java @@ -18,6 +18,7 @@ package org.apache.iotdb.db.protocol.rest.v2.handler; import org.apache.iotdb.commons.exception.IoTDBException; +import org.apache.iotdb.db.protocol.rest.handler.QueryRowLimitUtils; import org.apache.iotdb.db.protocol.rest.model.ExecutionStatus; import org.apache.iotdb.db.queryengine.common.header.DatasetHeader; import org.apache.iotdb.db.queryengine.plan.execution.IQueryExecution; @@ -28,7 +29,6 @@ import org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowChildPathsSta import org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowStatement; import org.apache.iotdb.db.queryengine.plan.statement.metadata.model.ShowModelsStatement; import org.apache.iotdb.db.queryengine.plan.statement.sys.AuthorStatement; -import org.apache.iotdb.db.protocol.rest.handler.QueryRowLimitUtils; import org.apache.iotdb.rpc.TSStatusCode; import org.apache.tsfile.block.column.Column; diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/rest/v2/impl/RestApiServiceImpl.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/rest/v2/impl/RestApiServiceImpl.java index cea8d4ea409..80e86c1a998 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/rest/v2/impl/RestApiServiceImpl.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/rest/v2/impl/RestApiServiceImpl.java @@ -37,7 +37,6 @@ import org.apache.iotdb.db.protocol.rest.v2.handler.StatementConstructionHandler import org.apache.iotdb.db.protocol.rest.v2.model.InsertRecordsRequest; import org.apache.iotdb.db.protocol.rest.v2.model.InsertTabletRequest; import org.apache.iotdb.db.protocol.rest.v2.model.PrefixPathList; -import org.apache.iotdb.db.protocol.rest.v2.model.QueryDataSet; import org.apache.iotdb.db.protocol.rest.v2.model.SQL; import org.apache.iotdb.db.protocol.session.IClientSession; import org.apache.iotdb.db.protocol.session.SessionManager; @@ -47,7 +46,6 @@ import org.apache.iotdb.db.queryengine.plan.Coordinator; import org.apache.iotdb.db.queryengine.plan.analyze.ClusterPartitionFetcher; import org.apache.iotdb.db.queryengine.plan.analyze.IPartitionFetcher; import org.apache.iotdb.db.queryengine.plan.analyze.cache.schema.DataNodeSchemaCache; -import org.apache.iotdb.db.queryengine.plan.analyze.cache.schema.DeviceLastCache; import org.apache.iotdb.db.queryengine.plan.analyze.schema.ClusterSchemaFetcher; import org.apache.iotdb.db.queryengine.plan.analyze.schema.ISchemaFetcher; import org.apache.iotdb.db.queryengine.plan.execution.ExecutionResult; @@ -64,14 +62,12 @@ import org.apache.iotdb.db.utils.SetThreadName; import org.apache.iotdb.rpc.TSStatusCode; import org.apache.iotdb.service.rpc.thrift.TSLastDataQueryReq; -import org.apache.tsfile.common.constant.TsFileConstant; import org.apache.tsfile.read.TimeValuePair; import javax.ws.rs.core.Response; import javax.ws.rs.core.SecurityContext; import java.time.ZoneId; -import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -169,40 +165,9 @@ public class RestApiServiceImpl extends RestApiService { } } - // Cache hit: build response directly - QueryDataSet targetDataSet = new QueryDataSet(); - - FastLastHandler.setupTargetDataSet(targetDataSet); - List<Object> timeseries = new ArrayList<>(); - List<Object> valueList = new ArrayList<>(); - List<Object> dataTypeList = new ArrayList<>(); - int fetched = 0; - - for (final Map.Entry<PartialPath, Map<String, TimeValuePair>> device2MeasurementLastEntry : - resultMap.entrySet()) { - final String deviceWithSeparator = - device2MeasurementLastEntry.getKey() + TsFileConstant.PATH_SEPARATOR; - for (Map.Entry<String, TimeValuePair> measurementEntry : - device2MeasurementLastEntry.getValue().entrySet()) { - final TimeValuePair tvPair = measurementEntry.getValue(); - if (tvPair != DeviceLastCache.EMPTY_TIME_VALUE_PAIR) { - if (QueryRowLimitUtils.exceedsLimit(fetched, 1, defaultQueryRowLimit)) { - return QueryRowLimitUtils.buildRowSizeLimitExceededResponse(defaultQueryRowLimit); - } - valueList.add(tvPair.getValue().getStringValue()); - dataTypeList.add(tvPair.getValue().getDataType().name()); - targetDataSet.addTimestampsItem(tvPair.getTimestamp()); - timeseries.add(deviceWithSeparator + measurementEntry.getKey()); - fetched++; - } - } - } - if (!timeseries.isEmpty()) { - targetDataSet.addValuesItem(timeseries); - targetDataSet.addValuesItem(valueList); - targetDataSet.addValuesItem(dataTypeList); - } - return Response.ok().entity(targetDataSet).build(); + // Cache hit: build response directly (capped by defaultQueryRowLimit). + finish = true; + return FastLastHandler.fillLastValueDataSet(resultMap, defaultQueryRowLimit); } catch (Exception e) { finish = true; diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/protocol/rest/handler/QueryRowLimitUtilsTest.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/protocol/rest/handler/QueryRowLimitUtilsTest.java index d1d9f2a42a0..3f21e8ea167 100644 --- a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/protocol/rest/handler/QueryRowLimitUtilsTest.java +++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/protocol/rest/handler/QueryRowLimitUtilsTest.java @@ -32,13 +32,18 @@ public class QueryRowLimitUtilsTest { assertEquals(10, QueryRowLimitUtils.resolveActualRowSizeLimit(null, 10)); assertEquals(10, QueryRowLimitUtils.resolveActualRowSizeLimit(100, 10)); assertEquals(5, QueryRowLimitUtils.resolveActualRowSizeLimit(5, 10)); + // A caller-provided MAX_VALUE must be clamped down to the configured hard limit. + assertEquals(10, QueryRowLimitUtils.resolveActualRowSizeLimit(Integer.MAX_VALUE, 10)); } @Test - public void resolveActualRowSizeLimitShouldKeepHardLimitPositive() { - assertEquals(1, QueryRowLimitUtils.resolveActualRowSizeLimit(null, 0)); - assertEquals(1, QueryRowLimitUtils.resolveActualRowSizeLimit(100, 0)); - assertEquals(1, QueryRowLimitUtils.resolveActualRowSizeLimit(null, -1)); + public void resolveActualRowSizeLimitShouldFallBackToDefaultForNonPositiveConfig() { + // A non-positive rest_query_default_row_size_limit used to mean "unlimited"; it now falls back + // to the built-in default (10000) instead of being clamped down to a single row. + assertEquals(10000, QueryRowLimitUtils.resolveActualRowSizeLimit(null, 0)); + // A user request below the cap is still honored: min(100, default 10000) == 100. + assertEquals(100, QueryRowLimitUtils.resolveActualRowSizeLimit(100, 0)); + assertEquals(10000, QueryRowLimitUtils.resolveActualRowSizeLimit(null, -1)); } @Test @@ -47,6 +52,8 @@ public class QueryRowLimitUtilsTest { assertTrue(QueryRowLimitUtils.exceedsLimit(2, 1, 2)); assertTrue(QueryRowLimitUtils.exceedsLimit(0, 2, 1)); assertFalse(QueryRowLimitUtils.exceedsLimit(0, 0, 1)); - assertTrue(QueryRowLimitUtils.exceedsLimit(0, 2, 0)); + // A non-positive limit falls back to the default (10000), so small batches do not exceed it. + assertFalse(QueryRowLimitUtils.exceedsLimit(0, 2, 0)); + assertTrue(QueryRowLimitUtils.exceedsLimit(0, 10001, 0)); } } diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/protocol/rest/v1/handler/QueryDataSetHandlerTest.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/protocol/rest/v1/handler/QueryDataSetHandlerTest.java index cc3f1a12bed..9f5d3a097ea 100644 --- a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/protocol/rest/v1/handler/QueryDataSetHandlerTest.java +++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/protocol/rest/v1/handler/QueryDataSetHandlerTest.java @@ -196,6 +196,5 @@ public class QueryDataSetHandlerTest { public String getClientHostname() { return null; } - } } diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/protocol/rest/v2/handler/FastLastHandlerTest.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/protocol/rest/v2/handler/FastLastHandlerTest.java new file mode 100644 index 00000000000..786db7492d1 --- /dev/null +++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/protocol/rest/v2/handler/FastLastHandlerTest.java @@ -0,0 +1,108 @@ +/* + * 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.protocol.rest.v2.handler; + +import org.apache.iotdb.commons.path.PartialPath; +import org.apache.iotdb.db.protocol.rest.model.ExecutionStatus; +import org.apache.iotdb.db.protocol.rest.v2.model.QueryDataSet; +import org.apache.iotdb.db.queryengine.plan.analyze.cache.schema.DeviceLastCache; +import org.apache.iotdb.rpc.TSStatusCode; + +import org.apache.tsfile.enums.TSDataType; +import org.apache.tsfile.read.TimeValuePair; +import org.apache.tsfile.utils.TsPrimitiveType; +import org.junit.Test; + +import javax.ws.rs.core.Response; + +import java.util.HashMap; +import java.util.Map; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public class FastLastHandlerTest { + + private static final String DEVICE = "root.sg25.d1"; + + @Test + public void fillLastValueDataSetShouldReturnAllEntriesWhenUnderLimit() throws Exception { + Map<PartialPath, Map<String, TimeValuePair>> resultMap = newResultMap("s1", "s2", "s3"); + + Response response = FastLastHandler.fillLastValueDataSet(resultMap, 5); + + assertTrue(response.getEntity() instanceof QueryDataSet); + QueryDataSet dataSet = (QueryDataSet) response.getEntity(); + assertEquals(3, dataSet.getTimestamps().size()); + // [timeseries, valueList, dataTypeList], each holding one row per measurement + assertEquals(3, dataSet.getValues().size()); + assertEquals(3, dataSet.getValues().get(0).size()); + } + + @Test + public void fillLastValueDataSetShouldCapAtLimitAndReportError() throws Exception { + // Regression for the fastLastQuery cache-hit path: a warm cache with more entries than the + // configured limit must NOT materialize the whole result into heap. + Map<PartialPath, Map<String, TimeValuePair>> resultMap = + newResultMap("s1", "s2", "s3", "s4", "s5"); + + Response response = FastLastHandler.fillLastValueDataSet(resultMap, 2); + + assertTrue(response.getEntity() instanceof ExecutionStatus); + ExecutionStatus status = (ExecutionStatus) response.getEntity(); + assertEquals(TSStatusCode.QUERY_PROCESS_ERROR.getStatusCode(), status.getCode().intValue()); + } + + @Test + public void fillLastValueDataSetShouldSkipPlaceholderAndNullEntries() throws Exception { + Map<PartialPath, Map<String, TimeValuePair>> resultMap = + newResultMap("s1", "placeholder", "nullValue", "s4"); + + Response response = FastLastHandler.fillLastValueDataSet(resultMap, 10); + + assertTrue(response.getEntity() instanceof QueryDataSet); + QueryDataSet dataSet = (QueryDataSet) response.getEntity(); + // Only the two real entries (s1, s4) are materialized; placeholder/null entries are skipped. + assertEquals(2, dataSet.getTimestamps().size()); + } + + /** Builds a single-device resultMap; the special names insert sentinel entries. */ + private static Map<PartialPath, Map<String, TimeValuePair>> newResultMap( + String... measurementNames) throws Exception { + Map<String, TimeValuePair> measurements = new HashMap<>(); + long timestamp = 100L; + for (String name : measurementNames) { + measurements.put(name, newEntry(name, timestamp++)); + } + Map<PartialPath, Map<String, TimeValuePair>> resultMap = new HashMap<>(); + resultMap.put(new PartialPath(DEVICE), measurements); + return resultMap; + } + + private static TimeValuePair newEntry(String name, long timestamp) { + if ("placeholder".equals(name)) { + return DeviceLastCache.EMPTY_TIME_VALUE_PAIR; + } + if ("nullValue".equals(name)) { + return new TimeValuePair(timestamp, null); + } + return new TimeValuePair(timestamp, TsPrimitiveType.getByType(TSDataType.INT64, timestamp)); + } +} diff --git a/iotdb-core/node-commons/src/assembly/resources/conf/iotdb-system.properties.template b/iotdb-core/node-commons/src/assembly/resources/conf/iotdb-system.properties.template index f3d5f36c2ec..bda26c3cb93 100644 --- a/iotdb-core/node-commons/src/assembly/resources/conf/iotdb-system.properties.template +++ b/iotdb-core/node-commons/src/assembly/resources/conf/iotdb-system.properties.template @@ -565,6 +565,7 @@ enable_swagger=false # The maximum row limit for REST and Grafana query responses. # The request rowLimit/row_limit value cannot exceed this limit. +# A non-positive value is invalid and falls back to the default (10000); it no longer means unlimited. # effectiveMode: restart # Datatype: int rest_query_default_row_size_limit=10000
