This is an automated email from the ASF dual-hosted git repository.
jackietien 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 1dc47d48e07 Rest Service add FastLastQuery method
1dc47d48e07 is described below
commit 1dc47d48e074211940c1e5a0d9ef8440eabacbcf
Author: CloudWise-Lukemiao <[email protected]>
AuthorDate: Thu Jun 26 09:19:39 2025 +0800
Rest Service add FastLastQuery method
---
.../protocol/rest/v2/handler/FastLastHandler.java | 71 +++++++
.../rest/v2/handler/RequestValidationHandler.java | 8 +
.../protocol/rest/v2/impl/RestApiServiceImpl.java | 230 ++++++++++++++++-----
.../openapi/src/main/openapi3/iotdb_rest_v2.yaml | 25 +++
4 files changed, 278 insertions(+), 56 deletions(-)
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
new file mode 100644
index 00000000000..59ebb57ffbb
--- /dev/null
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/rest/v2/handler/FastLastHandler.java
@@ -0,0 +1,71 @@
+/*
+ * 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.common.rpc.thrift.TSStatus;
+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.session.IClientSession;
+import org.apache.iotdb.rpc.TSStatusCode;
+import org.apache.iotdb.service.rpc.thrift.TSLastDataQueryReq;
+
+import javax.ws.rs.core.Response;
+
+import java.util.ArrayList;
+import java.util.Collections;
+
+public class FastLastHandler {
+
+ public static TSLastDataQueryReq createTSLastDataQueryReq(
+ IClientSession clientSession, PrefixPathList prefixPathList) {
+ TSLastDataQueryReq req = new TSLastDataQueryReq();
+ req.sessionId = clientSession.getId();
+ req.paths =
+ Collections.singletonList(String.join(".",
prefixPathList.getPrefixPaths()) + ".**");
+ req.time = Long.MIN_VALUE;
+ req.setLegalPathNodes(true);
+ return req;
+ }
+
+ public static Response buildErrorResponse(TSStatusCode statusCode) {
+ return Response.ok()
+ .entity(
+ new org.apache.iotdb.db.protocol.rest.model.ExecutionStatus()
+ .code(statusCode.getStatusCode())
+ .message(statusCode.name()))
+ .build();
+ }
+
+ public static Response buildExecutionStatusResponse(TSStatus status) {
+ return Response.ok()
+ .entity(new
ExecutionStatus().code(status.getCode()).message(status.getMessage()))
+ .build();
+ }
+
+ public static void setupTargetDataSet(
+ org.apache.iotdb.db.protocol.rest.v2.model.QueryDataSet dataSet) {
+ dataSet.addExpressionsItem("Timeseries");
+ dataSet.addExpressionsItem("Value");
+ dataSet.addExpressionsItem("DataType");
+ dataSet.addDataTypesItem("TEXT");
+ dataSet.addDataTypesItem("TEXT");
+ dataSet.addDataTypesItem("TEXT");
+ dataSet.setValues(new ArrayList<>());
+ dataSet.setTimestamps(new ArrayList<>());
+ }
+}
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/rest/v2/handler/RequestValidationHandler.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/rest/v2/handler/RequestValidationHandler.java
index 9a620da64ed..c1fc9c6327f 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/rest/v2/handler/RequestValidationHandler.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/rest/v2/handler/RequestValidationHandler.java
@@ -20,6 +20,7 @@ package org.apache.iotdb.db.protocol.rest.v2.handler;
import org.apache.iotdb.db.protocol.rest.v2.model.ExpressionRequest;
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.SQL;
import org.apache.commons.lang3.Validate;
@@ -40,6 +41,13 @@ public class RequestValidationHandler {
}
}
+ public static void validatePrefixPaths(PrefixPathList prefixPathList) {
+ Objects.requireNonNull(prefixPathList.getPrefixPaths(), "prefix_paths
should not be null");
+ if (prefixPathList.getPrefixPaths().isEmpty()) {
+ throw new IllegalArgumentException("prefix_paths should not be empty");
+ }
+ }
+
public static void validateInsertTabletRequest(InsertTabletRequest
insertTabletRequest) {
Objects.requireNonNull(insertTabletRequest.getTimestamps(), "timestamps
should not be null");
Objects.requireNonNull(insertTabletRequest.getIsAligned(), "is_aligned
should not be null");
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 781f2b3b3ab..53699256761 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
@@ -18,23 +18,30 @@
package org.apache.iotdb.db.protocol.rest.v2.impl;
import org.apache.iotdb.common.rpc.thrift.TSStatus;
+import org.apache.iotdb.commons.path.PartialPath;
import org.apache.iotdb.db.conf.IoTDBConfig;
import org.apache.iotdb.db.conf.IoTDBDescriptor;
import org.apache.iotdb.db.conf.rest.IoTDBRestServiceDescriptor;
import org.apache.iotdb.db.protocol.rest.handler.AuthorizationHandler;
+import org.apache.iotdb.db.protocol.rest.model.ExecutionStatus;
import org.apache.iotdb.db.protocol.rest.utils.InsertTabletSortDataUtils;
+import org.apache.iotdb.db.protocol.rest.v2.NotFoundException;
import org.apache.iotdb.db.protocol.rest.v2.RestApiService;
import org.apache.iotdb.db.protocol.rest.v2.handler.ExceptionHandler;
import org.apache.iotdb.db.protocol.rest.v2.handler.ExecuteStatementHandler;
+import org.apache.iotdb.db.protocol.rest.v2.handler.FastLastHandler;
import org.apache.iotdb.db.protocol.rest.v2.handler.QueryDataSetHandler;
import org.apache.iotdb.db.protocol.rest.v2.handler.RequestValidationHandler;
import
org.apache.iotdb.db.protocol.rest.v2.handler.StatementConstructionHandler;
-import org.apache.iotdb.db.protocol.rest.v2.model.ExecutionStatus;
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;
import org.apache.iotdb.db.protocol.thrift.OperationType;
+import org.apache.iotdb.db.queryengine.common.SessionInfo;
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;
@@ -43,21 +50,32 @@ import
org.apache.iotdb.db.queryengine.plan.analyze.schema.ISchemaFetcher;
import org.apache.iotdb.db.queryengine.plan.execution.ExecutionResult;
import org.apache.iotdb.db.queryengine.plan.execution.IQueryExecution;
import org.apache.iotdb.db.queryengine.plan.parser.StatementGenerator;
-import org.apache.iotdb.db.queryengine.plan.planner.LocalExecutionPlanner;
-import org.apache.iotdb.db.queryengine.plan.relational.sql.parser.SqlParser;
+import
org.apache.iotdb.db.queryengine.plan.relational.metadata.fetcher.cache.TableDeviceSchemaCache;
+import
org.apache.iotdb.db.queryengine.plan.relational.metadata.fetcher.cache.TableId;
import org.apache.iotdb.db.queryengine.plan.statement.Statement;
import org.apache.iotdb.db.queryengine.plan.statement.crud.InsertRowsStatement;
import
org.apache.iotdb.db.queryengine.plan.statement.crud.InsertTabletStatement;
-import
org.apache.iotdb.db.queryengine.plan.statement.metadata.view.CreateTableViewStatement;
+import org.apache.iotdb.db.schemaengine.SchemaEngine;
+import org.apache.iotdb.db.schemaengine.schemaregion.ISchemaRegion;
import org.apache.iotdb.db.utils.CommonUtils;
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.enums.TSDataType;
+import org.apache.tsfile.file.metadata.IDeviceID;
+import org.apache.tsfile.read.TimeValuePair;
+import org.apache.tsfile.utils.Pair;
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;
import java.util.Optional;
public class RestApiServiceImpl extends RestApiService {
@@ -83,6 +101,126 @@ public class RestApiServiceImpl extends RestApiService {
IoTDBRestServiceDescriptor.getInstance().getConfig().getRestQueryDefaultRowSizeLimit();
}
+ @Override
+ public Response executeFastLastQueryStatement(
+ PrefixPathList prefixPathList, SecurityContext securityContext) {
+ Long queryId = null;
+ Statement statement = null;
+ boolean finish = false;
+ long startTime = System.nanoTime();
+
+ try {
+ RequestValidationHandler.validatePrefixPaths(prefixPathList);
+
+ PartialPath prefixPath =
+ new PartialPath(prefixPathList.getPrefixPaths().toArray(new
String[0]));
+ final Map<TableId, Map<IDeviceID, Map<String, Pair<TSDataType,
TimeValuePair>>>> resultMap =
+ new HashMap<>();
+ int sensorNum = 0;
+
+ final String prefixString = prefixPath.toString();
+ for (final ISchemaRegion region :
SchemaEngine.getInstance().getAllSchemaRegions()) {
+ if (!prefixString.startsWith(region.getDatabaseFullPath())
+ && !region.getDatabaseFullPath().startsWith(prefixString)) {
+ continue;
+ }
+ sensorNum += region.fillLastQueryMap(prefixPath, resultMap);
+ }
+ // Check cache first
+ if (!TableDeviceSchemaCache.getInstance().getLastCache(resultMap)) {
+ IClientSession clientSession =
SESSION_MANAGER.getCurrSessionAndUpdateIdleTime();
+ TSLastDataQueryReq tsLastDataQueryReq =
+ FastLastHandler.createTSLastDataQueryReq(clientSession,
prefixPathList);
+ statement = StatementGenerator.createStatement(tsLastDataQueryReq);
+
+ if (ExecuteStatementHandler.validateStatement(statement)) {
+ return
FastLastHandler.buildErrorResponse(TSStatusCode.EXECUTE_STATEMENT_ERROR);
+ }
+
+
Optional.ofNullable(authorizationHandler.checkAuthority(securityContext,
statement))
+ .ifPresent(Response.class::cast);
+
+ queryId = SESSION_MANAGER.requestQueryId();
+ SessionInfo sessionInfo =
SESSION_MANAGER.getSessionInfo(clientSession);
+
+ ExecutionResult result =
+ COORDINATOR.executeForTreeModel(
+ statement,
+ queryId,
+ sessionInfo,
+ "",
+ partitionFetcher,
+ schemaFetcher,
+ config.getQueryTimeoutThreshold(),
+ true);
+
+ finish = true;
+
+ if (result.status.code != TSStatusCode.SUCCESS_STATUS.getStatusCode()
+ && result.status.code !=
TSStatusCode.REDIRECTION_RECOMMEND.getStatusCode()) {
+ return FastLastHandler.buildExecutionStatusResponse(result.status);
+ }
+
+ IQueryExecution queryExecution =
COORDINATOR.getQueryExecution(queryId);
+ try (SetThreadName ignored = new
SetThreadName(result.queryId.getId())) {
+ return QueryDataSetHandler.fillQueryDataSet(
+ queryExecution, statement, defaultQueryRowLimit);
+ }
+ }
+
+ // 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<>();
+
+ for (final Map.Entry<TableId, Map<IDeviceID, Map<String,
Pair<TSDataType, TimeValuePair>>>>
+ result : resultMap.entrySet()) {
+ for (final Map.Entry<IDeviceID, Map<String, Pair<TSDataType,
TimeValuePair>>>
+ device2MeasurementLastEntry : result.getValue().entrySet()) {
+ final String deviceWithSeparator =
+ device2MeasurementLastEntry.getKey().toString() +
TsFileConstant.PATH_SEPARATOR;
+ for (final Map.Entry<String, Pair<TSDataType, TimeValuePair>>
measurementLastEntry :
+ device2MeasurementLastEntry.getValue().entrySet()) {
+ final TimeValuePair tvPair =
measurementLastEntry.getValue().getRight();
+ valueList.add(tvPair.getValue().getStringValue());
+ dataTypeList.add(tvPair.getValue().getDataType().name());
+ targetDataSet.addTimestampsItem(tvPair.getTimestamp());
+ timeseries.add(deviceWithSeparator +
measurementLastEntry.getKey());
+ }
+ }
+ }
+ if (!timeseries.isEmpty()) {
+ targetDataSet.addValuesItem(timeseries);
+ targetDataSet.addValuesItem(valueList);
+ targetDataSet.addValuesItem(dataTypeList);
+ }
+ return Response.ok().entity(targetDataSet).build();
+
+ } catch (Exception e) {
+ finish = true;
+ return
Response.ok().entity(ExceptionHandler.tryCatchException(e)).build();
+ } finally {
+ long costTime = System.nanoTime() - startTime;
+ Optional.ofNullable(statement)
+ .ifPresent(
+ s ->
+ CommonUtils.addStatementExecutionLatency(
+ OperationType.EXECUTE_QUERY_STATEMENT,
s.getType().name(), costTime));
+ if (queryId != null) {
+ if (finish) {
+ long executionTime = COORDINATOR.getTotalExecutionTime(queryId);
+ CommonUtils.addQueryLatency(
+ statement != null ? statement.getType() : null,
+ executionTime > 0 ? executionTime : costTime);
+ }
+ COORDINATOR.cleanupQueryExecution(queryId);
+ }
+ }
+ }
+
@Override
public Response executeNonQueryStatement(SQL sql, SecurityContext
securityContext) {
Long queryId = null;
@@ -95,7 +233,7 @@ public class RestApiServiceImpl extends RestApiService {
if (statement == null) {
return Response.ok()
.entity(
- new org.apache.iotdb.db.protocol.rest.model.ExecutionStatus()
+ new ExecutionStatus()
.code(TSStatusCode.SQL_PARSE_ERROR.getStatusCode())
.message("This operation type is not supported"))
.build();
@@ -103,42 +241,27 @@ public class RestApiServiceImpl extends RestApiService {
if (!ExecuteStatementHandler.validateStatement(statement)) {
return Response.ok()
.entity(
- new org.apache.iotdb.db.protocol.rest.model.ExecutionStatus()
+ new ExecutionStatus()
.code(TSStatusCode.EXECUTE_STATEMENT_ERROR.getStatusCode())
.message(TSStatusCode.EXECUTE_STATEMENT_ERROR.name()))
.build();
}
- final ExecutionResult result;
- queryId = SESSION_MANAGER.requestQueryId();
- if (statement instanceof CreateTableViewStatement) {
- result =
- COORDINATOR.executeForTableModel(
- ((CreateTableViewStatement) statement).getCreateTableView(),
- new SqlParser(),
- SESSION_MANAGER.getCurrSessionAndUpdateIdleTime(),
- queryId,
-
SESSION_MANAGER.getSessionInfo(SESSION_MANAGER.getCurrSession()),
- sql.getSql(),
- LocalExecutionPlanner.getInstance().metadata,
- config.getQueryTimeoutThreshold(),
- false);
- } else {
- Response response =
authorizationHandler.checkAuthority(securityContext, statement);
- if (response != null) {
- return response;
- }
- result =
- COORDINATOR.executeForTreeModel(
- statement,
- queryId,
-
SESSION_MANAGER.getSessionInfo(SESSION_MANAGER.getCurrSession()),
- sql.getSql(),
- partitionFetcher,
- schemaFetcher,
- config.getQueryTimeoutThreshold(),
- false);
+ Response response = authorizationHandler.checkAuthority(securityContext,
statement);
+ if (response != null) {
+ return response;
}
+ queryId = SESSION_MANAGER.requestQueryId();
+ ExecutionResult result =
+ COORDINATOR.executeForTreeModel(
+ statement,
+ queryId,
+ SESSION_MANAGER.getSessionInfo(SESSION_MANAGER.getCurrSession()),
+ sql.getSql(),
+ partitionFetcher,
+ schemaFetcher,
+ config.getQueryTimeoutThreshold(),
+ false);
finish = true;
return responseGenerateHelper(result);
} catch (Exception e) {
@@ -146,12 +269,9 @@ public class RestApiServiceImpl extends RestApiService {
return
Response.ok().entity(ExceptionHandler.tryCatchException(e)).build();
} finally {
long costTime = System.nanoTime() - startTime;
- Optional.ofNullable(statement)
- .ifPresent(
- s -> {
- CommonUtils.addStatementExecutionLatency(
- OperationType.EXECUTE_NON_QUERY_PLAN, s.getType().name(),
costTime);
- });
+ if (statement != null)
+ CommonUtils.addStatementExecutionLatency(
+ OperationType.EXECUTE_NON_QUERY_PLAN, statement.getType().name(),
costTime);
if (queryId != null) {
if (finish) {
long executionTime = COORDINATOR.getTotalExecutionTime(queryId);
@@ -176,7 +296,7 @@ public class RestApiServiceImpl extends RestApiService {
if (statement == null) {
return Response.ok()
.entity(
- new org.apache.iotdb.db.protocol.rest.model.ExecutionStatus()
+ new ExecutionStatus()
.code(TSStatusCode.SQL_PARSE_ERROR.getStatusCode())
.message("This operation type is not supported"))
.build();
@@ -185,7 +305,7 @@ public class RestApiServiceImpl extends RestApiService {
if (ExecuteStatementHandler.validateStatement(statement)) {
return Response.ok()
.entity(
- new org.apache.iotdb.db.protocol.rest.model.ExecutionStatus()
+ new ExecutionStatus()
.code(TSStatusCode.EXECUTE_STATEMENT_ERROR.getStatusCode())
.message(TSStatusCode.EXECUTE_STATEMENT_ERROR.name()))
.build();
@@ -232,10 +352,9 @@ public class RestApiServiceImpl extends RestApiService {
long costTime = System.nanoTime() - startTime;
Optional.ofNullable(statement)
.ifPresent(
- s -> {
- CommonUtils.addStatementExecutionLatency(
- OperationType.EXECUTE_QUERY_STATEMENT, s.getType().name(),
costTime);
- });
+ s ->
+ CommonUtils.addStatementExecutionLatency(
+ OperationType.EXECUTE_QUERY_STATEMENT,
s.getType().name(), costTime));
if (queryId != null) {
if (finish) {
long executionTime = COORDINATOR.getTotalExecutionTime(queryId);
@@ -249,7 +368,8 @@ public class RestApiServiceImpl extends RestApiService {
@Override
public Response insertRecords(
- InsertRecordsRequest insertRecordsRequest, SecurityContext
securityContext) {
+ InsertRecordsRequest insertRecordsRequest, SecurityContext
securityContext)
+ throws NotFoundException {
Long queryId = null;
long startTime = System.nanoTime();
InsertRowsStatement insertRowsStatement = null;
@@ -282,10 +402,9 @@ public class RestApiServiceImpl extends RestApiService {
long costTime = System.nanoTime() - startTime;
Optional.ofNullable(insertRowsStatement)
.ifPresent(
- s -> {
- CommonUtils.addStatementExecutionLatency(
- OperationType.INSERT_RECORDS, s.getType().name(),
costTime);
- });
+ s ->
+ CommonUtils.addStatementExecutionLatency(
+ OperationType.INSERT_RECORDS, s.getType().name(),
costTime));
if (queryId != null) {
COORDINATOR.cleanupQueryExecution(queryId);
}
@@ -337,10 +456,9 @@ public class RestApiServiceImpl extends RestApiService {
long costTime = System.nanoTime() - startTime;
Optional.ofNullable(insertTabletStatement)
.ifPresent(
- s -> {
- CommonUtils.addStatementExecutionLatency(
- OperationType.INSERT_TABLET, s.getType().name(), costTime);
- });
+ s ->
+ CommonUtils.addStatementExecutionLatency(
+ OperationType.INSERT_TABLET, s.getType().name(),
costTime));
if (queryId != null) {
COORDINATOR.cleanupQueryExecution(queryId);
}
diff --git a/iotdb-protocol/openapi/src/main/openapi3/iotdb_rest_v2.yaml
b/iotdb-protocol/openapi/src/main/openapi3/iotdb_rest_v2.yaml
index 04d12359da4..0cae51bef23 100644
--- a/iotdb-protocol/openapi/src/main/openapi3/iotdb_rest_v2.yaml
+++ b/iotdb-protocol/openapi/src/main/openapi3/iotdb_rest_v2.yaml
@@ -102,6 +102,23 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/QueryDataSet'
+ /rest/v2/fastLastQuery:
+ post:
+ summary: executeFastLastQueryStatement
+ description: executeFastLastQueryStatement
+ operationId: executeFastLastQueryStatement
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/PrefixPathList'
+ responses:
+ "200":
+ description: QueryDataSet
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/QueryDataSet'
/grafana/v2/login:
get:
@@ -185,6 +202,14 @@ components:
type: integer
format: int32
+ PrefixPathList:
+ title: PrefixPathList
+ type: object
+ properties:
+ prefix_paths:
+ type: array
+ items:
+ type: string
InsertTabletRequest:
title: InsertTabletRequest
type: object