diff --git a/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/v2/impl/RestApiServiceImpl.java b/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/v2/impl/RestApiServiceImpl.java index f6c42533a6231..e05929c6a639b 100644 --- a/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/v2/impl/RestApiServiceImpl.java +++ b/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/v2/impl/RestApiServiceImpl.java @@ -40,6 +40,7 @@ import org.apache.iotdb.db.queryengine.plan.statement.StatementType; 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.crud.QueryStatement; import org.apache.iotdb.db.schemaengine.SchemaEngine; import org.apache.iotdb.db.schemaengine.schemaregion.ISchemaRegion; import org.apache.iotdb.db.utils.CommonUtils; @@ -111,7 +112,7 @@ public RestApiServiceImpl() { public Response executeFastLastQueryStatement( PrefixPathList prefixPathList, SecurityContext securityContext) { Long queryId = null; - Statement statement = null; + QueryStatement statement = null; boolean finish = false; long startTime = System.nanoTime(); Throwable t = null; @@ -123,7 +124,17 @@ public Response executeFastLastQueryStatement( new PartialPath(prefixPathList.getPrefixPaths().toArray(new String[0])); final Map>>> resultMap = new HashMap<>(); - int sensorNum = 0; + + // Check permission, the cost is rather low because the req only contains one prefix path + final IClientSession clientSession = SESSION_MANAGER.getCurrSession(); + final TSLastDataQueryReq tsLastDataQueryReq = + FastLastHandler.createTSLastDataQueryReq(clientSession, prefixPathList); + statement = StatementGenerator.createStatement(tsLastDataQueryReq); + + final Response response = authorizationHandler.checkAuthority(securityContext, statement); + if (response != null) { + return response; + } final String prefixString = prefixPath.toString(); for (final ISchemaRegion region : SchemaEngine.getInstance().getAllSchemaRegions()) { @@ -131,22 +142,15 @@ public Response executeFastLastQueryStatement( && !region.getDatabaseFullPath().startsWith(prefixString)) { continue; } - sensorNum += region.fillLastQueryMap(prefixPath, resultMap); + region.fillLastQueryMap(prefixPath, resultMap, statement.getAuthorityScope()); } + // Check cache first if (!TableDeviceSchemaCache.getInstance().getLastCache(resultMap)) { - IClientSession clientSession = SESSION_MANAGER.getCurrSession(); - 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); diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBRestServiceIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBRestServiceIT.java index 76a246149cd94..eb2573c7f8441 100644 --- a/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBRestServiceIT.java +++ b/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBRestServiceIT.java @@ -19,6 +19,7 @@ package org.apache.iotdb.db.it; import org.apache.iotdb.commons.schema.column.ColumnHeaderConstant; +import org.apache.iotdb.db.it.utils.TestUtils; import org.apache.iotdb.it.env.EnvFactory; import org.apache.iotdb.it.env.cluster.node.DataNodeWrapper; import org.apache.iotdb.it.framework.IoTDBTestRunner; @@ -54,6 +55,7 @@ import java.sql.Statement; import java.util.ArrayList; import java.util.Base64; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; @@ -476,6 +478,7 @@ public void insertAndQuery() { selectLast(httpClient); queryV2(httpClient); + selectFastLast(httpClient); queryGroupByLevelV2(httpClient); queryRowLimitV2(httpClient); queryShowChildPathsV2(httpClient); @@ -886,6 +889,71 @@ public void queryWithWrongAuthorization() { } } + @Test + public void queryFastLastWithWrongAuthorization() { + CloseableHttpResponse response = null; + + TestUtils.executeNonQuery("create user abcd 'strongPassword@1234'"); + try { + final CloseableHttpClient httpClient = HttpClientBuilder.create().build(); + final HttpPost httpPost = new HttpPost("http://127.0.0.1:" + port + "/rest/v2/fastLastQuery"); + httpPost.addHeader("Content-type", "application/json; charset=utf-8"); + httpPost.setHeader("Accept", "application/json"); + final String authorization = getAuthorization("abcd", "strongPassword@1234"); + httpPost.setHeader("Authorization", authorization); + final String sql = "{\"prefix_paths\":[\"root\",\"sg25\"]}"; + httpPost.setEntity(new StringEntity(sql, Charset.defaultCharset())); + for (int i = 0; i < 30; i++) { + try { + response = httpClient.execute(httpPost); + break; + } catch (Exception e) { + if (i == 29) { + throw e; + } + try { + Thread.sleep(1000); + } catch (InterruptedException ex) { + throw new RuntimeException(ex); + } + } + } + + Assert.assertEquals(200, response.getStatusLine().getStatusCode()); + String message = EntityUtils.toString(response.getEntity(), "utf-8"); + ObjectMapper mapper = new ObjectMapper(); + Map map = mapper.readValue(message, Map.class); + List timestampsResult = (List) map.get("timestamps"); + List expressionsResult = (List) map.get("expressions"); + List> valuesResult = (List>) map.get("values"); + Assert.assertTrue(map.size() > 0); + List expressions = + new ArrayList() { + { + add("Timeseries"); + add("Value"); + add("DataType"); + } + }; + + Assert.assertEquals(expressions, expressionsResult); + Assert.assertEquals(Collections.emptyList(), timestampsResult); + Assert.assertEquals(Collections.emptyList(), valuesResult); + } catch (IOException e) { + e.printStackTrace(); + fail(e.getMessage()); + } finally { + try { + if (response != null) { + response.close(); + } + } catch (IOException e) { + e.printStackTrace(); + fail(e.getMessage()); + } + } + } + public void query(CloseableHttpClient httpClient) { CloseableHttpResponse response = null; try { @@ -1651,6 +1719,98 @@ public void queryV2(CloseableHttpClient httpClient) { } } + public void selectFastLast(CloseableHttpClient httpClient) { + // Only used in 1D scenarios + if (EnvFactory.getEnv().getDataNodeWrapperList().size() > 1) { + return; + } + CloseableHttpResponse response = null; + try { + HttpPost httpPost = getHttpPost("http://127.0.0.1:" + port + "/rest/v2/fastLastQuery"); + String sql = "{\"prefix_paths\":[\"root\",\"sg25\"]}"; + httpPost.setEntity(new StringEntity(sql, Charset.defaultCharset())); + response = httpClient.execute(httpPost); + HttpEntity responseEntity = response.getEntity(); + String message = EntityUtils.toString(responseEntity, "utf-8"); + ObjectMapper mapper = new ObjectMapper(); + Map map = mapper.readValue(message, Map.class); + List timestampsResult = (List) map.get("timestamps"); + List expressionsResult = (List) map.get("expressions"); + List> valuesResult = (List>) map.get("values"); + Assert.assertTrue(map.size() > 0); + List expressions = + new ArrayList() { + { + add("Timeseries"); + add("Value"); + add("DataType"); + } + }; + List timestamps = + new ArrayList() { + { + add(1635232153960l); + add(1635232153960l); + add(1635232153960l); + add(1635232143960l); + add(1635232153960l); + add(1635232153960l); + } + }; + List values1 = + new ArrayList() { + { + add("root.sg25.s3"); + add("root.sg25.s4"); + add("root.sg25.s5"); + add("root.sg25.s6"); + add("root.sg25.s7"); + add("root.sg25.s8"); + } + }; + List values2 = + new ArrayList() { + { + add(""); + add("2"); + add("1635000012345556"); + add("1.41"); + add("false"); + add("3.5555"); + } + }; + List values3 = + new ArrayList() { + { + add("TEXT"); + add("INT32"); + add("INT64"); + add("FLOAT"); + add("BOOLEAN"); + add("DOUBLE"); + } + }; + + Assert.assertEquals(expressions, expressionsResult); + Assert.assertEquals(timestamps, timestampsResult); + Assert.assertEquals(values1, valuesResult.get(0)); + Assert.assertEquals(values2, valuesResult.get(1)); + Assert.assertEquals(values3, valuesResult.get(2)); + } catch (IOException e) { + e.printStackTrace(); + fail(e.getMessage()); + } finally { + try { + if (response != null) { + response.close(); + } + } catch (IOException e) { + e.printStackTrace(); + fail(e.getMessage()); + } + } + } + public void queryGroupByLevelV2(CloseableHttpClient httpClient) { CloseableHttpResponse response = null; try { diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/utils/TestUtils.java b/integration-test/src/test/java/org/apache/iotdb/db/it/utils/TestUtils.java index 43a11647c3740..9c2a09024c4d9 100644 --- a/integration-test/src/test/java/org/apache/iotdb/db/it/utils/TestUtils.java +++ b/integration-test/src/test/java/org/apache/iotdb/db/it/utils/TestUtils.java @@ -1451,8 +1451,9 @@ public static void assertResultSetEqual( public static void assertResultSetEqual( SessionDataSet actualResultSet, List expectedColumnNames, - Set expectedRetArray, + Set expectedRetSet, boolean ignoreTimeStamp) { + final Set copiedSet = new HashSet<>(expectedRetSet); try { List actualColumnNames = actualResultSet.getColumnNames(); if (ignoreTimeStamp) { @@ -1462,12 +1463,11 @@ public static void assertResultSetEqual( assertEquals(expectedColumnNames, actualColumnNames.subList(1, actualColumnNames.size())); } - int count = 0; while (actualResultSet.hasNext()) { RowRecord rowRecord = actualResultSet.next(); - assertTrue(expectedRetArray.remove(rowRecord.toString().replace('\t', ','))); + assertTrue(copiedSet.remove(rowRecord.toString().replace('\t', ','))); } - assertEquals(expectedRetArray.size(), count); + assertEquals(0, copiedSet.size()); } catch (IoTDBConnectionException | StatementExecutionException e) { e.printStackTrace(); fail(e.getMessage()); diff --git a/integration-test/src/test/java/org/apache/iotdb/session/it/IoTDBSessionQueryIT.java b/integration-test/src/test/java/org/apache/iotdb/session/it/IoTDBSessionQueryIT.java index 8bd6833ec089d..f65f2b4496fdd 100644 --- a/integration-test/src/test/java/org/apache/iotdb/session/it/IoTDBSessionQueryIT.java +++ b/integration-test/src/test/java/org/apache/iotdb/session/it/IoTDBSessionQueryIT.java @@ -22,6 +22,7 @@ import org.apache.iotdb.common.rpc.thrift.TAggregationType; import org.apache.iotdb.commons.conf.IoTDBConstant; import org.apache.iotdb.db.it.utils.AlignedWriteUtil; +import org.apache.iotdb.db.it.utils.TestUtils; import org.apache.iotdb.isession.ISession; import org.apache.iotdb.isession.SessionDataSet; import org.apache.iotdb.it.env.EnvFactory; @@ -29,6 +30,7 @@ import org.apache.iotdb.itbase.category.ClusterIT; import org.apache.iotdb.itbase.category.LocalStandaloneIT; import org.apache.iotdb.rpc.IoTDBConnectionException; +import org.apache.iotdb.rpc.RedirectException; import org.apache.iotdb.rpc.StatementExecutionException; import org.junit.AfterClass; @@ -249,6 +251,81 @@ public void lastQueryForOneDeviceNoSchema() throws IoTDBConnectionException { } } + @Test + public void lastQueryWithPrefixTest() throws IoTDBConnectionException { + // Only used in 1D scenarios + if (EnvFactory.getEnv().getDataNodeWrapperList().size() > 1) { + return; + } + final Set retArray = + new HashSet<>( + Arrays.asList( + "30,root.sg1.d1.s3,30,INT64", + "30,root.sg1.d1.s4,false,BOOLEAN", + "40,root.sg1.d1.s5,aligned_test40,TEXT", + "23,root.sg1.d1.s1,230000.0,FLOAT", + "40,root.sg1.d1.s2,40,INT32")); + + try (final ISession session = EnvFactory.getEnv().getSessionConnection()) { + // Push last cache first + try (final SessionDataSet resultSet = + session.executeFastLastDataQueryForOnePrefixPath(Arrays.asList("root", "sg1", "d1"))) { + assertResultSetEqual(resultSet, lastQueryColumnNames, retArray, true); + } + + try (final SessionDataSet resultSet = + session.executeFastLastDataQueryForOnePrefixPath(Arrays.asList("root", "sg1", "d1"))) { + assertResultSetEqual(resultSet, lastQueryColumnNames, retArray, true); + } + } catch (StatementExecutionException | RedirectException e) { + e.printStackTrace(); + fail(e.getMessage()); + } + } + + @Test + public void lastQueryWithoutPermissionTest() throws IoTDBConnectionException { + // Only used in 1D scenarios + if (EnvFactory.getEnv().getDataNodeWrapperList().size() > 1) { + return; + } + final String[] retArray = new String[] {}; + final Set retArray2 = + new HashSet<>( + Arrays.asList( + "30,root.sg1.d1.s3,30,INT64", + "30,root.sg1.d1.s4,false,BOOLEAN", + "40,root.sg1.d1.s5,aligned_test40,TEXT", + "23,root.sg1.d1.s1,230000.0,FLOAT", + "40,root.sg1.d1.s2,40,INT32")); + TestUtils.executeNonQuery(EnvFactory.getEnv(), "create user abcd 'veryComplexPassword@123'"); + + try (final ISession session = + EnvFactory.getEnv().getSessionConnection("abcd", "veryComplexPassword@123"); + final ISession rootSession = EnvFactory.getEnv().getSessionConnection()) { + // Push last cache first + try (final SessionDataSet resultSet = + rootSession.executeFastLastDataQueryForOnePrefixPath( + Arrays.asList("root", "sg1", "d1"))) { + assertResultSetEqual(resultSet, lastQueryColumnNames, retArray2, true); + } + + try (final SessionDataSet resultSet = + session.executeLastDataQueryForOneDevice( + "root.sg1", "root.sg1.d1", Arrays.asList("notExist", "s1"), true)) { + assertResultSetEqual(resultSet, lastQueryColumnNames, retArray, true); + } + + try (final SessionDataSet resultSet = + session.executeFastLastDataQueryForOnePrefixPath(Arrays.asList("root", "sg1", "d1"))) { + assertResultSetEqual(resultSet, lastQueryColumnNames, retArray, true); + } + } catch (StatementExecutionException | RedirectException e) { + e.printStackTrace(); + fail(e.getMessage()); + } + } + // ------------------------------ Aggregation Query ------------------------------ @Test public void aggregationQueryTest() { diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/table/RenameTableColumnProcedure.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/table/RenameTableColumnProcedure.java index da51dad267266..a2a6c72577cf9 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/table/RenameTableColumnProcedure.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/table/RenameTableColumnProcedure.java @@ -180,7 +180,9 @@ private void rollbackRenameColumn(final ConfigNodeProcedureEnv env) { env.getConfigManager() .getClusterSchemaManager() .executePlan( - new RenameTableColumnPlan(database, tableName, newName, oldName), + this instanceof RenameViewColumnProcedure + ? new RenameViewColumnPlan(database, tableName, newName, oldName) + : new RenameTableColumnPlan(database, tableName, newName, oldName), isGeneratedByPipe); if (status.getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) { setFailure(new ProcedureException(new IoTDBException(status))); diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/table/SetTablePropertiesProcedure.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/table/SetTablePropertiesProcedure.java index eedbf7fdb3d0a..138ae9c9b50ea 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/table/SetTablePropertiesProcedure.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/table/SetTablePropertiesProcedure.java @@ -203,7 +203,9 @@ private void rollbackSetProperties(final ConfigNodeProcedureEnv env) { env.getConfigManager() .getClusterSchemaManager() .executePlan( - new SetTablePropertiesPlan(database, tableName, originalProperties), + this instanceof SetViewPropertiesProcedure + ? new SetViewPropertiesPlan(database, tableName, originalProperties) + : new SetTablePropertiesPlan(database, tableName, originalProperties), isGeneratedByPipe); if (status.getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) { setFailure(new ProcedureException(new IoTDBException(status))); diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/thrift/impl/ClientRPCServiceImpl.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/thrift/impl/ClientRPCServiceImpl.java index ed754c418c635..06b60117c5fc0 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/thrift/impl/ClientRPCServiceImpl.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/thrift/impl/ClientRPCServiceImpl.java @@ -42,6 +42,7 @@ import org.apache.iotdb.commons.path.MeasurementPath; import org.apache.iotdb.commons.path.NonAlignedFullPath; import org.apache.iotdb.commons.path.PartialPath; +import org.apache.iotdb.commons.path.PathPatternTree; import org.apache.iotdb.commons.utils.PathUtils; import org.apache.iotdb.db.audit.DNAuditLogger; import org.apache.iotdb.db.auth.AuthorityChecker; @@ -113,6 +114,7 @@ import org.apache.iotdb.db.queryengine.plan.statement.crud.InsertRowsOfOneDeviceStatement; 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.crud.QueryStatement; import org.apache.iotdb.db.queryengine.plan.statement.metadata.CreateAlignedTimeSeriesStatement; import org.apache.iotdb.db.queryengine.plan.statement.metadata.CreateMultiTimeSeriesStatement; import org.apache.iotdb.db.queryengine.plan.statement.metadata.CreateTimeSeriesStatement; @@ -1170,7 +1172,7 @@ public TSExecuteStatementResp executeFastLastDataQueryForOnePrefixPath( try { final long queryId = SESSION_MANAGER.requestQueryId(clientSession, req.statementId); - // 1. Map ISchemaFetcher.getAllSensors(prefix) ~= 50ms + // 1.1 Map ISchemaFetcher.getAllSensors(prefix) ~= 50ms final PartialPath prefixPath = new PartialPath(req.getPrefixes().toArray(new String[0])); if (prefixPath.hasWildcard()) { @@ -1184,13 +1186,26 @@ public TSExecuteStatementResp executeFastLastDataQueryForOnePrefixPath( new HashMap<>(); int sensorNum = 0; + // 1.2 Check permission, the cost is rather low because the req only contains one prefix path + final QueryStatement s = StatementGenerator.createStatement(convert(req)); + final TSStatus status = + AuthorityChecker.checkAuthority( + s, + new TreeAccessCheckContext( + clientSession.getUserId(), + clientSession.getUsername(), + clientSession.getClientAddress())); + if (status.getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) { + return RpcUtils.getTSExecuteStatementResp(status); + } + 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); + sensorNum += region.fillLastQueryMap(prefixPath, resultMap, s.getAuthorityScope()); } // 2.DATA_NODE_SCHEMA_CACHE.getLastCache() @@ -1286,6 +1301,20 @@ public TSExecuteStatementResp executeFastLastDataQueryForOneDeviceV2( long startTime = System.nanoTime(); Throwable t = null; try { + // Place the permission check first + final QueryStatement s = StatementGenerator.createStatement(convert(req)); + // permission check + final TSStatus status = + AuthorityChecker.checkAuthority( + s, + new TreeAccessCheckContext( + clientSession.getUserId(), + clientSession.getUsername(), + clientSession.getClientAddress())); + if (status.getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) { + return RpcUtils.getTSExecuteStatementResp(status); + } + String db; String device; PartialPath devicePath; @@ -1315,7 +1344,7 @@ public TSExecuteStatementResp executeFastLastDataQueryForOneDeviceV2( // no valid DataRegion if (regionReplicaSets.isEmpty() || regionReplicaSets.size() == 1 && NOT_ASSIGNED == regionReplicaSets.get(0)) { - TSExecuteStatementResp resp = + final TSExecuteStatementResp resp = createResponse(DatasetHeaderFactory.getLastQueryHeader(), queryId); resp.setStatus(RpcUtils.getStatus(TSStatusCode.SUCCESS_STATUS, "")); resp.setQueryResult(Collections.emptyList()); @@ -1325,7 +1354,7 @@ public TSExecuteStatementResp executeFastLastDataQueryForOneDeviceV2( return resp; } - TEndPoint lastRegionLeader = + final TEndPoint lastRegionLeader = regionReplicaSets .get(regionReplicaSets.size() - 1) .dataNodeLocations @@ -1336,41 +1365,51 @@ public TSExecuteStatementResp executeFastLastDataQueryForOneDeviceV2( // read directly from cache if (isSameNode(lastRegionLeader)) { // the device's all dataRegions' leader are on current node, can use null entry in cache - boolean canUseNullEntry = + final boolean canUseNullEntry = regionReplicaSets.stream() .limit(regionReplicaSets.size() - 1L) .allMatch( regionReplicaSet -> isSameNode( regionReplicaSet.dataNodeLocations.get(0).mPPDataExchangeEndPoint)); - int sensorNum = req.sensors.size(); - TsBlockBuilder builder = LastQueryUtil.createTsBlockBuilder(sensorNum); + final int sensorNum = req.sensors.size(); + final TsBlockBuilder builder = LastQueryUtil.createTsBlockBuilder(sensorNum); boolean allCached = true; - for (String sensor : req.sensors) { - MeasurementPath fullPath; + + PathPatternTree queryTree = new PathPatternTree(); + for (final String sensor : req.sensors) { + final MeasurementPath fullPath; if (req.isLegalPathNodes()) { fullPath = devicePath.concatAsMeasurementPath(sensor); } else { fullPath = devicePath.concatAsMeasurementPath((new PartialPath(sensor)).getFullPath()); } - TimeValuePair timeValuePair = DATA_NODE_SCHEMA_CACHE.getLastCache(fullPath); - if (timeValuePair == null) { - allCached = false; - break; - } else if (timeValuePair.getValue() == null) { - // there is no data for this sensor - if (!canUseNullEntry) { + queryTree.appendPathPattern(fullPath); + } + queryTree.constructTree(); + queryTree = s.getAuthorityScope().intersectWithFullPathPrefixTree(queryTree); + + if (!queryTree.isEmpty()) { + for (final MeasurementPath fullPath : queryTree.getAllPathPatterns(true)) { + final TimeValuePair timeValuePair = DATA_NODE_SCHEMA_CACHE.getLastCache(fullPath); + if (timeValuePair == null) { allCached = false; break; + } else if (timeValuePair.getValue() == null) { + // there is no data for this sensor + if (!canUseNullEntry) { + allCached = false; + break; + } + } else { + // we don't consider TTL + LastQueryUtil.appendLastValueRespectBlob( + builder, + timeValuePair.getTimestamp(), + new Binary(fullPath.getFullPath(), TSFileConfig.STRING_CHARSET), + timeValuePair.getValue(), + timeValuePair.getValue().getDataType().name()); } - } else { - // we don't consider TTL - LastQueryUtil.appendLastValueRespectBlob( - builder, - timeValuePair.getTimestamp(), - new Binary(fullPath.getFullPath(), TSFileConfig.STRING_CHARSET), - timeValuePair.getValue(), - timeValuePair.getValue().getDataType().name()); } } // cache hit @@ -1390,20 +1429,6 @@ public TSExecuteStatementResp executeFastLastDataQueryForOneDeviceV2( } } - // cache miss - Statement s = StatementGenerator.createStatement(convert(req)); - // permission check - TSStatus status = - AuthorityChecker.checkAuthority( - s, - new TreeAccessCheckContext( - clientSession.getUserId(), - clientSession.getUsername(), - clientSession.getClientAddress())); - if (status.getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) { - return RpcUtils.getTSExecuteStatementResp(status); - } - quota = DataNodeThrottleQuotaManager.getInstance() .checkQuota(SESSION_MANAGER.getCurrSession().getUsername(), s); diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/parser/StatementGenerator.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/parser/StatementGenerator.java index 4fc5e50a060af..901196d0e1b08 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/parser/StatementGenerator.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/parser/StatementGenerator.java @@ -176,7 +176,7 @@ public static Statement createStatement(TSRawDataQueryReq rawDataQueryReq) return queryStatement; } - public static Statement createStatement(TSLastDataQueryReq lastDataQueryReq) + public static QueryStatement createStatement(TSLastDataQueryReq lastDataQueryReq) throws IllegalPathException { final long startTime = System.nanoTime(); // construct query statement diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/ISchemaRegion.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/ISchemaRegion.java index 4a11165353cd6..8d87435e108a8 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/ISchemaRegion.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/ISchemaRegion.java @@ -359,7 +359,8 @@ long countPathsUsingTemplate(int templateId, PathPatternTree patternTree) int fillLastQueryMap( final PartialPath pattern, - final Map>>> mapToFill) + final Map>>> mapToFill, + final PathPatternTree scope) throws MetadataException; // endregion diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/impl/SchemaRegionMemoryImpl.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/impl/SchemaRegionMemoryImpl.java index c5c3b7f57b8cf..2e200cf8e8c55 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/impl/SchemaRegionMemoryImpl.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/impl/SchemaRegionMemoryImpl.java @@ -1461,9 +1461,10 @@ public void updateSubtreeMeasurementCountForTemplate(final int templateId, final @Override public int fillLastQueryMap( final PartialPath pattern, - final Map>>> mapToFill) + final Map>>> mapToFill, + final PathPatternTree scope) throws MetadataException { - return mTree.fillLastQueryMap(pattern, mapToFill); + return mTree.fillLastQueryMap(pattern, mapToFill, scope); } @Override diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/impl/SchemaRegionPBTreeImpl.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/impl/SchemaRegionPBTreeImpl.java index 2f4bec896ddf4..19517f9060186 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/impl/SchemaRegionPBTreeImpl.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/impl/SchemaRegionPBTreeImpl.java @@ -1517,8 +1517,9 @@ public void deleteTableDevicesInBlackList( @Override public int fillLastQueryMap( - PartialPath pattern, - Map>>> mapToFill) { + final PartialPath pattern, + final Map>>> mapToFill, + final PathPatternTree scope) { throw new UnsupportedOperationException("Not implemented"); } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/mtree/impl/mem/MTreeBelowSGMemoryImpl.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/mtree/impl/mem/MTreeBelowSGMemoryImpl.java index ed519030b630e..d872a1130a4ee 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/mtree/impl/mem/MTreeBelowSGMemoryImpl.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/mtree/impl/mem/MTreeBelowSGMemoryImpl.java @@ -1299,12 +1299,12 @@ public IDeviceSchemaInfo next() { public int fillLastQueryMap( final PartialPath prefixPath, - final Map>>> mapToFill) + final Map>>> mapToFill, + final PathPatternTree scope) throws MetadataException { final int[] sensorNum = {0}; try (final EntityUpdater updater = - new EntityUpdater( - rootNode, prefixPath, store, true, SchemaConstant.ALL_MATCH_SCOPE) { + new EntityUpdater(rootNode, prefixPath, store, true, scope) { @Override protected void updateEntity(final IDeviceMNode node) {