This is an automated email from the ASF dual-hosted git repository.
rong 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 02b64d2 [IOTDB-2313] GC overhead limit when use "select * from
root.**" (#4778)
02b64d2 is described below
commit 02b64d213987975683d99c0718dfc363d401c434
Author: CloudWise-Lukemiao
<[email protected]>
AuthorDate: Fri Jan 14 14:46:13 2022 +0800
[IOTDB-2313] GC overhead limit when use "select * from root.**" (#4778)
Co-authored-by: Steve Yurong Su <[email protected]>
---
.../Communication-Service-Protocol/RestService.md | 45 ++++++++++++----------
openapi/src/main/openapi3/iotdb-rest.yaml | 2 +
.../assembly/resources/conf/iotdb-rest.properties | 5 ++-
.../iotdb/db/conf/rest/IoTDBRestServiceConfig.java | 10 +++++
.../db/conf/rest/IoTDBRestServiceDescriptor.java | 5 +++
.../protocol/rest/handler/QueryDataSetHandler.java | 23 ++++++++++-
.../protocol/rest/impl/GrafanaApiServiceImpl.java | 2 +-
.../db/protocol/rest/impl/RestApiServiceImpl.java | 26 +++++++++++--
server/src/test/resources/iotdb-rest.properties | 5 ++-
session/src/test/resources/iotdb-rest.properties | 5 ++-
10 files changed, 98 insertions(+), 30 deletions(-)
diff --git a/docs/zh/UserGuide/Communication-Service-Protocol/RestService.md
b/docs/zh/UserGuide/Communication-Service-Protocol/RestService.md
index 37dbdd7..46b99db 100644
--- a/docs/zh/UserGuide/Communication-Service-Protocol/RestService.md
+++ b/docs/zh/UserGuide/Communication-Service-Protocol/RestService.md
@@ -81,6 +81,7 @@ $ curl -H "Authorization:Basic cm9vdDpyb2901"
http://127.0.0.1:18080/ping
|参数名称 |参数类型 |是否必填|参数描述|
| ------------ | ------------ | ------------ |------------ |
| sql | string | 是 | |
+| rowLimit | integer | 否 | 一次查询能返回的结果集的最大行数。<br />如果不设置该参数,将使用配置文件的
`rest_query_default_row_size_limit` 作为默认值。<br />当返回结果集的行数超出限制时,将返回状态码 `411`。 |
请求示例:
```shell
@@ -206,63 +207,65 @@ enable_rest_service=true
rest_service_port=18080
```
-* REST Service 是否开启 SSL 配置,将 `enable_https` 设置为 `true` 以启用该模块,而将 `false`
设置为禁用该模块。默认情况下,该值为 `false`。
+* 一次查询能返回的结果集最大行数。当返回结果集的行数超出参数限制时,您只会得到在行数范围内的结果集,且将得到状态码`411`。
```properties
-enable_https=false
+rest_query_default_row_size_limit=10000
```
-* keyStore 所在路径(非必填)
+* 缓存客户登录信息的过期时间(用于加速用户鉴权的速度,单位为秒,默认是8个小时)
```properties
-key_store_path=
+cache_expire=28800
```
-
-* keyStore 密码(非必填)
+* 缓存中存储的最大用户数量(默认是100)
```properties
-key_store_pwd=
+cache_max_num=100
```
-
-* trustStore 所在路径(非必填)
+* 缓存初始容量(默认是10)
```properties
-trust_store_path=
+cache_init_num=10
```
-* trustStore 密码(非必填)
+* REST Service 是否开启 SSL 配置,将 `enable_https` 设置为 `true` 以启用该模块,而将 `false`
设置为禁用该模块。默认情况下,该值为 `false`。
```properties
-trust_store_pwd=
+enable_https=false
```
-
-* SSL 超时时间,单位为秒
+* keyStore 所在路径(非必填)
```properties
-idle_timeout=5000
+key_store_path=
```
-* 缓存客户登录信息的过期时间(用于加速用户鉴权的速度,单位为秒,默认是8个小时)
+* keyStore 密码(非必填)
```properties
-cache_expire=28800
+key_store_pwd=
```
-* 缓存中存储的最大用户数量(默认是100)
+* trustStore 所在路径(非必填)
```properties
-cache_max_num=100
+trust_store_path=
```
-* 缓存初始容量(默认是10)
+* trustStore 密码(非必填)
```properties
-cache_init_num=10
+trust_store_pwd=
```
+* SSL 超时时间,单位为秒
+
+```properties
+idle_timeout=5000
+```
diff --git a/openapi/src/main/openapi3/iotdb-rest.yaml
b/openapi/src/main/openapi3/iotdb-rest.yaml
index 85397c3..bcc238c 100644
--- a/openapi/src/main/openapi3/iotdb-rest.yaml
+++ b/openapi/src/main/openapi3/iotdb-rest.yaml
@@ -139,6 +139,8 @@ components:
properties:
sql:
type: string
+ rowLimit:
+ type: Integer
InsertTabletRequest:
title: InsertTabletRequest
diff --git a/server/src/assembly/resources/conf/iotdb-rest.properties
b/server/src/assembly/resources/conf/iotdb-rest.properties
index 6f9d59f..c942a7f 100644
--- a/server/src/assembly/resources/conf/iotdb-rest.properties
+++ b/server/src/assembly/resources/conf/iotdb-rest.properties
@@ -27,7 +27,10 @@
# the binding port of the REST service
# rest_service_port=18080
-# the expiration time of the user login infomation cache (in seconds)
+# the default row limit to a REST query response when the rowSize parameter is
not given in request
+# rest_query_default_row_size_limit=10000
+
+# the expiration time of the user login information cache (in seconds)
# cache_expire_in_seconds=28800
# maximum number of users can be stored in the user login cache.
diff --git
a/server/src/main/java/org/apache/iotdb/db/conf/rest/IoTDBRestServiceConfig.java
b/server/src/main/java/org/apache/iotdb/db/conf/rest/IoTDBRestServiceConfig.java
index 80ef8d4..a5b101d 100644
---
a/server/src/main/java/org/apache/iotdb/db/conf/rest/IoTDBRestServiceConfig.java
+++
b/server/src/main/java/org/apache/iotdb/db/conf/rest/IoTDBRestServiceConfig.java
@@ -53,6 +53,8 @@ public class IoTDBRestServiceConfig {
/** init number of users stored in cache */
private int cacheInitNum = 10;
+ private int restQueryFetchSize = 10000;
+
public String getTrustStorePwd() {
return trustStorePwd;
}
@@ -140,4 +142,12 @@ public class IoTDBRestServiceConfig {
public void setCacheInitNum(int cacheInitNum) {
this.cacheInitNum = cacheInitNum;
}
+
+ public int getRestQueryDefaultRowSizeLimit() {
+ return restQueryFetchSize;
+ }
+
+ public void setRestQueryDefaultRowSizeLimit(int restQueryFetchSize) {
+ this.restQueryFetchSize = restQueryFetchSize;
+ }
}
diff --git
a/server/src/main/java/org/apache/iotdb/db/conf/rest/IoTDBRestServiceDescriptor.java
b/server/src/main/java/org/apache/iotdb/db/conf/rest/IoTDBRestServiceDescriptor.java
index 848c64e..86c3f42 100644
---
a/server/src/main/java/org/apache/iotdb/db/conf/rest/IoTDBRestServiceDescriptor.java
+++
b/server/src/main/java/org/apache/iotdb/db/conf/rest/IoTDBRestServiceDescriptor.java
@@ -65,6 +65,11 @@ public class IoTDBRestServiceDescriptor {
Integer.parseInt(
properties.getProperty(
"rest_service_port",
Integer.toString(conf.getRestServicePort()))));
+ conf.setRestQueryDefaultRowSizeLimit(
+ Integer.parseInt(
+ properties.getProperty(
+ "rest_query_default_row_size_limit",
+ Integer.toString(conf.getRestQueryDefaultRowSizeLimit()))));
conf.setEnableHttps(
Boolean.parseBoolean(
diff --git
a/server/src/main/java/org/apache/iotdb/db/protocol/rest/handler/QueryDataSetHandler.java
b/server/src/main/java/org/apache/iotdb/db/protocol/rest/handler/QueryDataSetHandler.java
index af746e3..8e8ffc4 100644
---
a/server/src/main/java/org/apache/iotdb/db/protocol/rest/handler/QueryDataSetHandler.java
+++
b/server/src/main/java/org/apache/iotdb/db/protocol/rest/handler/QueryDataSetHandler.java
@@ -17,10 +17,12 @@
package org.apache.iotdb.db.protocol.rest.handler;
+import org.apache.iotdb.db.protocol.rest.model.ExecutionStatus;
import org.apache.iotdb.db.qp.physical.PhysicalPlan;
import org.apache.iotdb.db.qp.physical.crud.QueryPlan;
import org.apache.iotdb.db.qp.physical.sys.ShowChildPathsPlan;
import org.apache.iotdb.db.query.expression.ResultColumn;
+import org.apache.iotdb.rpc.TSStatusCode;
import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
import org.apache.iotdb.tsfile.read.common.Field;
import org.apache.iotdb.tsfile.read.common.RowRecord;
@@ -37,7 +39,11 @@ public class QueryDataSetHandler {
private QueryDataSetHandler() {}
- public static Response fillDateSet(QueryDataSet dataSet, QueryPlan
queryPlan) {
+ /**
+ * @param actualRowSizeLimit max number of rows to return. no limit when
actualRowSizeLimit <= 0.
+ */
+ public static Response fillDateSet(
+ QueryDataSet dataSet, QueryPlan queryPlan, final int actualRowSizeLimit)
{
org.apache.iotdb.db.protocol.rest.model.QueryDataSet queryDataSet =
new org.apache.iotdb.db.protocol.rest.model.QueryDataSet();
@@ -52,7 +58,20 @@ public class QueryDataSetHandler {
dataSetIndexes[i] =
sourcePathToQueryDataSetIndex.get(resultColumn.getResultColumnName());
}
+ int fetched = 0;
while (dataSet.hasNext()) {
+ if (0 < actualRowSizeLimit && actualRowSizeLimit <= fetched) {
+ return Response.ok()
+ .entity(
+ new ExecutionStatus()
+ .code(TSStatusCode.QUERY_PROCESS_ERROR.getStatusCode())
+ .message(
+ String.format(
+ "Dataset row size exceeded the given max row
size (%d)",
+ actualRowSizeLimit)))
+ .build();
+ }
+
RowRecord rowRecord = dataSet.next();
List<Field> fields = rowRecord.getFields();
@@ -69,6 +88,8 @@ public class QueryDataSetHandler {
: field.getObjectValue(field.getDataType()));
}
}
+
+ ++fetched;
}
} catch (IOException e) {
return
Response.ok().entity(ExceptionHandler.tryCatchException(e)).build();
diff --git
a/server/src/main/java/org/apache/iotdb/db/protocol/rest/impl/GrafanaApiServiceImpl.java
b/server/src/main/java/org/apache/iotdb/db/protocol/rest/impl/GrafanaApiServiceImpl.java
index 21bb8fb..e377375 100644
---
a/server/src/main/java/org/apache/iotdb/db/protocol/rest/impl/GrafanaApiServiceImpl.java
+++
b/server/src/main/java/org/apache/iotdb/db/protocol/rest/impl/GrafanaApiServiceImpl.java
@@ -157,7 +157,7 @@ public class GrafanaApiServiceImpl extends
GrafanaApiService {
QueryDataSet queryDataSet =
serviceProvider.createQueryDataSet(
queryContext, physicalPlan, IoTDBConstant.DEFAULT_FETCH_SIZE);
- return QueryDataSetHandler.fillDateSet(queryDataSet, (QueryPlan)
physicalPlan);
+ return QueryDataSetHandler.fillDateSet(queryDataSet, (QueryPlan)
physicalPlan, 0);
} finally {
ServiceProvider.SESSION_MANAGER.releaseQueryResourceNoExceptions(queryId);
}
diff --git
a/server/src/main/java/org/apache/iotdb/db/protocol/rest/impl/RestApiServiceImpl.java
b/server/src/main/java/org/apache/iotdb/db/protocol/rest/impl/RestApiServiceImpl.java
index 7624515..0549668 100644
---
a/server/src/main/java/org/apache/iotdb/db/protocol/rest/impl/RestApiServiceImpl.java
+++
b/server/src/main/java/org/apache/iotdb/db/protocol/rest/impl/RestApiServiceImpl.java
@@ -18,6 +18,7 @@
package org.apache.iotdb.db.protocol.rest.impl;
import org.apache.iotdb.db.conf.IoTDBConstant;
+import org.apache.iotdb.db.conf.rest.IoTDBRestServiceDescriptor;
import org.apache.iotdb.db.exception.query.QueryProcessException;
import org.apache.iotdb.db.protocol.rest.RestApiService;
import org.apache.iotdb.db.protocol.rest.handler.AuthorizationHandler;
@@ -46,12 +47,17 @@ public class RestApiServiceImpl extends RestApiService {
public static ServiceProvider serviceProvider = IoTDB.serviceProvider;
- protected final Planner planner;
+ private final Planner planner;
private final AuthorizationHandler authorizationHandler;
+ private final Integer defaultQueryRowLimit;
+
public RestApiServiceImpl() throws QueryProcessException {
- this.authorizationHandler = new AuthorizationHandler(serviceProvider);
planner = serviceProvider.getPlanner();
+ authorizationHandler = new AuthorizationHandler(serviceProvider);
+
+ defaultQueryRowLimit =
+
IoTDBRestServiceDescriptor.getInstance().getConfig().getRestQueryDefaultRowSizeLimit();
}
@Override
@@ -94,12 +100,24 @@ public class RestApiServiceImpl extends RestApiService {
.message(TSStatusCode.EXECUTE_STATEMENT_ERROR.name()))
.build();
}
+ QueryPlan queryPlan = (QueryPlan) physicalPlan;
- Response response = authorizationHandler.checkAuthority(securityContext,
physicalPlan);
+ Response response = authorizationHandler.checkAuthority(securityContext,
queryPlan);
if (response != null) {
return response;
}
+ // set max row limit to avoid OOM
+ Integer rowLimitInRequest = sql.getRowLimit();
+ if (rowLimitInRequest == null) {
+ rowLimitInRequest = defaultQueryRowLimit;
+ }
+ int rowLimitInQueryPlan = queryPlan.getRowLimit();
+ if (rowLimitInQueryPlan <= 0) {
+ rowLimitInQueryPlan = defaultQueryRowLimit;
+ }
+ final int actualRowSizeLimit = Math.min(rowLimitInRequest,
rowLimitInQueryPlan);
+
final long queryId =
QueryResourceManager.getInstance().assignQueryId(true);
try {
QueryContext queryContext =
@@ -112,7 +130,7 @@ public class RestApiServiceImpl extends RestApiService {
QueryDataSet queryDataSet =
serviceProvider.createQueryDataSet(
queryContext, physicalPlan, IoTDBConstant.DEFAULT_FETCH_SIZE);
- return QueryDataSetHandler.fillDateSet(queryDataSet, (QueryPlan)
physicalPlan);
+ return QueryDataSetHandler.fillDateSet(queryDataSet, queryPlan,
actualRowSizeLimit);
} finally {
ServiceProvider.SESSION_MANAGER.releaseQueryResourceNoExceptions(queryId);
}
diff --git a/server/src/test/resources/iotdb-rest.properties
b/server/src/test/resources/iotdb-rest.properties
index a807831..75d0ae1 100644
--- a/server/src/test/resources/iotdb-rest.properties
+++ b/server/src/test/resources/iotdb-rest.properties
@@ -27,7 +27,10 @@ enable_rest_service=true
# the binding port of the REST service
# rest_service_port=18080
-# the expiration time of the user login infomation cache (in seconds)
+# the default row limit to a REST query response when the rowSize parameter is
not given in request
+# rest_query_default_row_size_limit=10000
+
+# the expiration time of the user login information cache (in seconds)
# cache_expire_in_seconds=28800
# maximum number of users can be stored in the user login cache.
diff --git a/session/src/test/resources/iotdb-rest.properties
b/session/src/test/resources/iotdb-rest.properties
index a807831..75d0ae1 100644
--- a/session/src/test/resources/iotdb-rest.properties
+++ b/session/src/test/resources/iotdb-rest.properties
@@ -27,7 +27,10 @@ enable_rest_service=true
# the binding port of the REST service
# rest_service_port=18080
-# the expiration time of the user login infomation cache (in seconds)
+# the default row limit to a REST query response when the rowSize parameter is
not given in request
+# rest_query_default_row_size_limit=10000
+
+# the expiration time of the user login information cache (in seconds)
# cache_expire_in_seconds=28800
# maximum number of users can be stored in the user login cache.