This is an automated email from the ASF dual-hosted git repository.
Caideyipi 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 312d3841a97 Excluded system & audit from COUNT TIMESERIES and included
views (#17703)
312d3841a97 is described below
commit 312d3841a9715f3ad24394ff38bb5ceccfb5183a
Author: Caideyipi <[email protected]>
AuthorDate: Thu May 28 18:02:47 2026 +0800
Excluded system & audit from COUNT TIMESERIES and included views (#17703)
---
.../iotdb/db/it/schema/IoTDBMetadataFetchIT.java | 28 ++++
.../regionscan/IoTDBActiveSchemaQueryIT.java | 34 +++++
.../db/queryengine/common/TimeseriesContext.java | 106 ++++++++++++-
.../schema/CountGroupByLevelScanOperator.java | 15 +-
.../operator/schema/SchemaCountOperator.java | 4 +
.../operator/schema/source/ISchemaSource.java | 4 +
.../schema/source/SchemaSourceFactory.java | 3 +-
.../schema/source/TimeSeriesSchemaSource.java | 23 +++
.../source/ActiveTimeSeriesRegionScanOperator.java | 15 +-
.../queryengine/plan/analyze/AnalyzeVisitor.java | 136 ++++++++++++++---
.../plan/planner/OperatorTreeGenerator.java | 44 ++++--
.../operator/schema/SchemaCountOperatorTest.java | 113 ++++++++++++++
.../schema/source/TimeSeriesSchemaSourceTest.java | 168 +++++++++++++++++++++
13 files changed, 653 insertions(+), 40 deletions(-)
diff --git
a/integration-test/src/test/java/org/apache/iotdb/db/it/schema/IoTDBMetadataFetchIT.java
b/integration-test/src/test/java/org/apache/iotdb/db/it/schema/IoTDBMetadataFetchIT.java
index 1b6818d39f0..82f08cb81fc 100644
---
a/integration-test/src/test/java/org/apache/iotdb/db/it/schema/IoTDBMetadataFetchIT.java
+++
b/integration-test/src/test/java/org/apache/iotdb/db/it/schema/IoTDBMetadataFetchIT.java
@@ -26,6 +26,7 @@ import org.apache.iotdb.util.AbstractSchemaIT;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.runners.Parameterized;
@@ -494,6 +495,26 @@ public class IoTDBMetadataFetchIT extends AbstractSchemaIT
{
}
}
+ @Test
+ @Ignore
+ public void showCountTimeSeriesExcludeInternalDatabaseAndIncludeView()
throws SQLException {
+ try (Connection connection = EnvFactory.getEnv().getConnection();
+ Statement statement = connection.createStatement()) {
+ final long baseVisibleCount = queryCount(statement, "COUNT TIMESERIES
root.ln*.**");
+ statement.execute("CREATE DATABASE root.count_it");
+ statement.execute(
+ "CREATE TIMESERIES root.count_it.src.s1 WITH DATATYPE = INT32,
ENCODING = PLAIN");
+ statement.execute(
+ "CREATE TIMESERIES root.count_it.src.s2 WITH DATATYPE = INT32,
ENCODING = PLAIN");
+ statement.execute("CREATE VIEW root.count_it.dst.v1 AS SELECT s1 FROM
root.count_it.src;");
+
+ final long localCount = queryCount(statement, "COUNT TIMESERIES
root.count_it.**");
+ assertEquals(3L, localCount);
+ assertEquals(
+ baseVisibleCount + localCount, queryCount(statement, "COUNT
TIMESERIES root.**"));
+ }
+ }
+
@Test
public void showCountTimeSeriesWithTag() throws SQLException {
try (Connection connection = EnvFactory.getEnv().getConnection();
@@ -865,4 +886,11 @@ public class IoTDBMetadataFetchIT extends AbstractSchemaIT
{
}
}
}
+
+ private long queryCount(final Statement statement, final String sql) throws
SQLException {
+ try (ResultSet resultSet = statement.executeQuery(sql)) {
+ Assert.assertTrue(resultSet.next());
+ return resultSet.getLong(1);
+ }
+ }
}
diff --git
a/integration-test/src/test/java/org/apache/iotdb/db/it/schema/regionscan/IoTDBActiveSchemaQueryIT.java
b/integration-test/src/test/java/org/apache/iotdb/db/it/schema/regionscan/IoTDBActiveSchemaQueryIT.java
index c0e7673d7d6..dc706140fd3 100644
---
a/integration-test/src/test/java/org/apache/iotdb/db/it/schema/regionscan/IoTDBActiveSchemaQueryIT.java
+++
b/integration-test/src/test/java/org/apache/iotdb/db/it/schema/regionscan/IoTDBActiveSchemaQueryIT.java
@@ -27,6 +27,7 @@ import org.apache.iotdb.util.AbstractSchemaIT;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.runners.Parameterized;
@@ -236,6 +237,39 @@ public class IoTDBActiveSchemaQueryIT extends
AbstractSchemaIT {
}
}
+ @Test
+ @Ignore
+ public void testCountTimeSeriesWithTimeConditionIncludesView() {
+ try (Connection connection = EnvFactory.getEnv().getConnection();
+ Statement statement = connection.createStatement()) {
+ statement.execute("CREATE DATABASE root.view_count");
+ statement.execute(
+ "CREATE TIMESERIES root.view_count.src.s1 WITH DATATYPE = INT32,
ENCODING = PLAIN");
+ statement.execute(
+ "CREATE TIMESERIES root.view_count.src.s2 WITH DATATYPE = INT32,
ENCODING = PLAIN");
+ statement.execute("CREATE VIEW root.view_count.dst.v1 AS SELECT s1 FROM
root.view_count.src");
+
+ checkResultSet(
+ statement,
+ "count timeseries root.view_count.**",
+ new HashSet<>(Collections.singletonList("3,")));
+
+ statement.execute("insert into root.view_count.src(timestamp,s1)
values(1,1)");
+
+ checkResultSet(
+ statement,
+ "count timeseries root.view_count.** where time>0",
+ new HashSet<>(Collections.singletonList("2,")));
+ checkResultSet(
+ statement,
+ "count timeseries root.view_count.dst.** where time>0",
+ new HashSet<>(Collections.singletonList("1,")));
+ } catch (Exception e) {
+ e.printStackTrace();
+ Assert.fail(e.getMessage());
+ }
+ }
+
@Test
public void testShowDevices() {
try (Connection connection = EnvFactory.getEnv().getConnection();
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/TimeseriesContext.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/TimeseriesContext.java
index 9225b97fc70..aaf8b51787d 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/TimeseriesContext.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/TimeseriesContext.java
@@ -28,7 +28,10 @@ import org.apache.tsfile.utils.ReadWriteIOUtils;
import java.io.DataOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
+import java.util.Collections;
+import java.util.HashSet;
import java.util.Objects;
+import java.util.Set;
import static
org.apache.iotdb.db.queryengine.execution.operator.schema.source.TimeSeriesSchemaSource.mapToString;
@@ -42,8 +45,17 @@ public class TimeseriesContext {
private final String deadband;
private final String deadbandParameters;
+ private final int activeCountMultiplier;
+ private final Set<String> activeLogicalViewCountSet;
public TimeseriesContext(IMeasurementSchemaInfo schemaInfo) {
+ this(schemaInfo, 1, Collections.emptySet());
+ }
+
+ public TimeseriesContext(
+ IMeasurementSchemaInfo schemaInfo,
+ int activeCountMultiplier,
+ Set<String> activeLogicalViewCountSet) {
this.dataType = schemaInfo.getSchema().getType().toString();
this.encoding = schemaInfo.getSchema().getEncodingType().toString();
this.compression = schemaInfo.getSchema().getCompressor().toString();
@@ -54,6 +66,8 @@ public class TimeseriesContext {
MetaUtils.parseDeadbandInfo(schemaInfo.getSchema().getProps());
this.deadband = deadbandInfo.left;
this.deadbandParameters = deadbandInfo.right;
+ this.activeCountMultiplier = activeCountMultiplier;
+ this.activeLogicalViewCountSet = new HashSet<>(activeLogicalViewCountSet);
}
public String getDataType() {
@@ -88,6 +102,14 @@ public class TimeseriesContext {
return deadband;
}
+ public int getActiveCountMultiplier() {
+ return activeCountMultiplier;
+ }
+
+ public Set<String> getActiveLogicalViewCountSet() {
+ return activeLogicalViewCountSet;
+ }
+
public TimeseriesContext(
String dataType,
String alias,
@@ -97,6 +119,30 @@ public class TimeseriesContext {
String attributes,
String deadband,
String deadbandParameters) {
+ this(
+ dataType,
+ alias,
+ encoding,
+ compression,
+ tags,
+ attributes,
+ deadband,
+ deadbandParameters,
+ 1,
+ Collections.emptySet());
+ }
+
+ public TimeseriesContext(
+ String dataType,
+ String alias,
+ String encoding,
+ String compression,
+ String tags,
+ String attributes,
+ String deadband,
+ String deadbandParameters,
+ int activeCountMultiplier,
+ Set<String> activeLogicalViewCountSet) {
this.dataType = dataType;
this.alias = alias;
this.encoding = encoding;
@@ -105,6 +151,24 @@ public class TimeseriesContext {
this.attributes = attributes;
this.deadband = deadband;
this.deadbandParameters = deadbandParameters;
+ this.activeCountMultiplier = activeCountMultiplier;
+ this.activeLogicalViewCountSet = new HashSet<>(activeLogicalViewCountSet);
+ }
+
+ public TimeseriesContext mergeActiveCount(TimeseriesContext that) {
+ Set<String> mergedActiveLogicalViewCountSet = new
HashSet<>(activeLogicalViewCountSet);
+ mergedActiveLogicalViewCountSet.addAll(that.activeLogicalViewCountSet);
+ return new TimeseriesContext(
+ dataType,
+ alias,
+ encoding,
+ compression,
+ tags,
+ attributes,
+ deadband,
+ deadbandParameters,
+ activeCountMultiplier + that.activeCountMultiplier,
+ mergedActiveLogicalViewCountSet);
}
public void serializeAttributes(ByteBuffer byteBuffer) {
@@ -116,6 +180,11 @@ public class TimeseriesContext {
ReadWriteIOUtils.write(attributes, byteBuffer);
ReadWriteIOUtils.write(deadband, byteBuffer);
ReadWriteIOUtils.write(deadbandParameters, byteBuffer);
+ ReadWriteIOUtils.write(activeCountMultiplier, byteBuffer);
+ ReadWriteIOUtils.write(activeLogicalViewCountSet.size(), byteBuffer);
+ for (String logicalView : activeLogicalViewCountSet) {
+ ReadWriteIOUtils.write(logicalView, byteBuffer);
+ }
}
public void serializeAttributes(DataOutputStream stream) throws IOException {
@@ -127,6 +196,11 @@ public class TimeseriesContext {
ReadWriteIOUtils.write(attributes, stream);
ReadWriteIOUtils.write(deadband, stream);
ReadWriteIOUtils.write(deadbandParameters, stream);
+ ReadWriteIOUtils.write(activeCountMultiplier, stream);
+ ReadWriteIOUtils.write(activeLogicalViewCountSet.size(), stream);
+ for (String logicalView : activeLogicalViewCountSet) {
+ ReadWriteIOUtils.write(logicalView, stream);
+ }
}
public static TimeseriesContext deserialize(ByteBuffer buffer) {
@@ -138,8 +212,23 @@ public class TimeseriesContext {
String attributes = ReadWriteIOUtils.readString(buffer);
String deadband = ReadWriteIOUtils.readString(buffer);
String deadbandParameters = ReadWriteIOUtils.readString(buffer);
+ int activeCountMultiplier = ReadWriteIOUtils.readInt(buffer);
+ int activeLogicalViewCountSetSize = ReadWriteIOUtils.readInt(buffer);
+ Set<String> activeLogicalViewCountSet = new HashSet<>();
+ for (int i = 0; i < activeLogicalViewCountSetSize; i++) {
+ activeLogicalViewCountSet.add(ReadWriteIOUtils.readString(buffer));
+ }
return new TimeseriesContext(
- dataType, alias, encoding, compression, tags, attributes, deadband,
deadbandParameters);
+ dataType,
+ alias,
+ encoding,
+ compression,
+ tags,
+ attributes,
+ deadband,
+ deadbandParameters,
+ activeCountMultiplier,
+ activeLogicalViewCountSet);
}
@Override
@@ -159,13 +248,24 @@ public class TimeseriesContext {
&& Objects.equals(tags, that.tags)
&& Objects.equals(attributes, that.attributes)
&& Objects.equals(deadband, that.deadband)
- && Objects.equals(deadbandParameters, that.deadbandParameters);
+ && Objects.equals(deadbandParameters, that.deadbandParameters)
+ && activeCountMultiplier == that.activeCountMultiplier
+ && Objects.equals(activeLogicalViewCountSet,
that.activeLogicalViewCountSet);
return res;
}
@Override
public int hashCode() {
return Objects.hash(
- dataType, alias, encoding, compression, tags, attributes, deadband,
deadbandParameters);
+ dataType,
+ alias,
+ encoding,
+ compression,
+ tags,
+ attributes,
+ deadband,
+ deadbandParameters,
+ activeCountMultiplier,
+ activeLogicalViewCountSet);
}
}
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/CountGroupByLevelScanOperator.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/CountGroupByLevelScanOperator.java
index 69f36680fb7..35c57dafa4d 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/CountGroupByLevelScanOperator.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/CountGroupByLevelScanOperator.java
@@ -27,6 +27,7 @@ import
org.apache.iotdb.db.queryengine.execution.driver.SchemaDriverContext;
import org.apache.iotdb.db.queryengine.execution.operator.OperatorContext;
import
org.apache.iotdb.db.queryengine.execution.operator.schema.source.ISchemaSource;
import
org.apache.iotdb.db.queryengine.execution.operator.source.SourceOperator;
+import org.apache.iotdb.db.schemaengine.schemaregion.ISchemaRegion;
import
org.apache.iotdb.db.schemaengine.schemaregion.read.resp.info.ISchemaInfo;
import
org.apache.iotdb.db.schemaengine.schemaregion.read.resp.reader.ISchemaReader;
@@ -95,6 +96,10 @@ public class CountGroupByLevelScanOperator<T extends
ISchemaInfo> implements Sou
return operatorContext;
}
+ private ISchemaRegion getSchemaRegion() {
+ return ((SchemaDriverContext)
operatorContext.getDriverContext()).getSchemaRegion();
+ }
+
@Override
public ListenableFuture<?> isBlocked() {
if (isBlocked == null) {
@@ -109,6 +114,11 @@ public class CountGroupByLevelScanOperator<T extends
ISchemaInfo> implements Sou
*/
private ListenableFuture<?> tryGetNext() {
if (schemaReader == null) {
+ if (schemaSource.shouldSkipSchemaRegion(getSchemaRegion())) {
+ next = null;
+ isFinished = true;
+ return NOT_BLOCKED;
+ }
schemaReader = createTimeSeriesReader();
}
while (true) {
@@ -172,15 +182,14 @@ public class CountGroupByLevelScanOperator<T extends
ISchemaInfo> implements Sou
@Override
public boolean hasNext() throws Exception {
isBlocked().get(); // wait for the next TsBlock
- if (!schemaReader.isSuccess()) {
+ if (schemaReader != null && !schemaReader.isSuccess()) {
throw new SchemaExecutionException(schemaReader.getFailure());
}
return next != null;
}
public ISchemaReader<T> createTimeSeriesReader() {
- return schemaSource.getSchemaReader(
- ((SchemaDriverContext)
operatorContext.getDriverContext()).getSchemaRegion());
+ return schemaSource.getSchemaReader(getSchemaRegion());
}
private TsBlock constructTsBlockAndClearMap(Map<PartialPath, Long> countMap)
{
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/SchemaCountOperator.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/SchemaCountOperator.java
index 9b2884233c1..4cafe40c36b 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/SchemaCountOperator.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/SchemaCountOperator.java
@@ -100,6 +100,10 @@ public class SchemaCountOperator<T extends ISchemaInfo>
implements SourceOperato
*/
private ListenableFuture<?> tryGetNext() {
ISchemaRegion schemaRegion = getSchemaRegion();
+ if (schemaSource.shouldSkipSchemaRegion(schemaRegion)) {
+ next = constructTsBlock(0);
+ return NOT_BLOCKED;
+ }
if (schemaSource.hasSchemaStatistic(schemaRegion)) {
long statisticCount = schemaSource.getSchemaStatistic(schemaRegion);
// Check if database path itself is counted as a device (bug fix)
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/source/ISchemaSource.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/source/ISchemaSource.java
index 41bd5f3fbe0..4417203fdc8 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/source/ISchemaSource.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/source/ISchemaSource.java
@@ -57,6 +57,10 @@ public interface ISchemaSource<T extends ISchemaInfo> {
long getSchemaStatistic(final ISchemaRegion schemaRegion);
+ default boolean shouldSkipSchemaRegion(final ISchemaRegion schemaRegion) {
+ return false;
+ }
+
default boolean checkRegionDatabaseIncluded(final ISchemaRegion
schemaRegion) {
return true;
}
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/source/SchemaSourceFactory.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/source/SchemaSourceFactory.java
index 87560ad47be..f45dc6a9b06 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/source/SchemaSourceFactory.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/source/SchemaSourceFactory.java
@@ -48,7 +48,7 @@ public class SchemaSourceFactory {
Map<Integer, Template> templateMap,
PathPatternTree scope) {
return new TimeSeriesSchemaSource(
- pathPattern, isPrefixMatch, 0, 0, schemaFilter, templateMap, false,
scope, null);
+ pathPattern, isPrefixMatch, 0, 0, schemaFilter, templateMap, false,
true, scope, null);
}
// show time series
@@ -69,6 +69,7 @@ public class SchemaSourceFactory {
schemaFilter,
templateMap,
true,
+ false,
scope,
timeseriesOrdering);
}
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/source/TimeSeriesSchemaSource.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/source/TimeSeriesSchemaSource.java
index a56cfa228bf..5ac6d59b089 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/source/TimeSeriesSchemaSource.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/source/TimeSeriesSchemaSource.java
@@ -27,6 +27,7 @@ import org.apache.iotdb.commons.schema.SchemaConstant;
import org.apache.iotdb.commons.schema.column.ColumnHeader;
import org.apache.iotdb.commons.schema.column.ColumnHeaderConstant;
import org.apache.iotdb.commons.schema.filter.SchemaFilter;
+import org.apache.iotdb.commons.schema.table.Audit;
import org.apache.iotdb.commons.schema.template.Template;
import org.apache.iotdb.commons.schema.view.ViewType;
import org.apache.iotdb.db.queryengine.plan.statement.component.Ordering;
@@ -55,6 +56,7 @@ public class TimeSeriesSchemaSource implements
ISchemaSource<ITimeSeriesSchemaIn
private final SchemaFilter schemaFilter;
private final Map<Integer, Template> templateMap;
private final boolean needViewDetail;
+ private final boolean excludeInternalDatabase;
private final Ordering timeseriesOrdering;
TimeSeriesSchemaSource(
@@ -65,6 +67,7 @@ public class TimeSeriesSchemaSource implements
ISchemaSource<ITimeSeriesSchemaIn
SchemaFilter schemaFilter,
Map<Integer, Template> templateMap,
boolean needViewDetail,
+ boolean excludeInternalDatabase,
PathPatternTree scope,
Ordering timeseriesOrdering) {
this.pathPattern = pathPattern;
@@ -74,6 +77,7 @@ public class TimeSeriesSchemaSource implements
ISchemaSource<ITimeSeriesSchemaIn
this.schemaFilter = schemaFilter;
this.templateMap = templateMap;
this.needViewDetail = needViewDetail;
+ this.excludeInternalDatabase = excludeInternalDatabase;
this.scope = scope;
this.timeseriesOrdering = timeseriesOrdering;
}
@@ -141,6 +145,25 @@ public class TimeSeriesSchemaSource implements
ISchemaSource<ITimeSeriesSchemaIn
return schemaRegion.getSchemaRegionStatistics().getSeriesNumber(true);
}
+ @Override
+ public boolean shouldSkipSchemaRegion(final ISchemaRegion schemaRegion) {
+ if (!excludeInternalDatabase) {
+ return false;
+ }
+
+ final String database = schemaRegion.getDatabaseFullPath();
+ if (!SchemaConstant.SYSTEM_DATABASE.equals(database)
+ && !SchemaConstant.AUDIT_DATABASE.equals(database)
+ && !Audit.TABLE_MODEL_AUDIT_DATABASE.equals(database)) {
+ return false;
+ }
+
+ final String[] nodes = pathPattern.getNodes();
+ return nodes.length < 2
+ || !SchemaConstant.ROOT.equals(nodes[0])
+ || !database.endsWith("." + nodes[1]);
+ }
+
public static String mapToString(Map<String, String> map) {
if (map == null || map.isEmpty()) {
return null;
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/ActiveTimeSeriesRegionScanOperator.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/ActiveTimeSeriesRegionScanOperator.java
index b6ac9ecd850..2dd1272f473 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/ActiveTimeSeriesRegionScanOperator.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/ActiveTimeSeriesRegionScanOperator.java
@@ -35,13 +35,16 @@ import org.apache.tsfile.utils.Binary;
import org.apache.tsfile.utils.RamUsageEstimator;
import java.io.IOException;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.stream.Collectors;
public class ActiveTimeSeriesRegionScanOperator extends
AbstractRegionScanDataSourceOperator {
// Timeseries which need to be checked.
private final Map<IDeviceID, Map<String, TimeseriesContext>>
timeSeriesToSchemasInfo;
+ private final Set<String> countedLogicalViews;
private static final Binary VIEW_TYPE = new Binary("BASE".getBytes());
private final Binary dataBaseName;
private static final long INSTANCE_SIZE =
@@ -60,6 +63,7 @@ public class ActiveTimeSeriesRegionScanOperator extends
AbstractRegionScanDataSo
this.operatorContext = operatorContext;
this.sourceId = sourceId;
this.timeSeriesToSchemasInfo = timeSeriesToSchemasInfo;
+ this.countedLogicalViews = new HashSet<>();
this.regionScanUtil = new RegionScanForActiveTimeSeriesUtil(timeFilter,
ttlCache);
this.dataBaseName =
new Binary(
@@ -101,7 +105,16 @@ public class ActiveTimeSeriesRegionScanOperator extends
AbstractRegionScanDataSo
if (outputCount) {
for (Map.Entry<IDeviceID, List<String>> entry :
activeTimeSeries.entrySet()) {
List<String> timeSeriesList = entry.getValue();
- count += timeSeriesList.size();
+ Map<String, TimeseriesContext> timeSeriesInfo =
timeSeriesToSchemasInfo.get(entry.getKey());
+ for (String timeSeries : timeSeriesList) {
+ TimeseriesContext schemaInfo = timeSeriesInfo.get(timeSeries);
+ count += schemaInfo.getActiveCountMultiplier();
+ for (String logicalView : schemaInfo.getActiveLogicalViewCountSet())
{
+ if (countedLogicalViews.add(logicalView)) {
+ count++;
+ }
+ }
+ }
removeTimeseriesListFromDevice(entry.getKey(), timeSeriesList);
}
return;
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/AnalyzeVisitor.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/AnalyzeVisitor.java
index 7aa8d1e8636..9d91a29d78b 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/AnalyzeVisitor.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/AnalyzeVisitor.java
@@ -2931,7 +2931,8 @@ public class AnalyzeVisitor extends
StatementVisitor<Analysis, MPPQueryContext>
Analysis analysis,
MPPQueryContext context,
PathPatternTree authorityScope,
- boolean canSeeAuditDB)
+ boolean canSeeAuditDB,
+ boolean includeLogicalView)
throws IllegalPathException {
analyzeGlobalTimeConditionInShowMetaData(timeCondition, analysis);
context.generateGlobalTimeFilter(analysis);
@@ -2944,7 +2945,15 @@ public class AnalyzeVisitor extends
StatementVisitor<Analysis, MPPQueryContext>
analysis.setFinishQueryAfterAnalyze(true);
return false;
}
- removeLogicViewMeasurement(schemaTree);
+ List<DeviceSchemaInfo> deviceSchemaInfoList;
+ if (includeLogicalView) {
+ deviceSchemaInfoList = schemaTree.getMatchedDevices(ALL_MATCH_PATTERN);
+ updateSchemaTreeByViews(analysis, schemaTree, context, canSeeAuditDB);
+ } else {
+ removeLogicViewMeasurement(schemaTree);
+ deviceSchemaInfoList = schemaTree.getMatchedDevices(ALL_MATCH_PATTERN);
+ }
+
Map<PartialPath, Map<PartialPath, List<TimeseriesContext>>>
deviceToTimeseriesContext =
new HashMap<>();
/**
@@ -2952,38 +2961,56 @@ public class AnalyzeVisitor extends
StatementVisitor<Analysis, MPPQueryContext>
* as a normal node, not a device+templateId. This means that all nodes
are what we need.). We
* can use ALL_MATCH_PATTERN to get result.
*/
- List<DeviceSchemaInfo> deviceSchemaInfoList =
schemaTree.getMatchedDevices(ALL_MATCH_PATTERN);
Set<IDeviceID> deviceSet = new HashSet<>();
for (DeviceSchemaInfo deviceSchemaInfo : deviceSchemaInfoList) {
boolean isAligned = deviceSchemaInfo.isAligned();
PartialPath devicePath = deviceSchemaInfo.getDevicePath();
- deviceSet.add(devicePath.getIDeviceIDAsFullDevice());
if (isAligned) {
List<String> measurementList = new ArrayList<>();
List<IMeasurementSchema> schemaList = new ArrayList<>();
List<TimeseriesContext> timeseriesContextList = new ArrayList<>();
for (IMeasurementSchemaInfo measurementSchemaInfo :
deviceSchemaInfo.getMeasurementSchemaInfoList()) {
+ if (includeLogicalView && measurementSchemaInfo.isLogicalView()) {
+ addLogicalViewSourcesForActiveCount(
+ devicePath,
+ measurementSchemaInfo,
+ schemaTree,
+ deviceToTimeseriesContext,
+ deviceSet);
+ continue;
+ }
schemaList.add(measurementSchemaInfo.getSchema());
measurementList.add(measurementSchemaInfo.getName());
timeseriesContextList.add(new
TimeseriesContext(measurementSchemaInfo));
}
- AlignedPath alignedPath =
- new AlignedPath(devicePath.getNodes(), measurementList,
schemaList);
- deviceToTimeseriesContext
- .computeIfAbsent(devicePath, k -> new HashMap<>())
- .put(alignedPath, timeseriesContextList);
+ if (!measurementList.isEmpty()) {
+ deviceSet.add(devicePath.getIDeviceIDAsFullDevice());
+ AlignedPath alignedPath =
+ new AlignedPath(devicePath.getNodes(), measurementList,
schemaList);
+ deviceToTimeseriesContext
+ .computeIfAbsent(devicePath, k -> new HashMap<>())
+ .put(alignedPath, timeseriesContextList);
+ }
} else {
for (IMeasurementSchemaInfo measurementSchemaInfo :
deviceSchemaInfo.getMeasurementSchemaInfoList()) {
- MeasurementPath measurementPath =
- new MeasurementPath(
-
devicePath.concatNode(measurementSchemaInfo.getName()).getNodes());
- deviceToTimeseriesContext
- .computeIfAbsent(devicePath, k -> new HashMap<>())
- .put(
- measurementPath,
- Collections.singletonList(new
TimeseriesContext(measurementSchemaInfo)));
+ if (includeLogicalView && measurementSchemaInfo.isLogicalView()) {
+ addLogicalViewSourcesForActiveCount(
+ devicePath,
+ measurementSchemaInfo,
+ schemaTree,
+ deviceToTimeseriesContext,
+ deviceSet);
+ } else {
+ addPhysicalTimeseriesForActiveCount(
+ devicePath,
+ measurementSchemaInfo,
+ false,
+ new TimeseriesContext(measurementSchemaInfo),
+ deviceToTimeseriesContext,
+ deviceSet);
+ }
}
}
}
@@ -2995,6 +3022,75 @@ public class AnalyzeVisitor extends
StatementVisitor<Analysis, MPPQueryContext>
return true;
}
+ private void addLogicalViewSourcesForActiveCount(
+ PartialPath viewDevicePath,
+ IMeasurementSchemaInfo viewSchemaInfo,
+ ISchemaTree schemaTree,
+ Map<PartialPath, Map<PartialPath, List<TimeseriesContext>>>
deviceToTimeseriesContext,
+ Set<IDeviceID> deviceSet) {
+ LogicalViewSchema logicalViewSchema =
viewSchemaInfo.getSchemaAsLogicalViewSchema();
+ if (logicalViewSchema == null) {
+ return;
+ }
+
+ String viewPath =
viewDevicePath.concatNode(viewSchemaInfo.getName()).getFullPath();
+ for (PartialPath sourcePath :
getSourcePaths(logicalViewSchema.getExpression())) {
+ if (sourcePath.getNodeLength() <= 1) {
+ continue;
+ }
+ PartialPath sourceDevicePath =
+ new PartialPath(Arrays.copyOf(sourcePath.getNodes(),
sourcePath.getNodeLength() - 1));
+ DeviceSchemaInfo sourceDeviceSchemaInfo =
+ schemaTree.searchDeviceSchemaInfo(
+ sourceDevicePath,
Collections.singletonList(sourcePath.getMeasurement()));
+ if (sourceDeviceSchemaInfo == null
+ || sourceDeviceSchemaInfo.getMeasurementSchemaInfoList().isEmpty()) {
+ continue;
+ }
+
+ IMeasurementSchemaInfo sourceSchemaInfo =
+ sourceDeviceSchemaInfo.getMeasurementSchemaInfoList().get(0);
+ if (sourceSchemaInfo == null || sourceSchemaInfo.isLogicalView()) {
+ continue;
+ }
+
+ addPhysicalTimeseriesForActiveCount(
+ sourceDevicePath,
+ sourceSchemaInfo,
+ sourceDeviceSchemaInfo.isAligned(),
+ new TimeseriesContext(sourceSchemaInfo, 0,
Collections.singleton(viewPath)),
+ deviceToTimeseriesContext,
+ deviceSet);
+ }
+ }
+
+ private void addPhysicalTimeseriesForActiveCount(
+ PartialPath devicePath,
+ IMeasurementSchemaInfo measurementSchemaInfo,
+ boolean isAligned,
+ TimeseriesContext timeseriesContext,
+ Map<PartialPath, Map<PartialPath, List<TimeseriesContext>>>
deviceToTimeseriesContext,
+ Set<IDeviceID> deviceSet) {
+ deviceSet.add(devicePath.getIDeviceIDAsFullDevice());
+ PartialPath timeseriesPath =
+ isAligned
+ ? new AlignedPath(
+ devicePath.getNodes(),
+ Collections.singletonList(measurementSchemaInfo.getName()),
+ Collections.singletonList(measurementSchemaInfo.getSchema()))
+ : new MeasurementPath(
+
devicePath.concatNode(measurementSchemaInfo.getName()).getNodes());
+ Map<PartialPath, List<TimeseriesContext>> timeseriesContextMap =
+ deviceToTimeseriesContext.computeIfAbsent(devicePath, k -> new
HashMap<>());
+ List<TimeseriesContext> existingContextList =
timeseriesContextMap.get(timeseriesPath);
+ if (existingContextList == null) {
+ timeseriesContextMap.put(
+ timeseriesPath, new
ArrayList<>(Collections.singletonList(timeseriesContext)));
+ } else {
+ existingContextList.set(0,
existingContextList.get(0).mergeActiveCount(timeseriesContext));
+ }
+ }
+
@Override
public Analysis visitShowTimeSeries(
ShowTimeSeriesStatement showTimeSeriesStatement, MPPQueryContext
context) {
@@ -3020,7 +3116,8 @@ public class AnalyzeVisitor extends
StatementVisitor<Analysis, MPPQueryContext>
analysis,
context,
showTimeSeriesStatement.getAuthorityScope(),
- showTimeSeriesStatement.isCanSeeAuditDB());
+ showTimeSeriesStatement.isCanSeeAuditDB(),
+ false);
if (!hasSchema) {
analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowTimeSeriesHeader());
return analysis;
@@ -3271,7 +3368,8 @@ public class AnalyzeVisitor extends
StatementVisitor<Analysis, MPPQueryContext>
analysis,
context,
countTimeSeriesStatement.getAuthorityScope(),
- countTimeSeriesStatement.isCanSeeAuditDB());
+ countTimeSeriesStatement.isCanSeeAuditDB(),
+ true);
if (!hasSchema) {
analysis.setRespDatasetHeader(DatasetHeaderFactory.getCountTimeSeriesHeader());
return analysis;
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/OperatorTreeGenerator.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/OperatorTreeGenerator.java
index 9f1aa7fc291..7ed81c7e842 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/OperatorTreeGenerator.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/OperatorTreeGenerator.java
@@ -3745,13 +3745,20 @@ public class OperatorTreeGenerator implements
PlanVisitor<Operator, LocalExecuti
for (Map.Entry<PartialPath, List<TimeseriesContext>> entry :
entryMap.getValue().entrySet()) {
PartialPath path = entry.getKey();
if (path instanceof MeasurementPath) {
- timeseriesSchemaInfoMap.put(path.getMeasurement(),
entry.getValue().get(0));
- context.addPath(
- new NonAlignedFullPath(
- path.getIDeviceID(),
- new MeasurementSchema(
- path.getMeasurement(),
-
TSDataType.valueOf(entry.getValue().get(0).getDataType()))));
+ String measurement = path.getMeasurement();
+ TimeseriesContext timeseriesContext = entry.getValue().get(0);
+ TimeseriesContext existingContext =
timeseriesSchemaInfoMap.get(measurement);
+ if (existingContext == null) {
+ timeseriesSchemaInfoMap.put(measurement, timeseriesContext);
+ context.addPath(
+ new NonAlignedFullPath(
+ path.getIDeviceID(),
+ new MeasurementSchema(
+ measurement,
TSDataType.valueOf(timeseriesContext.getDataType()))));
+ } else {
+ timeseriesSchemaInfoMap.put(
+ measurement,
existingContext.mergeActiveCount(timeseriesContext));
+ }
} else if (path instanceof AlignedPath) {
AlignedPath alignedPath = (AlignedPath) path;
List<String> measurementList = alignedPath.getMeasurementList();
@@ -3761,14 +3768,25 @@ public class OperatorTreeGenerator implements
PlanVisitor<Operator, LocalExecuti
}
int size = measurementList.size();
List<IMeasurementSchema> schemaList = new ArrayList<>(size);
+ List<String> newMeasurementList = new ArrayList<>(size);
for (int i = 0; i < size; i++) {
- timeseriesSchemaInfoMap.put(measurementList.get(i),
entry.getValue().get(i));
- schemaList.add(
- new MeasurementSchema(
- measurementList.get(i),
- TSDataType.valueOf(entry.getValue().get(i).getDataType())));
+ String measurement = measurementList.get(i);
+ TimeseriesContext timeseriesContext = entry.getValue().get(i);
+ TimeseriesContext existingContext =
timeseriesSchemaInfoMap.get(measurement);
+ if (existingContext == null) {
+ timeseriesSchemaInfoMap.put(measurement, timeseriesContext);
+ newMeasurementList.add(measurement);
+ schemaList.add(
+ new MeasurementSchema(
+ measurement,
TSDataType.valueOf(timeseriesContext.getDataType())));
+ } else {
+ timeseriesSchemaInfoMap.put(
+ measurement,
existingContext.mergeActiveCount(timeseriesContext));
+ }
+ }
+ if (!newMeasurementList.isEmpty()) {
+ context.addPath(new AlignedFullPath(path.getIDeviceID(),
newMeasurementList, schemaList));
}
- context.addPath(new AlignedFullPath(path.getIDeviceID(),
measurementList, schemaList));
}
}
return timeseriesSchemaInfoMap;
diff --git
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/execution/operator/schema/SchemaCountOperatorTest.java
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/execution/operator/schema/SchemaCountOperatorTest.java
index b59689a8deb..3cd50ebf513 100644
---
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/execution/operator/schema/SchemaCountOperatorTest.java
+++
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/execution/operator/schema/SchemaCountOperatorTest.java
@@ -114,6 +114,82 @@ public class SchemaCountOperatorTest {
}
}
+ @Test
+ public void testSchemaCountOperatorSkipSchemaRegion() throws Exception {
+ ExecutorService instanceNotificationExecutor =
+ IoTDBThreadPoolFactory.newFixedThreadPool(1,
"test-instance-notification");
+ try {
+ QueryId queryId = new QueryId("stub_query");
+ FragmentInstanceId instanceId =
+ new FragmentInstanceId(new PlanFragmentId(queryId, 0),
"stub-instance");
+ FragmentInstanceStateMachine stateMachine =
+ new FragmentInstanceStateMachine(instanceId,
instanceNotificationExecutor);
+ FragmentInstanceContext fragmentInstanceContext =
+ createFragmentInstanceContext(instanceId, stateMachine);
+ DriverContext driverContext = new DriverContext(fragmentInstanceContext,
0);
+ PlanNodeId planNodeId = queryId.genPlanNodeId();
+ ISchemaRegion schemaRegion = Mockito.mock(ISchemaRegion.class);
+ OperatorContext operatorContext =
+ driverContext.addOperatorContext(
+ 1, planNodeId, SchemaCountOperator.class.getSimpleName());
+ operatorContext.setDriverContext(
+ new SchemaDriverContext(fragmentInstanceContext, schemaRegion, 0));
+ ISchemaSource<ISchemaInfo> schemaSource =
Mockito.mock(ISchemaSource.class);
+
Mockito.when(schemaSource.shouldSkipSchemaRegion(schemaRegion)).thenReturn(true);
+
+ SchemaCountOperator<?> schemaCountOperator =
+ new SchemaCountOperator<>(
+ planNodeId, driverContext.getOperatorContexts().get(0),
schemaSource);
+
+ assertTrue(schemaCountOperator.hasNext());
+ TsBlock tsBlock = schemaCountOperator.next();
+ assertEquals(0, tsBlock.getColumn(0).getLong(0));
+ assertTrue(schemaCountOperator.isFinished());
+ Mockito.verify(schemaSource,
Mockito.never()).getSchemaReader(schemaRegion);
+ } finally {
+ instanceNotificationExecutor.shutdown();
+ }
+ }
+
+ @Test
+ public void testSchemaCountOperatorUseSchemaStatistic() throws Exception {
+ ExecutorService instanceNotificationExecutor =
+ IoTDBThreadPoolFactory.newFixedThreadPool(1,
"test-instance-notification");
+ try {
+ QueryId queryId = new QueryId("stub_query");
+ FragmentInstanceId instanceId =
+ new FragmentInstanceId(new PlanFragmentId(queryId, 0),
"stub-instance");
+ FragmentInstanceStateMachine stateMachine =
+ new FragmentInstanceStateMachine(instanceId,
instanceNotificationExecutor);
+ FragmentInstanceContext fragmentInstanceContext =
+ createFragmentInstanceContext(instanceId, stateMachine);
+ DriverContext driverContext = new DriverContext(fragmentInstanceContext,
0);
+ PlanNodeId planNodeId = queryId.genPlanNodeId();
+ ISchemaRegion schemaRegion = Mockito.mock(ISchemaRegion.class);
+ OperatorContext operatorContext =
+ driverContext.addOperatorContext(
+ 1, planNodeId, SchemaCountOperator.class.getSimpleName());
+ operatorContext.setDriverContext(
+ new SchemaDriverContext(fragmentInstanceContext, schemaRegion, 0));
+ ISchemaSource<ISchemaInfo> schemaSource =
Mockito.mock(ISchemaSource.class);
+
Mockito.when(schemaSource.hasSchemaStatistic(schemaRegion)).thenReturn(true);
+
Mockito.when(schemaSource.getSchemaStatistic(schemaRegion)).thenReturn(7L);
+
Mockito.when(schemaSource.checkRegionDatabaseIncluded(schemaRegion)).thenReturn(true);
+
+ SchemaCountOperator<?> schemaCountOperator =
+ new SchemaCountOperator<>(
+ planNodeId, driverContext.getOperatorContexts().get(0),
schemaSource);
+
+ assertTrue(schemaCountOperator.hasNext());
+ TsBlock tsBlock = schemaCountOperator.next();
+ assertEquals(7, tsBlock.getColumn(0).getLong(0));
+ Mockito.verify(schemaSource).getSchemaStatistic(schemaRegion);
+ Mockito.verify(schemaSource,
Mockito.never()).getSchemaReader(schemaRegion);
+ } finally {
+ instanceNotificationExecutor.shutdown();
+ }
+ }
+
@Test
public void testLevelTimeSeriesCountOperator() {
ExecutorService instanceNotificationExecutor =
@@ -185,6 +261,43 @@ public class SchemaCountOperatorTest {
}
}
+ @Test
+ public void testLevelTimeSeriesCountOperatorSkipSchemaRegion() {
+ ExecutorService instanceNotificationExecutor =
+ IoTDBThreadPoolFactory.newFixedThreadPool(1,
"test-instance-notification");
+ try {
+ QueryId queryId = new QueryId("stub_query");
+ FragmentInstanceId instanceId =
+ new FragmentInstanceId(new PlanFragmentId(queryId, 0),
"stub-instance");
+ FragmentInstanceStateMachine stateMachine =
+ new FragmentInstanceStateMachine(instanceId,
instanceNotificationExecutor);
+ FragmentInstanceContext fragmentInstanceContext =
+ createFragmentInstanceContext(instanceId, stateMachine);
+ DriverContext driverContext = new DriverContext(fragmentInstanceContext,
0);
+ PlanNodeId planNodeId = queryId.genPlanNodeId();
+ OperatorContext operatorContext =
+ driverContext.addOperatorContext(
+ 1, planNodeId,
CountGroupByLevelScanOperator.class.getSimpleName());
+ ISchemaRegion schemaRegion = Mockito.mock(ISchemaRegion.class);
+ operatorContext.setDriverContext(
+ new SchemaDriverContext(fragmentInstanceContext, schemaRegion, 0));
+ ISchemaSource<ITimeSeriesSchemaInfo> schemaSource =
Mockito.mock(ISchemaSource.class);
+
Mockito.when(schemaSource.shouldSkipSchemaRegion(schemaRegion)).thenReturn(true);
+
+ CountGroupByLevelScanOperator<ITimeSeriesSchemaInfo>
timeSeriesCountOperator =
+ new CountGroupByLevelScanOperator<>(
+ planNodeId, driverContext.getOperatorContexts().get(0), 1,
schemaSource);
+
+ assertTrue(collectResult(timeSeriesCountOperator).isEmpty());
+ Mockito.verify(schemaSource,
Mockito.never()).getSchemaReader(schemaRegion);
+ } catch (Exception e) {
+ e.printStackTrace();
+ fail();
+ } finally {
+ instanceNotificationExecutor.shutdown();
+ }
+ }
+
private List<TsBlock> collectResult(CountGroupByLevelScanOperator<?>
operator) throws Exception {
List<TsBlock> tsBlocks = new ArrayList<>();
while (operator.hasNext()) {
diff --git
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/execution/operator/schema/source/TimeSeriesSchemaSourceTest.java
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/execution/operator/schema/source/TimeSeriesSchemaSourceTest.java
new file mode 100644
index 00000000000..3769018ed46
--- /dev/null
+++
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/execution/operator/schema/source/TimeSeriesSchemaSourceTest.java
@@ -0,0 +1,168 @@
+/*
+ * 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.execution.operator.schema.source;
+
+import org.apache.iotdb.commons.path.PartialPath;
+import org.apache.iotdb.commons.schema.SchemaConstant;
+import org.apache.iotdb.commons.schema.table.Audit;
+import org.apache.iotdb.db.schemaengine.rescon.ISchemaRegionStatistics;
+import org.apache.iotdb.db.schemaengine.schemaregion.ISchemaRegion;
+import
org.apache.iotdb.db.schemaengine.schemaregion.read.resp.info.ITimeSeriesSchemaInfo;
+
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import java.util.Collections;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class TimeSeriesSchemaSourceTest {
+
+ @Test
+ public void testCountSourceSkipsImplicitInternalDatabases() throws Exception
{
+ final ISchemaSource<ITimeSeriesSchemaInfo> countSource =
+ SchemaSourceFactory.getTimeSeriesSchemaCountSource(
+ new PartialPath("root.**"),
+ false,
+ null,
+ Collections.emptyMap(),
+ SchemaConstant.ALL_MATCH_SCOPE);
+
+ assertTrue(
+
countSource.shouldSkipSchemaRegion(mockSchemaRegion(SchemaConstant.SYSTEM_DATABASE)));
+
assertTrue(countSource.shouldSkipSchemaRegion(mockSchemaRegion(SchemaConstant.AUDIT_DATABASE)));
+ assertTrue(
+
countSource.shouldSkipSchemaRegion(mockSchemaRegion(Audit.TABLE_MODEL_AUDIT_DATABASE)));
+
assertFalse(countSource.shouldSkipSchemaRegion(mockSchemaRegion("root.sg")));
+ }
+
+ @Test
+ public void testCountSourceKeepsExplicitInternalDatabaseQueries() throws
Exception {
+ final ISchemaSource<ITimeSeriesSchemaInfo> systemCountSource =
+ SchemaSourceFactory.getTimeSeriesSchemaCountSource(
+ new PartialPath("root.__system.**"),
+ false,
+ null,
+ Collections.emptyMap(),
+ SchemaConstant.ALL_MATCH_SCOPE);
+ assertFalse(
+
systemCountSource.shouldSkipSchemaRegion(mockSchemaRegion(SchemaConstant.SYSTEM_DATABASE)));
+ assertTrue(
+
systemCountSource.shouldSkipSchemaRegion(mockSchemaRegion(SchemaConstant.AUDIT_DATABASE)));
+
+ final ISchemaSource<ITimeSeriesSchemaInfo> auditCountSource =
+ SchemaSourceFactory.getTimeSeriesSchemaCountSource(
+ new PartialPath("root.__audit.**"),
+ false,
+ null,
+ Collections.emptyMap(),
+ SchemaConstant.ALL_MATCH_SCOPE);
+ assertFalse(
+
auditCountSource.shouldSkipSchemaRegion(mockSchemaRegion(SchemaConstant.AUDIT_DATABASE)));
+ assertTrue(
+
auditCountSource.shouldSkipSchemaRegion(mockSchemaRegion(SchemaConstant.SYSTEM_DATABASE)));
+ }
+
+ @Test
+ public void testCountSourceSkipsWildcardSecondNodeForInternalDatabases()
throws Exception {
+ final ISchemaSource<ITimeSeriesSchemaInfo> countSource =
+ SchemaSourceFactory.getTimeSeriesSchemaCountSource(
+ new PartialPath("root.*.**"),
+ false,
+ null,
+ Collections.emptyMap(),
+ SchemaConstant.ALL_MATCH_SCOPE);
+
+ assertTrue(
+
countSource.shouldSkipSchemaRegion(mockSchemaRegion(SchemaConstant.SYSTEM_DATABASE)));
+
assertTrue(countSource.shouldSkipSchemaRegion(mockSchemaRegion(SchemaConstant.AUDIT_DATABASE)));
+
assertFalse(countSource.shouldSkipSchemaRegion(mockSchemaRegion("root.sg")));
+ }
+
+ @Test
+ public void testCountSourceKeepsExactInternalDatabaseQueries() throws
Exception {
+ final ISchemaSource<ITimeSeriesSchemaInfo> systemCountSource =
+ SchemaSourceFactory.getTimeSeriesSchemaCountSource(
+ new PartialPath("root.__system"),
+ false,
+ null,
+ Collections.emptyMap(),
+ SchemaConstant.ALL_MATCH_SCOPE);
+ assertFalse(
+
systemCountSource.shouldSkipSchemaRegion(mockSchemaRegion(SchemaConstant.SYSTEM_DATABASE)));
+
+ final ISchemaSource<ITimeSeriesSchemaInfo> auditCountSource =
+ SchemaSourceFactory.getTimeSeriesSchemaCountSource(
+ new PartialPath("root.__audit"),
+ false,
+ null,
+ Collections.emptyMap(),
+ SchemaConstant.ALL_MATCH_SCOPE);
+ assertFalse(
+
auditCountSource.shouldSkipSchemaRegion(mockSchemaRegion(SchemaConstant.AUDIT_DATABASE)));
+ }
+
+ @Test
+ public void testShowSourceDoesNotSkipInternalDatabases() throws Exception {
+ final ISchemaSource<ITimeSeriesSchemaInfo> showSource =
+ SchemaSourceFactory.getTimeSeriesSchemaScanSource(
+ new PartialPath("root.**"),
+ false,
+ 0,
+ 0,
+ null,
+ Collections.emptyMap(),
+ SchemaConstant.ALL_MATCH_SCOPE,
+ null);
+
+ assertFalse(
+
showSource.shouldSkipSchemaRegion(mockSchemaRegion(SchemaConstant.SYSTEM_DATABASE)));
+
assertFalse(showSource.shouldSkipSchemaRegion(mockSchemaRegion(SchemaConstant.AUDIT_DATABASE)));
+ }
+
+ @Test
+ public void testCountStatisticIncludesView() throws Exception {
+ final ISchemaSource<ITimeSeriesSchemaInfo> countSource =
+ SchemaSourceFactory.getTimeSeriesSchemaCountSource(
+ new PartialPath("root.sg.**"),
+ false,
+ null,
+ Collections.emptyMap(),
+ SchemaConstant.ALL_MATCH_SCOPE);
+ final ISchemaRegion schemaRegion = mockSchemaRegion("root.sg");
+ final ISchemaRegionStatistics schemaRegionStatistics =
+ Mockito.mock(ISchemaRegionStatistics.class);
+
+
Mockito.when(schemaRegion.getSchemaRegionStatistics()).thenReturn(schemaRegionStatistics);
+ Mockito.when(schemaRegionStatistics.getSeriesNumber(true)).thenReturn(5L);
+
+ assertEquals(5L, countSource.getSchemaStatistic(schemaRegion));
+ Mockito.verify(schemaRegionStatistics).getSeriesNumber(true);
+ Mockito.verify(schemaRegionStatistics,
Mockito.never()).getSeriesNumber(false);
+ }
+
+ private ISchemaRegion mockSchemaRegion(final String database) {
+ final ISchemaRegion schemaRegion = Mockito.mock(ISchemaRegion.class);
+ Mockito.when(schemaRegion.getDatabaseFullPath()).thenReturn(database);
+ return schemaRegion;
+ }
+}