This is an automated email from the ASF dual-hosted git repository.
qiaojialin 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 dd5071df75 New schema tree traverse implementation (#5686)
dd5071df75 is described below
commit dd5071df755264aed9a337994b2e77985bad1df6
Author: Marcos_Zyk <[email protected]>
AuthorDate: Wed Apr 27 16:00:10 2022 +0800
New schema tree traverse implementation (#5686)
---
.../db/metadata/tree/AbstractTreeVisitor.java | 376 +++++++++++++++++++++
.../tree/AbstractTreeVisitorWithLimitOffset.java | 106 ++++++
.../tree/ITreeNode.java} | 28 +-
.../db/mpp/common/schematree/DeviceSchemaInfo.java | 40 ++-
.../iotdb/db/mpp/common/schematree/SchemaTree.java | 33 +-
.../mpp/common/schematree/SchemaTreeVisitor.java | 237 -------------
.../schematree/{ => node}/SchemaEntityNode.java | 2 +-
.../schematree/{ => node}/SchemaInternalNode.java | 2 +-
.../{ => node}/SchemaMeasurementNode.java | 2 +-
.../common/schematree/{ => node}/SchemaNode.java | 6 +-
.../visitor/SchemaTreeDeviceVisitor.java | 61 ++++
.../visitor/SchemaTreeMeasurementVisitor.java | 80 +++++
.../schematree/visitor/SchemaTreeVisitor.java | 60 ++++
.../db/mpp/sql/analyze/FakeSchemaFetcherImpl.java | 8 +-
.../db/mpp/common/schematree/SchemaTreeTest.java | 167 +++++++--
.../operator/schema/SchemaFetchOperatorTest.java | 2 +-
16 files changed, 894 insertions(+), 316 deletions(-)
diff --git
a/server/src/main/java/org/apache/iotdb/db/metadata/tree/AbstractTreeVisitor.java
b/server/src/main/java/org/apache/iotdb/db/metadata/tree/AbstractTreeVisitor.java
new file mode 100644
index 0000000000..658a6ebfc3
--- /dev/null
+++
b/server/src/main/java/org/apache/iotdb/db/metadata/tree/AbstractTreeVisitor.java
@@ -0,0 +1,376 @@
+/*
+ * 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.metadata.tree;
+
+import org.apache.iotdb.db.metadata.path.PartialPath;
+
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Deque;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.regex.Pattern;
+
+import static
org.apache.iotdb.commons.conf.IoTDBConstant.MULTI_LEVEL_PATH_WILDCARD;
+import static
org.apache.iotdb.commons.conf.IoTDBConstant.ONE_LEVEL_PATH_WILDCARD;
+
+/**
+ * This class defines a dfs-based algorithm of tree-traversing with path
pattern match, and support
+ * iterating each element of the result.
+ *
+ * <p>This class takes three basis parameters as input:
+ *
+ * <ol>
+ * <li>N root: the root node of the tree to be traversed.
+ * <li>PartialPath patPattern: the pattern of path that the path of target
element matches
+ * <li>boolean isPrefixMatch: whether the pathPattern is used for matching
the prefix; if so, all
+ * elements with path starting with the matched prefix will be collected
+ * </ol>
+ *
+ * <p>If any tree wants to integrate and use this class. The following steps
must be attained:
+ *
+ * <ol>
+ * <li>The node of the tree must implement ITreeNode interface and the
generic N should be defined
+ * as the node class.
+ * <li>The result type R should be defined.
+ * <li>Implement the abstract methods, and for the concrete requirements,
please refer to the
+ * javadoc of specific method.
+ * </ol>
+ *
+ * @param <N> The node consisting the tree.
+ * @param <R> The result extracted from the tree.
+ */
+public abstract class AbstractTreeVisitor<N extends ITreeNode, R> implements
Iterator<R> {
+
+ protected final N root;
+ protected final String[] nodes;
+ protected final boolean isPrefixMatch;
+
+ protected final Deque<VisitorStackEntry<N>> visitorStack = new
ArrayDeque<>();
+ protected final Deque<N> ancestorStack = new ArrayDeque<>();
+
+ protected N nextMatchedNode;
+
+ protected AbstractTreeVisitor(N root, PartialPath pathPattern, boolean
isPrefixMatch) {
+ this.root = root;
+ this.nodes = optimizePathPattern(pathPattern);
+ this.isPrefixMatch = isPrefixMatch;
+
+ visitorStack.push(
+ new VisitorStackEntry<>(Collections.singletonList(root).iterator(), 0,
0, -1));
+ }
+
+ /**
+ * Optimize the given path pattern. Currently, the node name used for one
level match will be
+ * transformed into a regex.
+ */
+ private String[] optimizePathPattern(PartialPath pathPattern) {
+ String[] rawNodes = pathPattern.getNodes();
+ List<String> optimizedNodes = new ArrayList<>(rawNodes.length);
+ for (String rawNode : rawNodes) {
+ if (rawNode.equals(MULTI_LEVEL_PATH_WILDCARD)) {
+ optimizedNodes.add(MULTI_LEVEL_PATH_WILDCARD);
+ } else if (rawNode.contains(ONE_LEVEL_PATH_WILDCARD)) {
+ optimizedNodes.add(rawNode.replace("*", ".*"));
+ } else {
+ optimizedNodes.add(rawNode);
+ }
+ }
+
+ return optimizedNodes.toArray(new String[0]);
+ }
+
+ @Override
+ public boolean hasNext() {
+ if (nextMatchedNode == null) {
+ getNext();
+ }
+ return nextMatchedNode != null;
+ }
+
+ @Override
+ public R next() {
+ if (!hasNext()) {
+ throw new NoSuchElementException();
+ }
+ R result = generateResult();
+ nextMatchedNode = null;
+ return result;
+ }
+
+ /**
+ * Basically, the algorithm traverse the tree with dfs strategy. When it
comes to push children
+ * into stack, the path pattern will be used to filter the children.
+ *
+ * <p>When there's MULTI_LEVEL_WILDCARD in given path pattern. There are the
following notices:
+ *
+ * <ol>
+ * <li>When it comes to push children into stack and there's
MULTI_LEVEL_WILDCARD before the
+ * current patternIndex, all the children will be pushed.
+ * <li>When a node cannot match the target node name in the patternIndex
place and there's
+ * MULTI_LEVEL_WILDCARD before the current patternIndex, the node
names between the current
+ * patternIndex and lastMultiLevelWildcardIndex will be checked until
the partial path end
+ * with current node can match one. The children will be pushed with
the matched index + 1.
+ * </ol>
+ *
+ * <p>Each node and fullPath of the tree will be traversed at most once.
+ */
+ protected void getNext() {
+ nextMatchedNode = null;
+ VisitorStackEntry<N> stackEntry;
+ int patternIndex;
+ N node;
+ Iterator<N> iterator;
+ int lastMultiLevelWildcardIndex;
+ while (!visitorStack.isEmpty()) {
+ stackEntry = visitorStack.peek();
+ iterator = stackEntry.iterator;
+
+ if (!iterator.hasNext()) {
+ popStack();
+ continue;
+ }
+
+ node = iterator.next();
+ patternIndex = stackEntry.patternIndex;
+ lastMultiLevelWildcardIndex = stackEntry.lastMultiLevelWildcardIndex;
+
+ // only prefixMatch
+ if (patternIndex == nodes.length) {
+ if (processFullMatchedNode(node)) {
+ return;
+ }
+
+ if (!isLeafNode(node)) {
+ pushAllChildren(node, patternIndex, lastMultiLevelWildcardIndex);
+ }
+
+ if (nextMatchedNode != null) {
+ return;
+ }
+
+ continue;
+ }
+
+ if (checkIsMatch(patternIndex, node)) {
+ if (patternIndex == nodes.length - 1) {
+ if (processFullMatchedNode(node)) {
+ return;
+ }
+
+ if (!isLeafNode(node)) {
+ if (isPrefixMatch) {
+ pushAllChildren(node, patternIndex + 1,
lastMultiLevelWildcardIndex);
+ } else if (nodes[patternIndex].equals(MULTI_LEVEL_PATH_WILDCARD)) {
+ pushAllChildren(node, patternIndex, patternIndex);
+ }
+ }
+
+ if (nextMatchedNode != null) {
+ return;
+ }
+
+ continue;
+ }
+
+ if (processInternalMatchedNode(node)) {
+ return;
+ }
+
+ if (!isLeafNode(node)) {
+ if (nodes[patternIndex + 1].equals(MULTI_LEVEL_PATH_WILDCARD)) {
+ pushAllChildren(node, patternIndex + 1, patternIndex + 1);
+ } else {
+ if (lastMultiLevelWildcardIndex > -1) {
+ pushAllChildren(node, patternIndex + 1,
lastMultiLevelWildcardIndex);
+ } else if (nodes[patternIndex +
1].contains(ONE_LEVEL_PATH_WILDCARD)) {
+ pushAllChildren(node, patternIndex + 1,
lastMultiLevelWildcardIndex);
+ } else {
+ pushSingleChild(
+ node, nodes[patternIndex + 1], patternIndex + 1,
lastMultiLevelWildcardIndex);
+ }
+ }
+ }
+
+ if (nextMatchedNode != null) {
+ return;
+ }
+
+ } else {
+ if (lastMultiLevelWildcardIndex == -1) {
+ continue;
+ }
+
+ int lastMatchIndex = lastMultiLevelWildcardIndex;
+ for (int i = patternIndex - 1; i > lastMultiLevelWildcardIndex; i--) {
+ if (!checkIsMatch(i, node)) {
+ continue;
+ }
+
+ Iterator<N> ancestors = ancestorStack.iterator();
+ boolean allMatch = true;
+ for (int j = i - 1; j > lastMultiLevelWildcardIndex; j--) {
+ if (!checkIsMatch(j, ancestors.next())) {
+ allMatch = false;
+ break;
+ }
+ }
+
+ if (allMatch) {
+ lastMatchIndex = i;
+ break;
+ }
+ }
+
+ if (processInternalMatchedNode(node)) {
+ return;
+ }
+
+ if (!isLeafNode(node)) {
+ pushAllChildren(node, lastMatchIndex + 1,
lastMultiLevelWildcardIndex);
+ }
+
+ if (nextMatchedNode != null) {
+ return;
+ }
+ }
+ }
+ }
+
+ public void reset() {
+ visitorStack.clear();
+ ancestorStack.clear();
+ nextMatchedNode = null;
+ visitorStack.push(
+ new VisitorStackEntry<>(Collections.singletonList(root).iterator(), 0,
0, -1));
+ }
+
+ private void popStack() {
+ visitorStack.pop();
+ // The ancestor pop operation with level check supports the children of
one node pushed by
+ // batch.
+ if (!visitorStack.isEmpty() && visitorStack.peek().level <
ancestorStack.size()) {
+ ancestorStack.pop();
+ }
+ }
+
+ protected void pushSingleChild(
+ N parent, String childName, int patternIndex, int
lastMultiLevelWildcardIndex) {
+ N child = getChild(parent, childName);
+ if (child != null) {
+ ancestorStack.push(parent);
+ visitorStack.push(
+ new VisitorStackEntry<>(
+ Collections.singletonList(child).iterator(),
+ patternIndex,
+ ancestorStack.size(),
+ lastMultiLevelWildcardIndex));
+ }
+ }
+
+ protected void pushAllChildren(N parent, int patternIndex, int
lastMultiLevelWildcardIndex) {
+ ancestorStack.push(parent);
+ visitorStack.push(
+ new VisitorStackEntry<>(
+ getChildrenIterator(parent),
+ patternIndex,
+ ancestorStack.size(),
+ lastMultiLevelWildcardIndex));
+ }
+
+ protected boolean checkIsMatch(int patternIndex, N node) {
+ if (nodes[patternIndex].equals(MULTI_LEVEL_PATH_WILDCARD)) {
+ return true;
+ } else if (nodes[patternIndex].contains(ONE_LEVEL_PATH_WILDCARD)) {
+ return checkOneLevelWildcardMatch(nodes[patternIndex], node);
+ } else {
+ return checkNameMatch(nodes[patternIndex], node);
+ }
+ }
+
+ protected boolean checkOneLevelWildcardMatch(String regex, N node) {
+ return Pattern.matches(regex, node.getName());
+ }
+
+ protected boolean checkNameMatch(String targetName, N node) {
+ return targetName.equals(node.getName());
+ }
+
+ protected String[] generateFullPathNodes(N node) {
+ List<String> nodeNames = new ArrayList<>();
+ Iterator<N> iterator = ancestorStack.descendingIterator();
+ while (iterator.hasNext()) {
+ nodeNames.add(iterator.next().getName());
+ }
+ nodeNames.add(node.getName());
+ return nodeNames.toArray(new String[0]);
+ }
+
+ // Check whether the given node is a leaf node of this tree.
+ protected abstract boolean isLeafNode(N node);
+
+ // Get a child with the given childName.
+ protected abstract N getChild(N parent, String childName);
+
+ // Get a iterator of all children.
+ protected abstract Iterator<N> getChildrenIterator(N parent);
+
+ /**
+ * Internal-match means the node matches an internal node name of the given
path pattern. root.sg
+ * internal match root.sg.**(pattern). This method should be implemented
according to concrete
+ * tasks.
+ *
+ * <p>If return true, the traversing process won't check the subtree with
the given node as root,
+ * and the result will be return immediately. If return false, the
traversing process will keep
+ * traversing the subtree.
+ */
+ protected abstract boolean processInternalMatchedNode(N node);
+
+ /**
+ * Full-match means the node matches the last node name of the given path
pattern. root.sg.d full
+ * match root.sg.**(pattern) This method should be implemented according to
concrete tasks.
+ *
+ * <p>If return true, the traversing process won't check the subtree with
the given node as root,
+ * and the result will be return immediately. f return false, the traversing
process will keep
+ * traversing the subtree.
+ */
+ protected abstract boolean processFullMatchedNode(N node);
+
+ /** The method used for generating the result based on the matched node. */
+ protected abstract R generateResult();
+
+ protected static class VisitorStackEntry<N> {
+
+ private final Iterator<N> iterator;
+ private final int patternIndex;
+ private final int level;
+ private final int lastMultiLevelWildcardIndex;
+
+ VisitorStackEntry(
+ Iterator<N> iterator, int patternIndex, int level, int
lastMultiLevelWildcardIndex) {
+ this.iterator = iterator;
+ this.patternIndex = patternIndex;
+ this.level = level;
+ this.lastMultiLevelWildcardIndex = lastMultiLevelWildcardIndex;
+ }
+ }
+}
diff --git
a/server/src/main/java/org/apache/iotdb/db/metadata/tree/AbstractTreeVisitorWithLimitOffset.java
b/server/src/main/java/org/apache/iotdb/db/metadata/tree/AbstractTreeVisitorWithLimitOffset.java
new file mode 100644
index 0000000000..d9e3b8336c
--- /dev/null
+++
b/server/src/main/java/org/apache/iotdb/db/metadata/tree/AbstractTreeVisitorWithLimitOffset.java
@@ -0,0 +1,106 @@
+/*
+ * 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.metadata.tree;
+
+import org.apache.iotdb.db.metadata.path.PartialPath;
+
+/**
+ * This class defines a dfs-based traversing algorithm with limit and offset
based on
+ * AbstractTreeVisitor.
+ *
+ * <p>This class takes two extra parameters as input:
+ *
+ * <ol>
+ * <li>int limit: the max count of the results collected by one traversing
process.
+ * <li>int offset: the index of first matched node to be collected.
+ * </ol>
+ */
+public abstract class AbstractTreeVisitorWithLimitOffset<N extends ITreeNode,
R>
+ extends AbstractTreeVisitor<N, R> {
+
+ protected final int limit;
+ protected final int offset;
+ protected final boolean hasLimit;
+
+ protected int count = 0;
+ protected int curOffset = -1;
+
+ protected AbstractTreeVisitorWithLimitOffset(
+ N root, PartialPath pathPattern, int limit, int offset, boolean
isPrefixMatch) {
+ super(root, pathPattern, isPrefixMatch);
+ this.limit = limit;
+ this.offset = offset;
+ hasLimit = limit != 0;
+ }
+
+ @Override
+ public boolean hasNext() {
+ if (hasLimit) {
+ return count < limit && super.hasNext();
+ }
+
+ return super.hasNext();
+ }
+
+ @Override
+ protected void getNext() {
+ if (hasLimit) {
+ if (curOffset < offset) {
+ while (curOffset < offset) {
+ super.getNext();
+ curOffset += 1;
+ if (nextMatchedNode == null) {
+ return;
+ }
+ }
+ } else {
+ super.getNext();
+ curOffset += 1;
+ }
+ } else {
+ super.getNext();
+ }
+ }
+
+ @Override
+ public R next() {
+ R result = super.next();
+ if (hasLimit) {
+ count++;
+ }
+ return result;
+ }
+
+ @Override
+ public void reset() {
+ super.reset();
+ count = 0;
+ curOffset = -1;
+ }
+
+ public int getNextOffset() {
+ return curOffset + 1;
+ }
+
+ @Override
+ protected boolean processInternalMatchedNode(N node) {
+ return false;
+ }
+}
diff --git
a/server/src/main/java/org/apache/iotdb/db/mpp/common/schematree/DeviceSchemaInfo.java
b/server/src/main/java/org/apache/iotdb/db/metadata/tree/ITreeNode.java
similarity index 51%
copy from
server/src/main/java/org/apache/iotdb/db/mpp/common/schematree/DeviceSchemaInfo.java
copy to server/src/main/java/org/apache/iotdb/db/metadata/tree/ITreeNode.java
index 8da6b056d1..f7300d282d 100644
---
a/server/src/main/java/org/apache/iotdb/db/mpp/common/schematree/DeviceSchemaInfo.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/tree/ITreeNode.java
@@ -17,31 +17,9 @@
* under the License.
*/
-package org.apache.iotdb.db.mpp.common.schematree;
+package org.apache.iotdb.db.metadata.tree;
-import org.apache.iotdb.db.metadata.path.PartialPath;
-import org.apache.iotdb.tsfile.write.schema.MeasurementSchema;
+public interface ITreeNode {
-import java.util.List;
-
-public class DeviceSchemaInfo {
-
- private PartialPath devicePath;
- private boolean isAligned;
- private List<MeasurementSchema> measurementSchemaList;
-
- public DeviceSchemaInfo(
- PartialPath devicePath, boolean isAligned, List<MeasurementSchema>
measurementSchemaList) {
- this.devicePath = devicePath;
- this.isAligned = isAligned;
- this.measurementSchemaList = measurementSchemaList;
- }
-
- public List<MeasurementSchema> getMeasurementSchemaList() {
- return measurementSchemaList;
- }
-
- public boolean isAligned() {
- return isAligned;
- }
+ String getName();
}
diff --git
a/server/src/main/java/org/apache/iotdb/db/mpp/common/schematree/DeviceSchemaInfo.java
b/server/src/main/java/org/apache/iotdb/db/mpp/common/schematree/DeviceSchemaInfo.java
index 8da6b056d1..9e1eecfc91 100644
---
a/server/src/main/java/org/apache/iotdb/db/mpp/common/schematree/DeviceSchemaInfo.java
+++
b/server/src/main/java/org/apache/iotdb/db/mpp/common/schematree/DeviceSchemaInfo.java
@@ -19,29 +19,55 @@
package org.apache.iotdb.db.mpp.common.schematree;
+import org.apache.iotdb.db.metadata.path.MeasurementPath;
import org.apache.iotdb.db.metadata.path.PartialPath;
+import org.apache.iotdb.db.mpp.common.schematree.node.SchemaMeasurementNode;
import org.apache.iotdb.tsfile.write.schema.MeasurementSchema;
import java.util.List;
+import java.util.stream.Collectors;
public class DeviceSchemaInfo {
- private PartialPath devicePath;
- private boolean isAligned;
- private List<MeasurementSchema> measurementSchemaList;
+ private final PartialPath devicePath;
+ private final boolean isAligned;
+ private final List<SchemaMeasurementNode> measurementNodeList;
public DeviceSchemaInfo(
- PartialPath devicePath, boolean isAligned, List<MeasurementSchema>
measurementSchemaList) {
+ PartialPath devicePath, boolean isAligned, List<SchemaMeasurementNode>
measurementNodeList) {
this.devicePath = devicePath;
this.isAligned = isAligned;
- this.measurementSchemaList = measurementSchemaList;
+ this.measurementNodeList = measurementNodeList;
}
- public List<MeasurementSchema> getMeasurementSchemaList() {
- return measurementSchemaList;
+ public PartialPath getDevicePath() {
+ return devicePath;
}
public boolean isAligned() {
return isAligned;
}
+
+ public List<MeasurementSchema> getMeasurementSchemaList() {
+ return measurementNodeList.stream()
+ .map(SchemaMeasurementNode::getSchema)
+ .collect(Collectors.toList());
+ }
+
+ public List<MeasurementPath> getMeasurements() {
+ return measurementNodeList.stream()
+ .map(
+ measurementNode -> {
+ MeasurementPath measurementPath =
+ new MeasurementPath(
+ devicePath.concatNode(measurementNode.getName()),
+ measurementNode.getSchema());
+ measurementPath.setUnderAlignedEntity(isAligned);
+ if (measurementNode.getAlias() != null) {
+
measurementPath.setMeasurementAlias(measurementNode.getAlias());
+ }
+ return measurementPath;
+ })
+ .collect(Collectors.toList());
+ }
}
diff --git
a/server/src/main/java/org/apache/iotdb/db/mpp/common/schematree/SchemaTree.java
b/server/src/main/java/org/apache/iotdb/db/mpp/common/schematree/SchemaTree.java
index d8a5586362..2bf2d8e72a 100644
---
a/server/src/main/java/org/apache/iotdb/db/mpp/common/schematree/SchemaTree.java
+++
b/server/src/main/java/org/apache/iotdb/db/mpp/common/schematree/SchemaTree.java
@@ -21,9 +21,14 @@ package org.apache.iotdb.db.mpp.common.schematree;
import org.apache.iotdb.commons.utils.TestOnly;
import org.apache.iotdb.db.exception.metadata.MetadataException;
-import
org.apache.iotdb.db.exception.metadata.template.NoTemplateOnMNodeException;
import org.apache.iotdb.db.metadata.path.MeasurementPath;
import org.apache.iotdb.db.metadata.path.PartialPath;
+import org.apache.iotdb.db.mpp.common.schematree.node.SchemaEntityNode;
+import org.apache.iotdb.db.mpp.common.schematree.node.SchemaInternalNode;
+import org.apache.iotdb.db.mpp.common.schematree.node.SchemaMeasurementNode;
+import org.apache.iotdb.db.mpp.common.schematree.node.SchemaNode;
+import
org.apache.iotdb.db.mpp.common.schematree.visitor.SchemaTreeDeviceVisitor;
+import
org.apache.iotdb.db.mpp.common.schematree.visitor.SchemaTreeMeasurementVisitor;
import org.apache.iotdb.tsfile.utils.Pair;
import org.apache.iotdb.tsfile.utils.ReadWriteIOUtils;
import org.apache.iotdb.tsfile.write.schema.MeasurementSchema;
@@ -33,11 +38,10 @@ import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.List;
-import java.util.Set;
import static org.apache.iotdb.commons.conf.IoTDBConstant.PATH_ROOT;
-import static
org.apache.iotdb.db.mpp.common.schematree.SchemaNode.SCHEMA_ENTITY_NODE;
-import static
org.apache.iotdb.db.mpp.common.schematree.SchemaNode.SCHEMA_MEASUREMENT_NODE;
+import static
org.apache.iotdb.db.mpp.common.schematree.node.SchemaNode.SCHEMA_ENTITY_NODE;
+import static
org.apache.iotdb.db.mpp.common.schematree.node.SchemaNode.SCHEMA_MEASUREMENT_NODE;
public class SchemaTree {
@@ -62,21 +66,21 @@ public class SchemaTree {
*/
public Pair<List<MeasurementPath>, Integer> searchMeasurementPaths(
PartialPath pathPattern, int slimit, int soffset, boolean isPrefixMatch)
{
- SchemaTreeVisitor visitor =
- new SchemaTreeVisitor(root, pathPattern, slimit, soffset,
isPrefixMatch);
+ SchemaTreeMeasurementVisitor visitor =
+ new SchemaTreeMeasurementVisitor(root, pathPattern, slimit, soffset,
isPrefixMatch);
return new Pair<>(visitor.getAllResult(), visitor.getNextOffset());
}
/**
- * Get all device paths matching the path pattern.
+ * Get all device matching the path pattern.
*
* @param pathPattern the pattern of the target devices.
- * @return A HashSet instance which stores devices paths matching the given
path pattern.
+ * @return A HashSet instance which stores info of the devices matching the
given path pattern.
*/
- public Set<PartialPath> getMatchedDevices(PartialPath pathPattern, boolean
isPrefixMatch)
+ public List<DeviceSchemaInfo> getMatchedDevices(PartialPath pathPattern,
boolean isPrefixMatch)
throws MetadataException {
- // TODO: @zyk
- throw new NoTemplateOnMNodeException("");
+ SchemaTreeDeviceVisitor visitor = new SchemaTreeDeviceVisitor(root,
pathPattern, isPrefixMatch);
+ return visitor.getAllResult();
}
public DeviceSchemaInfo searchDeviceSchemaInfo(
@@ -88,13 +92,12 @@ public class SchemaTree {
cur = cur.getChild(nodes[i]);
}
- List<MeasurementSchema> measurementSchemaList = new ArrayList<>();
+ List<SchemaMeasurementNode> measurementNodeList = new ArrayList<>();
for (String measurement : measurements) {
-
measurementSchemaList.add(cur.getChild(measurement).getAsMeasurementNode().getSchema());
+
measurementNodeList.add(cur.getChild(measurement).getAsMeasurementNode());
}
- return new DeviceSchemaInfo(
- devicePath, cur.getAsEntityNode().isAligned(), measurementSchemaList);
+ return new DeviceSchemaInfo(devicePath, cur.getAsEntityNode().isAligned(),
measurementNodeList);
}
public void appendMeasurementPaths(List<MeasurementPath>
measurementPathList) {
diff --git
a/server/src/main/java/org/apache/iotdb/db/mpp/common/schematree/SchemaTreeVisitor.java
b/server/src/main/java/org/apache/iotdb/db/mpp/common/schematree/SchemaTreeVisitor.java
deleted file mode 100644
index b186881064..0000000000
---
a/server/src/main/java/org/apache/iotdb/db/mpp/common/schematree/SchemaTreeVisitor.java
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- * 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.mpp.common.schematree;
-
-import org.apache.iotdb.db.metadata.path.MeasurementPath;
-import org.apache.iotdb.db.metadata.path.PartialPath;
-
-import java.util.ArrayDeque;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Deque;
-import java.util.Iterator;
-import java.util.List;
-import java.util.NoSuchElementException;
-import java.util.regex.Pattern;
-
-import static
org.apache.iotdb.commons.conf.IoTDBConstant.MULTI_LEVEL_PATH_WILDCARD;
-import static
org.apache.iotdb.commons.conf.IoTDBConstant.ONE_LEVEL_PATH_WILDCARD;
-
-public class SchemaTreeVisitor implements Iterator<MeasurementPath> {
-
- private final SchemaNode root;
- private final String[] nodes;
- private final boolean isPrefixMatch;
-
- private final int limit;
- private final int offset;
- private final boolean hasLimit;
-
- private int count = 0;
- private int curOffset = -1;
-
- private final Deque<Integer> indexStack = new ArrayDeque<>();
- private final Deque<Iterator<SchemaNode>> stack = new ArrayDeque<>();
- private final Deque<SchemaNode> context = new ArrayDeque<>();
-
- private SchemaMeasurementNode nextMatchedNode;
-
- public SchemaTreeVisitor(
- SchemaNode root, PartialPath pathPattern, int slimit, int soffset,
boolean isPrefixMatch) {
- this.root = root;
- nodes = pathPattern.getNodes();
- this.isPrefixMatch = isPrefixMatch;
-
- limit = slimit;
- offset = soffset;
- hasLimit = slimit != 0;
-
- indexStack.push(0);
- stack.push(Collections.singletonList(root).iterator());
- }
-
- @Override
- public boolean hasNext() {
- if (nextMatchedNode == null) {
- getNext();
- }
- return nextMatchedNode != null;
- }
-
- @Override
- public MeasurementPath next() {
- if (!hasNext()) {
- throw new NoSuchElementException();
- }
- MeasurementPath result = generateMeasurementPath();
- nextMatchedNode = null;
- return result;
- }
-
- public List<MeasurementPath> getAllResult() {
- List<MeasurementPath> result = new ArrayList<>();
- while (hasNext()) {
- result.add(next());
- }
- return result;
- }
-
- public int getNextOffset() {
- return curOffset + 1;
- }
-
- public void resetStatus() {
- count = 0;
- curOffset = -1;
- context.clear();
- indexStack.clear();
- indexStack.push(0);
- stack.clear();
- stack.push(Collections.singletonList(root).iterator());
- }
-
- private void getNext() {
- if (hasLimit && count == limit) {
- return;
- }
-
- int patternIndex;
- SchemaNode node;
- Iterator<SchemaNode> iterator;
- while (!stack.isEmpty()) {
- iterator = stack.peek();
-
- if (!iterator.hasNext()) {
- popStack();
- continue;
- }
-
- node = iterator.next();
- patternIndex = indexStack.peek();
- if (patternIndex >= nodes.length - 1) {
- if (node.isMeasurement()) {
- if (hasLimit) {
- curOffset += 1;
- if (curOffset < offset) {
- continue;
- }
- count++;
- }
-
- nextMatchedNode = node.getAsMeasurementNode();
- return;
- }
-
- if (nodes[nodes.length - 1].equals(MULTI_LEVEL_PATH_WILDCARD) ||
isPrefixMatch) {
- pushAllChildren(node, patternIndex);
- }
-
- continue;
- }
-
- if (nodes[patternIndex].equals(ONE_LEVEL_PATH_WILDCARD)) {
- String regex = nodes[patternIndex].replace("*", ".*");
- while (!checkOneLevelWildcardMatch(regex, node) && iterator.hasNext())
{
- node = iterator.next();
- }
- if (!checkOneLevelWildcardMatch(regex, node)) {
- popStack();
- continue;
- }
- }
-
- if (node.isMeasurement()) {
- continue;
- }
-
- if (nodes[patternIndex + 1].contains(ONE_LEVEL_PATH_WILDCARD)) {
- pushAllChildren(node, patternIndex + 1);
- } else {
- pushSingleChild(node, nodes[patternIndex + 1], patternIndex + 1);
- }
- }
- }
-
- private void popStack() {
- stack.pop();
- int patternIndex = indexStack.pop();
- if (patternIndex == 0) {
- return;
- }
- SchemaNode node = context.pop();
-
- if (indexStack.isEmpty()) {
- return;
- }
-
- int parentIndex = indexStack.peek();
- if (patternIndex != parentIndex
- && parentIndex < nodes.length - 1
- && nodes[parentIndex].equals(MULTI_LEVEL_PATH_WILDCARD)) {
- pushAllChildren(node, parentIndex);
- }
- }
-
- private void pushAllChildren(SchemaNode node, int patternIndex) {
- stack.push(node.getChildrenIterator());
- context.push(node);
- indexStack.push(patternIndex);
- }
-
- private void pushSingleChild(SchemaNode node, String childName, int
patternIndex) {
- SchemaNode child = node.getChild(childName);
- if (child != null) {
- stack.push(Collections.singletonList(child).iterator());
- } else {
- stack.push(Collections.emptyIterator());
- }
- context.push(node);
- indexStack.push(patternIndex);
- }
-
- private boolean checkOneLevelWildcardMatch(String regex, SchemaNode node) {
- if (!node.isMeasurement()) {
- return Pattern.matches(regex, node.getName());
- }
-
- SchemaMeasurementNode measurementNode = node.getAsMeasurementNode();
-
- return Pattern.matches(regex, measurementNode.getName())
- || Pattern.matches(regex, measurementNode.getAlias());
- }
-
- private MeasurementPath generateMeasurementPath() {
- List<String> nodeNames = new ArrayList<>();
- Iterator<SchemaNode> iterator = context.descendingIterator();
- while (iterator.hasNext()) {
- nodeNames.add(iterator.next().getName());
- }
- nodeNames.add(nextMatchedNode.getName());
- MeasurementPath result =
- new MeasurementPath(nodeNames.toArray(new String[0]),
nextMatchedNode.getSchema());
- result.setUnderAlignedEntity(context.peek().getAsEntityNode().isAligned());
- String alias = nextMatchedNode.getAlias();
- if (nodes[nodes.length - 1].equals(alias)) {
- result.setMeasurementAlias(alias);
- }
-
- return result;
- }
-}
diff --git
a/server/src/main/java/org/apache/iotdb/db/mpp/common/schematree/SchemaEntityNode.java
b/server/src/main/java/org/apache/iotdb/db/mpp/common/schematree/node/SchemaEntityNode.java
similarity index 98%
rename from
server/src/main/java/org/apache/iotdb/db/mpp/common/schematree/SchemaEntityNode.java
rename to
server/src/main/java/org/apache/iotdb/db/mpp/common/schematree/node/SchemaEntityNode.java
index d477c16194..a1e1aff60e 100644
---
a/server/src/main/java/org/apache/iotdb/db/mpp/common/schematree/SchemaEntityNode.java
+++
b/server/src/main/java/org/apache/iotdb/db/mpp/common/schematree/node/SchemaEntityNode.java
@@ -17,7 +17,7 @@
* under the License.
*/
-package org.apache.iotdb.db.mpp.common.schematree;
+package org.apache.iotdb.db.mpp.common.schematree.node;
import org.apache.iotdb.tsfile.utils.ReadWriteIOUtils;
diff --git
a/server/src/main/java/org/apache/iotdb/db/mpp/common/schematree/SchemaInternalNode.java
b/server/src/main/java/org/apache/iotdb/db/mpp/common/schematree/node/SchemaInternalNode.java
similarity index 97%
rename from
server/src/main/java/org/apache/iotdb/db/mpp/common/schematree/SchemaInternalNode.java
rename to
server/src/main/java/org/apache/iotdb/db/mpp/common/schematree/node/SchemaInternalNode.java
index 215ac84e98..10af366554 100644
---
a/server/src/main/java/org/apache/iotdb/db/mpp/common/schematree/SchemaInternalNode.java
+++
b/server/src/main/java/org/apache/iotdb/db/mpp/common/schematree/node/SchemaInternalNode.java
@@ -17,7 +17,7 @@
* under the License.
*/
-package org.apache.iotdb.db.mpp.common.schematree;
+package org.apache.iotdb.db.mpp.common.schematree.node;
import org.apache.iotdb.tsfile.utils.ReadWriteIOUtils;
diff --git
a/server/src/main/java/org/apache/iotdb/db/mpp/common/schematree/SchemaMeasurementNode.java
b/server/src/main/java/org/apache/iotdb/db/mpp/common/schematree/node/SchemaMeasurementNode.java
similarity index 98%
rename from
server/src/main/java/org/apache/iotdb/db/mpp/common/schematree/SchemaMeasurementNode.java
rename to
server/src/main/java/org/apache/iotdb/db/mpp/common/schematree/node/SchemaMeasurementNode.java
index b8d76be279..ea9a5d1f19 100644
---
a/server/src/main/java/org/apache/iotdb/db/mpp/common/schematree/SchemaMeasurementNode.java
+++
b/server/src/main/java/org/apache/iotdb/db/mpp/common/schematree/node/SchemaMeasurementNode.java
@@ -17,7 +17,7 @@
* under the License.
*/
-package org.apache.iotdb.db.mpp.common.schematree;
+package org.apache.iotdb.db.mpp.common.schematree.node;
import org.apache.iotdb.tsfile.utils.ReadWriteIOUtils;
import org.apache.iotdb.tsfile.write.schema.MeasurementSchema;
diff --git
a/server/src/main/java/org/apache/iotdb/db/mpp/common/schematree/SchemaNode.java
b/server/src/main/java/org/apache/iotdb/db/mpp/common/schematree/node/SchemaNode.java
similarity index 92%
rename from
server/src/main/java/org/apache/iotdb/db/mpp/common/schematree/SchemaNode.java
rename to
server/src/main/java/org/apache/iotdb/db/mpp/common/schematree/node/SchemaNode.java
index ed295fff42..069cbe02c8 100644
---
a/server/src/main/java/org/apache/iotdb/db/mpp/common/schematree/SchemaNode.java
+++
b/server/src/main/java/org/apache/iotdb/db/mpp/common/schematree/node/SchemaNode.java
@@ -17,14 +17,16 @@
* under the License.
*/
-package org.apache.iotdb.db.mpp.common.schematree;
+package org.apache.iotdb.db.mpp.common.schematree.node;
+
+import org.apache.iotdb.db.metadata.tree.ITreeNode;
import java.nio.ByteBuffer;
import java.util.Collections;
import java.util.Iterator;
import java.util.Map;
-public abstract class SchemaNode {
+public abstract class SchemaNode implements ITreeNode {
public static final byte SCHEMA_INTERNAL_NODE = 0;
public static final byte SCHEMA_ENTITY_NODE = 1;
diff --git
a/server/src/main/java/org/apache/iotdb/db/mpp/common/schematree/visitor/SchemaTreeDeviceVisitor.java
b/server/src/main/java/org/apache/iotdb/db/mpp/common/schematree/visitor/SchemaTreeDeviceVisitor.java
new file mode 100644
index 0000000000..c0a847783f
--- /dev/null
+++
b/server/src/main/java/org/apache/iotdb/db/mpp/common/schematree/visitor/SchemaTreeDeviceVisitor.java
@@ -0,0 +1,61 @@
+/*
+ * 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.mpp.common.schematree.visitor;
+
+import org.apache.iotdb.db.metadata.path.PartialPath;
+import org.apache.iotdb.db.mpp.common.schematree.DeviceSchemaInfo;
+import org.apache.iotdb.db.mpp.common.schematree.node.SchemaMeasurementNode;
+import org.apache.iotdb.db.mpp.common.schematree.node.SchemaNode;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+public class SchemaTreeDeviceVisitor extends
SchemaTreeVisitor<DeviceSchemaInfo> {
+
+ public SchemaTreeDeviceVisitor(SchemaNode root, PartialPath pathPattern,
boolean isPrefixMatch) {
+ super(root, pathPattern, 0, 0, isPrefixMatch);
+ }
+
+ @Override
+ protected boolean processFullMatchedNode(SchemaNode node) {
+ if (node.isEntity()) {
+ nextMatchedNode = node;
+ }
+ return false;
+ }
+
+ @Override
+ protected DeviceSchemaInfo generateResult() {
+ PartialPath path = new PartialPath(generateFullPathNodes(nextMatchedNode));
+ List<SchemaMeasurementNode> measurementNodeList = new ArrayList<>();
+ Iterator<SchemaNode> iterator = getChildrenIterator(nextMatchedNode);
+ SchemaNode node;
+ while (iterator.hasNext()) {
+ node = iterator.next();
+ if (node.isMeasurement()) {
+ measurementNodeList.add(node.getAsMeasurementNode());
+ }
+ }
+
+ return new DeviceSchemaInfo(
+ path, nextMatchedNode.getAsEntityNode().isAligned(),
measurementNodeList);
+ }
+}
diff --git
a/server/src/main/java/org/apache/iotdb/db/mpp/common/schematree/visitor/SchemaTreeMeasurementVisitor.java
b/server/src/main/java/org/apache/iotdb/db/mpp/common/schematree/visitor/SchemaTreeMeasurementVisitor.java
new file mode 100644
index 0000000000..3d49ebd7d1
--- /dev/null
+++
b/server/src/main/java/org/apache/iotdb/db/mpp/common/schematree/visitor/SchemaTreeMeasurementVisitor.java
@@ -0,0 +1,80 @@
+/*
+ * 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.mpp.common.schematree.visitor;
+
+import org.apache.iotdb.db.metadata.path.MeasurementPath;
+import org.apache.iotdb.db.metadata.path.PartialPath;
+import org.apache.iotdb.db.mpp.common.schematree.node.SchemaMeasurementNode;
+import org.apache.iotdb.db.mpp.common.schematree.node.SchemaNode;
+
+import java.util.regex.Pattern;
+
+public class SchemaTreeMeasurementVisitor extends
SchemaTreeVisitor<MeasurementPath> {
+
+ public SchemaTreeMeasurementVisitor(
+ SchemaNode root, PartialPath pathPattern, int slimit, int soffset,
boolean isPrefixMatch) {
+ super(root, pathPattern, slimit, soffset, isPrefixMatch);
+ }
+
+ @Override
+ protected boolean checkOneLevelWildcardMatch(String regex, SchemaNode node) {
+ if (!node.isMeasurement()) {
+ return Pattern.matches(regex, node.getName());
+ }
+
+ SchemaMeasurementNode measurementNode = node.getAsMeasurementNode();
+
+ return Pattern.matches(regex, measurementNode.getName())
+ || Pattern.matches(regex, measurementNode.getAlias());
+ }
+
+ @Override
+ protected boolean checkNameMatch(String targetName, SchemaNode node) {
+ if (node.isMeasurement()) {
+ return targetName.equals(node.getName())
+ || targetName.equals(node.getAsMeasurementNode().getAlias());
+ }
+ return targetName.equals(node.getName());
+ }
+
+ @Override
+ protected boolean processFullMatchedNode(SchemaNode node) {
+ if (node.isMeasurement()) {
+ nextMatchedNode = node;
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ protected MeasurementPath generateResult() {
+ MeasurementPath result =
+ new MeasurementPath(
+ generateFullPathNodes(nextMatchedNode),
+ nextMatchedNode.getAsMeasurementNode().getSchema());
+
result.setUnderAlignedEntity(ancestorStack.peek().getAsEntityNode().isAligned());
+ String alias = nextMatchedNode.getAsMeasurementNode().getAlias();
+ if (nodes[nodes.length - 1].equals(alias)) {
+ result.setMeasurementAlias(alias);
+ }
+
+ return result;
+ }
+}
diff --git
a/server/src/main/java/org/apache/iotdb/db/mpp/common/schematree/visitor/SchemaTreeVisitor.java
b/server/src/main/java/org/apache/iotdb/db/mpp/common/schematree/visitor/SchemaTreeVisitor.java
new file mode 100644
index 0000000000..01f99452a9
--- /dev/null
+++
b/server/src/main/java/org/apache/iotdb/db/mpp/common/schematree/visitor/SchemaTreeVisitor.java
@@ -0,0 +1,60 @@
+/*
+ * 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.mpp.common.schematree.visitor;
+
+import org.apache.iotdb.db.metadata.path.PartialPath;
+import org.apache.iotdb.db.metadata.tree.AbstractTreeVisitorWithLimitOffset;
+import org.apache.iotdb.db.mpp.common.schematree.node.SchemaNode;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+public abstract class SchemaTreeVisitor<R>
+ extends AbstractTreeVisitorWithLimitOffset<SchemaNode, R> {
+
+ public SchemaTreeVisitor(
+ SchemaNode root, PartialPath pathPattern, int limit, int offset, boolean
isPrefixMatch) {
+ super(root, pathPattern, limit, offset, isPrefixMatch);
+ }
+
+ public List<R> getAllResult() {
+ List<R> result = new ArrayList<>();
+ while (hasNext()) {
+ result.add(next());
+ }
+ return result;
+ }
+
+ @Override
+ protected boolean isLeafNode(SchemaNode node) {
+ return node.isMeasurement();
+ }
+
+ @Override
+ protected SchemaNode getChild(SchemaNode parent, String childName) {
+ return parent.getChild(childName);
+ }
+
+ @Override
+ protected Iterator<SchemaNode> getChildrenIterator(SchemaNode parent) {
+ return parent.getChildrenIterator();
+ }
+}
diff --git
a/server/src/main/java/org/apache/iotdb/db/mpp/sql/analyze/FakeSchemaFetcherImpl.java
b/server/src/main/java/org/apache/iotdb/db/mpp/sql/analyze/FakeSchemaFetcherImpl.java
index 66ca66f402..8924b1e09f 100644
---
a/server/src/main/java/org/apache/iotdb/db/mpp/sql/analyze/FakeSchemaFetcherImpl.java
+++
b/server/src/main/java/org/apache/iotdb/db/mpp/sql/analyze/FakeSchemaFetcherImpl.java
@@ -21,11 +21,11 @@ package org.apache.iotdb.db.mpp.sql.analyze;
import org.apache.iotdb.db.metadata.path.PartialPath;
import org.apache.iotdb.db.mpp.common.schematree.PathPatternTree;
-import org.apache.iotdb.db.mpp.common.schematree.SchemaEntityNode;
-import org.apache.iotdb.db.mpp.common.schematree.SchemaInternalNode;
-import org.apache.iotdb.db.mpp.common.schematree.SchemaMeasurementNode;
-import org.apache.iotdb.db.mpp.common.schematree.SchemaNode;
import org.apache.iotdb.db.mpp.common.schematree.SchemaTree;
+import org.apache.iotdb.db.mpp.common.schematree.node.SchemaEntityNode;
+import org.apache.iotdb.db.mpp.common.schematree.node.SchemaInternalNode;
+import org.apache.iotdb.db.mpp.common.schematree.node.SchemaMeasurementNode;
+import org.apache.iotdb.db.mpp.common.schematree.node.SchemaNode;
import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
import org.apache.iotdb.tsfile.write.schema.MeasurementSchema;
diff --git
a/server/src/test/java/org/apache/iotdb/db/mpp/common/schematree/SchemaTreeTest.java
b/server/src/test/java/org/apache/iotdb/db/mpp/common/schematree/SchemaTreeTest.java
index adbd42431e..9f8d6d486d 100644
---
a/server/src/test/java/org/apache/iotdb/db/mpp/common/schematree/SchemaTreeTest.java
+++
b/server/src/test/java/org/apache/iotdb/db/mpp/common/schematree/SchemaTreeTest.java
@@ -21,6 +21,11 @@ package org.apache.iotdb.db.mpp.common.schematree;
import org.apache.iotdb.db.exception.metadata.IllegalPathException;
import org.apache.iotdb.db.metadata.path.MeasurementPath;
import org.apache.iotdb.db.metadata.path.PartialPath;
+import org.apache.iotdb.db.mpp.common.schematree.node.SchemaEntityNode;
+import org.apache.iotdb.db.mpp.common.schematree.node.SchemaInternalNode;
+import org.apache.iotdb.db.mpp.common.schematree.node.SchemaMeasurementNode;
+import org.apache.iotdb.db.mpp.common.schematree.node.SchemaNode;
+import
org.apache.iotdb.db.mpp.common.schematree.visitor.SchemaTreeMeasurementVisitor;
import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
import org.apache.iotdb.tsfile.utils.Pair;
import org.apache.iotdb.tsfile.write.schema.MeasurementSchema;
@@ -45,28 +50,82 @@ public class SchemaTreeTest {
@Test
public void testMultiWildcard() throws IllegalPathException {
- SchemaNode root = generateSchemaTree();
- SchemaTreeVisitor visitor =
- new SchemaTreeVisitor(root, new PartialPath("root.**.s1"), 0, 0,
false);
+ SchemaNode root = generateSchemaTreeWithInternalRepeatedName();
+
+ SchemaTreeMeasurementVisitor visitor =
+ new SchemaTreeMeasurementVisitor(root, new
PartialPath("root.**.**.s"), 0, 0, false);
+ checkVisitorResult(
+ visitor,
+ 4,
+ new String[] {"root.a.a.a.a.a.s", "root.a.a.a.a.s", "root.a.a.a.s",
"root.a.a.s"},
+ null,
+ new boolean[] {false, false, false, false});
+
+ visitor = new SchemaTreeMeasurementVisitor(root, new
PartialPath("root.*.**.s"), 0, 0, false);
+ checkVisitorResult(
+ visitor,
+ 4,
+ new String[] {"root.a.a.a.a.a.s", "root.a.a.a.a.s", "root.a.a.a.s",
"root.a.a.s"},
+ null,
+ new boolean[] {false, false, false, false});
+
+ visitor =
+ new SchemaTreeMeasurementVisitor(root, new
PartialPath("root.**.a.**.s"), 0, 0, false);
checkVisitorResult(
visitor,
3,
- new String[] {"root.sg.d1.s1", "root.sg.d2.s1", "root.sg.d2.a.s1"},
+ new String[] {"root.a.a.a.a.a.s", "root.a.a.a.a.s", "root.a.a.a.s"},
null,
- new boolean[] {false, false, true});
+ new boolean[] {false, false, false});
+
+ visitor =
+ new SchemaTreeMeasurementVisitor(root, new
PartialPath("root.**.a.**.*.s"), 0, 0, false);
+ checkVisitorResult(
+ visitor,
+ 2,
+ new String[] {"root.a.a.a.a.a.s", "root.a.a.a.a.s"},
+ null,
+ new boolean[] {false, false, false});
+
+ visitor =
+ new SchemaTreeMeasurementVisitor(root, new
PartialPath("root.a.**.a.*.s"), 0, 0, false);
+ checkVisitorResult(
+ visitor,
+ 2,
+ new String[] {"root.a.a.a.a.a.s", "root.a.a.a.a.s"},
+ null,
+ new boolean[] {false, false, false});
+
+ visitor = new SchemaTreeMeasurementVisitor(root, new
PartialPath("root.**.c.s1"), 0, 0, false);
+ checkVisitorResult(
+ visitor,
+ 2,
+ new String[] {"root.c.c.c.d.c.c.s1", "root.c.c.c.d.c.s1"},
+ null,
+ new boolean[] {false, false});
+
+ visitor =
+ new SchemaTreeMeasurementVisitor(root, new
PartialPath("root.**.c.d.c.s1"), 0, 0, false);
+ checkVisitorResult(visitor, 1, new String[] {"root.c.c.c.d.c.s1"}, null,
new boolean[] {false});
+
+ visitor =
+ new SchemaTreeMeasurementVisitor(root, new
PartialPath("root.**.d.**.c.s1"), 0, 0, false);
+ checkVisitorResult(
+ visitor, 1, new String[] {"root.c.c.c.d.c.c.s1"}, null, new boolean[]
{false});
}
private void testSchemaTree(SchemaNode root) throws Exception {
- SchemaTreeVisitor visitor =
- new SchemaTreeVisitor(root, new PartialPath("root.sg.d2.a.s1"), 0, 0,
false);
+ SchemaTreeMeasurementVisitor visitor =
+ new SchemaTreeMeasurementVisitor(root, new
PartialPath("root.sg.d2.a.s1"), 0, 0, false);
checkVisitorResult(visitor, 1, new String[] {"root.sg.d2.a.s1"}, null, new
boolean[] {true});
- visitor = new SchemaTreeVisitor(root, new PartialPath("root.sg.*.s2"), 0,
0, false);
+ visitor = new SchemaTreeMeasurementVisitor(root, new
PartialPath("root.sg.*.s2"), 0, 0, false);
checkVisitorResult(
visitor, 2, new String[] {"root.sg.d1.s2", "root.sg.d2.s2"}, new
String[] {"", ""}, null);
- visitor = new SchemaTreeVisitor(root, new PartialPath("root.sg.*.status"),
0, 0, false);
+ visitor =
+ new SchemaTreeMeasurementVisitor(root, new
PartialPath("root.sg.*.status"), 0, 0, false);
checkVisitorResult(
visitor,
2,
@@ -74,7 +133,8 @@ public class SchemaTreeTest {
new String[] {"status", "status"},
null);
- visitor = new SchemaTreeVisitor(root, new PartialPath("root.sg.d2.*.*"),
0, 0, false);
+ visitor =
+ new SchemaTreeMeasurementVisitor(root, new
PartialPath("root.sg.d2.*.*"), 0, 0, false);
checkVisitorResult(
visitor,
2,
@@ -82,7 +142,7 @@ public class SchemaTreeTest {
new String[] {"", ""},
new boolean[] {true, true});
- visitor = new SchemaTreeVisitor(root, new PartialPath("root.sg.d1"), 0, 0,
true);
+ visitor = new SchemaTreeMeasurementVisitor(root, new
PartialPath("root.sg.d1"), 0, 0, true);
checkVisitorResult(
visitor,
2,
@@ -90,7 +150,7 @@ public class SchemaTreeTest {
new String[] {"", ""},
new boolean[] {false, false});
- visitor = new SchemaTreeVisitor(root, new PartialPath("root.sg.*.a"), 0,
0, true);
+ visitor = new SchemaTreeMeasurementVisitor(root, new
PartialPath("root.sg.*.a"), 0, 0, true);
checkVisitorResult(
visitor,
2,
@@ -99,7 +159,7 @@ public class SchemaTreeTest {
new boolean[] {true, true},
new int[] {0, 0});
- visitor = new SchemaTreeVisitor(root, new PartialPath("root.sg.*.*"), 2,
2, false);
+ visitor = new SchemaTreeMeasurementVisitor(root, new
PartialPath("root.sg.*.*"), 2, 2, false);
checkVisitorResult(
visitor,
2,
@@ -108,7 +168,7 @@ public class SchemaTreeTest {
new boolean[] {false, false},
new int[] {3, 4});
- visitor = new SchemaTreeVisitor(root, new PartialPath("root.sg.*"), 2, 3,
true);
+ visitor = new SchemaTreeMeasurementVisitor(root, new
PartialPath("root.sg.*"), 2, 3, true);
checkVisitorResult(
visitor,
2,
@@ -117,7 +177,7 @@ public class SchemaTreeTest {
new boolean[] {true, false},
new int[] {4, 5});
- visitor = new SchemaTreeVisitor(root, new PartialPath("root.sg.d1.**"), 0,
0, false);
+ visitor = new SchemaTreeMeasurementVisitor(root, new
PartialPath("root.sg.d1.**"), 0, 0, false);
checkVisitorResult(
visitor,
2,
@@ -125,7 +185,7 @@ public class SchemaTreeTest {
new String[] {"", ""},
new boolean[] {false, false});
- visitor = new SchemaTreeVisitor(root, new PartialPath("root.sg.d2.**"), 3,
1, true);
+ visitor = new SchemaTreeMeasurementVisitor(root, new
PartialPath("root.sg.d2.**"), 3, 1, true);
checkVisitorResult(
visitor,
3,
@@ -134,13 +194,14 @@ public class SchemaTreeTest {
new boolean[] {true, false, false},
new int[] {2, 3, 4});
- visitor = new SchemaTreeVisitor(root, new
PartialPath("root.sg.**.status"), 2, 1, true);
+ visitor =
+ new SchemaTreeMeasurementVisitor(root, new
PartialPath("root.sg.**.status"), 2, 1, true);
checkVisitorResult(
visitor,
2,
- new String[] {"root.sg.d2.s2", "root.sg.d2.a.s2"},
+ new String[] {"root.sg.d2.a.s2", "root.sg.d2.s2"},
new String[] {"status", "status"},
- new boolean[] {false, true},
+ new boolean[] {true, false},
new int[] {2, 3});
}
@@ -184,8 +245,51 @@ public class SchemaTreeTest {
return root;
}
+ /**
+ * Generate the following tree: root.a.s, root.a.a.s, root.a.a.a.s,
root.a.a.a.a.s,
+ * root.a.a.a.a.a.s, root.c.c.c.d.c.s1, root.c.c.c.d.c.c.s1
+ *
+ * @return the root node of the generated schemTree
+ */
+ private SchemaNode generateSchemaTreeWithInternalRepeatedName() {
+ SchemaNode root = new SchemaInternalNode("root");
+
+ SchemaNode parent = root;
+ SchemaNode a;
+ MeasurementSchema schema = new MeasurementSchema("s", TSDataType.INT32);
+ SchemaNode s;
+ for (int i = 0; i < 5; i++) {
+ a = new SchemaEntityNode("a");
+ s = new SchemaMeasurementNode("s", schema);
+ a.addChild("s", s);
+ parent.addChild("a", a);
+ parent = a;
+ }
+
+ parent = root;
+ SchemaNode c;
+ for (int i = 0; i < 3; i++) {
+ c = new SchemaInternalNode("c");
+ parent.addChild("c", c);
+ parent = c;
+ }
+
+ SchemaNode d = new SchemaInternalNode("d");
+ parent.addChild("d", d);
+ parent = d;
+
+ for (int i = 0; i < 2; i++) {
+ c = new SchemaEntityNode("c");
+ c.addChild("s1", new SchemaMeasurementNode("s1", schema));
+ parent.addChild("c", c);
+ parent = c;
+ }
+
+ return root;
+ }
+
private void checkVisitorResult(
- SchemaTreeVisitor visitor,
+ SchemaTreeMeasurementVisitor visitor,
int expectedNum,
String[] expectedPath,
String[] expectedAlias,
@@ -210,7 +314,7 @@ public class SchemaTreeTest {
}
private void checkVisitorResult(
- SchemaTreeVisitor visitor,
+ SchemaTreeMeasurementVisitor visitor,
int expectedNum,
String[] expectedPath,
String[] expectedAlias,
@@ -218,7 +322,7 @@ public class SchemaTreeTest {
int[] expectedOffset) {
checkVisitorResult(visitor, expectedNum, expectedPath, expectedAlias,
expectedAligned);
- visitor.resetStatus();
+ visitor.reset();
int i = 0;
MeasurementPath result;
while (visitor.hasNext()) {
@@ -266,6 +370,25 @@ public class SchemaTreeTest {
.collect(Collectors.toList()));
}
+ @Test
+ public void testGetMatchedDevices() throws Exception {
+ SchemaTree schemaTree = new SchemaTree(generateSchemaTree());
+
+ List<DeviceSchemaInfo> deviceSchemaInfoList =
+ schemaTree.getMatchedDevices(new PartialPath("root.sg.d2.a"), false);
+ Assert.assertEquals(1, deviceSchemaInfoList.size());
+ DeviceSchemaInfo deviceSchemaInfo = deviceSchemaInfoList.get(0);
+ Assert.assertEquals(new PartialPath("root.sg.d2.a"),
deviceSchemaInfo.getDevicePath());
+ Assert.assertTrue(deviceSchemaInfo.isAligned());
+ Assert.assertEquals(2, deviceSchemaInfo.getMeasurements().size());
+
+ deviceSchemaInfoList = schemaTree.getMatchedDevices(new
PartialPath("root.sg.*"), false);
+ Assert.assertEquals(2, deviceSchemaInfoList.size());
+
+ deviceSchemaInfoList = schemaTree.getMatchedDevices(new
PartialPath("root.sg.**"), false);
+ Assert.assertEquals(3, deviceSchemaInfoList.size());
+ }
+
@Test
public void testSerialization() throws Exception {
SchemaNode root = generateSchemaTree();
diff --git
a/server/src/test/java/org/apache/iotdb/db/mpp/operator/schema/SchemaFetchOperatorTest.java
b/server/src/test/java/org/apache/iotdb/db/mpp/operator/schema/SchemaFetchOperatorTest.java
index 2f5317e458..d58640c922 100644
---
a/server/src/test/java/org/apache/iotdb/db/mpp/operator/schema/SchemaFetchOperatorTest.java
+++
b/server/src/test/java/org/apache/iotdb/db/mpp/operator/schema/SchemaFetchOperatorTest.java
@@ -99,7 +99,7 @@ public class SchemaFetchOperatorTest {
schemaTree.searchMeasurementPaths(new
PartialPath("root.sg.**.status"), 0, 0, false);
Assert.assertEquals(3, pair.left.size());
Assert.assertEquals(
- Arrays.asList("root.sg.d1.s2", "root.sg.d2.s2", "root.sg.d2.a.s2"),
+ Arrays.asList("root.sg.d1.s2", "root.sg.d2.a.s2", "root.sg.d2.s2"),
pair.left.stream().map(MeasurementPath::getFullPath).collect(Collectors.toList()));
}