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/incubator-iotdb.git


The following commit(s) were added to refs/heads/master by this push:
     new 6a927f4  IOTDB-750 Allow SubDevices in IoTDB.
6a927f4 is described below

commit 6a927f42da843751f890b233d6c5612ff2d307d8
Author: Julian Feinauer <[email protected]>
AuthorDate: Sun Jun 7 22:12:51 2020 +0200

    IOTDB-750 Allow SubDevices in IoTDB.
    
    - Rename LeafMNode to MeasurementMNode and fix IT to show that a 
Measurement can now also have sub-measurements in the MTree.
---
 .../iotdb/db/engine/merge/task/MergeTask.java      |   4 +-
 .../engine/storagegroup/StorageGroupProcessor.java |   6 +-
 .../org/apache/iotdb/db/metadata/MManager.java     |  60 +++---
 .../java/org/apache/iotdb/db/metadata/MTree.java   | 109 ++++++-----
 .../iotdb/db/metadata/mnode/InternalMNode.java     |   2 +-
 .../{LeafMNode.java => MeasurementMNode.java}      |  57 +-----
 .../apache/iotdb/db/qp/executor/PlanExecutor.java  |  10 +-
 .../iotdb/db/query/executor/LastQueryExecutor.java |   6 +-
 .../iotdb/db/integration/IoTDBAddSubDeviceIT.java  | 203 +++++++++++++++++++++
 .../apache/iotdb/db/integration/IoTDBLastIT.java   |  12 +-
 .../iotdb/db/metadata/MManagerAdvancedTest.java    |  14 +-
 .../iotdb/db/metadata/MManagerImproveTest.java     |   4 +-
 .../org/apache/iotdb/db/metadata/MTreeTest.java    |  77 ++++----
 13 files changed, 357 insertions(+), 207 deletions(-)

diff --git 
a/server/src/main/java/org/apache/iotdb/db/engine/merge/task/MergeTask.java 
b/server/src/main/java/org/apache/iotdb/db/engine/merge/task/MergeTask.java
index 6d1a6fc..b6ac065 100644
--- a/server/src/main/java/org/apache/iotdb/db/engine/merge/task/MergeTask.java
+++ b/server/src/main/java/org/apache/iotdb/db/engine/merge/task/MergeTask.java
@@ -36,7 +36,7 @@ import org.apache.iotdb.db.engine.storagegroup.TsFileResource;
 import org.apache.iotdb.db.exception.metadata.MetadataException;
 import org.apache.iotdb.db.metadata.MManager;
 import org.apache.iotdb.db.metadata.mnode.InternalMNode;
-import org.apache.iotdb.db.metadata.mnode.LeafMNode;
+import org.apache.iotdb.db.metadata.mnode.MeasurementMNode;
 import org.apache.iotdb.db.metadata.mnode.MNode;
 import org.apache.iotdb.db.utils.MergeUtils;
 import org.apache.iotdb.tsfile.read.common.Path;
@@ -124,7 +124,7 @@ public class MergeTask implements Callable<Void> {
       InternalMNode deviceNode = (InternalMNode) 
MManager.getInstance().getNodeByPath(device);
       for (Entry<String, MNode> entry : deviceNode.getChildren().entrySet()) {
         Path path = new Path(device, entry.getKey());
-        measurementSchemaMap.put(path, ((LeafMNode) 
entry.getValue()).getSchema());
+        measurementSchemaMap.put(path, ((MeasurementMNode) 
entry.getValue()).getSchema());
         unmergedSeries.add(path);
       }
     }
diff --git 
a/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/StorageGroupProcessor.java
 
b/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/StorageGroupProcessor.java
index 3c22c38..8ba9020 100755
--- 
a/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/StorageGroupProcessor.java
+++ 
b/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/StorageGroupProcessor.java
@@ -73,7 +73,7 @@ import org.apache.iotdb.db.exception.query.OutOfTTLException;
 import org.apache.iotdb.db.exception.query.QueryProcessException;
 import org.apache.iotdb.db.metadata.MManager;
 import org.apache.iotdb.db.metadata.mnode.InternalMNode;
-import org.apache.iotdb.db.metadata.mnode.LeafMNode;
+import org.apache.iotdb.db.metadata.mnode.MeasurementMNode;
 import org.apache.iotdb.db.metadata.mnode.MNode;
 import org.apache.iotdb.db.qp.physical.crud.DeletePlan;
 import org.apache.iotdb.db.qp.physical.crud.InsertPlan;
