This is an automated email from the ASF dual-hosted git repository.

qiaojialin pushed a commit to branch persistent_schema
in repository https://gitbox.apache.org/repos/asf/iotdb.git


The following commit(s) were added to refs/heads/persistent_schema by this push:
     new f9a7ffd  [IOTDB-1839][To persistent_schema] Extract MTreeStore and 
Refactor MNode access (#4508)
f9a7ffd is described below

commit f9a7ffdae3f271834a6afc5b1eed9f2b1bc698ce
Author: Marcos_Zyk <[email protected]>
AuthorDate: Fri Dec 3 18:50:15 2021 +0800

    [IOTDB-1839][To persistent_schema] Extract MTreeStore and Refactor MNode 
access (#4508)
---
 docs/SystemDesign/SchemaManager/SchemaManager.md   |   2 +-
 .../zh/SystemDesign/SchemaManager/SchemaManager.md |   2 +-
 .../apache/iotdb/db/integration/IoTDBTtlIT.java    |   2 +-
 .../org/apache/iotdb/db/metadata/MManager.java     |  20 +-
 .../apache/iotdb/db/metadata/MetadataConstant.java |   3 +
 .../{MTree.java => service/MTreeService.java}      | 554 +++++++--------------
 .../mtree/{ => service}/traverser/Traverser.java   |  43 +-
 .../traverser/collector/CollectorTraverser.java    |  15 +-
 .../traverser/collector/EntityCollector.java       |  13 +-
 .../traverser/collector/MNodeCollector.java        |   8 +-
 .../traverser/collector/MeasurementCollector.java  |  13 +-
 .../traverser/collector/StorageGroupCollector.java |   8 +-
 .../traverser/counter/CounterTraverser.java        |  10 +-
 .../traverser/counter/EntityCounter.java           |   8 +-
 .../traverser/counter/MNodeLevelCounter.java       |   7 +-
 .../traverser/counter/MeasurementCounter.java      |   8 +-
 .../traverser/counter/StorageGroupCounter.java     |   8 +-
 .../iotdb/db/metadata/mtree/store/IMTreeStore.java |  63 +++
 .../db/metadata/mtree/store/MemMTreeStore.java     | 278 +++++++++++
 .../iotdb/db/metadata/MManagerBasicTest.java       |   2 +-
 .../org/apache/iotdb/db/metadata/MTreeTest.java    | 144 +-----
 21 files changed, 643 insertions(+), 568 deletions(-)

diff --git a/docs/SystemDesign/SchemaManager/SchemaManager.md 
b/docs/SystemDesign/SchemaManager/SchemaManager.md
index 1d9269f..704900d 100644
--- a/docs/SystemDesign/SchemaManager/SchemaManager.md
+++ b/docs/SystemDesign/SchemaManager/SchemaManager.md
@@ -143,7 +143,7 @@ Same as above, at the beginning of each operation, it will 
try to obatin the wri
 
 ## MTree
 
-* org.apache.iotdb.db.metadata.mtree.MTree
+* org.apache.iotdb.db.metadata.mtree.service.MTreeService
 
 There three types of nodes in MTree: StorageGroupMNode、InternalMNode(Non-leaf 
node)、LeafMNode(leaf node), they all extend to MNode.
 
diff --git a/docs/zh/SystemDesign/SchemaManager/SchemaManager.md 
b/docs/zh/SystemDesign/SchemaManager/SchemaManager.md
index 348fae2..41dce8f 100644
--- a/docs/zh/SystemDesign/SchemaManager/SchemaManager.md
+++ b/docs/zh/SystemDesign/SchemaManager/SchemaManager.md
@@ -136,7 +136,7 @@ IoTDB 的元数据统一由 MManger 管理,包括以下几个部分:
 
 ## 元数据树
 
-* org.apache.iotdb.db.metadata.mtree.MTree
+* org.apache.iotdb.db.metadata.mtree.service.MTreeService
 
 树中包括三种节点:StorageGroupMNode、InternalMNode(非叶子节点)、LeafMNode(叶子节点),他们都是 MNode 的子类。
 
diff --git 
a/integration/src/test/java/org/apache/iotdb/db/integration/IoTDBTtlIT.java 
b/integration/src/test/java/org/apache/iotdb/db/integration/IoTDBTtlIT.java
index 2073f81..5ba0291 100644
--- a/integration/src/test/java/org/apache/iotdb/db/integration/IoTDBTtlIT.java
+++ b/integration/src/test/java/org/apache/iotdb/db/integration/IoTDBTtlIT.java
@@ -215,7 +215,7 @@ public class IoTDBTtlIT {
       String result = doQuery(statement, "SHOW ALL TTL");
       assertTrue(
           result.equals("root.group1,null\n" + "root.group2.sgroup1,10000\n")
-              || result.equals("root.group2.sgroup1 10000\n" + 
"root.group1,null\n"));
+              || result.equals("root.group2.sgroup1,10000\n" + 
"root.group1,null\n"));
     }
   }
 }
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 433bd31..0a0bf4b 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
@@ -44,7 +44,7 @@ import org.apache.iotdb.db.metadata.mnode.IMNode;
 import org.apache.iotdb.db.metadata.mnode.IMeasurementMNode;
 import org.apache.iotdb.db.metadata.mnode.IStorageGroupMNode;
 import org.apache.iotdb.db.metadata.mnode.MeasurementMNode;
-import org.apache.iotdb.db.metadata.mtree.MTree;
+import org.apache.iotdb.db.metadata.mtree.service.MTreeService;
 import org.apache.iotdb.db.metadata.path.MeasurementPath;
 import org.apache.iotdb.db.metadata.path.PartialPath;
 import org.apache.iotdb.db.metadata.tag.TagManager;