@@ -767,7 +767,7 @@ public class StorageGroupProcessor {
       String[] measurementList = plan.getMeasurements();
       for (int i = 0; i < measurementList.length; i++) {
         // Update cached last value with high priority
-        ((LeafMNode) manager.getChild(node, measurementList[i]))
+        ((MeasurementMNode) manager.getChild(node, measurementList[i]))
             .updateCachedLast(plan.composeLastTimeValuePair(i), true, 
latestFlushedTime);
       }
     } catch (MetadataException e) {
@@ -824,7 +824,7 @@ public class StorageGroupProcessor {
         // Update cached last value with high priority
         MNode measurementNode = manager.getChild(node, measurementList[i]);
         if (measurementNode != null) {
-          ((LeafMNode) measurementNode)
+          ((MeasurementMNode) measurementNode)
               .updateCachedLast(plan.composeTimeValuePair(i), true, 
latestFlushedTime);
         }
       }
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/MManager.java 
b/server/src/main/java/org/apache/iotdb/db/metadata/MManager.java
index 7a857a6..ec46b77 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/MManager.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/MManager.java
@@ -53,7 +53,7 @@ import 
org.apache.iotdb.db.exception.metadata.PathNotExistException;
 import org.apache.iotdb.db.exception.metadata.StorageGroupAlreadySetException;
 import org.apache.iotdb.db.exception.metadata.StorageGroupNotSetException;
 import org.apache.iotdb.db.metadata.mnode.InternalMNode;
-import org.apache.iotdb.db.metadata.mnode.LeafMNode;
+import org.apache.iotdb.db.metadata.mnode.MeasurementMNode;
 import org.apache.iotdb.db.metadata.mnode.MNode;
 import org.apache.iotdb.db.metadata.mnode.StorageGroupMNode;
 import org.apache.iotdb.db.monitor.MonitorConstants;
@@ -98,7 +98,7 @@ public class MManager {
   private LRUCache<String, MeasurementSchema> mRemoteSchemaCache;
 
   // tag key -> tag value -> LeafMNode
-  private Map<String, Map<String, Set<LeafMNode>>> tagIndex = new HashMap<>();
+  private Map<String, Map<String, Set<MeasurementMNode>>> tagIndex = new 
HashMap<>();
 
   // storage group name -> the series number
   private Map<String, Integer> seriesNumberInStorageGroups = new HashMap<>();
@@ -329,7 +329,7 @@ public class MManager {
       IoTDBConfigDynamicAdapter.getInstance().addOrDeleteTimeSeries(1);
 
       // create time series in MTree
-      LeafMNode leafMNode = mtree
+      MeasurementMNode leafMNode = mtree
           .createTimeseries(path, plan.getDataType(), plan.getEncoding(), 
plan.getCompressor(),
               plan.getProps(), plan.getAlias());
 
@@ -445,7 +445,7 @@ public class MManager {
    * @param node
    * @throws IOException
    */
-  private void removeFromTagInvertedIndex(LeafMNode node) throws IOException {
+  private void removeFromTagInvertedIndex(MeasurementMNode node) throws 
IOException {
     if (node.getOffset() < 0) {
       return;
     }
@@ -482,7 +482,7 @@ public class MManager {
       throws MetadataException, IOException {
     lock.writeLock().lock();
     try {
-      Pair<String, LeafMNode> pair = 
mtree.deleteTimeseriesAndReturnEmptyStorageGroup(path);
+      Pair<String, MeasurementMNode> pair = 
mtree.deleteTimeseriesAndReturnEmptyStorageGroup(path);
       removeFromTagInvertedIndex(pair.right);
       String storageGroupName = pair.left;
 
@@ -550,8 +550,8 @@ public class MManager {
         mRemoteSchemaCache.removeItem(storageGroup);
 
         // try to delete storage group
-        List<LeafMNode> leafMNodes = mtree.deleteStorageGroup(storageGroup);
-        for (LeafMNode leafMNode : leafMNodes) {
+        List<MeasurementMNode> leafMNodes = 
mtree.deleteStorageGroup(storageGroup);
+        for (MeasurementMNode leafMNode : leafMNodes) {
           removeFromTagInvertedIndex(leafMNode);
         }
         mNodeCache.clear();
@@ -633,7 +633,7 @@ public class MManager {
         if (!deviceNode.hasChild(measurements[i])) {
           throw new MetadataException(measurements[i] + " does not exist in " 
+ deviceId);
         }
-        measurementSchemas[i] = ((LeafMNode) 
deviceNode.getChild(measurements[i])).getSchema();
+        measurementSchemas[i] = ((MeasurementMNode) 
deviceNode.getChild(measurements[i])).getSchema();
       }
       return measurementSchemas;
     } finally {
@@ -778,20 +778,20 @@ public class MManager {
       if (!tagIndex.containsKey(plan.getKey())) {
         throw new MetadataException("The key " + plan.getKey() + " is not a 
tag.");
       }
-      Map<String, Set<LeafMNode>> value2Node = tagIndex.get(plan.getKey());
+      Map<String, Set<MeasurementMNode>> value2Node = 
tagIndex.get(plan.getKey());
       if (value2Node.isEmpty()) {
         throw new MetadataException("The key " + plan.getKey() + " is not a 
tag.");
       }
-      Set<LeafMNode> allMatchedNodes = new 
TreeSet<>(Comparator.comparing(MNode::getFullPath));
+      Set<MeasurementMNode> allMatchedNodes = new 
TreeSet<>(Comparator.comparing(MNode::getFullPath));
       if (plan.isContains()) {
-        for (Entry<String, Set<LeafMNode>> entry : value2Node.entrySet()) {
+        for (Entry<String, Set<MeasurementMNode>> entry : 
value2Node.entrySet()) {
           String tagValue = entry.getKey();
           if (tagValue.contains(plan.getValue())) {
             allMatchedNodes.addAll(entry.getValue());
           }
         }
       } else {
-        for (Entry<String, Set<LeafMNode>> entry : value2Node.entrySet()) {
+        for (Entry<String, Set<MeasurementMNode>> entry : 
value2Node.entrySet()) {
           String tagValue = entry.getKey();
           if (plan.getValue().equals(tagValue)) {
             allMatchedNodes.addAll(entry.getValue());
@@ -804,7 +804,7 @@ public class MManager {
       int count = 0;
       int limit = plan.getLimit();
       int offset = plan.getOffset();
-      for (LeafMNode leaf : allMatchedNodes) {
+      for (MeasurementMNode leaf : allMatchedNodes) {
         if (match(leaf.getFullPath(), prefixNodes)) {
           if (limit != 0 || offset != 0) {
             curOffset++;
@@ -896,7 +896,7 @@ public class MManager {
       InternalMNode node = (InternalMNode) mtree.getNodeByPath(device);
       MNode leaf = node.getChild(measurement);
       if (leaf != null) {
-        return ((LeafMNode) leaf).getSchema();
+        return ((MeasurementMNode) leaf).getSchema();
       } else {
         return mRemoteSchemaCache
             .get(device + IoTDBConstant.PATH_SEPARATOR + measurement);
@@ -1114,7 +1114,7 @@ public class MManager {
   public void changeOffset(String path, long offset) throws MetadataException {
     lock.writeLock().lock();
     try {
-      ((LeafMNode) mtree.getNodeByPath(path)).setOffset(offset);
+      ((MeasurementMNode) mtree.getNodeByPath(path)).setOffset(offset);
     } finally {
       lock.writeLock().unlock();
     }
@@ -1123,7 +1123,7 @@ public class MManager {
   public void changeAlias(String path, String alias) throws MetadataException {
     lock.writeLock().lock();
     try {
-      LeafMNode leafMNode = (LeafMNode) mtree.getNodeByPath(path);
+      MeasurementMNode leafMNode = (MeasurementMNode) 
mtree.getNodeByPath(path);
       if (leafMNode.getAlias() != null) {
         leafMNode.getParent().deleteAliasChild(leafMNode.getAlias());
       }
@@ -1148,10 +1148,10 @@ public class MManager {
     lock.writeLock().lock();
     try {
       MNode mNode = mtree.getNodeByPath(fullPath);
-      if (!(mNode instanceof LeafMNode)) {
+      if (!(mNode instanceof MeasurementMNode)) {
         throw new PathNotExistException(fullPath);
       }
-      LeafMNode leafMNode = (LeafMNode) mNode;
+      MeasurementMNode leafMNode = (MeasurementMNode) mNode;
       // upsert alias
       if (alias != null && !alias.equals(leafMNode.getAlias())) {
 
@@ -1235,10 +1235,10 @@ public class MManager {
     lock.writeLock().lock();
     try {
       MNode mNode = mtree.getNodeByPath(fullPath);
-      if (!(mNode instanceof LeafMNode)) {
+      if (!(mNode instanceof MeasurementMNode)) {
         throw new PathNotExistException(fullPath);
       }
-      LeafMNode leafMNode = (LeafMNode) mNode;
+      MeasurementMNode leafMNode = (MeasurementMNode) mNode;
       // no tag or attribute, we need to add a new record in log
       if (leafMNode.getOffset() < 0) {
         long offset = tagLogFile.write(Collections.emptyMap(), attributesMap);
@@ -1278,10 +1278,10 @@ public class MManager {
     lock.writeLock().lock();
     try {
       MNode mNode = mtree.getNodeByPath(fullPath);
-      if (!(mNode instanceof LeafMNode)) {
+      if (!(mNode instanceof MeasurementMNode)) {
         throw new PathNotExistException(fullPath);
       }
-      LeafMNode leafMNode = (LeafMNode) mNode;
+      MeasurementMNode leafMNode = (MeasurementMNode) mNode;
       // no tag or attribute, we need to add a new record in log
       if (leafMNode.getOffset() < 0) {
         long offset = tagLogFile.write(tagsMap, Collections.emptyMap());
@@ -1331,10 +1331,10 @@ public class MManager {
     lock.writeLock().lock();
     try {
       MNode mNode = mtree.getNodeByPath(fullPath);
-      if (!(mNode instanceof LeafMNode)) {
+      if (!(mNode instanceof MeasurementMNode)) {
         throw new PathNotExistException(fullPath);
       }
-      LeafMNode leafMNode = (LeafMNode) mNode;
+      MeasurementMNode leafMNode = (MeasurementMNode) mNode;
       // no tag or attribute, just do nothing.
       if (leafMNode.getOffset() < 0) {
         return;
@@ -1384,10 +1384,10 @@ public class MManager {
     lock.writeLock().lock();
     try {
       MNode mNode = mtree.getNodeByPath(fullPath);
-      if (!(mNode instanceof LeafMNode)) {
+      if (!(mNode instanceof MeasurementMNode)) {
         throw new PathNotExistException(fullPath);
       }
-      LeafMNode leafMNode = (LeafMNode) mNode;
+      MeasurementMNode leafMNode = (MeasurementMNode) mNode;
       if (leafMNode.getOffset() < 0) {
         throw new MetadataException(
             String.format("TimeSeries [%s] does not have any tag/attribute.", 
fullPath));
@@ -1445,10 +1445,10 @@ public class MManager {
     lock.writeLock().lock();
     try {
       MNode mNode = mtree.getNodeByPath(fullPath);
-      if (!(mNode instanceof LeafMNode)) {
+      if (!(mNode instanceof MeasurementMNode)) {
         throw new PathNotExistException(fullPath);
       }
-      LeafMNode leafMNode = (LeafMNode) mNode;
+      MeasurementMNode leafMNode = (MeasurementMNode) mNode;
       if (leafMNode.getOffset() < 0) {
         throw new MetadataException(
             String.format("TimeSeries [%s] does not have [%s] tag/attribute.", 
fullPath, oldKey));
@@ -1522,8 +1522,8 @@ public class MManager {
     nodeDeque.addLast(startingNode);
     while (!nodeDeque.isEmpty()) {
       MNode node = nodeDeque.removeFirst();
-      if (node instanceof LeafMNode) {
-        MeasurementSchema nodeSchema = ((LeafMNode) node).getSchema();
+      if (node instanceof MeasurementMNode) {
+        MeasurementSchema nodeSchema = ((MeasurementMNode) node).getSchema();
         timeseriesSchemas.add(new MeasurementSchema(node.getFullPath(), 
nodeSchema.getType(),
             nodeSchema.getEncodingType(), nodeSchema.getCompressor()));
       } else if (!node.getChildren().isEmpty()) {
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/MTree.java 
b/server/src/main/java/org/apache/iotdb/db/metadata/MTree.java
index 6b944ec..bfb2398 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/MTree.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/MTree.java
@@ -18,26 +18,9 @@
  */
 package org.apache.iotdb.db.metadata;
 
-import static org.apache.iotdb.db.conf.IoTDBConstant.PATH_SEPARATOR;
-import static org.apache.iotdb.db.conf.IoTDBConstant.PATH_WILDCARD;
-
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
 import com.alibaba.fastjson.serializer.SerializerFeature;
-import java.io.Serializable;
-import java.util.ArrayDeque;
-import java.util.ArrayList;
-import java.util.Deque;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Queue;
-import java.util.Set;
-import java.util.TreeSet;
-import java.util.regex.Pattern;
 import org.apache.iotdb.db.conf.IoTDBConstant;
 import org.apache.iotdb.db.conf.IoTDBDescriptor;
 import org.apache.iotdb.db.exception.metadata.AliasAlreadyExistException;
@@ -48,7 +31,7 @@ import 
org.apache.iotdb.db.exception.metadata.PathNotExistException;
 import org.apache.iotdb.db.exception.metadata.StorageGroupAlreadySetException;
 import org.apache.iotdb.db.exception.metadata.StorageGroupNotSetException;
 import org.apache.iotdb.db.metadata.mnode.InternalMNode;
-import org.apache.iotdb.db.metadata.mnode.LeafMNode;
+import org.apache.iotdb.db.metadata.mnode.MeasurementMNode;
 import org.apache.iotdb.db.metadata.mnode.MNode;
 import org.apache.iotdb.db.metadata.mnode.StorageGroupMNode;
 import org.apache.iotdb.db.qp.physical.sys.ShowTimeSeriesPlan;
@@ -60,6 +43,24 @@ import org.apache.iotdb.tsfile.read.common.Path;
 import org.apache.iotdb.tsfile.utils.Pair;
 import org.apache.iotdb.tsfile.write.schema.MeasurementSchema;
 
+import java.io.Serializable;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Queue;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.regex.Pattern;
+
+import static org.apache.iotdb.db.conf.IoTDBConstant.PATH_SEPARATOR;
+import static org.apache.iotdb.db.conf.IoTDBConstant.PATH_WILDCARD;
+
 /**
  * The hierarchical struct of the Metadata Tree is implemented in this class.
  */
@@ -88,7 +89,7 @@ public class MTree implements Serializable {
    * @param props      props
    * @param alias      alias of measurement
    */
-  LeafMNode createTimeseries(
+  MeasurementMNode createTimeseries(
       String path,
       TSDataType dataType,
       TSEncoding encoding,
@@ -116,9 +117,6 @@ public class MTree implements Serializable {
       }
       cur = cur.getChild(nodeName);
     }
-    if (cur instanceof LeafMNode) {
-      throw new PathAlreadyExistException(cur.getFullPath());
-    }
     String leafName = nodeNames[nodeNames.length - 1];
     if (cur.hasChild(leafName)) {
       throw new PathAlreadyExistException(path);
@@ -126,7 +124,7 @@ public class MTree implements Serializable {
     if (alias != null && cur.hasChild(alias)) {
       throw new AliasAlreadyExistException(path, alias);
     }
-    LeafMNode leaf = new LeafMNode(cur, leafName, alias, dataType, encoding, 
compressor, props);
+    MeasurementMNode leaf = new MeasurementMNode(cur, leafName, alias, 
dataType, encoding, compressor, props);
     cur.addChild(leafName, leaf);
     // link alias to LeafMNode
     if (alias != null) {
@@ -220,7 +218,7 @@ public class MTree implements Serializable {
   /**
    * Delete a storage group
    */
-  List<LeafMNode> deleteStorageGroup(String path) throws MetadataException {
+  List<MeasurementMNode> deleteStorageGroup(String path) throws 
MetadataException {
     MNode cur = getNodeByPath(path);
     if (!(cur instanceof StorageGroupMNode)) {
       throw new StorageGroupNotSetException(path);
@@ -230,14 +228,14 @@ public class MTree implements Serializable {
     cur.getParent().deleteChild(cur.getName());
 
     // collect all the LeafMNode in this storage group
-    List<LeafMNode> leafMNodes = new LinkedList<>();
+    List<MeasurementMNode> leafMNodes = new LinkedList<>();
     Queue<MNode> queue = new LinkedList<>();
     queue.add(cur);
     while (!queue.isEmpty()) {
       MNode node = queue.poll();
       for (MNode child : node.getChildren().values()) {
-        if (child instanceof LeafMNode) {
-          leafMNodes.add((LeafMNode) child);
+        if (child instanceof MeasurementMNode) {
+          leafMNodes.add((MeasurementMNode) child);
         } else {
           queue.add(child);
         }
@@ -285,10 +283,10 @@ public class MTree implements Serializable {
    *
    * @param path Format: root.node(.node)+
    */
-  Pair<String, LeafMNode> deleteTimeseriesAndReturnEmptyStorageGroup(String 
path)
+  Pair<String, MeasurementMNode> 
deleteTimeseriesAndReturnEmptyStorageGroup(String path)
       throws MetadataException {
     MNode curNode = getNodeByPath(path);
-    if (!(curNode instanceof LeafMNode)) {
+    if (!(curNode instanceof MeasurementMNode)) {
       throw new PathNotExistException(path);
     }
     String[] nodes = MetaUtils.getNodeNames(path);
@@ -297,9 +295,9 @@ public class MTree implements Serializable {
     }
     // delete the last node of path
     curNode.getParent().deleteChild(curNode.getName());
-    LeafMNode deletedNode = (LeafMNode) curNode;
+    MeasurementMNode deletedNode = (MeasurementMNode) curNode;
     if (deletedNode.getAlias() != null) {
-      curNode.getParent().deleteAliasChild(((LeafMNode) curNode).getAlias());
+      curNode.getParent().deleteAliasChild(((MeasurementMNode) 
curNode).getAlias());
     }
     curNode = curNode.getParent();
     // delete all empty ancestors except storage group
@@ -319,7 +317,7 @@ public class MTree implements Serializable {
    * Get measurement schema for a given path. Path must be a complete Path 
from root to leaf node.
    */
   MeasurementSchema getSchema(String path) throws MetadataException {
-    LeafMNode node = (LeafMNode) getNodeByPath(path);
+    MeasurementMNode node = (MeasurementMNode) getNodeByPath(path);
     return node.getSchema();
   }
 
@@ -589,7 +587,7 @@ public class MTree implements Serializable {
     String nodeReg = MetaUtils.getNodeRegByIdx(idx, nodes);
     if (!(PATH_WILDCARD).equals(nodeReg)) {
       if (node.hasChild(nodeReg)) {
-        if (node.getChild(nodeReg) instanceof LeafMNode) {
+        if (node.getChild(nodeReg) instanceof MeasurementMNode) {
           return 1;
         } else {
           return getCount(node.getChild(nodeReg), nodes, idx + 1);
@@ -600,11 +598,10 @@ public class MTree implements Serializable {
     } else {
       int cnt = 0;
       for (MNode child : node.getChildren().values()) {
-        if (child instanceof LeafMNode) {
+        if (child instanceof MeasurementMNode) {
           cnt++;
-        } else {
-          cnt += getCount(child, nodes, idx + 1);
         }
+          cnt += getCount(child, nodes, idx + 1);
       }
       return cnt;
     }
@@ -664,37 +661,34 @@ public class MTree implements Serializable {
    */
   private void findPath(MNode node, String[] nodes, int idx, String parent,
       List<String[]> timeseriesSchemaList, boolean hasLimit) throws 
MetadataException {
-    if (node instanceof LeafMNode) {
-      if (nodes.length <= idx) {
-        if (hasLimit) {
-          curOffset.set(curOffset.get() + 1);
-          if (curOffset.get() < offset.get() || count.get().intValue() == 
limit.get().intValue()) {
-            return;
-          }
+    if (node instanceof MeasurementMNode && nodes.length <= idx) {
+      if (hasLimit) {
+        curOffset.set(curOffset.get() + 1);
+        if (curOffset.get() < offset.get() || count.get().intValue() == 
limit.get().intValue()) {
+          return;
         }
-        String nodeName;
-        if (node.getName().contains(TsFileConstant.PATH_SEPARATOR)) {
-          nodeName = "\"" + node + "\"";
-        } else {
+      }
+      String nodeName;
+      if (node.getName().contains(TsFileConstant.PATH_SEPARATOR)) {
+        nodeName = "\"" + node + "\"";
+      } else {
           nodeName = node.getName();
         }
         String nodePath = parent + nodeName;
         String[] tsRow = new String[7];
         tsRow[0] = nodePath;
-        tsRow[1] = ((LeafMNode) node).getAlias();
-        MeasurementSchema measurementSchema = ((LeafMNode) node).getSchema();
+        tsRow[1] = ((MeasurementMNode) node).getAlias();
+        MeasurementSchema measurementSchema = ((MeasurementMNode) 
node).getSchema();
         tsRow[2] = getStorageGroupName(nodePath);
         tsRow[3] = measurementSchema.getType().toString();
         tsRow[4] = measurementSchema.getEncodingType().toString();
         tsRow[5] = measurementSchema.getCompressor().toString();
-        tsRow[6] = String.valueOf(((LeafMNode) node).getOffset());
+        tsRow[6] = String.valueOf(((MeasurementMNode) node).getOffset());
         timeseriesSchemaList.add(tsRow);
 
         if (hasLimit) {
           count.set(count.get() + 1);
         }
-      }
-      return;
     }
     String nodeReg = MetaUtils.getNodeRegByIdx(idx, nodes);
     if (!nodeReg.contains(PATH_WILDCARD)) {
@@ -804,7 +798,7 @@ public class MTree implements Serializable {
     String nodeReg = MetaUtils.getNodeRegByIdx(idx, nodes);
     if (!(PATH_WILDCARD).equals(nodeReg)) {
       if (node.hasChild(nodeReg)) {
-        if (node.getChild(nodeReg) instanceof LeafMNode) {
+        if (node.getChild(nodeReg) instanceof MeasurementMNode) {
           res.add(parent + node.getName());
         } else {
           findDevices(node.getChild(nodeReg), nodes, idx + 1,
@@ -814,12 +808,11 @@ public class MTree implements Serializable {
     } else {
       boolean deviceAdded = false;
       for (MNode child : node.getChildren().values()) {
-        if (child instanceof LeafMNode && !deviceAdded) {
+        if (child instanceof MeasurementMNode && !deviceAdded) {
           res.add(parent + node.getName());
           deviceAdded = true;
-        } else if (!(child instanceof LeafMNode)) {
-          findDevices(child, nodes, idx + 1, parent + node.getName() + 
PATH_SEPARATOR, res);
         }
+        findDevices(child, nodes, idx + 1, parent + node.getName() + 
PATH_SEPARATOR, res);
       }
     }
   }
@@ -884,8 +877,8 @@ public class MTree implements Serializable {
       for (MNode child : node.getChildren().values()) {
         jsonObject.put(child.getName(), mNodeToJSON(child, storageGroupName));
       }
-    } else if (node instanceof LeafMNode) {
-      LeafMNode leafMNode = (LeafMNode) node;
+    } else if (node instanceof MeasurementMNode) {
+      MeasurementMNode leafMNode = (MeasurementMNode) node;
       jsonObject.put("DataType", leafMNode.getSchema().getType());
       jsonObject.put("Encoding", leafMNode.getSchema().getEncodingType());
       jsonObject.put("Compressor", leafMNode.getSchema().getCompressor());
diff --git 
a/server/src/main/java/org/apache/iotdb/db/metadata/mnode/InternalMNode.java 
b/server/src/main/java/org/apache/iotdb/db/metadata/mnode/InternalMNode.java
index 2dc48b6..c7dbcd5 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/mnode/InternalMNode.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/mnode/InternalMNode.java
@@ -62,7 +62,7 @@ public class InternalMNode extends MNode {
     if (children.containsKey(name)) {
       Lock writeLock;
       // if its child node is leaf node, we need to acquire the write lock of 
the current device node
-      if (children.get(name) instanceof LeafMNode) {
+      if (children.get(name) instanceof MeasurementMNode) {
         writeLock = lock.writeLock();
       } else {
         // otherwise, we only need to acquire the write lock of its child node.
diff --git 
a/server/src/main/java/org/apache/iotdb/db/metadata/mnode/LeafMNode.java 
b/server/src/main/java/org/apache/iotdb/db/metadata/mnode/MeasurementMNode.java
similarity index 72%
rename from 
server/src/main/java/org/apache/iotdb/db/metadata/mnode/LeafMNode.java
rename to 
server/src/main/java/org/apache/iotdb/db/metadata/mnode/MeasurementMNode.java
index 3f65929..6dd4aa1 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/mnode/LeafMNode.java
+++ 
b/server/src/main/java/org/apache/iotdb/db/metadata/mnode/MeasurementMNode.java
@@ -24,14 +24,12 @@ import 
org.apache.iotdb.tsfile.file.metadata.enums.TSEncoding;
 import org.apache.iotdb.tsfile.read.TimeValuePair;
 import org.apache.iotdb.tsfile.write.schema.MeasurementSchema;
 
-import java.util.Collections;
 import java.util.Map;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
-public class LeafMNode extends MNode {
-
-  private static final Logger logger = 
LoggerFactory.getLogger(LeafMNode.class);
+/**
+ * Represents an (Internal-)MNode which has a Measurement or Sensor attached 
to it.
+ */
+public class MeasurementMNode extends InternalMNode {
 
   private static final long serialVersionUID = -1199657856921206435L;
 
@@ -48,55 +46,13 @@ public class LeafMNode extends MNode {
   /**
    * @param alias alias of measurementName
    */
-  public LeafMNode(MNode parent, String measurementName, String alias, 
TSDataType dataType,
-      TSEncoding encoding, CompressionType type, Map<String, String> props) {
+  public MeasurementMNode(MNode parent, String measurementName, String alias, 
TSDataType dataType,
+                          TSEncoding encoding, CompressionType type, 
Map<String, String> props) {
     super(parent, measurementName);
     this.schema = new MeasurementSchema(measurementName, dataType, encoding, 
type, props);
     this.alias = alias;
   }
 
-  @Override
-  public boolean hasChild(String name) {
-    return false;
-  }
-
-  @Override
-  public void addChild(String name, MNode child) {
-    // Do nothing
-  }
-
-  @Override
-  public void deleteChild(String name) {
-    // Do nothing
-  }
-
-  @Override
-  public void deleteAliasChild(String alias) {
-    // Do nothing
-  }
-
-  @Override
-  public MNode getChild(String name) {
-    logger.warn("current node {} is a LeafMNode, can not get child {}", 
super.name, name);
-    throw new RuntimeException(
-        String.format("current node %s is a LeafMNode, can not get child %s", 
super.name, name));
-  }
-
-  @Override
-  public int getLeafCount() {
-    return 1;
-  }
-
-  @Override
-  public void addAlias(String alias, MNode child) {
-    // Do nothing
-  }
-
-  @Override
-  public Map<String, MNode> getChildren() {
-    return Collections.emptyMap();
-  }
-
   public MeasurementSchema getSchema() {
     return schema;
   }
@@ -123,6 +79,7 @@ public class LeafMNode extends MNode {
     }
   }
 
+  @Override
   public String getFullPath() {
     return concatFullPath();
   }
diff --git 
a/server/src/main/java/org/apache/iotdb/db/qp/executor/PlanExecutor.java 
b/server/src/main/java/org/apache/iotdb/db/qp/executor/PlanExecutor.java
index cce6140..6113424 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/executor/PlanExecutor.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/executor/PlanExecutor.java
@@ -77,7 +77,7 @@ import 
org.apache.iotdb.db.exception.metadata.StorageGroupNotSetException;
 import org.apache.iotdb.db.exception.query.QueryProcessException;
 import org.apache.iotdb.db.metadata.MManager;
 import org.apache.iotdb.db.metadata.mnode.InternalMNode;
-import org.apache.iotdb.db.metadata.mnode.LeafMNode;
+import org.apache.iotdb.db.metadata.mnode.MeasurementMNode;
 import org.apache.iotdb.db.metadata.mnode.MNode;
 import org.apache.iotdb.db.metadata.mnode.StorageGroupMNode;
 import org.apache.iotdb.db.qp.logical.Operator.OperatorType;
@@ -810,7 +810,7 @@ public class PlanExecutor implements IPlanExecutor {
                   schema.getEncodingType(),
                   schema.getCompressor(),
                   Collections.emptyMap());
-            } else if (node.getChild(chunkMetadata.getMeasurementUid()) 
instanceof InternalMNode) {
+            } else if (!(node.getChild(chunkMetadata.getMeasurementUid()) 
instanceof MeasurementMNode)) {
               throw new QueryProcessException(
                   String.format("Current Path is not leaf node. %s", series));
             }
@@ -959,7 +959,7 @@ public class PlanExecutor implements IPlanExecutor {
         Path path = new Path(deviceId, measurement);
         internalCreateTimeseries(path.toString(), dataType);
 
-        LeafMNode measurementNode = (LeafMNode) mManager.getChild(deviceNode, 
measurement);
+        MeasurementMNode measurementNode = (MeasurementMNode) 
mManager.getChild(deviceNode, measurement);
         measurementSchema = measurementNode.getSchema();
         if(!isInferType) {
           checkType(insertPlan, loc, measurementNode.getSchema().getType());
@@ -967,7 +967,7 @@ public class PlanExecutor implements IPlanExecutor {
       }
     } else if (deviceNode != null) {
       // device and measurement exists in MTree
-      LeafMNode measurementNode = (LeafMNode) 
MManager.getInstance().getChild(deviceNode, measurement);
+      MeasurementMNode measurementNode = (MeasurementMNode) 
MManager.getInstance().getChild(deviceNode, measurement);
       measurementSchema = measurementNode.getSchema();
     } else {
       // device in not in MTree, try the cache
@@ -1087,7 +1087,7 @@ public class PlanExecutor implements IPlanExecutor {
           internalCreateTimeseries(path.getFullPath(), dataType);
 
         }
-        LeafMNode measurementNode = (LeafMNode) mManager.getChild(node, 
measurement);
+        MeasurementMNode measurementNode = (MeasurementMNode) 
mManager.getChild(node, measurement);
 
         // check data type
         if (measurementNode.getSchema().getType() != 
insertTabletPlan.getDataTypes()[i]) {
diff --git 
a/server/src/main/java/org/apache/iotdb/db/query/executor/LastQueryExecutor.java
 
b/server/src/main/java/org/apache/iotdb/db/query/executor/LastQueryExecutor.java
index 7b7fb08..8b4f292 100644
--- 
a/server/src/main/java/org/apache/iotdb/db/query/executor/LastQueryExecutor.java
+++ 
b/server/src/main/java/org/apache/iotdb/db/query/executor/LastQueryExecutor.java
@@ -29,7 +29,7 @@ import org.apache.iotdb.db.exception.StorageEngineException;
 import org.apache.iotdb.db.exception.metadata.MetadataException;
 import org.apache.iotdb.db.exception.query.QueryProcessException;
 import org.apache.iotdb.db.metadata.MManager;
-import org.apache.iotdb.db.metadata.mnode.LeafMNode;
+import org.apache.iotdb.db.metadata.mnode.MeasurementMNode;
 import org.apache.iotdb.db.qp.physical.crud.LastQueryPlan;
 import org.apache.iotdb.db.query.context.QueryContext;
 import org.apache.iotdb.db.query.control.QueryResourceManager;
@@ -112,9 +112,9 @@ public class LastQueryExecutor {
       throws IOException, QueryProcessException, StorageEngineException {
 
     // Retrieve last value from MNode
-    LeafMNode node;
+    MeasurementMNode node;
     try {
-      node = (LeafMNode) 
MManager.getInstance().getNodeByPath(seriesPath.toString());
+      node = (MeasurementMNode) 
MManager.getInstance().getNodeByPath(seriesPath.toString());
     } catch (MetadataException e) {
       throw new QueryProcessException(e);
     }
diff --git 
a/server/src/test/java/org/apache/iotdb/db/integration/IoTDBAddSubDeviceIT.java 
b/server/src/test/java/org/apache/iotdb/db/integration/IoTDBAddSubDeviceIT.java
new file mode 100644
index 0000000..e01772d
--- /dev/null
+++ 
b/server/src/test/java/org/apache/iotdb/db/integration/IoTDBAddSubDeviceIT.java
@@ -0,0 +1,203 @@
+/*
+ * 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.integration;
+
+import org.apache.iotdb.db.utils.EnvironmentUtils;
+import org.apache.iotdb.jdbc.Config;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.Statement;
+import java.sql.Types;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+public class IoTDBAddSubDeviceIT {
+
+  private static String[] sqls = new String[]{
+      "CREATE TIMESERIES root.sg1.d1.s1 with datatype=INT32,encoding=RLE",
+      "CREATE TIMESERIES root.sg1.d1.s1.s1 with datatype=INT32,encoding=RLE",
+      "CREATE TIMESERIES root.sg1.d1.s1.s2 with datatype=INT32,encoding=RLE"
+  };
+
+  @BeforeClass
+  public static void setUp() throws Exception {
+    EnvironmentUtils.closeStatMonitor();
+    EnvironmentUtils.envSetUp();
+
+    insertData();
+
+  }
+
+  @AfterClass
+  public static void tearDown() throws Exception {
+    EnvironmentUtils.cleanEnv();
+  }
+
+  private static void insertData() throws ClassNotFoundException {
+    Class.forName(Config.JDBC_DRIVER_NAME);
+    try (Connection connection = DriverManager
+        .getConnection(Config.IOTDB_URL_PREFIX + "127.0.0.1:6667/", "root", 
"root");
+         Statement statement = connection.createStatement()) {
+
+      for (String sql : sqls) {
+        statement.execute(sql);
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
+  }
+
+  @Test
+  public void showDevices() throws ClassNotFoundException {
+    String[] retArray = new String[]{
+        "root.sg1.d1,",
+        "root.sg1.d1.s1,",
+    };
+
+    Class.forName(Config.JDBC_DRIVER_NAME);
+    try (Connection connection = DriverManager
+        .getConnection(Config.IOTDB_URL_PREFIX + "127.0.0.1:6667/", "root", 
"root");
+         Statement statement = connection.createStatement()) {
+      boolean hasResultSet = statement.execute(
+          "SHOW DEVICES");
+      Assert.assertTrue(hasResultSet);
+
+      try (ResultSet resultSet = statement.getResultSet()) {
+        ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
+        StringBuilder header = new StringBuilder();
+        for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
+          header.append(resultSetMetaData.getColumnName(i)).append(",");
+        }
+        Assert.assertEquals("devices,", header.toString());
+        Assert.assertEquals(Types.VARCHAR, resultSetMetaData.getColumnType(1));
+
+        int cnt = 0;
+        while (resultSet.next()) {
+          StringBuilder builder = new StringBuilder();
+          for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
+            builder.append(resultSet.getString(i)).append(",");
+          }
+          Assert.assertEquals(retArray[cnt], builder.toString());
+          cnt++;
+        }
+        Assert.assertEquals(retArray.length, cnt);
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail(e.getMessage());
+    }
+  }
+
+  @Test
+  public void showTimeseries() throws ClassNotFoundException {
+    String[] retArray = new String[]{
+        "root.sg1.d1.s1,null,root.sg1,INT32,RLE,SNAPPY,",
+        "root.sg1.d1.s1.s1,null,root.sg1,INT32,RLE,SNAPPY,",
+        "root.sg1.d1.s1.s2,null,root.sg1,INT32,RLE,SNAPPY,",
+    };
+
+    Class.forName(Config.JDBC_DRIVER_NAME);
+    try (Connection connection = DriverManager
+        .getConnection(Config.IOTDB_URL_PREFIX + "127.0.0.1:6667/", "root", 
"root");
+         Statement statement = connection.createStatement()) {
+      boolean hasResultSet = statement.execute(
+          "SHOW TIMESERIES");
+      Assert.assertTrue(hasResultSet);
+
+      try (ResultSet resultSet = statement.getResultSet()) {
+        ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
+        StringBuilder header = new StringBuilder();
+        for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
+          header.append(resultSetMetaData.getColumnName(i)).append(",");
+        }
+        Assert.assertEquals("timeseries,alias,storage 
group,dataType,encoding,compression,", header.toString());
+        Assert.assertEquals(Types.VARCHAR, resultSetMetaData.getColumnType(1));
+
+        int cnt = 0;
+        while (resultSet.next()) {
+          StringBuilder builder = new StringBuilder();
+          for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
+            builder.append(resultSet.getString(i)).append(",");
+          }
+          Assert.assertEquals(retArray[cnt], builder.toString());
+          cnt++;
+        }
+        Assert.assertEquals(retArray.length, cnt);
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail(e.getMessage());
+    }
+  }
+
+  @Test
+  public void insertDataInAllSeries() throws ClassNotFoundException {
+    String[] retArray = new String[]{
+        "0,1,2,3,",
+    };
+
+    Class.forName(Config.JDBC_DRIVER_NAME);
+    try (Connection connection = DriverManager
+        .getConnection(Config.IOTDB_URL_PREFIX + "127.0.0.1:6667/", "root", 
"root");
+         Statement statement = connection.createStatement()) {
+
+      statement.execute("INSERT INTO root.sg1.d1 (timestamp, s1) VALUES(0, 
1)");
+      statement.execute("INSERT INTO root.sg1.d1.s1 (timestamp, s1) VALUES(0, 
2)");
+      statement.execute("INSERT INTO root.sg1.d1.s1 (timestamp, s2) VALUES(0, 
3)");
+
+      // assertEquals(1, statement.getUpdateCount());
+
+      boolean hasResultSet = statement.execute(
+          "SELECT * FROM root.sg1.d1");
+      Assert.assertTrue(hasResultSet);
+
+      try (ResultSet resultSet = statement.getResultSet()) {
+        ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
+        StringBuilder header = new StringBuilder();
+        for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
+          header.append(resultSetMetaData.getColumnName(i)).append(",");
+        }
+        
Assert.assertEquals("Time,root.sg1.d1.s1,root.sg1.d1.s1.s1,root.sg1.d1.s1.s2,", 
header.toString());
+
+        int cnt = 0;
+        while (resultSet.next()) {
+          StringBuilder builder = new StringBuilder();
+          for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
+            builder.append(resultSet.getString(i)).append(",");
+          }
+          Assert.assertEquals(retArray[cnt], builder.toString());
+          cnt++;
+        }
+        Assert.assertEquals(retArray.length, cnt);
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail(e.getMessage());
+    }
+  }
+}
diff --git 
a/server/src/test/java/org/apache/iotdb/db/integration/IoTDBLastIT.java 
b/server/src/test/java/org/apache/iotdb/db/integration/IoTDBLastIT.java
index ee2c843..5bedf48 100644
--- a/server/src/test/java/org/apache/iotdb/db/integration/IoTDBLastIT.java
+++ b/server/src/test/java/org/apache/iotdb/db/integration/IoTDBLastIT.java
@@ -20,7 +20,7 @@ package org.apache.iotdb.db.integration;
 
 import org.apache.iotdb.db.exception.metadata.MetadataException;
 import org.apache.iotdb.db.metadata.MManager;
-import org.apache.iotdb.db.metadata.mnode.LeafMNode;
+import org.apache.iotdb.db.metadata.mnode.MeasurementMNode;
 import org.apache.iotdb.db.metadata.mnode.MNode;
 import org.apache.iotdb.db.utils.EnvironmentUtils;
 import org.apache.iotdb.jdbc.Config;
@@ -130,8 +130,8 @@ public class IoTDBLastIT {
         }
       }
 
-      LeafMNode node =
-          (LeafMNode) 
MManager.getInstance().getNodeByPath("root.ln.wf01.wt01.temperature");
+      MeasurementMNode node =
+          (MeasurementMNode) 
MManager.getInstance().getNodeByPath("root.ln.wf01.wt01.temperature");
       node.resetCache();
 
       statement.execute(
@@ -192,7 +192,7 @@ public class IoTDBLastIT {
         Statement statement = connection.createStatement()) {
 
       MNode node = 
MManager.getInstance().getNodeByPath("root.ln.wf01.wt02.temperature");
-      ((LeafMNode) node).resetCache();
+      ((MeasurementMNode) node).resetCache();
       boolean hasResultSet =
           statement.execute(
               "select last temperature,status,id from root.ln.wf01.wt02");
@@ -243,7 +243,7 @@ public class IoTDBLastIT {
         Statement statement = connection.createStatement()) {
 
       MNode node = 
MManager.getInstance().getNodeByPath("root.ln.wf01.wt03.temperature");
-      ((LeafMNode) node).resetCache();
+      ((MeasurementMNode) node).resetCache();
 
       statement.execute("INSERT INTO root.ln.wf01.wt03(timestamp,status, id) 
values(500, false, 9)");
       statement.execute("flush");
@@ -291,7 +291,7 @@ public class IoTDBLastIT {
       statement.execute("flush");
 
       MNode node = 
MManager.getInstance().getNodeByPath("root.ln.wf01.wt03.temperature");
-      ((LeafMNode) node).resetCache();
+      ((MeasurementMNode) node).resetCache();
 
       boolean hasResultSet = statement.execute(
           "select last temperature from root.ln.wf01.wt04");
diff --git 
a/server/src/test/java/org/apache/iotdb/db/metadata/MManagerAdvancedTest.java 
b/server/src/test/java/org/apache/iotdb/db/metadata/MManagerAdvancedTest.java
index 16fbecf..2176a7c 100644
--- 
a/server/src/test/java/org/apache/iotdb/db/metadata/MManagerAdvancedTest.java
+++ 
b/server/src/test/java/org/apache/iotdb/db/metadata/MManagerAdvancedTest.java
@@ -25,7 +25,7 @@ import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import org.apache.iotdb.db.exception.metadata.MetadataException;
-import org.apache.iotdb.db.metadata.mnode.LeafMNode;
+import org.apache.iotdb.db.metadata.mnode.MeasurementMNode;
 import org.apache.iotdb.db.metadata.mnode.MNode;
 import org.apache.iotdb.db.utils.EnvironmentUtils;
 import org.apache.iotdb.tsfile.common.conf.TSFileDescriptor;
@@ -129,7 +129,7 @@ public class MManagerAdvancedTest {
         TSFileDescriptor.getInstance().getConfig().getCompressor(), 
Collections.emptyMap());
 
     MNode node = mmanager.getNodeByPath("root.vehicle.d0");
-    Assert.assertEquals(TSDataType.INT32, ((LeafMNode) 
node.getChild("s0")).getSchema().getType());
+    Assert.assertEquals(TSDataType.INT32, ((MeasurementMNode) 
node.getChild("s0")).getSchema().getType());
 
     try {
       mmanager.getNodeByPath("root.vehicle.d100");
@@ -148,11 +148,11 @@ public class MManagerAdvancedTest {
     TimeValuePair tv2 = new TimeValuePair(2000, 
TsPrimitiveType.getByType(TSDataType.DOUBLE, 3.0));
     TimeValuePair tv3 = new TimeValuePair(1500, 
TsPrimitiveType.getByType(TSDataType.DOUBLE, 2.5));
     MNode node = mmanager.getNodeByPath("root.vehicle.d2.s0");
-    ((LeafMNode)node).updateCachedLast(tv1, true, Long.MIN_VALUE);
-    ((LeafMNode)node).updateCachedLast(tv2, true, Long.MIN_VALUE);
-    Assert.assertEquals(tv2.getTimestamp(), 
((LeafMNode)node).getCachedLast().getTimestamp());
-    ((LeafMNode)node).updateCachedLast(tv3, true, Long.MIN_VALUE);
-    Assert.assertEquals(tv2.getTimestamp(), 
((LeafMNode)node).getCachedLast().getTimestamp());
+    ((MeasurementMNode)node).updateCachedLast(tv1, true, Long.MIN_VALUE);
+    ((MeasurementMNode)node).updateCachedLast(tv2, true, Long.MIN_VALUE);
+    Assert.assertEquals(tv2.getTimestamp(), 
((MeasurementMNode)node).getCachedLast().getTimestamp());
+    ((MeasurementMNode)node).updateCachedLast(tv3, true, Long.MIN_VALUE);
+    Assert.assertEquals(tv2.getTimestamp(), 
((MeasurementMNode)node).getCachedLast().getTimestamp());
   }
 
   @Test
diff --git 
a/server/src/test/java/org/apache/iotdb/db/metadata/MManagerImproveTest.java 
b/server/src/test/java/org/apache/iotdb/db/metadata/MManagerImproveTest.java
index 3aaac3a..424ad52 100644
--- a/server/src/test/java/org/apache/iotdb/db/metadata/MManagerImproveTest.java
+++ b/server/src/test/java/org/apache/iotdb/db/metadata/MManagerImproveTest.java
@@ -27,7 +27,7 @@ import java.util.Collections;
 import java.util.List;
 import org.apache.iotdb.db.exception.metadata.MetadataException;
 import org.apache.iotdb.db.metadata.mnode.InternalMNode;
-import org.apache.iotdb.db.metadata.mnode.LeafMNode;
+import org.apache.iotdb.db.metadata.mnode.MeasurementMNode;
 import org.apache.iotdb.db.metadata.mnode.MNode;
 import org.apache.iotdb.db.utils.EnvironmentUtils;
 import org.apache.iotdb.tsfile.common.conf.TSFileDescriptor;
@@ -136,7 +136,7 @@ public class MManagerImproveTest {
       node = mManager.getDeviceNodeWithAutoCreateAndReadLock(deviceId);
       for (String s : measurementList) {
         assertTrue(node.hasChild(s));
-        LeafMNode measurementNode = (LeafMNode) node.getChild(s);
+        MeasurementMNode measurementNode = (MeasurementMNode) node.getChild(s);
         TSDataType dataType = measurementNode.getSchema().getType();
         assertEquals(TSDataType.TEXT, dataType);
       }
diff --git a/server/src/test/java/org/apache/iotdb/db/metadata/MTreeTest.java 
b/server/src/test/java/org/apache/iotdb/db/metadata/MTreeTest.java
index b84b568..539585a 100644
--- a/server/src/test/java/org/apache/iotdb/db/metadata/MTreeTest.java
+++ b/server/src/test/java/org/apache/iotdb/db/metadata/MTreeTest.java
@@ -35,7 +35,10 @@ import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 public class MTreeTest {
 
@@ -50,40 +53,19 @@ public class MTreeTest {
   }
 
   @Test
-  public void testAddLeftNodePath() throws MetadataException {
-    MTree root = new MTree();
-    root.setStorageGroup("root.laptop");
-    try {
-      root.createTimeseries("root.laptop.d1.s1", TSDataType.INT32, 
TSEncoding.RLE,
-          TSFileDescriptor.getInstance().getConfig().getCompressor(), 
Collections.EMPTY_MAP, null);
-    } catch (MetadataException e) {
-      e.printStackTrace();
-      fail(e.getMessage());
-    }
-    boolean hasException = false;
-    try {
-      root.createTimeseries("root.laptop.d1.s1.b", TSDataType.INT32, 
TSEncoding.RLE,
-          TSFileDescriptor.getInstance().getConfig().getCompressor(), 
Collections.EMPTY_MAP, null);
-    } catch (MetadataException e) {
-      hasException = true;
-    }
-    Assert.assertTrue(hasException);
-  }
-
-  @Test
   public void testAddLeftNodePathWithAlias() throws MetadataException {
     MTree root = new MTree();
     root.setStorageGroup("root.laptop");
     try {
       root.createTimeseries("root.laptop.d1.s1", TSDataType.INT32, 
TSEncoding.RLE,
-              TSFileDescriptor.getInstance().getConfig().getCompressor(), 
Collections.EMPTY_MAP, "status");
+              TSFileDescriptor.getInstance().getConfig().getCompressor(), 
Collections.emptyMap(), "status");
     } catch (MetadataException e) {
       e.printStackTrace();
       fail(e.getMessage());
     }
     try {
       root.createTimeseries("root.laptop.d1.s2", TSDataType.INT32, 
TSEncoding.RLE,
-              TSFileDescriptor.getInstance().getConfig().getCompressor(), 
Collections.EMPTY_MAP, "status");
+              TSFileDescriptor.getInstance().getConfig().getCompressor(), 
Collections.emptyMap(), "status");
       fail();
     } catch (MetadataException e) {
       assertTrue(e instanceof AliasAlreadyExistException);
@@ -99,7 +81,7 @@ public class MTreeTest {
     assertFalse(root.isPathExist("root.laptop.d1"));
     try {
       root.createTimeseries("root.laptop.d1.s1", TSDataType.INT32, 
TSEncoding.RLE,
-          TSFileDescriptor.getInstance().getConfig().getCompressor(), 
Collections.EMPTY_MAP, null);
+          TSFileDescriptor.getInstance().getConfig().getCompressor(), 
Collections.emptyMap(), null);
     } catch (MetadataException e1) {
       fail(e1.getMessage());
     }
@@ -108,7 +90,7 @@ public class MTreeTest {
     assertFalse(root.isPathExist("root.laptop.d1.s2"));
     try {
       root.createTimeseries("aa.bb.cc", TSDataType.INT32, TSEncoding.RLE,
-          TSFileDescriptor.getInstance().getConfig().getCompressor(), 
Collections.EMPTY_MAP, null);
+          TSFileDescriptor.getInstance().getConfig().getCompressor(), 
Collections.emptyMap(), null);
     } catch (MetadataException e) {
       Assert.assertEquals(String.format("%s is not a legal path", "aa.bb.cc"),
           e.getMessage());
@@ -123,21 +105,21 @@ public class MTreeTest {
       assertFalse(root.checkStorageGroupByPath("root.a.d0"));
       root.setStorageGroup("root.a.d0");
       root.createTimeseries("root.a.d0.s0", TSDataType.INT32, TSEncoding.RLE,
-          TSFileDescriptor.getInstance().getConfig().getCompressor(), 
Collections.EMPTY_MAP, null);
+          TSFileDescriptor.getInstance().getConfig().getCompressor(), 
Collections.emptyMap(), null);
       root.createTimeseries("root.a.d0.s1", TSDataType.INT32, TSEncoding.RLE,
-          TSFileDescriptor.getInstance().getConfig().getCompressor(), 
Collections.EMPTY_MAP, null);
+          TSFileDescriptor.getInstance().getConfig().getCompressor(), 
Collections.emptyMap(), null);
 
       assertFalse(root.isPathExist("root.a.d1"));
       assertFalse(root.checkStorageGroupByPath("root.a.d1"));
       root.setStorageGroup("root.a.d1");
       root.createTimeseries("root.a.d1.s0", TSDataType.INT32, TSEncoding.RLE,
-          TSFileDescriptor.getInstance().getConfig().getCompressor(), 
Collections.EMPTY_MAP, null);
+          TSFileDescriptor.getInstance().getConfig().getCompressor(), 
Collections.emptyMap(), null);
       root.createTimeseries("root.a.d1.s1", TSDataType.INT32, TSEncoding.RLE,
-          TSFileDescriptor.getInstance().getConfig().getCompressor(), 
Collections.EMPTY_MAP, null);
+          TSFileDescriptor.getInstance().getConfig().getCompressor(), 
Collections.emptyMap(), null);
 
       root.setStorageGroup("root.a.b.d0");
       root.createTimeseries("root.a.b.d0.s0", TSDataType.INT32, TSEncoding.RLE,
-          TSFileDescriptor.getInstance().getConfig().getCompressor(), 
Collections.EMPTY_MAP, null);
+          TSFileDescriptor.getInstance().getConfig().getCompressor(), 
Collections.emptyMap(), null);
 
     } catch (MetadataException e1) {
       e1.printStackTrace();
@@ -166,21 +148,21 @@ public class MTreeTest {
       assertFalse(root.checkStorageGroupByPath("root.a.d0"));
       root.setStorageGroup("root.a.d0");
       root.createTimeseries("root.a.d0.s0", TSDataType.INT32, TSEncoding.RLE,
-              TSFileDescriptor.getInstance().getConfig().getCompressor(), 
Collections.EMPTY_MAP, "temperature");
+              TSFileDescriptor.getInstance().getConfig().getCompressor(), 
Collections.emptyMap(), "temperature");
       root.createTimeseries("root.a.d0.s1", TSDataType.INT32, TSEncoding.RLE,
-              TSFileDescriptor.getInstance().getConfig().getCompressor(), 
Collections.EMPTY_MAP, "status");
+              TSFileDescriptor.getInstance().getConfig().getCompressor(), 
Collections.emptyMap(), "status");
 
       assertFalse(root.isPathExist("root.a.d1"));
       assertFalse(root.checkStorageGroupByPath("root.a.d1"));
       root.setStorageGroup("root.a.d1");
       root.createTimeseries("root.a.d1.s0", TSDataType.INT32, TSEncoding.RLE,
-              TSFileDescriptor.getInstance().getConfig().getCompressor(), 
Collections.EMPTY_MAP, "temperature");
+              TSFileDescriptor.getInstance().getConfig().getCompressor(), 
Collections.emptyMap(), "temperature");
       root.createTimeseries("root.a.d1.s1", TSDataType.INT32, TSEncoding.RLE,
-              TSFileDescriptor.getInstance().getConfig().getCompressor(), 
Collections.EMPTY_MAP, null);
+              TSFileDescriptor.getInstance().getConfig().getCompressor(), 
Collections.emptyMap(), null);
 
       root.setStorageGroup("root.a.b.d0");
       root.createTimeseries("root.a.b.d0.s0", TSDataType.INT32, TSEncoding.RLE,
-              TSFileDescriptor.getInstance().getConfig().getCompressor(), 
Collections.EMPTY_MAP, null);
+              TSFileDescriptor.getInstance().getConfig().getCompressor(), 
Collections.emptyMap(), null);
 
     } catch (MetadataException e1) {
       e1.printStackTrace();
@@ -306,16 +288,16 @@ public class MTreeTest {
     try {
       assertEquals("root.laptop.d1", 
root.getStorageGroupName("root.laptop.d1.s0"));
       root.createTimeseries("root.laptop.d1.s0", TSDataType.INT32, 
TSEncoding.RLE,
-          TSFileDescriptor.getInstance().getConfig().getCompressor(), 
Collections.EMPTY_MAP, null);
+          TSFileDescriptor.getInstance().getConfig().getCompressor(), 
Collections.emptyMap(), null);
       assertEquals("root.laptop.d1", 
root.getStorageGroupName("root.laptop.d1.s1"));
       root.createTimeseries("root.laptop.d1.s1", TSDataType.INT32, 
TSEncoding.RLE,
-          TSFileDescriptor.getInstance().getConfig().getCompressor(), 
Collections.EMPTY_MAP, null);
+          TSFileDescriptor.getInstance().getConfig().getCompressor(), 
Collections.emptyMap(), null);
       assertEquals("root.laptop.d2", 
root.getStorageGroupName("root.laptop.d2.s0"));
       root.createTimeseries("root.laptop.d2.s0", TSDataType.INT32, 
TSEncoding.RLE,
-          TSFileDescriptor.getInstance().getConfig().getCompressor(), 
Collections.EMPTY_MAP, null);
+          TSFileDescriptor.getInstance().getConfig().getCompressor(), 
Collections.emptyMap(), null);
       assertEquals("root.laptop.d2", 
root.getStorageGroupName("root.laptop.d2.s1"));
       root.createTimeseries("root.laptop.d2.s1", TSDataType.INT32, 
TSEncoding.RLE,
-          TSFileDescriptor.getInstance().getConfig().getCompressor(), 
Collections.EMPTY_MAP, null);
+          TSFileDescriptor.getInstance().getConfig().getCompressor(), 
Collections.emptyMap(), null);
     } catch (MetadataException e) {
       e.printStackTrace();
       fail(e.getMessage());
@@ -448,4 +430,19 @@ public class MTreeTest {
       fail(e.getMessage());
     }
   }
+
+  @Test
+  public void addSubDevice() throws MetadataException {
+    MTree root = new MTree();
+    root.setStorageGroup("root.laptop");
+    root.createTimeseries("root.laptop.d1.s1", TSDataType.INT32, 
TSEncoding.RLE,
+        TSFileDescriptor.getInstance().getConfig().getCompressor(), 
Collections.emptyMap(), null);
+    root.createTimeseries("root.laptop.d1.s1.b", TSDataType.INT32, 
TSEncoding.RLE,
+        TSFileDescriptor.getInstance().getConfig().getCompressor(), 
Collections.emptyMap(), null);
+
+    assertEquals(2, root.getDevices("root").size());
+    assertEquals(2, root.getAllTimeseriesCount("root"));
+    assertEquals(2, root.getAllTimeseriesName("root").size());
+    assertEquals(2, root.getAllTimeseriesPath("root").size());
+  }
 }

Reply via email to