@@ -187,7 +187,7 @@ public class MManager {
   private File logFile;
   private MLogWriter logWriter;
 
-  private MTree mtree;
+  private MTreeService mtree;
   // device -> DeviceMNode
   private RandomDeleteCache<PartialPath, IMNode> mNodeCache;
   private TagManager tagManager = TagManager.getInstance();
@@ -264,7 +264,7 @@ public class MManager {
       isRecovering = true;
 
       tagManager.init();
-      mtree = new MTree();
+      mtree = new MTreeService();
       mtree.init();
 
       int lineNumber = initFromLog(logFile);
@@ -1007,7 +1007,12 @@ public class MManager {
 
   /** Get all storage group paths */
   public List<PartialPath> getAllStorageGroupPaths() {
-    return mtree.getAllStorageGroupPaths();
+    try {
+      return mtree.getAllStorageGroupPaths();
+    } catch (MetadataException e) {
+      logger.error("Something wrong when collecting storage groups");
+      return Collections.emptyList();
+    }
   }
 
   /**
@@ -1264,7 +1269,12 @@ public class MManager {
 
   /** Get all storage group MNodes */
   public List<IStorageGroupMNode> getAllStorageGroupNodes() {
-    return mtree.getAllStorageGroupNodes();
+    try {
+      return mtree.getAllStorageGroupNodes();
+    } catch (MetadataException e) {
+      logger.error("Something wrong when collecting storage groups");
+      return Collections.emptyList();
+    }
   }
 
   IMNode getDeviceNode(PartialPath path) throws MetadataException {
diff --git 
a/server/src/main/java/org/apache/iotdb/db/metadata/MetadataConstant.java 
b/server/src/main/java/org/apache/iotdb/db/metadata/MetadataConstant.java
index bb7093c..0380b1b 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/MetadataConstant.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/MetadataConstant.java
@@ -19,6 +19,7 @@
 package org.apache.iotdb.db.metadata;
 
 import org.apache.iotdb.db.conf.IoTDBConstant;
+import org.apache.iotdb.db.metadata.path.PartialPath;
 
 public class MetadataConstant {
 
@@ -40,6 +41,8 @@ public class MetadataConstant {
   public static final String MTREE_SNAPSHOT_TMP =
       MTREE_PREFIX + IoTDBConstant.FILE_NAME_SEPARATOR + MTREE_VERSION + 
".snapshot.bin.tmp";
 
+  public static final PartialPath ALL_MATCH_PATTERN = new PartialPath(new 
String[] {"root", "**"});
+
   public static final byte INTERNAL_MNODE_TYPE = 0;
   public static final byte STORAGE_GROUP_MNODE_TYPE = 1;
   public static final byte MEASUREMENT_MNODE_TYPE = 2;
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/mtree/MTree.java 
b/server/src/main/java/org/apache/iotdb/db/metadata/mtree/service/MTreeService.java
similarity index 75%
rename from server/src/main/java/org/apache/iotdb/db/metadata/mtree/MTree.java
rename to 
server/src/main/java/org/apache/iotdb/db/metadata/mtree/service/MTreeService.java
index 13e43da..819ff40 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/mtree/MTree.java
+++ 
b/server/src/main/java/org/apache/iotdb/db/metadata/mtree/service/MTreeService.java
@@ -16,11 +16,10 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.iotdb.db.metadata.mtree;
+package org.apache.iotdb.db.metadata.mtree.service;
 
 import org.apache.iotdb.db.conf.IoTDBConstant;
 import org.apache.iotdb.db.conf.IoTDBDescriptor;
-import org.apache.iotdb.db.engine.fileSystem.SystemFileFactory;
 import org.apache.iotdb.db.exception.metadata.AliasAlreadyExistException;
 import org.apache.iotdb.db.exception.metadata.AlignedTimeseriesException;
 import org.apache.iotdb.db.exception.metadata.IllegalPathException;
@@ -34,8 +33,6 @@ import 
org.apache.iotdb.db.exception.metadata.TemplateImcompatibeException;
 import org.apache.iotdb.db.exception.metadata.TemplateIsInUseException;
 import org.apache.iotdb.db.metadata.MManager.StorageGroupFilter;
 import org.apache.iotdb.db.metadata.MetadataConstant;
-import org.apache.iotdb.db.metadata.logfile.MLogReader;
-import org.apache.iotdb.db.metadata.logfile.MLogWriter;
 import org.apache.iotdb.db.metadata.mnode.IEntityMNode;
 import org.apache.iotdb.db.metadata.mnode.IMNode;
 import org.apache.iotdb.db.metadata.mnode.IMeasurementMNode;
@@ -44,28 +41,25 @@ import org.apache.iotdb.db.metadata.mnode.InternalMNode;
 import org.apache.iotdb.db.metadata.mnode.MNodeUtils;
 import org.apache.iotdb.db.metadata.mnode.MeasurementMNode;
 import org.apache.iotdb.db.metadata.mnode.StorageGroupMNode;
-import org.apache.iotdb.db.metadata.mtree.traverser.collector.EntityCollector;
-import org.apache.iotdb.db.metadata.mtree.traverser.collector.MNodeCollector;
-import 
org.apache.iotdb.db.metadata.mtree.traverser.collector.MeasurementCollector;
-import 
org.apache.iotdb.db.metadata.mtree.traverser.collector.StorageGroupCollector;
-import org.apache.iotdb.db.metadata.mtree.traverser.counter.CounterTraverser;
-import org.apache.iotdb.db.metadata.mtree.traverser.counter.EntityCounter;
-import org.apache.iotdb.db.metadata.mtree.traverser.counter.MNodeLevelCounter;
-import org.apache.iotdb.db.metadata.mtree.traverser.counter.MeasurementCounter;
-import 
org.apache.iotdb.db.metadata.mtree.traverser.counter.StorageGroupCounter;
+import 
org.apache.iotdb.db.metadata.mtree.service.traverser.collector.EntityCollector;
+import 
org.apache.iotdb.db.metadata.mtree.service.traverser.collector.MNodeCollector;
+import 
org.apache.iotdb.db.metadata.mtree.service.traverser.collector.MeasurementCollector;
+import 
org.apache.iotdb.db.metadata.mtree.service.traverser.collector.StorageGroupCollector;
+import 
org.apache.iotdb.db.metadata.mtree.service.traverser.counter.CounterTraverser;
+import 
org.apache.iotdb.db.metadata.mtree.service.traverser.counter.EntityCounter;
+import 
org.apache.iotdb.db.metadata.mtree.service.traverser.counter.MNodeLevelCounter;
+import 
org.apache.iotdb.db.metadata.mtree.service.traverser.counter.MeasurementCounter;
+import 
org.apache.iotdb.db.metadata.mtree.service.traverser.counter.StorageGroupCounter;
+import org.apache.iotdb.db.metadata.mtree.store.IMTreeStore;
+import org.apache.iotdb.db.metadata.mtree.store.MemMTreeStore;
 import org.apache.iotdb.db.metadata.path.MeasurementPath;
 import org.apache.iotdb.db.metadata.path.PartialPath;
 import org.apache.iotdb.db.metadata.template.Template;
 import org.apache.iotdb.db.metadata.utils.MetaFormatUtils;
-import org.apache.iotdb.db.qp.physical.PhysicalPlan;
-import org.apache.iotdb.db.qp.physical.sys.MNodePlan;
-import org.apache.iotdb.db.qp.physical.sys.MeasurementMNodePlan;
 import org.apache.iotdb.db.qp.physical.sys.ShowDevicesPlan;
 import org.apache.iotdb.db.qp.physical.sys.ShowTimeSeriesPlan;
-import org.apache.iotdb.db.qp.physical.sys.StorageGroupMNodePlan;
 import org.apache.iotdb.db.query.context.QueryContext;
 import org.apache.iotdb.db.query.dataset.ShowDevicesResult;
-import org.apache.iotdb.db.utils.TestOnly;
 import org.apache.iotdb.tsfile.file.metadata.enums.CompressionType;
 import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
 import org.apache.iotdb.tsfile.file.metadata.enums.TSEncoding;
@@ -74,36 +68,29 @@ import 
org.apache.iotdb.tsfile.write.schema.IMeasurementSchema;
 import org.apache.iotdb.tsfile.write.schema.TimeseriesSchema;
 import org.apache.iotdb.tsfile.write.schema.UnaryMeasurementSchema;
 
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
-import com.google.gson.JsonElement;
-import com.google.gson.JsonObject;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.io.File;
 import java.io.IOException;
 import java.io.Serializable;
-import java.nio.file.Files;
-import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Comparator;
-import java.util.Deque;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Queue;
 import java.util.Set;
 import java.util.TreeSet;
-import java.util.concurrent.ConcurrentHashMap;
 import java.util.stream.Stream;
 
 import static java.util.stream.Collectors.toList;
 import static org.apache.iotdb.db.conf.IoTDBConstant.ONE_LEVEL_PATH_WILDCARD;
+import static org.apache.iotdb.db.metadata.MetadataConstant.ALL_MATCH_PATTERN;
 import static 
org.apache.iotdb.db.metadata.lastCache.LastCacheManager.getLastTimeStamp;
 
 /**
@@ -131,187 +118,37 @@ import static 
org.apache.iotdb.db.metadata.lastCache.LastCacheManager.getLastTim
  *       </ol>
  *   <li>Interfaces and Implementation for MNode Query
  *   <li>Interfaces and Implementation for Template check
- *   <li>TestOnly Interface
  * </ol>
  */
-public class MTree implements Serializable {
+public class MTreeService implements Serializable {
 
-  public static final Gson GSON = new 
GsonBuilder().setPrettyPrinting().create();
-  private static final long serialVersionUID = -4200394435237291964L;
-  private static final Logger logger = LoggerFactory.getLogger(MTree.class);
+  private static final Logger logger = 
LoggerFactory.getLogger(MTreeService.class);
   private IMNode root;
-
-  private String mtreeSnapshotPath;
-  private String mtreeSnapshotTmpPath;
+  private IMTreeStore store;
 
   // region MTree initialization, clear and serialization
-  public MTree() {
-    this.root = new InternalMNode(null, IoTDBConstant.PATH_ROOT);
-  }
-
-  private MTree(InternalMNode root) {
-    this.root = root;
+  public MTreeService() {
+    store = new MemMTreeStore();
+    this.root = store.getRoot();
   }
 
   public void init() throws IOException {
-    mtreeSnapshotPath =
-        IoTDBDescriptor.getInstance().getConfig().getSchemaDir()
-            + File.separator
-            + MetadataConstant.MTREE_SNAPSHOT;
-    mtreeSnapshotTmpPath =
-        IoTDBDescriptor.getInstance().getConfig().getSchemaDir()
-            + File.separator
-            + MetadataConstant.MTREE_SNAPSHOT_TMP;
-
-    File tmpFile = SystemFileFactory.INSTANCE.getFile(mtreeSnapshotTmpPath);
-    if (tmpFile.exists()) {
-      logger.warn("Creating MTree snapshot not successful before crashing...");
-      Files.delete(tmpFile.toPath());
-    }
-
-    File mtreeSnapshot = SystemFileFactory.INSTANCE.getFile(mtreeSnapshotPath);
-    long time = System.currentTimeMillis();
-    if (mtreeSnapshot.exists()) {
-      this.root = deserializeFrom(mtreeSnapshot).root;
-      logger.debug(
-          "spend {} ms to deserialize mtree from snapshot", 
System.currentTimeMillis() - time);
-    }
+    store.init();
+    this.root = store.getRoot();
   }
 
   public void clear() {
-    root = new InternalMNode(null, IoTDBConstant.PATH_ROOT);
+    store.clear();
+    root = store.getRoot();
   }
 
   public void createSnapshot() throws IOException {
-    long time = System.currentTimeMillis();
-    logger.info("Start creating MTree snapshot to {}", mtreeSnapshotPath);
-    try {
-      serializeTo(mtreeSnapshotTmpPath);
-      File tmpFile = SystemFileFactory.INSTANCE.getFile(mtreeSnapshotTmpPath);
-      File snapshotFile = 
SystemFileFactory.INSTANCE.getFile(mtreeSnapshotPath);
-      if (snapshotFile.exists()) {
-        Files.delete(snapshotFile.toPath());
-      }
-      if (tmpFile.renameTo(snapshotFile)) {
-        logger.info(
-            "Finish creating MTree snapshot to {}, spend {} ms.",
-            mtreeSnapshotPath,
-            System.currentTimeMillis() - time);
-      }
-    } catch (IOException e) {
-      logger.warn("Failed to create MTree snapshot to {}", mtreeSnapshotPath, 
e);
-      if (SystemFileFactory.INSTANCE.getFile(mtreeSnapshotTmpPath).exists()) {
-        try {
-          
Files.delete(SystemFileFactory.INSTANCE.getFile(mtreeSnapshotTmpPath).toPath());
-        } catch (IOException e1) {
-          logger.warn("delete file {} failed: {}", mtreeSnapshotTmpPath, 
e1.getMessage());
-        }
-      }
-      throw e;
-    }
-  }
-
-  private static String jsonToString(JsonObject jsonObject) {
-    return GSON.toJson(jsonObject);
-  }
-
-  public void serializeTo(String snapshotPath) throws IOException {
-    try (MLogWriter mLogWriter = new MLogWriter(snapshotPath)) {
-      root.serializeTo(mLogWriter);
-    }
-  }
-
-  public static MTree deserializeFrom(File mtreeSnapshot) {
-    try (MLogReader mLogReader = new MLogReader(mtreeSnapshot)) {
-      return new MTree(deserializeFromReader(mLogReader));
-    } catch (IOException e) {
-      logger.warn("Failed to deserialize from {}. Use a new MTree.", 
mtreeSnapshot.getPath());
-      return new MTree();
-    }
-  }
-
-  @SuppressWarnings("squid:S3776") // Suppress high Cognitive Complexity 
warning
-  private static InternalMNode deserializeFromReader(MLogReader mLogReader) {
-    Deque<IMNode> nodeStack = new ArrayDeque<>();
-    IMNode node = null;
-    while (mLogReader.hasNext()) {
-      PhysicalPlan plan = null;
-      try {
-        plan = mLogReader.next();
-        if (plan == null) {
-          continue;
-        }
-        int childrenSize = 0;
-        if (plan instanceof StorageGroupMNodePlan) {
-          node = StorageGroupMNode.deserializeFrom((StorageGroupMNodePlan) 
plan);
-          childrenSize = ((StorageGroupMNodePlan) plan).getChildSize();
-        } else if (plan instanceof MeasurementMNodePlan) {
-          node = MeasurementMNode.deserializeFrom((MeasurementMNodePlan) plan);
-          childrenSize = ((MeasurementMNodePlan) plan).getChildSize();
-        } else if (plan instanceof MNodePlan) {
-          node = InternalMNode.deserializeFrom((MNodePlan) plan);
-          childrenSize = ((MNodePlan) plan).getChildSize();
-        }
-
-        if (childrenSize != 0) {
-          ConcurrentHashMap<String, IMNode> childrenMap = new 
ConcurrentHashMap<>();
-          for (int i = 0; i < childrenSize; i++) {
-            IMNode child = nodeStack.removeFirst();
-            childrenMap.put(child.getName(), child);
-            if (child.isMeasurement()) {
-              if (!node.isEntity()) {
-                node = MNodeUtils.setToEntity(node);
-              }
-              String alias = child.getAsMeasurementMNode().getAlias();
-              if (alias != null) {
-                node.getAsEntityMNode().addAlias(alias, 
child.getAsMeasurementMNode());
-              }
-            }
-            child.setParent(node);
-          }
-          node.setChildren(childrenMap);
-        }
-        nodeStack.push(node);
-      } catch (Exception e) {
-        logger.error(
-            "Can not operate cmd {} for err:", plan == null ? "" : 
plan.getOperatorType(), e);
-      }
-    }
-    if (!IoTDBConstant.PATH_ROOT.equals(node.getName())) {
-      logger.error("Snapshot file corrupted!");
-      //      throw new MetadataException("Snapshot file corrupted!");
-    }
-
-    return (InternalMNode) node;
+    store.createSnapshot();
   }
 
   @Override
   public String toString() {
-    JsonObject jsonObject = new JsonObject();
-    jsonObject.add(root.getName(), mNodeToJSON(root, null));
-    return jsonToString(jsonObject);
-  }
-
-  private JsonObject mNodeToJSON(IMNode node, String storageGroupName) {
-    JsonObject jsonObject = new JsonObject();
-    if (node.getChildren().size() > 0) {
-      if (node.isStorageGroup()) {
-        storageGroupName = node.getFullPath();
-      }
-      for (IMNode child : node.getChildren().values()) {
-        jsonObject.add(child.getName(), mNodeToJSON(child, storageGroupName));
-      }
-    } else if (node.isMeasurement()) {
-      IMeasurementMNode leafMNode = node.getAsMeasurementMNode();
-      jsonObject.add("DataType", 
GSON.toJsonTree(leafMNode.getSchema().getType()));
-      jsonObject.add("Encoding", 
GSON.toJsonTree(leafMNode.getSchema().getEncodingType()));
-      jsonObject.add("Compressor", 
GSON.toJsonTree(leafMNode.getSchema().getCompressor()));
-      if (leafMNode.getSchema().getProps() != null) {
-        jsonObject.addProperty("args", 
leafMNode.getSchema().getProps().toString());
-      }
-      jsonObject.addProperty("StorageGroup", storageGroupName);
-    }
-    return jsonObject;
+    return store.toString();
   }
   // endregion
 
@@ -340,42 +177,9 @@ public class MTree implements Serializable {
       throw new IllegalPathException(path.getFullPath());
     }
     MetaFormatUtils.checkTimeseries(path);
-    IMNode cur = root;
-    boolean hasSetStorageGroup = false;
-    Template upperTemplate = cur.getSchemaTemplate();
-    // e.g, path = root.sg.d1.s1,  create internal nodes and set cur to d1 node
-    for (int i = 1; i < nodeNames.length - 1; i++) {
-      if (cur.isMeasurement()) {
-        throw new PathAlreadyExistException(cur.getFullPath());
-      }
-      if (cur.isStorageGroup()) {
-        hasSetStorageGroup = true;
-      }
-      String childName = nodeNames[i];
-
-      // even template not in use, measurement path shall not be conflict with 
MTree
-      if (upperTemplate != null && upperTemplate.getDirectNode(childName) != 
null) {
-        throw new TemplateImcompatibeException(
-            path.getFullPath(), upperTemplate.getName(), childName);
-      }
-
-      if (!cur.hasChild(childName)) {
-        if (!hasSetStorageGroup) {
-          throw new StorageGroupNotSetException("Storage group should be 
created first");
-        }
-
-        cur.addChild(childName, new InternalMNode(cur, childName));
-      }
-      cur = cur.getChild(childName);
-
-      if (cur.getSchemaTemplate() != null) {
-        upperTemplate = cur.getSchemaTemplate();
-      }
-    }
-
-    if (cur.isMeasurement()) {
-      throw new PathAlreadyExistException(cur.getFullPath());
-    }
+    Pair<IMNode, Template> pair = 
checkAndAutoCreateInternalPath(path.getDevicePath());
+    IMNode device = pair.left;
+    Template upperTemplate = pair.right;
 
     MetaFormatUtils.checkTimeseriesProps(path.getFullPath(), props);
 
@@ -384,11 +188,11 @@ public class MTree implements Serializable {
     // synchronize check and add, we need addChild and add Alias become atomic 
operation
     // only write on mtree will be synchronized
     synchronized (this) {
-      if (cur.hasChild(leafName)) {
+      if (store.hasChild(device, leafName)) {
         throw new PathAlreadyExistException(path.getFullPath());
       }
 
-      if (alias != null && cur.hasChild(alias)) {
+      if (alias != null && store.hasChild(device, alias)) {
         throw new AliasAlreadyExistException(path.getFullPath(), alias);
       }
 
@@ -397,7 +201,13 @@ public class MTree implements Serializable {
         throw new TemplateImcompatibeException(path.getFullPath(), 
upperTemplate.getName());
       }
 
-      IEntityMNode entityMNode = MNodeUtils.setToEntity(cur);
+      IEntityMNode entityMNode;
+      if (device.isEntity()) {
+        entityMNode = device.getAsEntityMNode();
+      } else {
+        entityMNode = MNodeUtils.setToEntity(device);
+        store.updateMNode(entityMNode);
+      }
 
       IMeasurementMNode measurementMNode =
           MeasurementMNode.getMeasurementMNode(
@@ -405,10 +215,10 @@ public class MTree implements Serializable {
               leafName,
               new UnaryMeasurementSchema(leafName, dataType, encoding, 
compressor, props),
               alias);
-      entityMNode.addChild(leafName, measurementMNode);
+      store.addChild(entityMNode, leafName, measurementMNode);
       // link alias to LeafMNode
       if (alias != null) {
-        entityMNode.addAlias(alias, measurementMNode);
+        store.addAlias(entityMNode, alias, measurementMNode);
       }
       return measurementMNode;
     }
@@ -433,14 +243,14 @@ public class MTree implements Serializable {
       throws MetadataException {
     MetaFormatUtils.checkSchemaMeasurementNames(measurements);
     Pair<IMNode, Template> pair = checkAndAutoCreateInternalPath(devicePath);
-    IMNode cur = pair.left;
+    IMNode device = pair.left;
     Template upperTemplate = pair.right;
 
     // synchronize check and add, we need addChild and add Alias become atomic 
operation
     // only write on mtree will be synchronized
     synchronized (this) {
       for (String measurement : measurements) {
-        if (cur.hasChild(measurement)) {
+        if (store.hasChild(device, measurement)) {
           throw new PathAlreadyExistException(devicePath.getFullPath() + "." + 
measurement);
         }
       }
@@ -455,14 +265,18 @@ public class MTree implements Serializable {
         }
       }
 
-      if (cur.isEntity()
-          && !cur.getAsEntityMNode().isAligned()
-          && (!cur.getChildren().isEmpty() || cur.isUseTemplate())) {
+      if (device.isEntity() && !device.getAsEntityMNode().isAligned()) {
         throw new AlignedTimeseriesException(
             "Aligned timeseries cannot be created under this entity", 
devicePath.getFullPath());
       }
 
-      IEntityMNode entityMNode = MNodeUtils.setToEntity(cur);
+      IEntityMNode entityMNode;
+      if (device.isEntity()) {
+        entityMNode = device.getAsEntityMNode();
+      } else {
+        entityMNode = MNodeUtils.setToEntity(device);
+        store.updateMNode(entityMNode);
+      }
 
       for (int i = 0; i < measurements.size(); i++) {
         IMeasurementMNode measurementMNode =
@@ -472,7 +286,7 @@ public class MTree implements Serializable {
                 new UnaryMeasurementSchema(
                     measurements.get(i), dataTypes.get(i), encodings.get(i), 
compressors.get(i)),
                 null);
-        entityMNode.addChild(measurements.get(i), measurementMNode);
+        store.addChild(entityMNode, measurements.get(i), measurementMNode);
       }
       entityMNode.setAligned(true);
     }
@@ -486,23 +300,25 @@ public class MTree implements Serializable {
     }
     MetaFormatUtils.checkTimeseries(devicePath);
     IMNode cur = root;
+    IMNode child;
     boolean hasSetStorageGroup = false;
     Template upperTemplate = cur.getSchemaTemplate();
     // e.g, path = root.sg.d1.s1,  create internal nodes and set cur to d1 node
     for (int i = 1; i < nodeNames.length; i++) {
       String childName = nodeNames[i];
-      if (!cur.hasChild(childName)) {
+      child = store.getChild(cur, childName);
+      if (child == null) {
         if (!hasSetStorageGroup) {
           throw new StorageGroupNotSetException("Storage group should be 
created first");
         }
         if (upperTemplate != null && upperTemplate.getDirectNode(childName) != 
null) {
-          throw new PathAlreadyExistException(
-              cur.getPartialPath().concatNode(childName).getFullPath()
-                  + " ( which is incompatible with template )");
+          throw new TemplateImcompatibeException(
+              devicePath.getFullPath(), upperTemplate.getName(), childName);
         }
-        cur.addChild(childName, new InternalMNode(cur, childName));
+        child = new InternalMNode(cur, childName);
+        store.addChild(cur, childName, child);
       }
-      cur = cur.getChild(childName);
+      cur = child;
 
       if (cur.isMeasurement()) {
         throw new PathAlreadyExistException(cur.getFullPath());
@@ -538,14 +354,17 @@ public class MTree implements Serializable {
     IMeasurementMNode deletedNode = getMeasurementMNode(path);
     IEntityMNode parent = deletedNode.getParent();
     // delete the last node of path
-    parent.deleteChild(path.getMeasurement());
+    store.deleteChild(parent, path.getMeasurement());
     if (deletedNode.getAlias() != null) {
-      parent.deleteAliasChild((deletedNode.getAlias()));
+      store.deleteAliasChild(parent, deletedNode.getAlias());
     }
     IMNode curNode = parent;
     if (!parent.isUseTemplate()) {
       boolean hasMeasurement = false;
-      for (IMNode child : parent.getChildren().values()) {
+      IMNode child;
+      Iterator<IMNode> iterator = store.getChildrenIterator(parent);
+      while (iterator.hasNext()) {
+        child = iterator.next();
         if (child.isMeasurement()) {
           hasMeasurement = true;
           break;
@@ -554,6 +373,7 @@ public class MTree implements Serializable {
       if (!hasMeasurement) {
         synchronized (this) {
           curNode = MNodeUtils.setToInternal(parent);
+          store.updateMNode(curNode);
         }
       }
     }
@@ -564,7 +384,7 @@ public class MTree implements Serializable {
       if (curNode.isStorageGroup()) {
         return new Pair<>(curNode.getPartialPath(), deletedNode);
       }
-      curNode.getParent().deleteChild(curNode.getName());
+      store.deleteChild(curNode.getParent(), curNode.getName());
       curNode = curNode.getParent();
     }
     return new Pair<>(null, deletedNode);
@@ -585,23 +405,25 @@ public class MTree implements Serializable {
       throw new IllegalPathException(deviceId.getFullPath());
     }
     IMNode cur = root;
+    IMNode child;
     Template upperTemplate = cur.getSchemaTemplate();
     for (int i = 1; i < nodeNames.length; i++) {
-      if (!cur.hasChild(nodeNames[i])) {
+      child = store.getChild(cur, nodeNames[i]);
+      if (child == null) {
         if (cur.isUseTemplate() && upperTemplate.getDirectNode(nodeNames[i]) 
!= null) {
           throw new PathAlreadyExistException(
               cur.getPartialPath().concatNode(nodeNames[i]).getFullPath());
         }
         if (i == sgLevel) {
-          cur.addChild(
-              nodeNames[i],
+          child =
               new StorageGroupMNode(
-                  cur, nodeNames[i], 
IoTDBDescriptor.getInstance().getConfig().getDefaultTTL()));
+                  cur, nodeNames[i], 
IoTDBDescriptor.getInstance().getConfig().getDefaultTTL());
         } else {
-          cur.addChild(nodeNames[i], new InternalMNode(cur, nodeNames[i]));
+          child = new InternalMNode(cur, nodeNames[i]);
         }
+        store.addChild(cur, nodeNames[i], child);
       }
-      cur = cur.getChild(nodeNames[i]);
+      cur = child;
       // update upper template
       upperTemplate = cur.getSchemaTemplate() == null ? upperTemplate : 
cur.getSchemaTemplate();
     }
@@ -613,7 +435,9 @@ public class MTree implements Serializable {
     // synchronize check and replace, we need replaceChild become atomic 
operation
     // only write on mtree will be synchronized
     synchronized (this) {
-      return MNodeUtils.setToEntity(node);
+      IEntityMNode entityMNode = MNodeUtils.setToEntity(node);
+      store.updateMNode(entityMNode);
+      return entityMNode;
     }
   }
   // endregion
@@ -631,22 +455,24 @@ public class MTree implements Serializable {
       throw new IllegalPathException(path.getFullPath());
     }
     IMNode cur = root;
+    IMNode child;
     Template upperTemplate = cur.getSchemaTemplate();
     int i = 1;
     // e.g., path = root.a.b.sg, create internal nodes for a, b
     while (i < nodeNames.length - 1) {
-      IMNode temp = cur.getChild(nodeNames[i]);
-      if (temp == null) {
+      child = store.getChild(cur, nodeNames[i]);
+      if (child == null) {
         if (cur.isUseTemplate() && upperTemplate.hasSchema(nodeNames[i])) {
           throw new PathAlreadyExistException(
               cur.getPartialPath().concatNode(nodeNames[i]).getFullPath());
         }
-        cur.addChild(nodeNames[i], new InternalMNode(cur, nodeNames[i]));
-      } else if (temp.isStorageGroup()) {
+        child = new InternalMNode(cur, nodeNames[i]);
+        store.addChild(cur, nodeNames[i], child);
+      } else if (child.isStorageGroup()) {
         // before set storage group, check whether the exists or not
-        throw new StorageGroupAlreadySetException(temp.getFullPath());
+        throw new StorageGroupAlreadySetException(child.getFullPath());
       }
-      cur = cur.getChild(nodeNames[i]);
+      cur = child;
       upperTemplate = cur.getSchemaTemplate() == null ? upperTemplate : 
cur.getSchemaTemplate();
       i++;
     }
@@ -654,9 +480,10 @@ public class MTree implements Serializable {
     // synchronize check and add, we need addChild become atomic operation
     // only write on mtree will be synchronized
     synchronized (this) {
-      if (cur.hasChild(nodeNames[i])) {
+      child = store.getChild(cur, nodeNames[i]);
+      if (child != null) {
         // node b has child sg
-        if (cur.getChild(nodeNames[i]).isStorageGroup()) {
+        if (child.isStorageGroup()) {
           throw new StorageGroupAlreadySetException(path.getFullPath());
         } else {
           throw new StorageGroupAlreadySetException(path.getFullPath(), true);
@@ -669,7 +496,7 @@ public class MTree implements Serializable {
         IStorageGroupMNode storageGroupMNode =
             new StorageGroupMNode(
                 cur, nodeNames[i], 
IoTDBDescriptor.getInstance().getConfig().getDefaultTTL());
-        cur.addChild(nodeNames[i], storageGroupMNode);
+        store.addChild(cur, nodeNames[i], storageGroupMNode);
       }
     }
   }
@@ -682,7 +509,7 @@ public class MTree implements Serializable {
     }
     // Suppose current system has root.a.b.sg1, root.a.sg2, and delete 
root.a.b.sg1
     // delete the storage group node sg1
-    cur.getParent().deleteChild(cur.getName());
+    store.deleteChild(cur.getParent(), cur.getName());
 
     // collect all the LeafMNode in this storage group
     List<IMeasurementMNode> leafMNodes = new LinkedList<>();
@@ -690,7 +517,10 @@ public class MTree implements Serializable {
     queue.add(cur);
     while (!queue.isEmpty()) {
       IMNode node = queue.poll();
-      for (IMNode child : node.getChildren().values()) {
+      Iterator<IMNode> iterator = store.getChildrenIterator(node);
+      IMNode child;
+      while (iterator.hasNext()) {
+        child = iterator.next();
         if (child.isMeasurement()) {
           leafMNodes.add(child.getAsMeasurementMNode());
         } else {
@@ -701,8 +531,8 @@ public class MTree implements Serializable {
 
     cur = cur.getParent();
     // delete node b while retain root.a.sg2
-    while (!IoTDBConstant.PATH_ROOT.equals(cur.getName()) && 
cur.getChildren().size() == 0) {
-      cur.getParent().deleteChild(cur.getName());
+    while (cur.isEmptyInternal()) {
+      store.deleteChild(cur.getParent(), cur.getName());
       cur = cur.getParent();
     }
     return leafMNodes;
@@ -717,19 +547,21 @@ public class MTree implements Serializable {
    */
   public boolean isPathExist(PartialPath path) {
     String[] nodeNames = path.getNodes();
-    IMNode cur = root;
     if (!nodeNames[0].equals(root.getName())) {
       return false;
     }
+    IMNode cur = root;
+    IMNode child;
     Template upperTemplate = cur.getSchemaTemplate();
     for (int i = 1; i < nodeNames.length; i++) {
-      if (!cur.hasChild(nodeNames[i])) {
+      child = store.getChild(cur, nodeNames[i]);
+      if (child == null) {
         if (!cur.isUseTemplate() || upperTemplate.getDirectNode(nodeNames[i]) 
== null) {
           return false;
         }
-        cur = upperTemplate.getDirectNode(nodeNames[i]);
+        child = upperTemplate.getDirectNode(nodeNames[i]);
       }
-      cur = cur.getChild(nodeNames[i]);
+      cur = child;
       if (cur.isMeasurement()) {
         return i == nodeNames.length - 1;
       }
@@ -756,13 +588,13 @@ public class MTree implements Serializable {
     IMNode cur = root;
     int i = 1;
     while (i < nodeNames.length - 1) {
-      cur = cur.getChild(nodeNames[i]);
+      cur = store.getChild(cur, nodeNames[i]);
       if (cur == null || cur.isStorageGroup()) {
         return false;
       }
       i++;
     }
-    cur = cur.getChild(nodeNames[i]);
+    cur = store.getChild(cur, nodeNames[i]);
     return cur != null && cur.isStorageGroup();
   }
 
@@ -771,7 +603,7 @@ public class MTree implements Serializable {
     String[] nodes = path.getNodes();
     IMNode cur = root;
     for (int i = 1; i < nodes.length; i++) {
-      cur = cur.getChild(nodes[i]);
+      cur = store.getChild(cur, nodes[i]);
       if (cur == null) {
         return false;
       } else if (cur.isStorageGroup()) {
@@ -792,7 +624,7 @@ public class MTree implements Serializable {
     String[] nodes = path.getNodes();
     IMNode cur = root;
     for (int i = 1; i < nodes.length; i++) {
-      cur = cur.getChild(nodes[i]);
+      cur = store.getChild(cur, nodes[i]);
       if (cur == null) {
         throw new StorageGroupNotSetException(path.getFullPath());
       } else if (cur.isStorageGroup()) {
@@ -832,7 +664,7 @@ public class MTree implements Serializable {
       throws MetadataException {
     List<PartialPath> result = new LinkedList<>();
     StorageGroupCollector<List<PartialPath>> collector =
-        new StorageGroupCollector<List<PartialPath>>(root, pathPattern) {
+        new StorageGroupCollector<List<PartialPath>>(root, pathPattern, store) 
{
           @Override
           protected void collectStorageGroup(IStorageGroupMNode node) {
             result.add(node.getPartialPath());
@@ -848,19 +680,8 @@ public class MTree implements Serializable {
    *
    * @return a list contains all distinct storage groups
    */
-  public List<PartialPath> getAllStorageGroupPaths() {
-    List<PartialPath> res = new ArrayList<>();
-    Deque<IMNode> nodeStack = new ArrayDeque<>();
-    nodeStack.add(root);
-    while (!nodeStack.isEmpty()) {
-      IMNode current = nodeStack.pop();
-      if (current.isStorageGroup()) {
-        res.add(current.getPartialPath());
-      } else {
-        nodeStack.addAll(current.getChildren().values());
-      }
-    }
-    return res;
+  public List<PartialPath> getAllStorageGroupPaths() throws MetadataException {
+    return getMatchedStorageGroups(ALL_MATCH_PATTERN);
   }
 
   /**
@@ -871,7 +692,7 @@ public class MTree implements Serializable {
   public Map<String, String> groupPathByStorageGroup(PartialPath path) throws 
MetadataException {
     Map<String, String> result = new HashMap<>();
     StorageGroupCollector<Map<String, String>> collector =
-        new StorageGroupCollector<Map<String, String>>(root, path) {
+        new StorageGroupCollector<Map<String, String>>(root, path, store) {
           @Override
           protected void collectStorageGroup(IStorageGroupMNode node) {
             PartialPath sgPath = node.getPartialPath();
@@ -895,7 +716,7 @@ public class MTree implements Serializable {
       throws MetadataException {
     Set<PartialPath> result = new TreeSet<>();
     EntityCollector<Set<PartialPath>> collector =
-        new EntityCollector<Set<PartialPath>>(root, pathPattern) {
+        new EntityCollector<Set<PartialPath>>(root, pathPattern, store) {
           @Override
           protected void collectEntity(IEntityMNode node) throws 
MetadataException {
             result.add(getCurrentPartialPath(node));
@@ -910,7 +731,7 @@ public class MTree implements Serializable {
     List<ShowDevicesResult> res = new ArrayList<>();
     EntityCollector<List<ShowDevicesResult>> collector =
         new EntityCollector<List<ShowDevicesResult>>(
-            root, plan.getPath(), plan.getLimit(), plan.getOffset()) {
+            root, plan.getPath(), store, plan.getLimit(), plan.getOffset()) {
           @Override
           protected void collectEntity(IEntityMNode node) throws 
MetadataException {
             PartialPath device = getCurrentPartialPath(node);
@@ -930,7 +751,7 @@ public class MTree implements Serializable {
   public Set<PartialPath> getDevicesByTimeseries(PartialPath timeseries) 
throws MetadataException {
     Set<PartialPath> result = new HashSet<>();
     MeasurementCollector<Set<PartialPath>> collector =
-        new MeasurementCollector<Set<PartialPath>>(root, timeseries) {
+        new MeasurementCollector<Set<PartialPath>>(root, timeseries, store) {
           @Override
           protected void collectMeasurement(IMeasurementMNode node) throws 
MetadataException {
             result.add(getCurrentPartialPath(node).getDevicePath());
@@ -963,7 +784,7 @@ public class MTree implements Serializable {
       PartialPath pathPattern, int limit, int offset) throws MetadataException 
{
     List<MeasurementPath> result = new LinkedList<>();
     MeasurementCollector<List<PartialPath>> collector =
-        new MeasurementCollector<List<PartialPath>>(root, pathPattern, limit, 
offset) {
+        new MeasurementCollector<List<PartialPath>>(root, pathPattern, store, 
limit, offset) {
           @Override
           protected void collectMeasurement(IMeasurementMNode node) throws 
MetadataException {
             MeasurementPath path = getCurrentMeasurementPathInTraverse(node);
@@ -1021,7 +842,7 @@ public class MTree implements Serializable {
     List<Pair<PartialPath, String[]>> result = new LinkedList<>();
     MeasurementCollector<List<Pair<PartialPath, String[]>>> collector =
         new MeasurementCollector<List<Pair<PartialPath, String[]>>>(
-            root, pathPattern, limit, offset) {
+            root, pathPattern, store, limit, offset) {
           @Override
           protected void collectMeasurement(IMeasurementMNode node) throws 
MetadataException {
             IMeasurementSchema measurementSchema = node.getSchema();
@@ -1063,7 +884,7 @@ public class MTree implements Serializable {
       PartialPath prefixPath) throws MetadataException {
     Map<PartialPath, IMeasurementSchema> result = new HashMap<>();
     MeasurementCollector<List<IMeasurementSchema>> collector =
-        new MeasurementCollector<List<IMeasurementSchema>>(root, prefixPath) {
+        new MeasurementCollector<List<IMeasurementSchema>>(root, prefixPath, 
store) {
           @Override
           protected void collectMeasurement(IMeasurementMNode node) throws 
MetadataException {
             result.put(getCurrentPartialPath(node), node.getSchema());
@@ -1083,7 +904,7 @@ public class MTree implements Serializable {
       PartialPath prefixPath, List<IMeasurementSchema> measurementSchemas)
       throws MetadataException {
     MeasurementCollector<List<IMeasurementSchema>> collector =
-        new MeasurementCollector<List<IMeasurementSchema>>(root, prefixPath) {
+        new MeasurementCollector<List<IMeasurementSchema>>(root, prefixPath, 
store) {
           @Override
           protected void collectMeasurement(IMeasurementMNode node) {
             measurementSchemas.add(node.getSchema());
@@ -1102,7 +923,7 @@ public class MTree implements Serializable {
       PartialPath prefixPath, Collection<TimeseriesSchema> timeseriesSchemas)
       throws MetadataException {
     MeasurementCollector<List<IMeasurementSchema>> collector =
-        new MeasurementCollector<List<IMeasurementSchema>>(root, prefixPath) {
+        new MeasurementCollector<List<IMeasurementSchema>>(root, prefixPath, 
store) {
           @Override
           protected void collectMeasurement(IMeasurementMNode node) throws 
MetadataException {
             IMeasurementSchema nodeSchema = node.getSchema();
@@ -1135,7 +956,8 @@ public class MTree implements Serializable {
   public Set<String> getChildNodePathInNextLevel(PartialPath pathPattern) 
throws MetadataException {
     try {
       MNodeCollector<Set<String>> collector =
-          new MNodeCollector<Set<String>>(root, 
pathPattern.concatNode(ONE_LEVEL_PATH_WILDCARD)) {
+          new MNodeCollector<Set<String>>(
+              root, pathPattern.concatNode(ONE_LEVEL_PATH_WILDCARD), store) {
             @Override
             protected void transferToResult(IMNode node) {
               try {
@@ -1168,7 +990,8 @@ public class MTree implements Serializable {
   public Set<String> getChildNodeNameInNextLevel(PartialPath pathPattern) 
throws MetadataException {
     try {
       MNodeCollector<Set<String>> collector =
-          new MNodeCollector<Set<String>>(root, 
pathPattern.concatNode(ONE_LEVEL_PATH_WILDCARD)) {
+          new MNodeCollector<Set<String>>(
+              root, pathPattern.concatNode(ONE_LEVEL_PATH_WILDCARD), store) {
             @Override
             protected void transferToResult(IMNode node) {
               resultSet.add(node.getName());
@@ -1186,7 +1009,7 @@ public class MTree implements Serializable {
   public List<PartialPath> getNodesListInGivenLevel(
       PartialPath pathPattern, int nodeLevel, StorageGroupFilter filter) 
throws MetadataException {
     MNodeCollector<List<PartialPath>> collector =
-        new MNodeCollector<List<PartialPath>>(root, pathPattern) {
+        new MNodeCollector<List<PartialPath>>(root, pathPattern, store) {
           @Override
           protected void transferToResult(IMNode node) {
             try {
@@ -1211,7 +1034,7 @@ public class MTree implements Serializable {
    * @param pathPattern a path pattern or a full path, may contain wildcard
    */
   public int getAllTimeseriesCount(PartialPath pathPattern) throws 
MetadataException {
-    CounterTraverser counter = new MeasurementCounter(root, pathPattern);
+    CounterTraverser counter = new MeasurementCounter(root, pathPattern, 
store);
     counter.traverse();
     return counter.getCount();
   }
@@ -1222,7 +1045,7 @@ public class MTree implements Serializable {
    * @param pathPattern a path pattern or a full path, may contain wildcard
    */
   public int getDevicesNum(PartialPath pathPattern) throws MetadataException {
-    CounterTraverser counter = new EntityCounter(root, pathPattern);
+    CounterTraverser counter = new EntityCounter(root, pathPattern, store);
     counter.traverse();
     return counter.getCount();
   }
@@ -1233,7 +1056,7 @@ public class MTree implements Serializable {
    * @param pathPattern a path pattern or a full path, may contain wildcard.
    */
   public int getStorageGroupNum(PartialPath pathPattern) throws 
MetadataException {
-    CounterTraverser counter = new StorageGroupCounter(root, pathPattern);
+    CounterTraverser counter = new StorageGroupCounter(root, pathPattern, 
store);
     counter.traverse();
     return counter.getCount();
   }
@@ -1241,7 +1064,7 @@ public class MTree implements Serializable {
   /** Get the count of nodes in the given level matching the given path. */
   public int getNodesCountInGivenLevel(PartialPath pathPattern, int level)
       throws MetadataException {
-    MNodeLevelCounter counter = new MNodeLevelCounter(root, pathPattern, 
level);
+    MNodeLevelCounter counter = new MNodeLevelCounter(root, pathPattern, 
store, level);
     counter.traverse();
     return counter.getCount();
   }
@@ -1274,7 +1097,7 @@ public class MTree implements Serializable {
       if (cur.getSchemaTemplate() != null) {
         upperTemplate = cur.getSchemaTemplate();
       }
-      IMNode next = cur.getChild(nodes[i]);
+      IMNode next = store.getChild(cur, nodes[i]);
       if (next == null) {
         if (upperTemplate == null
             || !cur.isUseTemplate()
@@ -1307,8 +1130,8 @@ public class MTree implements Serializable {
         upperTemplate = cur.getSchemaTemplate();
       }
 
-      if (cur.getChild(nodes[i]) != null) {
-        cur = cur.getChild(nodes[i]);
+      if (store.getChild(cur, nodes[i]) != null) {
+        cur = store.getChild(cur, nodes[i]);
       } else {
         // seek child in template
         if (!storageGroupChecked) {
@@ -1363,7 +1186,7 @@ public class MTree implements Serializable {
     }
     IMNode cur = root;
     for (int i = 1; i < nodes.length; i++) {
-      cur = cur.getChild(nodes[i]);
+      cur = store.getChild(cur, nodes[i]);
       if (cur == null) {
         break;
       }
@@ -1375,19 +1198,17 @@ public class MTree implements Serializable {
   }
 
   /** Get all storage group MNodes */
-  public List<IStorageGroupMNode> getAllStorageGroupNodes() {
-    List<IStorageGroupMNode> ret = new ArrayList<>();
-    Deque<IMNode> nodeStack = new ArrayDeque<>();
-    nodeStack.add(root);
-    while (!nodeStack.isEmpty()) {
-      IMNode current = nodeStack.pop();
-      if (current.isStorageGroup()) {
-        ret.add(current.getAsStorageGroupMNode());
-      } else {
-        nodeStack.addAll(current.getChildren().values());
-      }
-    }
-    return ret;
+  public List<IStorageGroupMNode> getAllStorageGroupNodes() throws 
MetadataException {
+    List<IStorageGroupMNode> result = new LinkedList<>();
+    StorageGroupCollector<List<IStorageGroupMNode>> collector =
+        new StorageGroupCollector<List<IStorageGroupMNode>>(root, 
ALL_MATCH_PATTERN, store) {
+          @Override
+          protected void collectStorageGroup(IStorageGroupMNode node) {
+            result.add(node);
+          }
+        };
+    collector.traverse();
+    return result;
   }
 
   public IMeasurementMNode getMeasurementMNode(PartialPath path) throws 
MetadataException {
@@ -1409,21 +1230,23 @@ public class MTree implements Serializable {
    */
   public void checkTemplateOnPath(PartialPath path) throws MetadataException {
     String[] nodeNames = path.getNodes();
-    IMNode cur = root;
     if (!nodeNames[0].equals(root.getName())) {
       return;
     }
+    IMNode cur = root;
     if (cur.getSchemaTemplate() != null) {
       throw new MetadataException("Template already exists on " + 
cur.getFullPath());
     }
+    IMNode child;
     for (int i = 1; i < nodeNames.length; i++) {
       if (cur.isMeasurement()) {
         return;
       }
-      if (!cur.hasChild(nodeNames[i])) {
+      child = store.getChild(cur, nodeNames[i]);
+      if (child == null) {
         return;
       }
-      cur = cur.getChild(nodeNames[i]);
+      cur = child;
       if (cur.getSchemaTemplate() != null) {
         throw new MetadataException("Template already exists on " + 
cur.getFullPath());
       }
@@ -1460,7 +1283,10 @@ public class MTree implements Serializable {
       if (!mountedNode.isEntity()) {
         return setToEntity(mountedNode);
       } else {
-        for (IMNode child : mountedNode.getChildren().values()) {
+        IMNode child;
+        Iterator<IMNode> iterator = store.getChildrenIterator(mountedNode);
+        while (iterator.hasNext()) {
+          child = iterator.next();
           if (child.isMeasurement()) {
             if (template.isDirectAligned() != 
mountedNode.getAsEntityMNode().isAligned()) {
               throw new MetadataException(
@@ -1483,7 +1309,10 @@ public class MTree implements Serializable {
     if (node.isMeasurement()) {
       return;
     }
-    for (IMNode child : node.getChildren().values()) {
+    IMNode child;
+    Iterator<IMNode> iterator = store.getChildrenIterator(node);
+    while (iterator.hasNext()) {
+      child = iterator.next();
       if (child.isMeasurement()) {
         continue;
       }
@@ -1498,7 +1327,10 @@ public class MTree implements Serializable {
     if (node.isMeasurement()) {
       return;
     }
-    for (IMNode child : node.getChildren().values()) {
+    IMNode child;
+    Iterator<IMNode> iterator = store.getChildrenIterator(node);
+    while (iterator.hasNext()) {
+      child = iterator.next();
       if (child.isMeasurement()) {
         continue;
       }
@@ -1520,10 +1352,12 @@ public class MTree implements Serializable {
     }
     String[] pathNodes = path.getNodes();
     IMNode cur = root;
+    IMNode child;
     Template upperTemplate = cur.getUpperTemplate();
     for (int i = 1; i < pathNodes.length; i++) {
-      if (cur.hasChild(pathNodes[i])) {
-        cur = cur.getChild(pathNodes[i]);
+      child = store.getChild(cur, pathNodes[i]);
+      if (child != null) {
+        cur = child;
         if (cur.isMeasurement()) {
           return false;
         }
@@ -1556,16 +1390,17 @@ public class MTree implements Serializable {
   public int getMountedNodeIndexOnMeasurementPath(PartialPath measurementPath)
       throws MetadataException {
     String[] fullPathNodes = measurementPath.getNodes();
-    IMNode cur = root;
-    Template upperTemplate = cur.getSchemaTemplate();
-
-    if (!cur.getName().equals(fullPathNodes[0])) {
+    if (!root.getName().equals(fullPathNodes[0])) {
       throw new IllegalPathException(measurementPath.toString());
     }
 
+    IMNode cur = root;
+    IMNode child;
+    Template upperTemplate = cur.getSchemaTemplate();
     for (int index = 1; index < fullPathNodes.length; index++) {
       upperTemplate = cur.getSchemaTemplate() != null ? 
cur.getSchemaTemplate() : upperTemplate;
-      if (!cur.hasChild(fullPathNodes[index])) {
+      child = store.getChild(cur, fullPathNodes[index]);
+      if (child == null) {
         if (upperTemplate != null) {
           String suffixPath =
               new PartialPath(Arrays.copyOfRange(fullPathNodes, index, 
fullPathNodes.length))
@@ -1588,7 +1423,7 @@ public class MTree implements Serializable {
         }
       } else {
         // has child on MTree
-        cur = cur.getChild(fullPathNodes[index]);
+        cur = child;
       }
     }
     // all nodes on path exist in MTree, device node should be the penultimate 
one
@@ -1596,51 +1431,4 @@ public class MTree implements Serializable {
   }
 
   // endregion
-
-  // region TestOnly Interface
-  /** combine multiple metadata in string format */
-  @TestOnly
-  public static JsonObject combineMetadataInStrings(String[] metadataStrs) {
-    JsonObject[] jsonObjects = new JsonObject[metadataStrs.length];
-    for (int i = 0; i < jsonObjects.length; i++) {
-      jsonObjects[i] = GSON.fromJson(metadataStrs[i], JsonObject.class);
-    }
-
-    JsonObject root = jsonObjects[0];
-    for (int i = 1; i < jsonObjects.length; i++) {
-      root = combineJsonObjects(root, jsonObjects[i]);
-    }
-
-    return root;
-  }
-
-  private static JsonObject combineJsonObjects(JsonObject a, JsonObject b) {
-    JsonObject res = new JsonObject();
-
-    Set<String> retainSet = new HashSet<>(a.keySet());
-    retainSet.retainAll(b.keySet());
-    Set<String> aCha = new HashSet<>(a.keySet());
-    Set<String> bCha = new HashSet<>(b.keySet());
-    aCha.removeAll(retainSet);
-    bCha.removeAll(retainSet);
-
-    for (String key : aCha) {
-      res.add(key, a.get(key));
-    }
-
-    for (String key : bCha) {
-      res.add(key, b.get(key));
-    }
-    for (String key : retainSet) {
-      JsonElement v1 = a.get(key);
-      JsonElement v2 = b.get(key);
-      if (v1 instanceof JsonObject && v2 instanceof JsonObject) {
-        res.add(key, combineJsonObjects((JsonObject) v1, (JsonObject) v2));
-      } else {
-        res.add(v1.getAsString(), v2);
-      }
-    }
-    return res;
-  }
-  // endregion
 }
diff --git 
a/server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/Traverser.java
 
b/server/src/main/java/org/apache/iotdb/db/metadata/mtree/service/traverser/Traverser.java
similarity index 87%
rename from 
server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/Traverser.java
rename to 
server/src/main/java/org/apache/iotdb/db/metadata/mtree/service/traverser/Traverser.java
index 4385a63..059f3ad 100644
--- 
a/server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/Traverser.java
+++ 
b/server/src/main/java/org/apache/iotdb/db/metadata/mtree/service/traverser/Traverser.java
@@ -16,11 +16,12 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.iotdb.db.metadata.mtree.traverser;
+package org.apache.iotdb.db.metadata.mtree.service.traverser;
 
 import org.apache.iotdb.db.exception.metadata.IllegalPathException;
 import org.apache.iotdb.db.exception.metadata.MetadataException;
 import org.apache.iotdb.db.metadata.mnode.IMNode;
+import org.apache.iotdb.db.metadata.mtree.store.IMTreeStore;
 import org.apache.iotdb.db.metadata.path.PartialPath;
 import org.apache.iotdb.db.metadata.template.Template;
 import org.apache.iotdb.tsfile.common.constant.TsFileConstant;
@@ -41,6 +42,8 @@ import static 
org.apache.iotdb.db.conf.IoTDBConstant.ONE_LEVEL_PATH_WILDCARD;
  */
 public abstract class Traverser {
 
+  protected IMTreeStore store;
+
   protected IMNode startNode;
   protected String[] nodes;
 
@@ -53,7 +56,7 @@ public abstract class Traverser {
   // default false means fullPath pattern match
   protected boolean isPrefixMatch = false;
 
-  public Traverser(IMNode startNode, PartialPath path) throws 
MetadataException {
+  public Traverser(IMNode startNode, PartialPath path, IMTreeStore store) 
throws MetadataException {
     String[] nodes = path.getNodes();
     if (nodes.length == 0 || !nodes[0].equals(startNode.getName())) {
       throw new IllegalPathException(
@@ -61,6 +64,7 @@ public abstract class Traverser {
     }
     this.startNode = startNode;
     this.nodes = nodes;
+    this.store = store;
     this.traverseContext = new ArrayDeque<>();
   }
 
@@ -143,7 +147,10 @@ public abstract class Traverser {
   protected void processMultiLevelWildcard(IMNode node, int idx, int level)
       throws MetadataException {
     traverseContext.push(node);
-    for (IMNode child : node.getChildren().values()) {
+    IMNode child;
+    Iterator<IMNode> iterator = store.getChildrenIterator(node);
+    while (iterator.hasNext()) {
+      child = iterator.next();
       traverse(child, idx + 1, level + 1);
     }
     traverseContext.pop();
@@ -154,8 +161,8 @@ public abstract class Traverser {
 
     Template upperTemplate = node.getUpperTemplate();
     traverseContext.push(node);
-    for (IMNode child : upperTemplate.getDirectNodes()) {
-      traverse(child, idx + 1, level + 1);
+    for (IMNode childInTemplate : upperTemplate.getDirectNodes()) {
+      traverse(childInTemplate, idx + 1, level + 1);
     }
     traverseContext.pop();
   }
@@ -164,7 +171,10 @@ public abstract class Traverser {
     boolean multiLevelWildcard = nodes[idx].equals(MULTI_LEVEL_PATH_WILDCARD);
     String targetNameRegex = nodes[idx + 1].replace("*", ".*");
     traverseContext.push(node);
-    for (IMNode child : node.getChildren().values()) {
+    IMNode child;
+    Iterator<IMNode> iterator = store.getChildrenIterator(node);
+    while (iterator.hasNext()) {
+      child = iterator.next();
       if (child.isMeasurement()) {
         String alias = child.getAsMeasurementMNode().getAlias();
         if (!Pattern.matches(targetNameRegex, child.getName())
@@ -182,7 +192,9 @@ public abstract class Traverser {
 
     if (multiLevelWildcard) {
       traverseContext.push(node);
-      for (IMNode child : node.getChildren().values()) {
+      iterator = store.getChildrenIterator(node);
+      while (iterator.hasNext()) {
+        child = iterator.next();
         traverse(child, idx, level + 1);
       }
       traverseContext.pop();
@@ -195,18 +207,18 @@ public abstract class Traverser {
     Template upperTemplate = node.getUpperTemplate();
 
     traverseContext.push(node);
-    for (IMNode child : upperTemplate.getDirectNodes()) {
-      if (!Pattern.matches(targetNameRegex, child.getName())) {
+    for (IMNode childInTemplate : upperTemplate.getDirectNodes()) {
+      if (!Pattern.matches(targetNameRegex, childInTemplate.getName())) {
         continue;
       }
-      traverse(child, idx + 1, level + 1);
+      traverse(childInTemplate, idx + 1, level + 1);
     }
     traverseContext.pop();
 
     if (multiLevelWildcard) {
       traverseContext.push(node);
-      for (IMNode child : upperTemplate.getDirectNodes()) {
-        traverse(child, idx, level + 1);
+      for (IMNode childInTemplate : upperTemplate.getDirectNodes()) {
+        traverse(childInTemplate, idx, level + 1);
       }
       traverseContext.pop();
     }
@@ -216,7 +228,7 @@ public abstract class Traverser {
   protected void processNameMatch(IMNode node, int idx, int level) throws 
MetadataException {
     boolean multiLevelWildcard = nodes[idx].equals(MULTI_LEVEL_PATH_WILDCARD);
     String targetName = nodes[idx + 1];
-    IMNode next = node.getChild(targetName);
+    IMNode next = store.getChild(node, targetName);
     if (next != null) {
       traverseContext.push(node);
       traverse(next, idx + 1, level + 1);
@@ -224,7 +236,10 @@ public abstract class Traverser {
     }
     if (multiLevelWildcard) {
       traverseContext.push(node);
-      for (IMNode child : node.getChildren().values()) {
+      IMNode child;
+      Iterator<IMNode> iterator = store.getChildrenIterator(node);
+      while (iterator.hasNext()) {
+        child = iterator.next();
         traverse(child, idx, level + 1);
       }
       traverseContext.pop();
diff --git 
a/server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/collector/CollectorTraverser.java
 
b/server/src/main/java/org/apache/iotdb/db/metadata/mtree/service/traverser/collector/CollectorTraverser.java
similarity index 84%
rename from 
server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/collector/CollectorTraverser.java
rename to 
server/src/main/java/org/apache/iotdb/db/metadata/mtree/service/traverser/collector/CollectorTraverser.java
index a9af73e..9ca9063 100644
--- 
a/server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/collector/CollectorTraverser.java
+++ 
b/server/src/main/java/org/apache/iotdb/db/metadata/mtree/service/traverser/collector/CollectorTraverser.java
@@ -16,11 +16,12 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.iotdb.db.metadata.mtree.traverser.collector;
+package org.apache.iotdb.db.metadata.mtree.service.traverser.collector;
 
 import org.apache.iotdb.db.exception.metadata.MetadataException;
 import org.apache.iotdb.db.metadata.mnode.IMNode;
-import org.apache.iotdb.db.metadata.mtree.traverser.Traverser;
+import org.apache.iotdb.db.metadata.mtree.service.traverser.Traverser;
+import org.apache.iotdb.db.metadata.mtree.store.IMTreeStore;
 import org.apache.iotdb.db.metadata.path.PartialPath;
 
 // This class defines the generic resultSet as traversal result and add more 
restrictions on MTree
@@ -37,13 +38,15 @@ public abstract class CollectorTraverser<T> extends 
Traverser {
 
   protected T resultSet;
 
-  public CollectorTraverser(IMNode startNode, PartialPath path) throws 
MetadataException {
-    super(startNode, path);
+  public CollectorTraverser(IMNode startNode, PartialPath path, IMTreeStore 
store)
+      throws MetadataException {
+    super(startNode, path, store);
   }
 
-  public CollectorTraverser(IMNode startNode, PartialPath path, int limit, int 
offset)
+  public CollectorTraverser(
+      IMNode startNode, PartialPath path, IMTreeStore store, int limit, int 
offset)
       throws MetadataException {
-    super(startNode, path);
+    super(startNode, path, store);
     this.limit = limit;
     this.offset = offset;
     if (limit > 0 || offset > 0) {
diff --git 
a/server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/collector/EntityCollector.java
 
b/server/src/main/java/org/apache/iotdb/db/metadata/mtree/service/traverser/collector/EntityCollector.java
similarity index 81%
rename from 
server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/collector/EntityCollector.java
rename to 
server/src/main/java/org/apache/iotdb/db/metadata/mtree/service/traverser/collector/EntityCollector.java
index 9a20ec3..84d00ae 100644
--- 
a/server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/collector/EntityCollector.java
+++ 
b/server/src/main/java/org/apache/iotdb/db/metadata/mtree/service/traverser/collector/EntityCollector.java
@@ -16,23 +16,26 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.iotdb.db.metadata.mtree.traverser.collector;
+package org.apache.iotdb.db.metadata.mtree.service.traverser.collector;
 
 import org.apache.iotdb.db.exception.metadata.MetadataException;
 import org.apache.iotdb.db.metadata.mnode.IEntityMNode;
 import org.apache.iotdb.db.metadata.mnode.IMNode;
+import org.apache.iotdb.db.metadata.mtree.store.IMTreeStore;
 import org.apache.iotdb.db.metadata.path.PartialPath;
 
 // This class defines EntityMNode as target node and defines the Entity 
process framework.
 public abstract class EntityCollector<T> extends CollectorTraverser<T> {
 
-  public EntityCollector(IMNode startNode, PartialPath path) throws 
MetadataException {
-    super(startNode, path);
+  public EntityCollector(IMNode startNode, PartialPath path, IMTreeStore store)
+      throws MetadataException {
+    super(startNode, path, store);
   }
 
-  public EntityCollector(IMNode startNode, PartialPath path, int limit, int 
offset)
+  public EntityCollector(
+      IMNode startNode, PartialPath path, IMTreeStore store, int limit, int 
offset)
       throws MetadataException {
-    super(startNode, path, limit, offset);
+    super(startNode, path, store, limit, offset);
   }
 
   @Override
diff --git 
a/server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/collector/MNodeCollector.java
 
b/server/src/main/java/org/apache/iotdb/db/metadata/mtree/service/traverser/collector/MNodeCollector.java
similarity index 89%
rename from 
server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/collector/MNodeCollector.java
rename to 
server/src/main/java/org/apache/iotdb/db/metadata/mtree/service/traverser/collector/MNodeCollector.java
index ad9c9b6..7b5e56d 100644
--- 
a/server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/collector/MNodeCollector.java
+++ 
b/server/src/main/java/org/apache/iotdb/db/metadata/mtree/service/traverser/collector/MNodeCollector.java
@@ -16,11 +16,12 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.iotdb.db.metadata.mtree.traverser.collector;
+package org.apache.iotdb.db.metadata.mtree.service.traverser.collector;
 
 import org.apache.iotdb.db.exception.metadata.MetadataException;
 import org.apache.iotdb.db.metadata.MManager.StorageGroupFilter;
 import org.apache.iotdb.db.metadata.mnode.IMNode;
+import org.apache.iotdb.db.metadata.mtree.store.IMTreeStore;
 import org.apache.iotdb.db.metadata.path.PartialPath;
 
 // This class defines any node in MTree as potential target node.
@@ -32,8 +33,9 @@ public abstract class MNodeCollector<T> extends 
CollectorTraverser<T> {
   // level query option
   protected int targetLevel;
 
-  public MNodeCollector(IMNode startNode, PartialPath path) throws 
MetadataException {
-    super(startNode, path);
+  public MNodeCollector(IMNode startNode, PartialPath path, IMTreeStore store)
+      throws MetadataException {
+    super(startNode, path, store);
   }
 
   @Override
diff --git 
a/server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/collector/MeasurementCollector.java
 
b/server/src/main/java/org/apache/iotdb/db/metadata/mtree/service/traverser/collector/MeasurementCollector.java
similarity index 89%
rename from 
server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/collector/MeasurementCollector.java
rename to 
server/src/main/java/org/apache/iotdb/db/metadata/mtree/service/traverser/collector/MeasurementCollector.java
index 46f8e87..176745c 100644
--- 
a/server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/collector/MeasurementCollector.java
+++ 
b/server/src/main/java/org/apache/iotdb/db/metadata/mtree/service/traverser/collector/MeasurementCollector.java
@@ -16,11 +16,12 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.iotdb.db.metadata.mtree.traverser.collector;
+package org.apache.iotdb.db.metadata.mtree.service.traverser.collector;
 
 import org.apache.iotdb.db.exception.metadata.MetadataException;
 import org.apache.iotdb.db.metadata.mnode.IMNode;
 import org.apache.iotdb.db.metadata.mnode.IMeasurementMNode;
+import org.apache.iotdb.db.metadata.mtree.store.IMTreeStore;
 import org.apache.iotdb.db.metadata.path.MeasurementPath;
 import org.apache.iotdb.db.metadata.path.PartialPath;
 import org.apache.iotdb.tsfile.common.constant.TsFileConstant;
@@ -30,14 +31,16 @@ import java.util.Iterator;
 // This class defines MeasurementMNode as target node and defines the 
measurement process framework.
 public abstract class MeasurementCollector<T> extends CollectorTraverser<T> {
 
-  public MeasurementCollector(IMNode startNode, PartialPath path) throws 
MetadataException {
-    super(startNode, path);
+  public MeasurementCollector(IMNode startNode, PartialPath path, IMTreeStore 
store)
+      throws MetadataException {
+    super(startNode, path, store);
     isMeasurementTraverser = true;
   }
 
-  public MeasurementCollector(IMNode startNode, PartialPath path, int limit, 
int offset)
+  public MeasurementCollector(
+      IMNode startNode, PartialPath path, IMTreeStore store, int limit, int 
offset)
       throws MetadataException {
-    super(startNode, path, limit, offset);
+    super(startNode, path, store, limit, offset);
     isMeasurementTraverser = true;
   }
 
diff --git 
a/server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/collector/StorageGroupCollector.java
 
b/server/src/main/java/org/apache/iotdb/db/metadata/mtree/service/traverser/collector/StorageGroupCollector.java
similarity index 89%
rename from 
server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/collector/StorageGroupCollector.java
rename to 
server/src/main/java/org/apache/iotdb/db/metadata/mtree/service/traverser/collector/StorageGroupCollector.java
index a2aba15..200cb4d 100644
--- 
a/server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/collector/StorageGroupCollector.java
+++ 
b/server/src/main/java/org/apache/iotdb/db/metadata/mtree/service/traverser/collector/StorageGroupCollector.java
@@ -16,11 +16,12 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.iotdb.db.metadata.mtree.traverser.collector;
+package org.apache.iotdb.db.metadata.mtree.service.traverser.collector;
 
 import org.apache.iotdb.db.exception.metadata.MetadataException;
 import org.apache.iotdb.db.metadata.mnode.IMNode;
 import org.apache.iotdb.db.metadata.mnode.IStorageGroupMNode;
+import org.apache.iotdb.db.metadata.mtree.store.IMTreeStore;
 import org.apache.iotdb.db.metadata.path.PartialPath;
 
 // This class implements storage group path collection function.
@@ -28,8 +29,9 @@ public abstract class StorageGroupCollector<T> extends 
CollectorTraverser<T> {
 
   protected boolean collectInternal = false;
 
-  public StorageGroupCollector(IMNode startNode, PartialPath path) throws 
MetadataException {
-    super(startNode, path);
+  public StorageGroupCollector(IMNode startNode, PartialPath path, IMTreeStore 
store)
+      throws MetadataException {
+    super(startNode, path, store);
   }
 
   @Override
diff --git 
a/server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/counter/CounterTraverser.java
 
b/server/src/main/java/org/apache/iotdb/db/metadata/mtree/service/traverser/counter/CounterTraverser.java
similarity index 76%
rename from 
server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/counter/CounterTraverser.java
rename to 
server/src/main/java/org/apache/iotdb/db/metadata/mtree/service/traverser/counter/CounterTraverser.java
index 71dba16..2496aab 100644
--- 
a/server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/counter/CounterTraverser.java
+++ 
b/server/src/main/java/org/apache/iotdb/db/metadata/mtree/service/traverser/counter/CounterTraverser.java
@@ -16,11 +16,12 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.iotdb.db.metadata.mtree.traverser.counter;
+package org.apache.iotdb.db.metadata.mtree.service.traverser.counter;
 
 import org.apache.iotdb.db.exception.metadata.MetadataException;
 import org.apache.iotdb.db.metadata.mnode.IMNode;
-import org.apache.iotdb.db.metadata.mtree.traverser.Traverser;
+import org.apache.iotdb.db.metadata.mtree.service.traverser.Traverser;
+import org.apache.iotdb.db.metadata.mtree.store.IMTreeStore;
 import org.apache.iotdb.db.metadata.path.PartialPath;
 
 // This class define the count as traversal result.
@@ -28,8 +29,9 @@ public abstract class CounterTraverser extends Traverser {
 
   protected int count;
 
-  public CounterTraverser(IMNode startNode, PartialPath path) throws 
MetadataException {
-    super(startNode, path);
+  public CounterTraverser(IMNode startNode, PartialPath path, IMTreeStore 
store)
+      throws MetadataException {
+    super(startNode, path, store);
   }
 
   public int getCount() {
diff --git 
a/server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/counter/EntityCounter.java
 
b/server/src/main/java/org/apache/iotdb/db/metadata/mtree/service/traverser/counter/EntityCounter.java
similarity index 83%
rename from 
server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/counter/EntityCounter.java
rename to 
server/src/main/java/org/apache/iotdb/db/metadata/mtree/service/traverser/counter/EntityCounter.java
index 1aa4bb5..837b088 100644
--- 
a/server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/counter/EntityCounter.java
+++ 
b/server/src/main/java/org/apache/iotdb/db/metadata/mtree/service/traverser/counter/EntityCounter.java
@@ -16,17 +16,19 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.iotdb.db.metadata.mtree.traverser.counter;
+package org.apache.iotdb.db.metadata.mtree.service.traverser.counter;
 
 import org.apache.iotdb.db.exception.metadata.MetadataException;
 import org.apache.iotdb.db.metadata.mnode.IMNode;
+import org.apache.iotdb.db.metadata.mtree.store.IMTreeStore;
 import org.apache.iotdb.db.metadata.path.PartialPath;
 
 // This class implements the entity count function.
 public class EntityCounter extends CounterTraverser {
 
-  public EntityCounter(IMNode startNode, PartialPath path) throws 
MetadataException {
-    super(startNode, path);
+  public EntityCounter(IMNode startNode, PartialPath path, IMTreeStore store)
+      throws MetadataException {
+    super(startNode, path, store);
   }
 
   @Override
diff --git 
a/server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/counter/MNodeLevelCounter.java
 
b/server/src/main/java/org/apache/iotdb/db/metadata/mtree/service/traverser/counter/MNodeLevelCounter.java
similarity index 85%
rename from 
server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/counter/MNodeLevelCounter.java
rename to 
server/src/main/java/org/apache/iotdb/db/metadata/mtree/service/traverser/counter/MNodeLevelCounter.java
index 90a1784..bc137c2 100644
--- 
a/server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/counter/MNodeLevelCounter.java
+++ 
b/server/src/main/java/org/apache/iotdb/db/metadata/mtree/service/traverser/counter/MNodeLevelCounter.java
@@ -16,10 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.iotdb.db.metadata.mtree.traverser.counter;
+package org.apache.iotdb.db.metadata.mtree.service.traverser.counter;
 
 import org.apache.iotdb.db.exception.metadata.MetadataException;
 import org.apache.iotdb.db.metadata.mnode.IMNode;
+import org.apache.iotdb.db.metadata.mtree.store.IMTreeStore;
 import org.apache.iotdb.db.metadata.path.PartialPath;
 
 // This node implements node count function.
@@ -28,9 +29,9 @@ public class MNodeLevelCounter extends CounterTraverser {
   // level query option
   protected int targetLevel;
 
-  public MNodeLevelCounter(IMNode startNode, PartialPath path, int targetLevel)
+  public MNodeLevelCounter(IMNode startNode, PartialPath path, IMTreeStore 
store, int targetLevel)
       throws MetadataException {
-    super(startNode, path);
+    super(startNode, path, store);
     this.targetLevel = targetLevel;
   }
 
diff --git 
a/server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/counter/MeasurementCounter.java
 
b/server/src/main/java/org/apache/iotdb/db/metadata/mtree/service/traverser/counter/MeasurementCounter.java
similarity index 84%
rename from 
server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/counter/MeasurementCounter.java
rename to 
server/src/main/java/org/apache/iotdb/db/metadata/mtree/service/traverser/counter/MeasurementCounter.java
index acaa288..4870181 100644
--- 
a/server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/counter/MeasurementCounter.java
+++ 
b/server/src/main/java/org/apache/iotdb/db/metadata/mtree/service/traverser/counter/MeasurementCounter.java
@@ -16,18 +16,20 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.iotdb.db.metadata.mtree.traverser.counter;
+package org.apache.iotdb.db.metadata.mtree.service.traverser.counter;
 
 import org.apache.iotdb.db.exception.metadata.MetadataException;
 import org.apache.iotdb.db.metadata.mnode.IMNode;
+import org.apache.iotdb.db.metadata.mtree.store.IMTreeStore;
 import org.apache.iotdb.db.metadata.path.PartialPath;
 
 // This method implements the measurement count function.
 // One MultiMeasurement will only be count once.
 public class MeasurementCounter extends CounterTraverser {
 
-  public MeasurementCounter(IMNode startNode, PartialPath path) throws 
MetadataException {
-    super(startNode, path);
+  public MeasurementCounter(IMNode startNode, PartialPath path, IMTreeStore 
store)
+      throws MetadataException {
+    super(startNode, path, store);
     isMeasurementTraverser = true;
   }
 
diff --git 
a/server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/counter/StorageGroupCounter.java
 
b/server/src/main/java/org/apache/iotdb/db/metadata/mtree/service/traverser/counter/StorageGroupCounter.java
similarity index 83%
rename from 
server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/counter/StorageGroupCounter.java
rename to 
server/src/main/java/org/apache/iotdb/db/metadata/mtree/service/traverser/counter/StorageGroupCounter.java
index 635a641..13bcf6f 100644
--- 
a/server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/counter/StorageGroupCounter.java
+++ 
b/server/src/main/java/org/apache/iotdb/db/metadata/mtree/service/traverser/counter/StorageGroupCounter.java
@@ -16,17 +16,19 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.iotdb.db.metadata.mtree.traverser.counter;
+package org.apache.iotdb.db.metadata.mtree.service.traverser.counter;
 
 import org.apache.iotdb.db.exception.metadata.MetadataException;
 import org.apache.iotdb.db.metadata.mnode.IMNode;
+import org.apache.iotdb.db.metadata.mtree.store.IMTreeStore;
 import org.apache.iotdb.db.metadata.path.PartialPath;
 
 // This class implements storage group count function.
 public class StorageGroupCounter extends CounterTraverser {
 
-  public StorageGroupCounter(IMNode startNode, PartialPath path) throws 
MetadataException {
-    super(startNode, path);
+  public StorageGroupCounter(IMNode startNode, PartialPath path, IMTreeStore 
store)
+      throws MetadataException {
+    super(startNode, path, store);
   }
 
   @Override
diff --git 
a/server/src/main/java/org/apache/iotdb/db/metadata/mtree/store/IMTreeStore.java
 
b/server/src/main/java/org/apache/iotdb/db/metadata/mtree/store/IMTreeStore.java
new file mode 100644
index 0000000..ab7c557
--- /dev/null
+++ 
b/server/src/main/java/org/apache/iotdb/db/metadata/mtree/store/IMTreeStore.java
@@ -0,0 +1,63 @@
+/*
+ * 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.mtree.store;
+
+import org.apache.iotdb.db.metadata.mnode.IEntityMNode;
+import org.apache.iotdb.db.metadata.mnode.IMNode;
+import org.apache.iotdb.db.metadata.mnode.IMeasurementMNode;
+
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * This interface defines the basic access methods of an MTreeStore.
+ *
+ * <p>MTreeStore could be implemented as memory-based or disk-based for 
different scenarios.
+ */
+public interface IMTreeStore {
+
+  void init() throws IOException;
+
+  IMNode getRoot();
+
+  boolean hasChild(IMNode parent, String name);
+
+  IMNode getChild(IMNode parent, String name);
+
+  Map<String, IMNode> getChildren(IMNode parent);
+
+  Iterator<IMNode> getChildrenIterator(IMNode parent);
+
+  void addChild(IMNode parent, String childName, IMNode child);
+
+  void addAlias(IEntityMNode parent, String alias, IMeasurementMNode child);
+
+  void deleteChild(IMNode parent, String childName);
+
+  void deleteAliasChild(IEntityMNode parent, String alias);
+
+  void updateMNode(IMNode node);
+
+  void createSnapshot() throws IOException;
+
+  void clear();
+
+  String toString();
+}
diff --git 
a/server/src/main/java/org/apache/iotdb/db/metadata/mtree/store/MemMTreeStore.java
 
b/server/src/main/java/org/apache/iotdb/db/metadata/mtree/store/MemMTreeStore.java
new file mode 100644
index 0000000..e7b9b0c
--- /dev/null
+++ 
b/server/src/main/java/org/apache/iotdb/db/metadata/mtree/store/MemMTreeStore.java
@@ -0,0 +1,278 @@
+/*
+ * 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.mtree.store;
+
+import org.apache.iotdb.db.conf.IoTDBConstant;
+import org.apache.iotdb.db.conf.IoTDBDescriptor;
+import org.apache.iotdb.db.engine.fileSystem.SystemFileFactory;
+import org.apache.iotdb.db.metadata.MetadataConstant;
+import org.apache.iotdb.db.metadata.logfile.MLogReader;
+import org.apache.iotdb.db.metadata.logfile.MLogWriter;
+import org.apache.iotdb.db.metadata.mnode.IEntityMNode;
+import org.apache.iotdb.db.metadata.mnode.IMNode;
+import org.apache.iotdb.db.metadata.mnode.IMeasurementMNode;
+import org.apache.iotdb.db.metadata.mnode.InternalMNode;
+import org.apache.iotdb.db.metadata.mnode.MNodeUtils;
+import org.apache.iotdb.db.metadata.mnode.MeasurementMNode;
+import org.apache.iotdb.db.metadata.mnode.StorageGroupMNode;
+import org.apache.iotdb.db.qp.physical.PhysicalPlan;
+import org.apache.iotdb.db.qp.physical.sys.MNodePlan;
+import org.apache.iotdb.db.qp.physical.sys.MeasurementMNodePlan;
+import org.apache.iotdb.db.qp.physical.sys.StorageGroupMNodePlan;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.util.ArrayDeque;
+import java.util.Deque;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/** This is a memory-based implementation of IMTreeStore. All MNodes are 
stored in memory. */
+public class MemMTreeStore implements IMTreeStore {
+
+  public static final Gson GSON = new 
GsonBuilder().setPrettyPrinting().create();
+  private static final Logger logger = 
LoggerFactory.getLogger(MemMTreeStore.class);
+
+  private IMNode root;
+
+  private String mtreeSnapshotPath;
+  private String mtreeSnapshotTmpPath;
+
+  public MemMTreeStore() {
+    this.root = new InternalMNode(null, IoTDBConstant.PATH_ROOT);
+  }
+
+  public void init() throws IOException {
+    mtreeSnapshotPath =
+        IoTDBDescriptor.getInstance().getConfig().getSchemaDir()
+            + File.separator
+            + MetadataConstant.MTREE_SNAPSHOT;
+    mtreeSnapshotTmpPath =
+        IoTDBDescriptor.getInstance().getConfig().getSchemaDir()
+            + File.separator
+            + MetadataConstant.MTREE_SNAPSHOT_TMP;
+
+    File tmpFile = SystemFileFactory.INSTANCE.getFile(mtreeSnapshotTmpPath);
+    if (tmpFile.exists()) {
+      logger.warn("Creating MTree snapshot not successful before crashing...");
+      Files.delete(tmpFile.toPath());
+    }
+
+    File mtreeSnapshot = SystemFileFactory.INSTANCE.getFile(mtreeSnapshotPath);
+    long time = System.currentTimeMillis();
+    if (mtreeSnapshot.exists()) {
+      this.root = deserializeFrom(mtreeSnapshot);
+      logger.debug(
+          "spend {} ms to deserialize mtree from snapshot", 
System.currentTimeMillis() - time);
+    }
+  }
+
+  @Override
+  public IMNode getRoot() {
+    return root;
+  }
+
+  @Override
+  public boolean hasChild(IMNode parent, String name) {
+    return parent.hasChild(name);
+  }
+
+  @Override
+  public IMNode getChild(IMNode parent, String name) {
+    return parent.getChild(name);
+  }
+
+  @Override
+  public Map<String, IMNode> getChildren(IMNode parent) {
+    return parent.getChildren();
+  }
+
+  @Override
+  public Iterator<IMNode> getChildrenIterator(IMNode parent) {
+    return parent.getChildren().values().iterator();
+  }
+
+  @Override
+  public void addChild(IMNode parent, String childName, IMNode child) {
+    parent.addChild(childName, child);
+  }
+
+  @Override
+  public void addAlias(IEntityMNode parent, String alias, IMeasurementMNode 
child) {
+    parent.addAlias(alias, child);
+  }
+
+  @Override
+  public void deleteChild(IMNode parent, String childName) {
+    parent.deleteChild(childName);
+  }
+
+  @Override
+  public void deleteAliasChild(IEntityMNode parent, String alias) {
+    parent.deleteAliasChild(alias);
+  }
+
+  @Override
+  public void updateMNode(IMNode node) {}
+
+  @Override
+  public void createSnapshot() throws IOException {
+    long time = System.currentTimeMillis();
+    logger.info("Start creating MTree snapshot to {}", mtreeSnapshotPath);
+    try {
+      serializeTo(mtreeSnapshotTmpPath);
+      File tmpFile = SystemFileFactory.INSTANCE.getFile(mtreeSnapshotTmpPath);
+      File snapshotFile = 
SystemFileFactory.INSTANCE.getFile(mtreeSnapshotPath);
+      if (snapshotFile.exists()) {
+        Files.delete(snapshotFile.toPath());
+      }
+      if (tmpFile.renameTo(snapshotFile)) {
+        logger.info(
+            "Finish creating MTree snapshot to {}, spend {} ms.",
+            mtreeSnapshotPath,
+            System.currentTimeMillis() - time);
+      }
+    } catch (IOException e) {
+      logger.warn("Failed to create MTree snapshot to {}", mtreeSnapshotPath, 
e);
+      if (SystemFileFactory.INSTANCE.getFile(mtreeSnapshotTmpPath).exists()) {
+        try {
+          
Files.delete(SystemFileFactory.INSTANCE.getFile(mtreeSnapshotTmpPath).toPath());
+        } catch (IOException e1) {
+          logger.warn("delete file {} failed: {}", mtreeSnapshotTmpPath, 
e1.getMessage());
+        }
+      }
+      throw e;
+    }
+  }
+
+  public void serializeTo(String snapshotPath) throws IOException {
+    try (MLogWriter mLogWriter = new MLogWriter(snapshotPath)) {
+      root.serializeTo(mLogWriter);
+    }
+  }
+
+  public static InternalMNode deserializeFrom(File mtreeSnapshot) {
+    try (MLogReader mLogReader = new MLogReader(mtreeSnapshot)) {
+      return deserializeFromReader(mLogReader);
+    } catch (IOException e) {
+      logger.warn("Failed to deserialize from {}. Use a new MTree.", 
mtreeSnapshot.getPath());
+      return new InternalMNode(null, IoTDBConstant.PATH_ROOT);
+    }
+  }
+
+  @SuppressWarnings("squid:S3776") // Suppress high Cognitive Complexity 
warning
+  private static InternalMNode deserializeFromReader(MLogReader mLogReader) {
+    Deque<IMNode> nodeStack = new ArrayDeque<>();
+    IMNode node = null;
+    while (mLogReader.hasNext()) {
+      PhysicalPlan plan = null;
+      try {
+        plan = mLogReader.next();
+        if (plan == null) {
+          continue;
+        }
+        int childrenSize = 0;
+        if (plan instanceof StorageGroupMNodePlan) {
+          node = StorageGroupMNode.deserializeFrom((StorageGroupMNodePlan) 
plan);
+          childrenSize = ((StorageGroupMNodePlan) plan).getChildSize();
+        } else if (plan instanceof MeasurementMNodePlan) {
+          node = MeasurementMNode.deserializeFrom((MeasurementMNodePlan) plan);
+          childrenSize = ((MeasurementMNodePlan) plan).getChildSize();
+        } else if (plan instanceof MNodePlan) {
+          node = InternalMNode.deserializeFrom((MNodePlan) plan);
+          childrenSize = ((MNodePlan) plan).getChildSize();
+        }
+
+        if (childrenSize != 0) {
+          ConcurrentHashMap<String, IMNode> childrenMap = new 
ConcurrentHashMap<>();
+          for (int i = 0; i < childrenSize; i++) {
+            IMNode child = nodeStack.removeFirst();
+            childrenMap.put(child.getName(), child);
+            if (child.isMeasurement()) {
+              if (!node.isEntity()) {
+                node = MNodeUtils.setToEntity(node);
+              }
+              String alias = child.getAsMeasurementMNode().getAlias();
+              if (alias != null) {
+                node.getAsEntityMNode().addAlias(alias, 
child.getAsMeasurementMNode());
+              }
+            }
+            child.setParent(node);
+          }
+          node.setChildren(childrenMap);
+        }
+        nodeStack.push(node);
+      } catch (Exception e) {
+        logger.error(
+            "Can not operate cmd {} for err:", plan == null ? "" : 
plan.getOperatorType(), e);
+      }
+    }
+    if (!IoTDBConstant.PATH_ROOT.equals(node.getName())) {
+      logger.error("Snapshot file corrupted!");
+    }
+
+    return (InternalMNode) node;
+  }
+
+  @Override
+  public void clear() {
+    root = new InternalMNode(null, IoTDBConstant.PATH_ROOT);
+  }
+
+  @Override
+  public String toString() {
+    JsonObject jsonObject = new JsonObject();
+    jsonObject.add(root.getName(), mNodeToJSON(root, null));
+    return jsonToString(jsonObject);
+  }
+
+  private JsonObject mNodeToJSON(IMNode node, String storageGroupName) {
+    JsonObject jsonObject = new JsonObject();
+    if (node.getChildren().size() > 0) {
+      if (node.isStorageGroup()) {
+        storageGroupName = node.getFullPath();
+      }
+      for (IMNode child : node.getChildren().values()) {
+        jsonObject.add(child.getName(), mNodeToJSON(child, storageGroupName));
+      }
+    } else if (node.isMeasurement()) {
+      IMeasurementMNode leafMNode = node.getAsMeasurementMNode();
+      jsonObject.add("DataType", 
GSON.toJsonTree(leafMNode.getSchema().getType()));
+      jsonObject.add("Encoding", 
GSON.toJsonTree(leafMNode.getSchema().getEncodingType()));
+      jsonObject.add("Compressor", 
GSON.toJsonTree(leafMNode.getSchema().getCompressor()));
+      if (leafMNode.getSchema().getProps() != null) {
+        jsonObject.addProperty("args", 
leafMNode.getSchema().getProps().toString());
+      }
+      jsonObject.addProperty("StorageGroup", storageGroupName);
+    }
+    return jsonObject;
+  }
+
+  private static String jsonToString(JsonObject jsonObject) {
+    return GSON.toJson(jsonObject);
+  }
+}
diff --git 
a/server/src/test/java/org/apache/iotdb/db/metadata/MManagerBasicTest.java 
b/server/src/test/java/org/apache/iotdb/db/metadata/MManagerBasicTest.java
index d1227cc..eb81cff 100644
--- a/server/src/test/java/org/apache/iotdb/db/metadata/MManagerBasicTest.java
+++ b/server/src/test/java/org/apache/iotdb/db/metadata/MManagerBasicTest.java
@@ -1149,7 +1149,7 @@ public class MManagerBasicTest {
       fail();
     } catch (Exception e) {
       assertEquals(
-          "Path [root.tree.sg0.GPS.s9] overlaps with [treeTemplate] on [GPS]", 
e.getMessage());
+          "Path [root.tree.sg0.GPS] overlaps with [treeTemplate] on [GPS]", 
e.getMessage());
     }
 
     CreateTimeSeriesPlan createTimeSeriesPlan4 =
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 e396e32..428a88e 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
@@ -25,7 +25,7 @@ import 
org.apache.iotdb.db.exception.metadata.PathAlreadyExistException;
 import org.apache.iotdb.db.metadata.MManager.StorageGroupFilter;
 import org.apache.iotdb.db.metadata.mnode.IMNode;
 import org.apache.iotdb.db.metadata.mnode.MeasurementMNode;
-import org.apache.iotdb.db.metadata.mtree.MTree;
+import org.apache.iotdb.db.metadata.mtree.service.MTreeService;
 import org.apache.iotdb.db.metadata.path.MeasurementPath;
 import org.apache.iotdb.db.metadata.path.PartialPath;
 import org.apache.iotdb.db.utils.EnvironmentUtils;
@@ -67,7 +67,7 @@ public class MTreeTest {
   @Test
   @SuppressWarnings("squid:S5783")
   public void testSetStorageGroupExceptionMessage() throws 
IllegalPathException {
-    MTree root = new MTree();
+    MTreeService root = new MTreeService();
     try {
       root.setStorageGroup(new PartialPath("root.edge1.access"));
       root.setStorageGroup(new PartialPath("root.edge1"));
@@ -93,7 +93,7 @@ public class MTreeTest {
 
   @Test
   public void testAddLeftNodePathWithAlias() throws MetadataException {
-    MTree root = new MTree();
+    MTreeService root = new MTreeService();
     root.setStorageGroup(new PartialPath("root.laptop"));
     try {
       root.createTimeseries(
@@ -122,7 +122,7 @@ public class MTreeTest {
 
   @Test
   public void testAddAndPathExist() throws MetadataException {
-    MTree root = new MTree();
+    MTreeService root = new MTreeService();
     String path1 = "root";
     root.setStorageGroup(new PartialPath("root.laptop"));
     assertTrue(root.isPathExist(new PartialPath(path1)));
@@ -156,7 +156,7 @@ public class MTreeTest {
 
   @Test
   public void testAddAndQueryPath() {
-    MTree root = new MTree();
+    MTreeService root = new MTreeService();
     try {
       assertFalse(root.isPathExist(new PartialPath("root.a.d0")));
       assertFalse(root.checkStorageGroupByPath(new PartialPath("root.a.d0")));
@@ -223,7 +223,7 @@ public class MTreeTest {
 
   @Test
   public void testAddAndQueryPathWithAlias() {
-    MTree root = new MTree();
+    MTreeService root = new MTreeService();
     try {
       assertFalse(root.isPathExist(new PartialPath("root.a.d0")));
       assertFalse(root.checkStorageGroupByPath(new PartialPath("root.a.d0")));
@@ -311,112 +311,8 @@ public class MTreeTest {
   }
 
   @Test
-  public void testCombineMetadataInStrings() {
-    MTree root = new MTree();
-    MTree root1 = new MTree();
-    MTree root2 = new MTree();
-    MTree root3 = new MTree();
-    try {
-      CompressionType compressionType = 
TSFileDescriptor.getInstance().getConfig().getCompressor();
-
-      root.setStorageGroup(new PartialPath("root.a.d0"));
-      root.createTimeseries(
-          new PartialPath("root.a.d0.s0"),
-          TSDataType.valueOf("INT32"),
-          TSEncoding.valueOf("RLE"),
-          compressionType,
-          Collections.emptyMap(),
-          null);
-      root.createTimeseries(
-          new PartialPath("root.a.d0.s1"),
-          TSDataType.valueOf("INT32"),
-          TSEncoding.valueOf("RLE"),
-          compressionType,
-          Collections.emptyMap(),
-          null);
-
-      root.setStorageGroup(new PartialPath("root.a.d1"));
-      root.createTimeseries(
-          new PartialPath("root.a.d1.s0"),
-          TSDataType.valueOf("INT32"),
-          TSEncoding.valueOf("RLE"),
-          compressionType,
-          Collections.emptyMap(),
-          null);
-      root.createTimeseries(
-          new PartialPath("root.a.d1.s1"),
-          TSDataType.valueOf("INT32"),
-          TSEncoding.valueOf("RLE"),
-          compressionType,
-          Collections.emptyMap(),
-          null);
-
-      root.setStorageGroup(new PartialPath("root.a.b.d0"));
-      root.createTimeseries(
-          new PartialPath("root.a.b.d0.s0"),
-          TSDataType.valueOf("INT32"),
-          TSEncoding.valueOf("RLE"),
-          compressionType,
-          Collections.emptyMap(),
-          null);
-
-      root1.setStorageGroup(new PartialPath("root.a.d0"));
-      root1.createTimeseries(
-          new PartialPath("root.a.d0.s0"),
-          TSDataType.valueOf("INT32"),
-          TSEncoding.valueOf("RLE"),
-          compressionType,
-          Collections.emptyMap(),
-          null);
-      root1.createTimeseries(
-          new PartialPath("root.a.d0.s1"),
-          TSDataType.valueOf("INT32"),
-          TSEncoding.valueOf("RLE"),
-          compressionType,
-          Collections.emptyMap(),
-          null);
-
-      root2.setStorageGroup(new PartialPath("root.a.d1"));
-      root2.createTimeseries(
-          new PartialPath("root.a.d1.s0"),
-          TSDataType.valueOf("INT32"),
-          TSEncoding.valueOf("RLE"),
-          compressionType,
-          Collections.emptyMap(),
-          null);
-      root2.createTimeseries(
-          new PartialPath("root.a.d1.s1"),
-          TSDataType.valueOf("INT32"),
-          TSEncoding.valueOf("RLE"),
-          compressionType,
-          Collections.emptyMap(),
-          null);
-
-      root3.setStorageGroup(new PartialPath("root.a.b.d0"));
-      root3.createTimeseries(
-          new PartialPath("root.a.b.d0.s0"),
-          TSDataType.valueOf("INT32"),
-          TSEncoding.valueOf("RLE"),
-          compressionType,
-          Collections.emptyMap(),
-          null);
-
-      String[] metadatas = new String[3];
-      metadatas[0] = root1.toString();
-      metadatas[1] = root2.toString();
-      metadatas[2] = root3.toString();
-      assertEquals(
-          MTree.combineMetadataInStrings(metadatas),
-          MTree.combineMetadataInStrings(new String[] {root.toString()}));
-    } catch (MetadataException e) {
-      e.printStackTrace();
-      fail(e.getMessage());
-    }
-  }
-
-  @Test
   public void testGetAllChildNodeNamesByPath() {
-    MTree root = new MTree();
+    MTreeService root = new MTreeService();
     try {
       root.setStorageGroup(new PartialPath("root.a.d0"));
       root.createTimeseries(
@@ -460,7 +356,7 @@ public class MTreeTest {
   @Test
   public void testSetStorageGroup() throws IllegalPathException {
     // set storage group first
-    MTree root = new MTree();
+    MTreeService root = new MTreeService();
     try {
       root.setStorageGroup(new PartialPath("root.laptop.d1"));
       assertTrue(root.isPathExist(new PartialPath("root.laptop.d1")));
@@ -562,7 +458,7 @@ public class MTreeTest {
   @Test
   public void testCheckStorageGroup() {
     // set storage group first
-    MTree root = new MTree();
+    MTreeService root = new MTreeService();
     try {
       assertFalse(root.isStorageGroup(new PartialPath("root")));
       assertFalse(root.isStorageGroup(new PartialPath("root1.laptop.d2")));
@@ -589,7 +485,7 @@ public class MTreeTest {
   @Test
   public void testGetAllFileNamesByPath() {
     // set storage group first
-    MTree root = new MTree();
+    MTreeService root = new MTreeService();
     try {
       root.setStorageGroup(new PartialPath("root.laptop.d1"));
       root.setStorageGroup(new PartialPath("root.laptop.d2"));
@@ -626,7 +522,7 @@ public class MTreeTest {
   @Test
   public void testCheckStorageExistOfPath() {
     // set storage group first
-    MTree root = new MTree();
+    MTreeService root = new MTreeService();
     try {
       assertTrue(root.getBelongedStorageGroups(new 
PartialPath("root")).isEmpty());
       assertTrue(root.getBelongedStorageGroups(new 
PartialPath("root.vehicle")).isEmpty());
@@ -656,7 +552,7 @@ public class MTreeTest {
   @Test
   public void testGetAllTimeseriesCount() {
     // set storage group first
-    MTree root = new MTree();
+    MTreeService root = new MTreeService();
     try {
       root.setStorageGroup(new PartialPath("root.laptop"));
       root.createTimeseries(
@@ -706,7 +602,7 @@ public class MTreeTest {
 
   @Test
   public void testAddSubDevice() throws MetadataException {
-    MTree root = new MTree();
+    MTreeService root = new MTreeService();
     root.setStorageGroup(new PartialPath("root.laptop"));
     root.createTimeseries(
         new PartialPath("root.laptop.d1.s1"),
@@ -733,7 +629,7 @@ public class MTreeTest {
 
   @Test
   public void testIllegalStorageGroup() {
-    MTree root = new MTree();
+    MTreeService root = new MTreeService();
     try {
       root.setStorageGroup(new PartialPath("root.\"sg.ln\""));
     } catch (MetadataException e) {
@@ -745,7 +641,7 @@ public class MTreeTest {
 
   @Test
   public void testSearchStorageGroup() throws MetadataException {
-    MTree root = new MTree();
+    MTreeService root = new MTreeService();
     String path1 = "root";
     String sgPath1 = "root.vehicle";
     root.setStorageGroup(new PartialPath(sgPath1));
@@ -776,7 +672,7 @@ public class MTreeTest {
 
   @Test
   public void testCreateTimeseries() throws MetadataException {
-    MTree root = new MTree();
+    MTreeService root = new MTreeService();
     String sgPath = "root.sg1";
     root.setStorageGroup(new PartialPath(sgPath));
 
@@ -807,7 +703,7 @@ public class MTreeTest {
 
   @Test
   public void testCountEntity() throws MetadataException {
-    MTree root = new MTree();
+    MTreeService root = new MTreeService();
     root.setStorageGroup(new PartialPath("root.laptop"));
     root.createTimeseries(
         new PartialPath("root.laptop.s1"),
@@ -865,7 +761,7 @@ public class MTreeTest {
 
   @Test
   public void testCountStorageGroup() throws MetadataException {
-    MTree root = new MTree();
+    MTreeService root = new MTreeService();
     root.setStorageGroup(new PartialPath("root.sg1"));
     root.setStorageGroup(new PartialPath("root.a.sg1"));
     root.setStorageGroup(new PartialPath("root.a.b.sg1"));
@@ -894,7 +790,7 @@ public class MTreeTest {
 
   @Test
   public void testGetNodeListInLevel() throws MetadataException {
-    MTree root = new MTree();
+    MTreeService root = new MTreeService();
     root.setStorageGroup(new PartialPath("root.sg1"));
     root.createTimeseries(
         new PartialPath("root.sg1.d1.s1"),
@@ -940,7 +836,7 @@ public class MTreeTest {
 
   @Test
   public void testGetDeviceForTimeseries() throws MetadataException {
-    MTree root = new MTree();
+    MTreeService root = new MTreeService();
     root.setStorageGroup(new PartialPath("root.sg1"));
     root.createTimeseries(
         new PartialPath("root.sg1.d1.s1"),

Reply via email to