You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iotdb.apache.org by hx...@apache.org on 2020/07/29 11:47:15 UTC

[incubator-iotdb] branch modulize updated: [not finished] extract MManager as interface

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

hxd pushed a commit to branch modulize
in repository https://gitbox.apache.org/repos/asf/incubator-iotdb.git


The following commit(s) were added to refs/heads/modulize by this push:
     new da117e4  [not finished] extract MManager as interface
da117e4 is described below

commit da117e40c6f59254d41e0ec76ae41cc5a504b92f
Author: xiangdong huang <sa...@gmail.com>
AuthorDate: Wed Jul 29 19:46:56 2020 +0800

    [not finished] extract MManager as interface
---
 .../org/apache/iotdb/db/engine/StorageEngine.java  |   7 +-
 .../iotdb/db/engine/merge/task/MergeTask.java      |  10 +-
 .../engine/storagegroup/StorageGroupProcessor.java |  24 +--
 .../apache/iotdb/db/metadata/ISchemaManager.java   | 230 +++++++++++++++++++--
 .../org/apache/iotdb/db/metadata/MManager.java     | 134 ++++++------
 .../java/org/apache/iotdb/db/metadata/MTree.java   | 153 +++++++-------
 .../iotdb/db/metadata/mnode/IMeasurementMNode.java |  82 ++++++++
 .../iotdb/db/metadata/mnode/ISchemaNode.java       |  67 ++++++
 .../db/metadata/mnode/IStorageGroupMNode.java      |  36 ++++
 .../org/apache/iotdb/db/metadata/mnode/MNode.java  |  76 ++++---
 .../iotdb/db/metadata/mnode/MeasurementMNode.java  |  40 ++--
 .../iotdb/db/metadata/mnode/StorageGroupMNode.java |   9 +-
 .../apache/iotdb/db/qp/executor/PlanExecutor.java  |  11 +-
 .../iotdb/db/qp/physical/crud/InsertPlan.java      |   8 +-
 .../db/query/dataset/AlignByDeviceDataSet.java     |   4 +-
 .../iotdb/db/query/executor/LastQueryExecutor.java |   6 +-
 .../db/engine/cache/ChunkMetadataCacheTest.java    |   4 +-
 .../engine/modification/DeletionFileNodeTest.java  |   3 +-
 .../db/engine/modification/DeletionQueryTest.java  |   3 +-
 .../storagegroup/StorageGroupProcessorTest.java    |   7 +-
 .../iotdb/db/engine/storagegroup/TTLTest.java      |   9 +-
 .../apache/iotdb/db/integration/IoTDBLastIT.java   |  20 +-
 .../iotdb/db/metadata/MManagerAdvancedTest.java    |  20 +-
 .../iotdb/db/metadata/MManagerImproveTest.java     |   8 +-
 24 files changed, 683 insertions(+), 288 deletions(-)

diff --git a/server/src/main/java/org/apache/iotdb/db/engine/StorageEngine.java b/server/src/main/java/org/apache/iotdb/db/engine/StorageEngine.java
index a11e944..9793dc2 100644
--- a/server/src/main/java/org/apache/iotdb/db/engine/StorageEngine.java
+++ b/server/src/main/java/org/apache/iotdb/db/engine/StorageEngine.java
@@ -36,6 +36,7 @@ import org.apache.iotdb.db.exception.metadata.MetadataException;
 import org.apache.iotdb.db.exception.metadata.StorageGroupNotSetException;
 import org.apache.iotdb.db.exception.query.QueryProcessException;
 import org.apache.iotdb.db.exception.runtime.StorageEngineFailureException;
+import org.apache.iotdb.db.metadata.mnode.IStorageGroupMNode;
 import org.apache.iotdb.db.metadata.mnode.StorageGroupMNode;
 import org.apache.iotdb.db.qp.physical.crud.InsertRowPlan;
 import org.apache.iotdb.db.qp.physical.crud.InsertTabletPlan;
@@ -154,9 +155,9 @@ public class StorageEngine implements IService {
     /*
      * recover all storage group processors.
      */
-    List<StorageGroupMNode> sgNodes = IoTDB.metaManager.getAllStorageGroupNodes();
+    List<IStorageGroupMNode> sgNodes = IoTDB.metaManager.getAllStorageGroupNodes();
     List<Future> futures = new ArrayList<>();
-    for (StorageGroupMNode storageGroup : sgNodes) {
+    for (IStorageGroupMNode storageGroup : sgNodes) {
       futures.add(recoveryThreadPool.submit((Callable<Void>) () -> {
         try {
           StorageGroupProcessor processor = new StorageGroupProcessor(systemDir,
@@ -285,7 +286,7 @@ public class StorageEngine implements IService {
               logger.info("construct a processor instance, the storage group is {}, Thread is {}",
                 storageGroupName, Thread.currentThread().getId());
               processor = new StorageGroupProcessor(systemDir, storageGroupName, fileFlushPolicy);
-              StorageGroupMNode storageGroup = IoTDB.metaManager
+              IStorageGroupMNode storageGroup = IoTDB.metaManager
                 .getStorageGroupNode(storageGroupName);
               processor.setDataTTL(storageGroup.getDataTTL());
               processorMap.put(storageGroupName, processor);
diff --git a/server/src/main/java/org/apache/iotdb/db/engine/merge/task/MergeTask.java b/server/src/main/java/org/apache/iotdb/db/engine/merge/task/MergeTask.java
index f7db174..e467477 100644
--- a/server/src/main/java/org/apache/iotdb/db/engine/merge/task/MergeTask.java
+++ b/server/src/main/java/org/apache/iotdb/db/engine/merge/task/MergeTask.java
@@ -24,8 +24,8 @@ import org.apache.iotdb.db.engine.merge.manage.MergeResource;
 import org.apache.iotdb.db.engine.merge.recover.MergeLogger;
 import org.apache.iotdb.db.engine.storagegroup.TsFileResource;
 import org.apache.iotdb.db.exception.metadata.MetadataException;
-import org.apache.iotdb.db.metadata.mnode.MNode;
-import org.apache.iotdb.db.metadata.mnode.MeasurementMNode;
+import org.apache.iotdb.db.metadata.mnode.IMeasurementMNode;
+import org.apache.iotdb.db.metadata.mnode.ISchemaNode;
 import org.apache.iotdb.db.service.IoTDB;
 import org.apache.iotdb.db.utils.MergeUtils;
 import org.apache.iotdb.tsfile.read.common.Path;
@@ -126,10 +126,10 @@ public class MergeTask implements Callable<Void> {
     Map<Path, MeasurementSchema> measurementSchemaMap = new HashMap<>();
     List<Path> unmergedSeries = new ArrayList<>();
     for (String device : devices) {
-      MNode deviceNode = IoTDB.metaManager.getNodeByPath(device);
-      for (Entry<String, MNode> entry : deviceNode.getChildren().entrySet()) {
+      ISchemaNode deviceNode = IoTDB.metaManager.getNodeByPath(device);
+      for (Entry<String, ISchemaNode> entry : deviceNode.getChildren().entrySet()) {
         Path path = new Path(device, entry.getKey());
-        measurementSchemaMap.put(path, ((MeasurementMNode) entry.getValue()).getSchema());
+        measurementSchemaMap.put(path, ((IMeasurementMNode) entry.getValue()).getSchema());
         unmergedSeries.add(path);
       }
     }
diff --git a/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/StorageGroupProcessor.java b/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/StorageGroupProcessor.java
index 571c30a..a90b575 100755
--- a/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/StorageGroupProcessor.java
+++ b/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/StorageGroupProcessor.java
@@ -78,8 +78,8 @@ import org.apache.iotdb.db.exception.query.OutOfTTLException;
 import org.apache.iotdb.db.exception.query.QueryProcessException;
 import org.apache.iotdb.db.metadata.ISchemaManager;
 import org.apache.iotdb.db.metadata.MManager;
-import org.apache.iotdb.db.metadata.mnode.MNode;
-import org.apache.iotdb.db.metadata.mnode.MeasurementMNode;
+import org.apache.iotdb.db.metadata.mnode.IMeasurementMNode;
+import org.apache.iotdb.db.metadata.mnode.ISchemaNode;
 import org.apache.iotdb.db.qp.physical.crud.DeletePlan;
 import org.apache.iotdb.db.qp.physical.crud.InsertRowPlan;
 import org.apache.iotdb.db.qp.physical.crud.InsertTabletPlan;
@@ -894,16 +894,16 @@ public class StorageGroupProcessor {
   }
 
   private void tryToUpdateBatchInsertLastCache(InsertTabletPlan plan, Long latestFlushedTime) {
-    MNode node = plan.getDeviceMNode();
+    ISchemaNode node = plan.getDeviceMNode();
     String[] measurementList = plan.getMeasurements();
     for (int i = 0; i < measurementList.length; i++) {
       if (plan.getColumns()[i] == null) {
         continue;
       }
       // Update cached last value with high priority
-      MeasurementMNode tmpMeasurementNode = null;
+      IMeasurementMNode tmpMeasurementNode = null;
       if (node != null) {
-        tmpMeasurementNode = (MeasurementMNode) node.getChild(measurementList[i]);
+        tmpMeasurementNode = (IMeasurementMNode) node.getChild(measurementList[i]);
       }
       if (tmpMeasurementNode != null) {
         // just for performance, because in single node version, we do not need the full path of measurement
@@ -950,16 +950,16 @@ public class StorageGroupProcessor {
   }
 
   private void tryToUpdateInsertLastCache(InsertRowPlan plan, Long latestFlushedTime) {
-    MNode node = plan.getDeviceMNode();
+    ISchemaNode node = plan.getDeviceMNode();
     String[] measurementList = plan.getMeasurements();
     for (int i = 0; i < measurementList.length; i++) {
       if (plan.getValues()[i] == null) {
         continue;
       }
       // Update cached last value with high priority
-      MeasurementMNode tmpMeasurementNode = null;
+      IMeasurementMNode tmpMeasurementNode = null;
       if (node != null) {
-        tmpMeasurementNode = (MeasurementMNode) node.getChild(measurementList[i]);
+        tmpMeasurementNode = (IMeasurementMNode) node.getChild(measurementList[i]);
       }
       if (tmpMeasurementNode != null) {
         // just for performance, because in single node version, we do not need the full path of measurement
@@ -1563,17 +1563,17 @@ public class StorageGroupProcessor {
 
   private void tryToDeleteLastCache(String deviceId, String measurementId, long startTime,
       long endTime) throws WriteProcessException {
-    MNode node = null;
+    ISchemaNode node = null;
     try {
       ISchemaManager manager = MManager.getInstance();
       node = manager.getDeviceNodeWithAutoCreateAndReadLock(deviceId);
 
-      MNode measurementNode = manager.getChild(node, measurementId);
+      ISchemaNode measurementNode = manager.getChild(node, measurementId);
       if (measurementNode != null) {
-        TimeValuePair lastPair = ((MeasurementMNode) measurementNode).getCachedLast();
+        TimeValuePair lastPair = ((IMeasurementMNode) measurementNode).getCachedLast();
         if (lastPair != null && startTime <= lastPair.getTimestamp()
             && lastPair.getTimestamp() <= endTime) {
-          ((MeasurementMNode) measurementNode).resetCache();
+          ((IMeasurementMNode) measurementNode).resetCache();
         }
       }
     } catch (MetadataException e) {
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/ISchemaManager.java b/server/src/main/java/org/apache/iotdb/db/metadata/ISchemaManager.java
index 3e66be1..b52ddbe 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/ISchemaManager.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/ISchemaManager.java
@@ -26,10 +26,9 @@ import java.util.Set;
 import org.apache.iotdb.db.exception.metadata.IllegalPathException;
 import org.apache.iotdb.db.exception.metadata.MetadataException;
 import org.apache.iotdb.db.exception.metadata.StorageGroupNotSetException;
-import org.apache.iotdb.db.metadata.MManager.StorageGroupFilter;
-import org.apache.iotdb.db.metadata.mnode.MNode;
-import org.apache.iotdb.db.metadata.mnode.MeasurementMNode;
-import org.apache.iotdb.db.metadata.mnode.StorageGroupMNode;
+import org.apache.iotdb.db.metadata.mnode.IMeasurementMNode;
+import org.apache.iotdb.db.metadata.mnode.ISchemaNode;
+import org.apache.iotdb.db.metadata.mnode.IStorageGroupMNode;
 import org.apache.iotdb.db.qp.physical.crud.InsertPlan;
 import org.apache.iotdb.db.qp.physical.sys.CreateTimeSeriesPlan;
 import org.apache.iotdb.db.qp.physical.sys.ShowTimeSeriesPlan;
@@ -163,7 +162,7 @@ public interface ISchemaManager {
    *
    * @return all storage group nodes in the system
    */
-  List<StorageGroupMNode> getAllStorageGroupNodes();
+  List<IStorageGroupMNode> getAllStorageGroupNodes();
 
   /**
    * get all full paths which match the given prefix Path.
@@ -212,73 +211,266 @@ public interface ISchemaManager {
   MeasurementSchema getSeriesSchema(String device, String measurement)
           throws MetadataException;
 
+  /**
+   * get the direct child nodes of the given path.
+   * @param path a prefix of a path, starts with root, can contain *.
+   * @return the full paths of the child nodes
+   * @throws MetadataException
+   */
   Set<String> getChildNodePathInNextLevel(String path) throws MetadataException;
 
+  /**
+   * Whether a (prefix) path exist. The path does not contain *.
+   * @param path
+   * @return
+   */
   boolean isPathExist(String path);
 
-  MNode getNodeByPath(String path) throws MetadataException;
+  /**
+   * convert the given path to a schemaNode structure
+   * @param path a path which has no *.
+   * @return
+   * @throws MetadataException
+   */
+  ISchemaNode getNodeByPath(String path) throws MetadataException;
 
-  StorageGroupMNode getStorageGroupNode(String path) throws MetadataException;
+  /**
+   * check whether the path is a registered Storage group.
+   * If so, convert it to IStorageGroupMNode structure.
+   * Otherwise, throw StorageGroupNotFound Exception
+   * @param path
+   * @return
+   * @throws MetadataException
+   */
+  IStorageGroupMNode getStorageGroupNode(String path) throws MetadataException;
 
-  MNode getDeviceNodeWithAutoCreateAndReadLock(
+  /**
+   * get the device node structure, and apply the read lock of the node.
+   * If the node does not exist, and autoCreateSchema==true, then create it (and its parents)
+   * @param path a path which represents a device.
+   * @param autoCreateSchema whether register the device into IoTDB instance.
+   * @param sgLevel which level of the path will be considered as the storage group.
+   * @return the Node that represents to the device. (node.children() will be measurements)
+   * @throws MetadataException
+   */
+  ISchemaNode getDeviceNodeWithAutoCreateAndReadLock(
       String path, boolean autoCreateSchema, int sgLevel) throws MetadataException;
 
-  MNode getDeviceNodeWithAutoCreateAndReadLock(String path) throws MetadataException;
+  /**
+   * get the device node structure, and apply the read lock of the node.
+   * If the node does not exist, and IoTDB allows auto create schema, then create it (and its parents)
+   * @param path  a path which represents a device.
+   * @return the Node that represents to the device. (node.children() will be measurements)
+   * @throws MetadataException
+   */
+  ISchemaNode getDeviceNodeWithAutoCreateAndReadLock(String path) throws MetadataException;
 
-  MNode getDeviceNode(String path) throws MetadataException;
+  /**
+   * get the device node structure
+   * @param path  a path which represents a device.
+   * @return
+   * @throws MetadataException PathNotExistException or StorageGroupNotSetException
+   */
+  ISchemaNode getDeviceNode(String path) throws MetadataException;
 
+  /**
+   * given a path, find the same string in memory to reduce the memory cost.
+   * @param path a path which represents a device.
+   * @return
+   */
   String getDeviceId(String path);
 
-  MNode getChild(MNode parent, String child);
+  /**
+   * find the child of a given node.
+   * @param parent
+   * @param child
+   * @return the child node structure or null if not found
+   */
+  ISchemaNode getChild(ISchemaNode parent, String child);
 
+  /**
+   * convert the whole schema into json format (except the first two lines).
+   * e.g.,
+   * <pre>
+   * ===  Timeseries Tree  ===
+   *
+   * {
+   * 	"root":{
+   * 		"ln":{
+   * 			"wf01":{
+   * 				"wt01":{
+   * 					"status":{
+   * 						"args":"{}",
+   * 						"StorageGroup":"root.ln",
+   * 						"DataType":"BOOLEAN",
+   * 						"Compressor":"UNCOMPRESSED",
+   * 						"Encoding":"PLAIN"
+   *          }
+   *        }
+   * 			}
+   * 		}
+   * 	}
+   * }
+   * </pre>
+   * @return
+   */
   String getMetadataInString();
 
   @TestOnly
+  /**
+   * just for test.
+   * set the maximal number of time series among all storage groups.
+   */
   void setMaxSeriesNumberAmongStorageGroup(long maxSeriesNumberAmongStorageGroup);
 
+  /**
+   * find the maximal number of time series among all storage groups.
+   * e.g., sg1 has 5 series, and sg2 has 10 series, and then the result is 10.
+   * @return
+   */
   long getMaximalSeriesNumberAmongStorageGroups();
 
+  /**
+   * set the data time-to-live under a given storage group.
+   * The data will be (lazy) removed after IoTDB instance's system time > dataTTL + data's timestamp
+   * @param storageGroup
+   * @param dataTTL unit: ms.
+   * @throws MetadataException
+   * @throws IOException
+   */
   void setTTL(String storageGroup, long dataTTL) throws MetadataException, IOException;
 
+  /**
+   * get the TTLs of all storage groups
+   * @return
+   */
   Map<String, Long> getStorageGroupsTTL();
 
-  void changeOffset(String path, long offset) throws MetadataException;
-
-  void changeAlias(String path, String alias) throws MetadataException;
-
+  /**
+   * update or insert new alias, tags, and attributes to a given time series
+   * @param alias can be null if you do not want to update/insert the alias
+   * @param tagsMap can be null if you do not want to update/insert the tags
+   * @param attributesMap can be null if you do not want to update/insert the attributes
+   * @param fullPath full path of a time series
+   * @throws MetadataException
+   * @throws IOException
+   */
   void upsertTagsAndAttributes(String alias, Map<String, String> tagsMap,
       Map<String, String> attributesMap, String fullPath) throws MetadataException, IOException;
 
+  /**
+   * add a set of attribute keys and attribute values to a given series.
+   * Attributes does not allow query by attribute value
+   * @param attributesMap
+   * @param fullPath full path of a time series
+   * @throws MetadataException
+   * @throws IOException
+   */
   void addAttributes(Map<String, String> attributesMap, String fullPath)
           throws MetadataException, IOException;
 
+  /**
+   * add a set of tag keys and tag values to a given series.
+   * @param tagsMap
+   * @param fullPath full path of a time series
+   * @throws MetadataException
+   * @throws IOException
+   */
   void addTags(Map<String, String> tagsMap, String fullPath)
               throws MetadataException, IOException;
 
+  /**
+   * remote the given keys from a time series's tags or attributes
+   * @param keySet
+   * @param fullPath
+   * @throws MetadataException
+   * @throws IOException
+   */
   void dropTagsOrAttributes(Set<String> keySet, String fullPath)
                   throws MetadataException, IOException;
 
+  /**
+   * add or change the values of tags or attributes
+   *
+   * For each key, if the key is an existing tag key, then update its value.
+   * If the key is not an existing tag key, then either update the key's value in attributes
+   * or save it as an attribute key.
+   *
+   * @param alterMap the updated tags or new/updated attributes key-value
+   * @param fullPath timeseries
+   */
   void setTagsOrAttributesValue(Map<String, String> alterMap, String fullPath)
                       throws MetadataException, IOException;
-
+  /**
+   * rename the tag or attribute's key of the timeseries
+   *
+   * @param oldKey   old key of tag or attribute
+   * @param newKey   new key of tag or attribute
+   * @param fullPath timeseries
+   */
   void renameTagOrAttributeKey(String oldKey, String newKey, String fullPath)
                           throws MetadataException, IOException;
 
-  void collectTimeseriesSchema(MNode startingNode,
+  /**
+   * collect all timeseries that have the given prefix path of the startingNode
+   * @param startingNode
+   * @param timeseriesSchemas
+   */
+  void collectTimeseriesSchema(ISchemaNode startingNode,
       Collection<TimeseriesSchema> timeseriesSchemas);
 
-  void collectMeasurementSchema(MNode startingNode,
+  /**
+   * collect all timeseries that have the given prefix path of the startingNode
+   * @param startingNode
+   * @param timeseriesSchemas
+   */
+  void collectMeasurementSchema(ISchemaNode startingNode,
       Collection<MeasurementSchema> timeseriesSchemas);
 
+  /**
+   * the same to collectMeasurementSchema(ISchemaNode startingNode,
+   *       Collection<MeasurementSchema> timeseriesSchemas)
+   * @param startingPath
+   * @param measurementSchemas
+   */
   void collectSeries(String startingPath, List<MeasurementSchema> measurementSchemas);
 
+  /**
+   * For a path, infer all storage groups it may belong to.
+   *
+   * The input path can have *. Therefore, there may be more than one storage groups match the prefix
+   * of the path.
+   *
+   * given a path, find all storage groups that can match the prefix of the path.
+   * For each storage group, use the storage group to replace the prefix of the path if the prefix contains *.
+   * Collect all storage groups as keys and the replaced paths as values.
+   *
+   * Notice:
+   *
+   * If the * is not at the tail of the path, then only one level will be inferred by the *.
+   * If the wildcard is at the tail, then the inference will go on until the storage groups are found
+   * and the wildcard will be kept.
+   *
+   * <p>
+   *   Assuming we have three SGs: root.group1, root.group2, root.area1.group3
+   *   <br/>Eg1: for input "root.*",
+   *   returns ("root.group1", "root.group1.*"), ("root.group2", "root.group2.*")
+   * ("root.area1.group3", "root.area1.group3.*")
+   * <br/> Eg2: for input "root.*.s1.*.b",
+   * returns ("root.group1", "root.group1.s1.*.b"), ("root.group2", "root.group2.s1.*.b")
+   *
+   * <p>Eg3: for input "root.area1.*", returns ("root.area1.group3", "root.area1.group3.*")
+   *
+   * @param path can be a prefix or a full path. can has *.
+   * @return StorageGroupName-FullPath pairs
+   */
   Map<String, String> determineStorageGroup(String path) throws IllegalPathException;
 
   void cacheMeta(String path, MeasurementMeta meta);
 
   void updateLastCache(String seriesPath, TimeValuePair timeValuePair,
       boolean highPriorityUpdate, Long latestFlushedTime,
-      MeasurementMNode node);
+      IMeasurementMNode node);
 
   TimeValuePair getLastCache(String seriesPath);
 
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 4f8eced..d5ad870 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
@@ -56,9 +56,10 @@ import org.apache.iotdb.db.exception.metadata.MetadataException;
 import org.apache.iotdb.db.exception.metadata.PathNotExistException;
 import org.apache.iotdb.db.exception.metadata.StorageGroupAlreadySetException;
 import org.apache.iotdb.db.exception.metadata.StorageGroupNotSetException;
-import org.apache.iotdb.db.metadata.mnode.MNode;
+import org.apache.iotdb.db.metadata.mnode.IMeasurementMNode;
+import org.apache.iotdb.db.metadata.mnode.ISchemaNode;
+import org.apache.iotdb.db.metadata.mnode.IStorageGroupMNode;
 import org.apache.iotdb.db.metadata.mnode.MeasurementMNode;
-import org.apache.iotdb.db.metadata.mnode.StorageGroupMNode;
 import org.apache.iotdb.db.monitor.MonitorConstants;
 import org.apache.iotdb.db.qp.constant.SQLConstant;
 import org.apache.iotdb.db.qp.physical.crud.InsertPlan;
@@ -111,10 +112,10 @@ public class MManager implements ISchemaManager {
   private TagLogFile tagLogFile;
   private boolean isRecovering;
   // device -> DeviceMNode
-  private RandomDeleteCache<String, MNode> mNodeCache;
+  private RandomDeleteCache<String, ISchemaNode> mNodeCache;
 
   // tag key -> tag value -> LeafMNode
-  private Map<String, Map<String, Set<MeasurementMNode>>> tagIndex = new HashMap<>();
+  private Map<String, Map<String, Set<IMeasurementMNode>>> tagIndex = new HashMap<>();
 
   // storage group name -> the series number
   private Map<String, Integer> seriesNumberInStorageGroups = new HashMap<>();
@@ -157,10 +158,10 @@ public class MManager implements ISchemaManager {
     isRecovering = true;
 
     int cacheSize = config.getmManagerCacheSize();
-    mNodeCache = new RandomDeleteCache<String, MNode>(cacheSize) {
+    mNodeCache = new RandomDeleteCache<String, ISchemaNode>(cacheSize) {
 
       @Override
-      public MNode loadObjectByKey(String key) throws CacheException {
+      public ISchemaNode loadObjectByKey(String key) throws CacheException {
         lock.readLock().lock();
         try {
           return mtree.getNodeByPathWithStorageGroupCheck(key);
@@ -208,7 +209,7 @@ public class MManager implements ISchemaManager {
       if (config.isEnableParameterAdapter()) {
         List<String> storageGroups = mtree.getAllStorageGroupNames();
         for (String sg : storageGroups) {
-          MNode node = mtree.getNodeByPath(sg);
+          ISchemaNode node = mtree.getNodeByPath(sg);
           seriesNumberInStorageGroups.put(sg, node.getLeafCount());
         }
         maxSeriesNumberAmongStorageGroup =
@@ -393,7 +394,7 @@ public class MManager implements ISchemaManager {
       IoTDBConfigDynamicAdapter.getInstance().addOrDeleteTimeSeries(1);
 
       // create time series in MTree
-      MeasurementMNode leafMNode = mtree
+      IMeasurementMNode leafMNode = mtree
           .createTimeseries(path, plan.getDataType(), plan.getEncoding(), plan.getCompressor(),
               plan.getProps(), plan.getAlias());
 
@@ -505,7 +506,7 @@ public class MManager implements ISchemaManager {
   /**
    * remove the node from the tag inverted index
    */
-  private void removeFromTagInvertedIndex(MeasurementMNode node) throws IOException {
+  private void removeFromTagInvertedIndex(IMeasurementMNode node) throws IOException {
     if (node.getOffset() < 0) {
       return;
     }
@@ -549,7 +550,7 @@ public class MManager implements ISchemaManager {
       throws MetadataException, IOException {
     lock.writeLock().lock();
     try {
-      Pair<String, MeasurementMNode> pair = mtree.deleteTimeseriesAndReturnEmptyStorageGroup(path);
+      Pair<String, IMeasurementMNode> pair = mtree.deleteTimeseriesAndReturnEmptyStorageGroup(path);
       removeFromTagInvertedIndex(pair.right);
       String storageGroupName = pair.left;
 
@@ -620,8 +621,8 @@ public class MManager implements ISchemaManager {
         mNodeCache.clear();
 
         // try to delete storage group
-        List<MeasurementMNode> leafMNodes = mtree.deleteStorageGroup(storageGroup);
-        for (MeasurementMNode leafMNode : leafMNodes) {
+        List<IMeasurementMNode> leafMNodes = mtree.deleteStorageGroup(storageGroup);
+        for (IMeasurementMNode leafMNode : leafMNodes) {
           removeFromTagInvertedIndex(leafMNode);
         }
 
@@ -689,13 +690,13 @@ public class MManager implements ISchemaManager {
       throws MetadataException {
     lock.readLock().lock();
     try {
-      MNode deviceNode = getNodeByPath(deviceId);
+      ISchemaNode deviceNode = getNodeByPath(deviceId);
       MeasurementSchema[] measurementSchemas = new MeasurementSchema[measurements.length];
       for (int i = 0; i < measurementSchemas.length; i++) {
         if (!deviceNode.hasChild(measurements[i])) {
           throw new MetadataException(measurements[i] + " does not exist in " + deviceId);
         }
-        measurementSchemas[i] = ((MeasurementMNode) deviceNode.getChild(measurements[i]))
+        measurementSchemas[i] = ((IMeasurementMNode) deviceNode.getChild(measurements[i]))
             .getSchema();
       }
       return measurementSchemas;
@@ -779,7 +780,7 @@ public class MManager implements ISchemaManager {
    * Get all storage group MNodes
    */
   @Override
-  public List<StorageGroupMNode> getAllStorageGroupNodes() {
+  public List<IStorageGroupMNode> getAllStorageGroupNodes() {
     lock.readLock().lock();
     try {
       return mtree.getAllStorageGroupNodes();
@@ -855,21 +856,21 @@ public class MManager implements ISchemaManager {
       if (!tagIndex.containsKey(plan.getKey())) {
         throw new MetadataException("The key " + plan.getKey() + " is not a tag.");
       }
-      Map<String, Set<MeasurementMNode>> value2Node = tagIndex.get(plan.getKey());
+      Map<String, Set<IMeasurementMNode>> value2Node = tagIndex.get(plan.getKey());
       if (value2Node.isEmpty()) {
         throw new MetadataException("The key " + plan.getKey() + " is not a tag.");
       }
 
-      List<MeasurementMNode> allMatchedNodes = new ArrayList<>();
+      List<IMeasurementMNode> allMatchedNodes = new ArrayList<>();
       if (plan.isContains()) {
-        for (Entry<String, Set<MeasurementMNode>> entry : value2Node.entrySet()) {
+        for (Entry<String, Set<IMeasurementMNode>> entry : value2Node.entrySet()) {
           String tagValue = entry.getKey();
           if (tagValue.contains(plan.getValue())) {
             allMatchedNodes.addAll(entry.getValue());
           }
         }
       } else {
-        for (Entry<String, Set<MeasurementMNode>> entry : value2Node.entrySet()) {
+        for (Entry<String, Set<IMeasurementMNode>> entry : value2Node.entrySet()) {
           String tagValue = entry.getKey();
           if (plan.getValue().equals(tagValue)) {
             allMatchedNodes.addAll(entry.getValue());
@@ -880,11 +881,11 @@ public class MManager implements ISchemaManager {
       // if ordered by heat, we sort all the timeseries by the descending order of the last insert timestamp
       if (plan.isOrderByHeat()) {
         allMatchedNodes = allMatchedNodes.stream().sorted(Comparator
-            .comparingLong((MeasurementMNode mNode) -> MTree.getLastTimeStamp(mNode, context))
-            .reversed().thenComparing(MNode::getFullPath)).collect(toList());
+            .comparingLong((IMeasurementMNode mNode) -> MTree.getLastTimeStamp(mNode, context))
+            .reversed().thenComparing(ISchemaNode::getFullPath)).collect(toList());
       } else {
         // otherwise, we just sort them by the alphabetical order
-        allMatchedNodes = allMatchedNodes.stream().sorted(Comparator.comparing(MNode::getFullPath))
+        allMatchedNodes = allMatchedNodes.stream().sorted(Comparator.comparing(ISchemaNode::getFullPath))
             .collect(toList());
       }
 
@@ -894,7 +895,7 @@ public class MManager implements ISchemaManager {
       int count = 0;
       int limit = plan.getLimit();
       int offset = plan.getOffset();
-      for (MeasurementMNode leaf : allMatchedNodes) {
+      for (IMeasurementMNode leaf : allMatchedNodes) {
         if (match(leaf.getFullPath(), prefixNodes)) {
           if (limit != 0 || offset != 0) {
             curOffset++;
@@ -1000,10 +1001,10 @@ public class MManager implements ISchemaManager {
       throws MetadataException {
     lock.readLock().lock();
     try {
-      MNode node = mtree.getNodeByPath(device);
-      MNode leaf = node.getChild(measurement);
+      ISchemaNode node = mtree.getNodeByPath(device);
+      ISchemaNode leaf = node.getChild(measurement);
       if (leaf != null) {
-        return ((MeasurementMNode) leaf).getSchema();
+        return ((IMeasurementMNode) leaf).getSchema();
       }
       return null;
     } catch (PathNotExistException | IllegalPathException e) {
@@ -1051,7 +1052,7 @@ public class MManager implements ISchemaManager {
    * Get node by path
    */
   @Override
-  public MNode getNodeByPath(String path) throws MetadataException {
+  public ISchemaNode getNodeByPath(String path) throws MetadataException {
     lock.readLock().lock();
     try {
       return mtree.getNodeByPath(path);
@@ -1065,7 +1066,7 @@ public class MManager implements ISchemaManager {
    * be thrown
    */
   @Override
-  public StorageGroupMNode getStorageGroupNode(String path) throws MetadataException {
+  public IStorageGroupMNode getStorageGroupNode(String path) throws MetadataException {
     lock.readLock().lock();
     try {
       return mtree.getStorageGroupNode(path);
@@ -1083,11 +1084,12 @@ public class MManager implements ISchemaManager {
    * @param path path
    */
   @Override
-  public MNode getDeviceNodeWithAutoCreateAndReadLock(
+  public ISchemaNode getDeviceNodeWithAutoCreateAndReadLock(
       String path, boolean autoCreateSchema, int sgLevel) throws MetadataException {
     lock.readLock().lock();
-    MNode node = null;
+    ISchemaNode node = null;
     boolean shouldSetStorageGroup;
+    // if the node exists, then get its read lock and return directly.
     try {
       node = mNodeCache.get(path);
       return node;
@@ -1102,7 +1104,9 @@ public class MManager implements ISchemaManager {
       lock.readLock().unlock();
     }
 
+    // if the node does not exist, try to create it.
     lock.writeLock().lock();
+    // to avoid concurrent problem, we have to double check after getting the write lock.
     try {
       try {
         node = mNodeCache.get(path);
@@ -1133,15 +1137,15 @@ public class MManager implements ISchemaManager {
    * !!!!!!Attention!!!!! must call the return node's readUnlock() if you call this method.
    */
   @Override
-  public MNode getDeviceNodeWithAutoCreateAndReadLock(String path) throws MetadataException {
+  public ISchemaNode getDeviceNodeWithAutoCreateAndReadLock(String path) throws MetadataException {
     return getDeviceNodeWithAutoCreateAndReadLock(
         path, config.isAutoCreateSchemaEnabled(), config.getDefaultStorageGroupLevel());
   }
 
   @Override
-  public MNode getDeviceNode(String path) throws MetadataException {
+  public ISchemaNode getDeviceNode(String path) throws MetadataException {
     lock.readLock().lock();
-    MNode node;
+    ISchemaNode node;
     try {
       node = mNodeCache.get(path);
       return node;
@@ -1161,7 +1165,7 @@ public class MManager implements ISchemaManager {
    */
   @Override
   public String getDeviceId(String path) {
-    MNode deviceNode = null;
+    ISchemaNode deviceNode = null;
     try {
       deviceNode = getDeviceNode(path);
       path = deviceNode.getFullPath();
@@ -1172,7 +1176,7 @@ public class MManager implements ISchemaManager {
   }
 
   @Override
-  public MNode getChild(MNode parent, String child) {
+  public ISchemaNode getChild(ISchemaNode parent, String child) {
     lock.readLock().lock();
     try {
       return parent.getChild(child);
@@ -1245,18 +1249,16 @@ public class MManager implements ISchemaManager {
    * @param path   timeseries
    * @param offset offset in the tag file
    */
-  @Override
-  public void changeOffset(String path, long offset) throws MetadataException {
+  private void changeOffset(String path, long offset) throws MetadataException {
     lock.writeLock().lock();
     try {
-      ((MeasurementMNode) mtree.getNodeByPath(path)).setOffset(offset);
+      ((IMeasurementMNode) mtree.getNodeByPath(path)).setOffset(offset);
     } finally {
       lock.writeLock().unlock();
     }
   }
 
-  @Override
-  public void changeAlias(String path, String alias) throws MetadataException {
+  private void changeAlias(String path, String alias) throws MetadataException {
     lock.writeLock().lock();
     try {
       MeasurementMNode leafMNode = (MeasurementMNode) mtree.getNodeByPath(path);
@@ -1284,7 +1286,7 @@ public class MManager implements ISchemaManager {
       Map<String, String> attributesMap, String fullPath) throws MetadataException, IOException {
     lock.writeLock().lock();
     try {
-      MNode mNode = mtree.getNodeByPath(fullPath);
+      ISchemaNode mNode = mtree.getNodeByPath(fullPath);
       if (!(mNode instanceof MeasurementMNode)) {
         throw new PathNotExistException(fullPath);
       }
@@ -1388,11 +1390,11 @@ public class MManager implements ISchemaManager {
       throws MetadataException, IOException {
     lock.writeLock().lock();
     try {
-      MNode mNode = mtree.getNodeByPath(fullPath);
+      ISchemaNode mNode = mtree.getNodeByPath(fullPath);
       if (!(mNode instanceof MeasurementMNode)) {
         throw new PathNotExistException(fullPath);
       }
-      MeasurementMNode leafMNode = (MeasurementMNode) mNode;
+      IMeasurementMNode leafMNode = (IMeasurementMNode) mNode;
       // no tag or attribute, we need to add a new record in log
       if (leafMNode.getOffset() < 0) {
         long offset = tagLogFile.write(Collections.emptyMap(), attributesMap);
@@ -1432,11 +1434,11 @@ public class MManager implements ISchemaManager {
       throws MetadataException, IOException {
     lock.writeLock().lock();
     try {
-      MNode mNode = mtree.getNodeByPath(fullPath);
+      ISchemaNode mNode = mtree.getNodeByPath(fullPath);
       if (!(mNode instanceof MeasurementMNode)) {
         throw new PathNotExistException(fullPath);
       }
-      MeasurementMNode leafMNode = (MeasurementMNode) mNode;
+      IMeasurementMNode leafMNode = (IMeasurementMNode) mNode;
       // no tag or attribute, we need to add a new record in log
       if (leafMNode.getOffset() < 0) {
         long offset = tagLogFile.write(tagsMap, Collections.emptyMap());
@@ -1486,11 +1488,11 @@ public class MManager implements ISchemaManager {
       throws MetadataException, IOException {
     lock.writeLock().lock();
     try {
-      MNode mNode = mtree.getNodeByPath(fullPath);
+      ISchemaNode mNode = mtree.getNodeByPath(fullPath);
       if (!(mNode instanceof MeasurementMNode)) {
         throw new PathNotExistException(fullPath);
       }
-      MeasurementMNode leafMNode = (MeasurementMNode) mNode;
+      IMeasurementMNode leafMNode = (IMeasurementMNode) mNode;
       // no tag or attribute, just do nothing.
       if (leafMNode.getOffset() < 0) {
         return;
@@ -1558,11 +1560,11 @@ public class MManager implements ISchemaManager {
       throws MetadataException, IOException {
     lock.writeLock().lock();
     try {
-      MNode mNode = mtree.getNodeByPath(fullPath);
+      ISchemaNode mNode = mtree.getNodeByPath(fullPath);
       if (!(mNode instanceof MeasurementMNode)) {
         throw new PathNotExistException(fullPath);
       }
-      MeasurementMNode leafMNode = (MeasurementMNode) mNode;
+      IMeasurementMNode leafMNode = (IMeasurementMNode) mNode;
       if (leafMNode.getOffset() < 0) {
         throw new MetadataException(
             String.format("TimeSeries [%s] does not have any tag/attribute.", fullPath));
@@ -1638,11 +1640,11 @@ public class MManager implements ISchemaManager {
       throws MetadataException, IOException {
     lock.writeLock().lock();
     try {
-      MNode mNode = mtree.getNodeByPath(fullPath);
+      ISchemaNode mNode = mtree.getNodeByPath(fullPath);
       if (!(mNode instanceof MeasurementMNode)) {
         throw new PathNotExistException(fullPath);
       }
-      MeasurementMNode leafMNode = (MeasurementMNode) mNode;
+      IMeasurementMNode leafMNode = (IMeasurementMNode) mNode;
       if (leafMNode.getOffset() < 0) {
         throw new MetadataException(
             String.format("TimeSeries [%s] does not have [%s] tag/attribute.", fullPath, oldKey));
@@ -1731,14 +1733,14 @@ public class MManager implements ISchemaManager {
   }
 
   @Override
-  public void collectTimeseriesSchema(MNode startingNode,
+  public void collectTimeseriesSchema(ISchemaNode startingNode,
       Collection<TimeseriesSchema> timeseriesSchemas) {
-    Deque<MNode> nodeDeque = new ArrayDeque<>();
+    Deque<ISchemaNode> nodeDeque = new ArrayDeque<>();
     nodeDeque.addLast(startingNode);
     while (!nodeDeque.isEmpty()) {
-      MNode node = nodeDeque.removeFirst();
+      ISchemaNode node = nodeDeque.removeFirst();
       if (node instanceof MeasurementMNode) {
-        MeasurementSchema nodeSchema = ((MeasurementMNode) node).getSchema();
+        MeasurementSchema nodeSchema = ((IMeasurementMNode) node).getSchema();
         timeseriesSchemas.add(new TimeseriesSchema(node.getFullPath(), nodeSchema.getType(),
             nodeSchema.getEncodingType(), nodeSchema.getCompressor()));
       } else if (!node.getChildren().isEmpty()) {
@@ -1748,14 +1750,14 @@ public class MManager implements ISchemaManager {
   }
 
   @Override
-  public void collectMeasurementSchema(MNode startingNode,
+  public void collectMeasurementSchema(ISchemaNode startingNode,
       Collection<MeasurementSchema> timeseriesSchemas) {
-    Deque<MNode> nodeDeque = new ArrayDeque<>();
+    Deque<ISchemaNode> nodeDeque = new ArrayDeque<>();
     nodeDeque.addLast(startingNode);
     while (!nodeDeque.isEmpty()) {
-      MNode node = nodeDeque.removeFirst();
+      ISchemaNode node = nodeDeque.removeFirst();
       if (node instanceof MeasurementMNode) {
-        MeasurementSchema nodeSchema = ((MeasurementMNode) node).getSchema();
+        MeasurementSchema nodeSchema = ((IMeasurementMNode) node).getSchema();
         timeseriesSchemas.add(new MeasurementSchema(node.getFullPath(), nodeSchema.getType(),
             nodeSchema.getEncodingType(), nodeSchema.getCompressor()));
       } else if (!node.getChildren().isEmpty()) {
@@ -1772,7 +1774,7 @@ public class MManager implements ISchemaManager {
    */
   @Override
   public void collectSeries(String startingPath, List<MeasurementSchema> measurementSchemas) {
-    MNode mNode;
+    ISchemaNode mNode;
     try {
       mNode = getNodeByPath(startingPath);
     } catch (MetadataException e) {
@@ -1837,12 +1839,12 @@ public class MManager implements ISchemaManager {
   @Override
   public void updateLastCache(String seriesPath, TimeValuePair timeValuePair,
       boolean highPriorityUpdate, Long latestFlushedTime,
-      MeasurementMNode node) {
+      IMeasurementMNode node) {
     if (node != null) {
       node.updateCachedLast(timeValuePair, highPriorityUpdate, latestFlushedTime);
     } else {
       try {
-        MeasurementMNode node1 = (MeasurementMNode) mtree.getNodeByPath(seriesPath);
+        IMeasurementMNode node1 = (IMeasurementMNode) mtree.getNodeByPath(seriesPath);
         node1.updateCachedLast(timeValuePair, highPriorityUpdate, latestFlushedTime);
       } catch (MetadataException e) {
         logger.warn("failed to update last cache for the {}, err:{}", seriesPath, e.getMessage());
@@ -1853,7 +1855,7 @@ public class MManager implements ISchemaManager {
   @Override
   public TimeValuePair getLastCache(String seriesPath) {
     try {
-      MeasurementMNode node = (MeasurementMNode) mtree.getNodeByPath(seriesPath);
+      IMeasurementMNode node = (IMeasurementMNode) mtree.getNodeByPath(seriesPath);
       return node.getCachedLast();
     } catch (MetadataException e) {
       logger.warn("failed to get last cache for the {}, err:{}", seriesPath, e.getMessage());
@@ -1924,7 +1926,7 @@ public class MManager implements ISchemaManager {
       String[] measurementList, InsertPlan plan) throws MetadataException {
     MeasurementSchema[] schemas = new MeasurementSchema[measurementList.length];
 
-    MNode deviceNode;
+    ISchemaNode deviceNode;
     // 1. get device node
     deviceNode = getDeviceNodeWithAutoCreateAndReadLock(deviceId);
 
@@ -1952,7 +1954,7 @@ public class MManager implements ISchemaManager {
               Collections.emptyMap());
         }
 
-        MeasurementMNode measurementNode = (MeasurementMNode) getChild(deviceNode,
+        IMeasurementMNode measurementNode = (IMeasurementMNode) getChild(deviceNode,
             measurementList[i]);
 
         // check type is match
@@ -2056,7 +2058,7 @@ public class MManager implements ISchemaManager {
   @Override
   public void unlockDeviceReadLock(String deviceId) {
     try {
-      MNode mNode = getDeviceNode(deviceId);
+      ISchemaNode mNode = getDeviceNode(deviceId);
       mNode.readUnlock();
     } catch (MetadataException e) {
       // ignore the exception
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/MTree.java b/server/src/main/java/org/apache/iotdb/db/metadata/MTree.java
index 0f8acd4..bc3fc87 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/MTree.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/MTree.java
@@ -61,6 +61,9 @@ import org.apache.iotdb.db.exception.metadata.PathNotExistException;
 import org.apache.iotdb.db.exception.metadata.StorageGroupAlreadySetException;
 import org.apache.iotdb.db.exception.metadata.StorageGroupNotSetException;
 import org.apache.iotdb.db.metadata.MManager.StorageGroupFilter;
+import org.apache.iotdb.db.metadata.mnode.IMeasurementMNode;
+import org.apache.iotdb.db.metadata.mnode.ISchemaNode;
+import org.apache.iotdb.db.metadata.mnode.IStorageGroupMNode;
 import org.apache.iotdb.db.metadata.mnode.MNode;
 import org.apache.iotdb.db.metadata.mnode.MeasurementMNode;
 import org.apache.iotdb.db.metadata.mnode.StorageGroupMNode;
@@ -85,7 +88,7 @@ public class MTree implements Serializable {
   private static final long serialVersionUID = -4200394435237291964L;
   private static final Logger logger = LoggerFactory.getLogger(MTree.class);
 
-  private MNode root;
+  private ISchemaNode root;
   private static transient ThreadLocal<Integer> limit = new ThreadLocal<>();
   private static transient ThreadLocal<Integer> offset = new ThreadLocal<>();
   private static transient ThreadLocal<Integer> count = new ThreadLocal<>();
@@ -95,7 +98,7 @@ public class MTree implements Serializable {
     this.root = new MNode(null, IoTDBConstant.PATH_ROOT);
   }
 
-  private MTree(MNode root) {
+  private MTree(ISchemaNode root) {
     this.root = root;
   }
 
@@ -110,7 +113,7 @@ public class MTree implements Serializable {
    * @param props      props
    * @param alias      alias of measurement
    */
-  MeasurementMNode createTimeseries(
+  IMeasurementMNode createTimeseries(
       String path,
       TSDataType dataType,
       TSEncoding encoding,
@@ -122,7 +125,7 @@ public class MTree implements Serializable {
     if (nodeNames.length <= 2 || !nodeNames[0].equals(root.getName())) {
       throw new IllegalPathException(path);
     }
-    MNode cur = root;
+    ISchemaNode cur = root;
     boolean hasSetStorageGroup = false;
     // 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++) {
@@ -160,12 +163,12 @@ public class MTree implements Serializable {
    *
    * <p>e.g., get root.sg.d1, get or create all internal nodes and return the node of d1
    */
-  MNode getDeviceNodeWithAutoCreating(String deviceId, int sgLevel) throws MetadataException {
+  ISchemaNode getDeviceNodeWithAutoCreating(String deviceId, int sgLevel) throws MetadataException {
     String[] nodeNames = MetaUtils.getNodeNames(deviceId);
     if (nodeNames.length <= 1 || !nodeNames[0].equals(root.getName())) {
       throw new IllegalPathException(deviceId);
     }
-    MNode cur = root;
+    ISchemaNode cur = root;
     for (int i = 1; i < nodeNames.length; i++) {
       if (!cur.hasChild(nodeNames[i])) {
         if (i == sgLevel) {
@@ -187,7 +190,7 @@ public class MTree implements Serializable {
    */
   boolean isPathExist(String path) {
     String[] nodeNames = MetaUtils.getNodeNames(path);
-    MNode cur = root;
+    ISchemaNode cur = root;
     if (!nodeNames[0].equals(root.getName())) {
       return false;
     }
@@ -209,14 +212,14 @@ public class MTree implements Serializable {
    */
   void setStorageGroup(String path) throws MetadataException {
     String[] nodeNames = MetaUtils.getNodeNames(path);
-    MNode cur = root;
+    ISchemaNode cur = root;
     if (nodeNames.length <= 1 || !nodeNames[0].equals(root.getName())) {
       throw new IllegalPathException(path);
     }
     int i = 1;
     // e.g., path = root.a.b.sg, create internal nodes for a, b
     while (i < nodeNames.length - 1) {
-      MNode temp = cur.getChild(nodeNames[i]);
+      ISchemaNode temp = cur.getChild(nodeNames[i]);
       if (temp == null) {
         cur.addChild(nodeNames[i], new MNode(cur, nodeNames[i]));
       } else if (temp instanceof StorageGroupMNode) {
@@ -240,8 +243,8 @@ public class MTree implements Serializable {
   /**
    * Delete a storage group
    */
-  List<MeasurementMNode> deleteStorageGroup(String path) throws MetadataException {
-    MNode cur = getNodeByPath(path);
+  List<IMeasurementMNode> deleteStorageGroup(String path) throws MetadataException {
+    ISchemaNode cur = getNodeByPath(path);
     if (!(cur instanceof StorageGroupMNode)) {
       throw new StorageGroupNotSetException(path);
     }
@@ -250,14 +253,14 @@ public class MTree implements Serializable {
     cur.getParent().deleteChild(cur.getName());
 
     // collect all the LeafMNode in this storage group
-    List<MeasurementMNode> leafMNodes = new LinkedList<>();
-    Queue<MNode> queue = new LinkedList<>();
+    List<IMeasurementMNode> leafMNodes = new LinkedList<>();
+    Queue<ISchemaNode> queue = new LinkedList<>();
     queue.add(cur);
     while (!queue.isEmpty()) {
-      MNode node = queue.poll();
-      for (MNode child : node.getChildren().values()) {
+      ISchemaNode node = queue.poll();
+      for (ISchemaNode child : node.getChildren().values()) {
         if (child instanceof MeasurementMNode) {
-          leafMNodes.add((MeasurementMNode) child);
+          leafMNodes.add((IMeasurementMNode) child);
         } else {
           queue.add(child);
         }
@@ -287,7 +290,7 @@ public class MTree implements Serializable {
     if (nodeNames.length <= 1 || !nodeNames[0].equals(IoTDBConstant.PATH_ROOT)) {
       return false;
     }
-    MNode cur = root;
+    ISchemaNode cur = root;
     int i = 1;
     while (i < nodeNames.length - 1) {
       cur = cur.getChild(nodeNames[i]);
@@ -305,9 +308,9 @@ public class MTree implements Serializable {
    *
    * @param path Format: root.node(.node)+
    */
-  Pair<String, MeasurementMNode> deleteTimeseriesAndReturnEmptyStorageGroup(String path)
+  Pair<String, IMeasurementMNode> deleteTimeseriesAndReturnEmptyStorageGroup(String path)
       throws MetadataException {
-    MNode curNode = getNodeByPath(path);
+    ISchemaNode curNode = getNodeByPath(path);
     if (!(curNode instanceof MeasurementMNode)) {
       throw new PathNotExistException(path);
     }
@@ -317,9 +320,9 @@ public class MTree implements Serializable {
     }
     // delete the last node of path
     curNode.getParent().deleteChild(curNode.getName());
-    MeasurementMNode deletedNode = (MeasurementMNode) curNode;
+    IMeasurementMNode deletedNode = (IMeasurementMNode) curNode;
     if (deletedNode.getAlias() != null) {
-      curNode.getParent().deleteAliasChild(((MeasurementMNode) curNode).getAlias());
+      curNode.getParent().deleteAliasChild(((IMeasurementMNode) curNode).getAlias());
     }
     curNode = curNode.getParent();
     // delete all empty ancestors except storage group
@@ -339,7 +342,7 @@ public class MTree implements Serializable {
    * Get measurement schema for a given path. Path must be a complete Path from root to leaf node.
    */
   MeasurementSchema getSchema(String path) throws MetadataException {
-    MeasurementMNode node = (MeasurementMNode) getNodeByPath(path);
+    IMeasurementMNode node = (IMeasurementMNode) getNodeByPath(path);
     return node.getSchema();
   }
 
@@ -347,14 +350,14 @@ public class MTree implements Serializable {
    * Get node by path with storage group check If storage group is not set,
    * StorageGroupNotSetException will be thrown
    */
-  MNode getNodeByPathWithStorageGroupCheck(String path) throws MetadataException {
+  ISchemaNode getNodeByPathWithStorageGroupCheck(String path) throws MetadataException {
     boolean storageGroupChecked = false;
     String[] nodes = MetaUtils.getNodeNames(path);
     if (nodes.length == 0 || !nodes[0].equals(root.getName())) {
       throw new IllegalPathException(path);
     }
 
-    MNode cur = root;
+    ISchemaNode cur = root;
     for (int i = 1; i < nodes.length; i++) {
       if (!cur.hasChild(nodes[i])) {
         if (!storageGroupChecked) {
@@ -378,10 +381,10 @@ public class MTree implements Serializable {
   /**
    * Get storage group node, if the give path is not a storage group, throw exception
    */
-  StorageGroupMNode getStorageGroupNode(String path) throws MetadataException {
-    MNode node = getNodeByPath(path);
+  IStorageGroupMNode getStorageGroupNode(String path) throws MetadataException {
+    ISchemaNode node = getNodeByPath(path);
     if (node instanceof StorageGroupMNode) {
-      return (StorageGroupMNode) node;
+      return (IStorageGroupMNode) node;
     } else {
       throw new StorageGroupNotSetException(path);
     }
@@ -392,12 +395,12 @@ public class MTree implements Serializable {
    *
    * @return last node in given seriesPath
    */
-  MNode getNodeByPath(String path) throws MetadataException {
+  ISchemaNode getNodeByPath(String path) throws MetadataException {
     String[] nodes = MetaUtils.getNodeNames(path);
     if (nodes.length == 0 || !nodes[0].equals(root.getName())) {
       throw new IllegalPathException(path);
     }
-    MNode cur = root;
+    ISchemaNode cur = root;
     for (int i = 1; i < nodes.length; i++) {
       if (!cur.hasChild(nodes[i])) {
         throw new PathNotExistException(path);
@@ -429,7 +432,7 @@ public class MTree implements Serializable {
    * @apiNote :for cluster
    */
   private void findStorageGroup(
-      MNode node, String[] nodes, int idx, String parent, List<String> storageGroupNames) {
+      ISchemaNode node, String[] nodes, int idx, String parent, List<String> storageGroupNames) {
     if (node instanceof StorageGroupMNode) {
       storageGroupNames.add(node.getFullPath());
       return;
@@ -445,7 +448,7 @@ public class MTree implements Serializable {
             storageGroupNames);
       }
     } else {
-      for (MNode child : node.getChildren().values()) {
+      for (ISchemaNode child : node.getChildren().values()) {
         findStorageGroup(
             child, nodes, idx + 1, parent + node.getName() + PATH_SEPARATOR, storageGroupNames);
       }
@@ -459,10 +462,10 @@ public class MTree implements Serializable {
    */
   List<String> getAllStorageGroupNames() {
     List<String> res = new ArrayList<>();
-    Deque<MNode> nodeStack = new ArrayDeque<>();
+    Deque<ISchemaNode> nodeStack = new ArrayDeque<>();
     nodeStack.add(root);
     while (!nodeStack.isEmpty()) {
-      MNode current = nodeStack.pop();
+      ISchemaNode current = nodeStack.pop();
       if (current instanceof StorageGroupMNode) {
         res.add(current.getFullPath());
       } else {
@@ -475,14 +478,14 @@ public class MTree implements Serializable {
   /**
    * Get all storage group MNodes
    */
-  List<StorageGroupMNode> getAllStorageGroupNodes() {
-    List<StorageGroupMNode> ret = new ArrayList<>();
-    Deque<MNode> nodeStack = new ArrayDeque<>();
+  List<IStorageGroupMNode> getAllStorageGroupNodes() {
+    List<IStorageGroupMNode> ret = new ArrayList<>();
+    Deque<ISchemaNode> nodeStack = new ArrayDeque<>();
     nodeStack.add(root);
     while (!nodeStack.isEmpty()) {
-      MNode current = nodeStack.pop();
+      ISchemaNode current = nodeStack.pop();
       if (current instanceof StorageGroupMNode) {
-        ret.add((StorageGroupMNode) current);
+        ret.add((IStorageGroupMNode) current);
       } else {
         nodeStack.addAll(current.getChildren().values());
       }
@@ -499,7 +502,7 @@ public class MTree implements Serializable {
    */
   String getStorageGroupName(String path) throws StorageGroupNotSetException {
     String[] nodes = MetaUtils.getNodeNames(path);
-    MNode cur = root;
+    ISchemaNode cur = root;
     for (int i = 1; i < nodes.length; i++) {
       cur = cur.getChild(nodes[i]);
       if (cur instanceof StorageGroupMNode) {
@@ -516,7 +519,7 @@ public class MTree implements Serializable {
    */
   boolean checkStorageGroupByPath(String path) {
     String[] nodes = MetaUtils.getNodeNames(path);
-    MNode cur = root;
+    ISchemaNode cur = root;
     for (int i = 1; i <= nodes.length; i++) {
       cur = cur.getChild(nodes[i]);
       if (cur == null) {
@@ -584,7 +587,7 @@ public class MTree implements Serializable {
     if (nodes.length == 0 || !nodes[0].equals(root.getName())) {
       throw new IllegalPathException(prefixPath);
     }
-    MNode node = root;
+    ISchemaNode node = root;
     for (int i = 1; i < nodes.length; i++) {
       if (node.getChild(nodes[i]) != null) {
         node = node.getChild(nodes[i]);
@@ -598,7 +601,7 @@ public class MTree implements Serializable {
   /**
    * Traverse the MTree to get the count of timeseries.
    */
-  private int getCount(MNode node, String[] nodes, int idx) throws MetadataException {
+  private int getCount(ISchemaNode node, String[] nodes, int idx) throws MetadataException {
     String nodeReg = MetaUtils.getNodeRegByIdx(idx, nodes);
     if (!(PATH_WILDCARD).equals(nodeReg)) {
       if (node.hasChild(nodeReg)) {
@@ -612,7 +615,7 @@ public class MTree implements Serializable {
       }
     } else {
       int cnt = 0;
-      for (MNode child : node.getChildren().values()) {
+      for (ISchemaNode child : node.getChildren().values()) {
         if (child instanceof MeasurementMNode) {
           cnt++;
         }
@@ -627,12 +630,12 @@ public class MTree implements Serializable {
    *
    * @param targetLevel Record the distance to the target level, 0 means the target level.
    */
-  private int getCountInGivenLevel(MNode node, int targetLevel) {
+  private int getCountInGivenLevel(ISchemaNode node, int targetLevel) {
     if (targetLevel == 0) {
       return 1;
     }
     int cnt = 0;
-    for (MNode child : node.getChildren().values()) {
+    for (ISchemaNode child : node.getChildren().values()) {
       cnt += getCountInGivenLevel(child, targetLevel - 1);
     }
     return cnt;
@@ -703,7 +706,7 @@ public class MTree implements Serializable {
    * @param timeseriesSchemaList List<timeseriesSchema> result: [name, alias, storage group,
    *                             dataType, encoding, compression, offset, lastTimeStamp]
    */
-  private void findPath(MNode node, String[] nodes, int idx, List<String[]> timeseriesSchemaList,
+  private void findPath(ISchemaNode node, String[] nodes, int idx, List<String[]> timeseriesSchemaList,
       boolean hasLimit, boolean needLast, QueryContext queryContext) throws MetadataException {
     if (node instanceof MeasurementMNode && nodes.length <= idx) {
       if (hasLimit) {
@@ -721,15 +724,15 @@ public class MTree implements Serializable {
       String nodePath = node.getParent().getFullPath() + TsFileConstant.PATH_SEPARATOR + nodeName;
       String[] tsRow = new String[8];
       tsRow[0] = nodePath;
-      tsRow[1] = ((MeasurementMNode) node).getAlias();
-      MeasurementSchema measurementSchema = ((MeasurementMNode) node).getSchema();
+      tsRow[1] = ((IMeasurementMNode) node).getAlias();
+      MeasurementSchema measurementSchema = ((IMeasurementMNode) node).getSchema();
       tsRow[2] = getStorageGroupName(nodePath);
       tsRow[3] = measurementSchema.getType().toString();
       tsRow[4] = measurementSchema.getEncodingType().toString();
       tsRow[5] = measurementSchema.getCompressor().toString();
-      tsRow[6] = String.valueOf(((MeasurementMNode) node).getOffset());
+      tsRow[6] = String.valueOf(((IMeasurementMNode) node).getOffset());
       tsRow[7] =
-          needLast ? String.valueOf(getLastTimeStamp((MeasurementMNode) node, queryContext)) : null;
+          needLast ? String.valueOf(getLastTimeStamp((IMeasurementMNode) node, queryContext)) : null;
       timeseriesSchemaList.add(tsRow);
 
       if (hasLimit) {
@@ -743,7 +746,7 @@ public class MTree implements Serializable {
             queryContext);
       }
     } else {
-      for (MNode child : node.getChildren().values()) {
+      for (ISchemaNode child : node.getChildren().values()) {
         if (!Pattern.matches(nodeReg.replace("*", ".*"), child.getName())) {
           continue;
         }
@@ -757,7 +760,7 @@ public class MTree implements Serializable {
     }
   }
 
-  static long getLastTimeStamp(MeasurementMNode node, QueryContext queryContext) {
+  static long getLastTimeStamp(IMeasurementMNode node, QueryContext queryContext) {
     TimeValuePair last = node.getCachedLast();
     if (last != null) {
       return node.getCachedLast().getTimestamp();
@@ -803,7 +806,7 @@ public class MTree implements Serializable {
    * @param length expected length of path
    */
   private void findChildNodePathInNextLevel(
-      MNode node, String[] nodes, int idx, String parent, Set<String> res, int length) {
+      ISchemaNode node, String[] nodes, int idx, String parent, Set<String> res, int length) {
     String nodeReg = MetaUtils.getNodeRegByIdx(idx, nodes);
     if (!nodeReg.contains(PATH_WILDCARD)) {
       if (idx == length) {
@@ -814,7 +817,7 @@ public class MTree implements Serializable {
       }
     } else {
       if (node.getChildren().size() > 0) {
-        for (MNode child : node.getChildren().values()) {
+        for (ISchemaNode child : node.getChildren().values()) {
           if (!Pattern.matches(nodeReg.replace("*", ".*"), child.getName())) {
             continue;
           }
@@ -860,7 +863,7 @@ public class MTree implements Serializable {
    * @param idx   the current index of array nodes
    * @param res   store all matched device names
    */
-  private void findDevices(MNode node, String[] nodes, int idx, Set<String> res) {
+  private void findDevices(ISchemaNode node, String[] nodes, int idx, Set<String> res) {
     String nodeReg = MetaUtils.getNodeRegByIdx(idx, nodes);
     if (!(PATH_WILDCARD).equals(nodeReg)) {
       if (node.hasChild(nodeReg)) {
@@ -872,7 +875,7 @@ public class MTree implements Serializable {
       }
     } else {
       boolean deviceAdded = false;
-      for (MNode child : node.getChildren().values()) {
+      for (ISchemaNode child : node.getChildren().values()) {
         if (child instanceof MeasurementMNode && !deviceAdded) {
           res.add(node.getFullPath());
           deviceAdded = true;
@@ -899,7 +902,7 @@ public class MTree implements Serializable {
       throw new IllegalPathException(path);
     }
     List<String> res = new ArrayList<>();
-    MNode node = root;
+    ISchemaNode node = root;
     for (int i = 1; i < nodes.length; i++) {
       if (node.getChild(nodes[i]) != null) {
         node = node.getChild(nodes[i]);
@@ -920,7 +923,7 @@ public class MTree implements Serializable {
    *
    * @param targetLevel Record the distance to the target level, 0 means the target level.
    */
-  private void findNodes(MNode node, String path, List<String> res, int targetLevel,
+  private void findNodes(ISchemaNode node, String path, List<String> res, int targetLevel,
       StorageGroupFilter filter) {
     if (node == null || node instanceof StorageGroupMNode && filter != null && !filter
         .satisfy(node.getFullPath())) {
@@ -930,7 +933,7 @@ public class MTree implements Serializable {
       res.add(path);
       return;
     }
-    for (MNode child : node.getChildren().values()) {
+    for (ISchemaNode child : node.getChildren().values()) {
       findNodes(child, path + PATH_SEPARATOR + child.toString(), res, targetLevel - 1, filter);
     }
   }
@@ -945,16 +948,16 @@ public class MTree implements Serializable {
   public static MTree deserializeFrom(File mtreeSnapshot) {
     try (BufferedReader br = new BufferedReader(new FileReader(mtreeSnapshot))) {
       String s;
-      Deque<MNode> nodeStack = new ArrayDeque<>();
-      MNode node = null;
+      Deque<ISchemaNode> nodeStack = new ArrayDeque<>();
+      ISchemaNode node = null;
 
       while ((s = br.readLine()) != null) {
         String[] nodeInfo = s.split(",");
         short nodeType = Short.parseShort(nodeInfo[0]);
         if (nodeType == MetadataConstant.STORAGE_GROUP_MNODE_TYPE) {
-          node = StorageGroupMNode.deserializeFrom(nodeInfo);
+          node = IStorageGroupMNode.deserializeFrom(nodeInfo);
         } else if (nodeType == MetadataConstant.MEASUREMENT_MNODE_TYPE) {
-          node = MeasurementMNode.deserializeFrom(nodeInfo);
+          node = IMeasurementMNode.deserializeFrom(nodeInfo);
         } else {
           node = new MNode(null, nodeInfo[1]);
         }
@@ -963,13 +966,13 @@ public class MTree implements Serializable {
         if (childrenSize == 0) {
           nodeStack.push(node);
         } else {
-          Map<String, MNode> childrenMap = new LinkedHashMap<>();
+          Map<String, ISchemaNode> childrenMap = new LinkedHashMap<>();
           for (int i = 0; i < childrenSize; i++) {
-            MNode child = nodeStack.removeFirst();
+            ISchemaNode child = nodeStack.removeFirst();
             child.setParent(node);
             childrenMap.put(child.getName(), child);
             if (child instanceof MeasurementMNode) {
-              String alias = ((MeasurementMNode) child).getAlias();
+              String alias = ((IMeasurementMNode) child).getAlias();
               if (alias != null) {
                 node.addAlias(alias, child);
               }
@@ -1002,17 +1005,17 @@ public class MTree implements Serializable {
     return JSON.toJSONString(jsonObject, SerializerFeature.PrettyFormat);
   }
 
-  private JSONObject mNodeToJSON(MNode node, String storageGroupName) {
+  private JSONObject mNodeToJSON(ISchemaNode node, String storageGroupName) {
     JSONObject jsonObject = new JSONObject();
     if (node.getChildren().size() > 0) {
       if (node instanceof StorageGroupMNode) {
         storageGroupName = node.getFullPath();
       }
-      for (MNode child : node.getChildren().values()) {
+      for (ISchemaNode child : node.getChildren().values()) {
         jsonObject.put(child.getName(), mNodeToJSON(child, storageGroupName));
       }
     } else if (node instanceof MeasurementMNode) {
-      MeasurementMNode leafMNode = (MeasurementMNode) node;
+      IMeasurementMNode leafMNode = (IMeasurementMNode) node;
       jsonObject.put("DataType", leafMNode.getSchema().getType());
       jsonObject.put("Encoding", leafMNode.getSchema().getEncodingType());
       jsonObject.put("Compressor", leafMNode.getSchema().getCompressor());
@@ -1072,7 +1075,7 @@ public class MTree implements Serializable {
       throw new IllegalPathException(path);
     }
 
-    Deque<MNode> nodeStack = new ArrayDeque<>();
+    Deque<ISchemaNode> nodeStack = new ArrayDeque<>();
     Deque<Integer> depthStack = new ArrayDeque<>();
     if (!root.getChildren().isEmpty()) {
       nodeStack.push(root);
@@ -1080,7 +1083,7 @@ public class MTree implements Serializable {
     }
 
     while (!nodeStack.isEmpty()) {
-      MNode mNode = nodeStack.removeFirst();
+      ISchemaNode mNode = nodeStack.removeFirst();
       int depth = depthStack.removeFirst();
 
       determineStorageGroup(depth + 1, nodes, mNode, paths, nodeStack, depthStack);
@@ -1096,17 +1099,17 @@ public class MTree implements Serializable {
   private void determineStorageGroup(
       int depth,
       String[] nodes,
-      MNode mNode,
+      ISchemaNode mNode,
       Map<String, String> paths,
-      Deque<MNode> nodeStack,
+      Deque<ISchemaNode> nodeStack,
       Deque<Integer> depthStack) {
     String currNode = depth >= nodes.length ? PATH_WILDCARD : nodes[depth];
-    for (Entry<String, MNode> entry : mNode.getChildren().entrySet()) {
+    for (Entry<String, ISchemaNode> entry : mNode.getChildren().entrySet()) {
       if (!currNode.equals(PATH_WILDCARD) && !currNode.equals(entry.getKey())) {
         continue;
       }
       // this child is desired
-      MNode child = entry.getValue();
+      ISchemaNode child = entry.getValue();
       if (child instanceof StorageGroupMNode) {
         // we have found one storage group, record it
         String sgName = child.getFullPath();
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/mnode/IMeasurementMNode.java b/server/src/main/java/org/apache/iotdb/db/metadata/mnode/IMeasurementMNode.java
new file mode 100644
index 0000000..517fdda
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/mnode/IMeasurementMNode.java
@@ -0,0 +1,82 @@
+/*
+ * 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.mnode;
+
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+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;
+import org.apache.iotdb.tsfile.read.TimeValuePair;
+import org.apache.iotdb.tsfile.write.schema.MeasurementSchema;
+
+public interface IMeasurementMNode extends ISchemaNode{
+
+  /**
+   * deserialize MeasuremetMNode from string array
+   *
+   * @param nodeInfo node information array. For example: "2,s0,speed,2,2,1,year:2020;month:jan;,-1,0"
+   * representing: [0] nodeType [1] name [2] alias [3] TSDataType.ordinal() [4] TSEncoding.ordinal()
+   * [5] CompressionType.ordinal() [6] props [7] offset [8] children size
+   */
+  static IMeasurementMNode deserializeFrom(String[] nodeInfo) {
+    String name = nodeInfo[1];
+    String alias = nodeInfo[2].equals("") ? null : nodeInfo[2];
+    Map<String, String> props = new HashMap<>();
+    if (!nodeInfo[6].equals("")) {
+      for (String propInfo : nodeInfo[6].split(";")) {
+        props.put(propInfo.split(":")[0], propInfo.split(":")[1]);
+      }
+    }
+    MeasurementSchema schema = new MeasurementSchema(name,
+        TSDataType.deserialize(Short.valueOf(nodeInfo[3])),
+        TSEncoding.deserialize(Short.valueOf(nodeInfo[4])),
+        CompressionType.deserialize(Short.valueOf(nodeInfo[5])), props);
+    IMeasurementMNode node = new MeasurementMNode(null, name, schema, alias);
+    node.setOffset(Long.valueOf(nodeInfo[7]));
+
+    return node;
+  }
+
+  MeasurementSchema getSchema();
+
+  TimeValuePair getCachedLast();
+
+  void updateCachedLast(
+      TimeValuePair timeValuePair, boolean highPriorityUpdate, Long latestFlushedTime);
+
+  String getFullPath();
+
+  void resetCache();
+
+  long getOffset();
+
+  void setOffset(long offset);
+
+  String getAlias();
+
+  void setAlias(String alias);
+
+  void setSchema(MeasurementSchema schema);
+
+  void serializeTo(BufferedWriter bw) throws IOException;
+}
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/mnode/ISchemaNode.java b/server/src/main/java/org/apache/iotdb/db/metadata/mnode/ISchemaNode.java
new file mode 100644
index 0000000..dd63f4a
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/mnode/ISchemaNode.java
@@ -0,0 +1,67 @@
+/*
+ * 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.mnode;
+
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.util.Map;
+import java.util.concurrent.locks.Lock;
+import org.apache.iotdb.db.exception.metadata.DeleteFailedException;
+
+public interface ISchemaNode {
+
+  boolean hasChild(String name);
+
+  void addChild(String name, ISchemaNode child);
+
+  void deleteChild(String name) throws DeleteFailedException;
+
+  void deleteAliasChild(String alias) throws DeleteFailedException;
+
+  ISchemaNode getChild(String name);
+
+  int getLeafCount();
+
+  void addAlias(String alias, ISchemaNode child);
+
+  String getFullPath();
+
+  ISchemaNode getParent();
+
+  void setParent(ISchemaNode parent);
+
+  Map<String, ISchemaNode> getChildren();
+
+  String getName();
+
+  void setName(String name);
+
+  void setChildren(Map<String, ISchemaNode> children);
+
+  void serializeTo(BufferedWriter bw) throws IOException;
+
+  void readLock();
+
+  void readUnlock();
+
+  Lock getWriteLock();
+
+  Lock getReadLock();
+}
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/mnode/IStorageGroupMNode.java b/server/src/main/java/org/apache/iotdb/db/metadata/mnode/IStorageGroupMNode.java
new file mode 100644
index 0000000..df93287
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/mnode/IStorageGroupMNode.java
@@ -0,0 +1,36 @@
+/*
+ * 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.mnode;
+
+import java.io.BufferedWriter;
+import java.io.IOException;
+
+public interface IStorageGroupMNode extends ISchemaNode{
+
+  static IStorageGroupMNode deserializeFrom(String[] nodeInfo) {
+    return new StorageGroupMNode(null, nodeInfo[1], Long.valueOf(nodeInfo[2]));
+  }
+
+  long getDataTTL();
+
+  void setDataTTL(long dataTTL);
+
+  void serializeTo(BufferedWriter bw) throws IOException;
+}
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/mnode/MNode.java b/server/src/main/java/org/apache/iotdb/db/metadata/mnode/MNode.java
index 002540d..4f2e955 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/mnode/MNode.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/mnode/MNode.java
@@ -29,6 +29,7 @@ import java.util.Map.Entry;
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReadWriteLock;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
 import org.apache.iotdb.db.conf.IoTDBConstant;
 import org.apache.iotdb.db.exception.metadata.DeleteFailedException;
 import org.apache.iotdb.db.metadata.MetadataConstant;
@@ -37,7 +38,7 @@ import org.apache.iotdb.db.metadata.MetadataConstant;
  * This class is the implementation of Metadata Node. One MNode instance represents one node in the
  * Metadata Tree
  */
-public class MNode implements Serializable {
+public class MNode implements Serializable, ISchemaNode {
 
   private static final long serialVersionUID = -770028375899514063L;
 
@@ -46,22 +47,22 @@ public class MNode implements Serializable {
    */
   protected String name;
 
-  protected MNode parent;
+  protected ISchemaNode parent;
 
   /**
    * from root to this node, only be set when used once for InternalMNode
    */
   protected String fullPath;
 
-  transient Map<String, MNode> children;
-  transient Map<String, MNode> aliasChildren;
+  transient Map<String, ISchemaNode> children;
+  transient Map<String, ISchemaNode> aliasChildren;
 
   protected transient ReadWriteLock lock = new ReentrantReadWriteLock();
 
   /**
    * Constructor of MNode.
    */
-  public MNode(MNode parent, String name) {
+  public MNode(ISchemaNode parent, String name) {
     this.parent = parent;
     this.name = name;
   }
@@ -69,6 +70,7 @@ public class MNode implements Serializable {
   /**
    * check whether the MNode has a child with the name
    */
+  @Override
   public boolean hasChild(String name) {
     return (children != null && children.containsKey(name)) ||
         (aliasChildren != null && aliasChildren.containsKey(name));
@@ -77,7 +79,8 @@ public class MNode implements Serializable {
   /**
    * node key, name or alias
    */
-  public void addChild(String name, MNode child) {
+  @Override
+  public void addChild(String name, ISchemaNode child) {
     if (children == null) {
       children = new LinkedHashMap<>();
     }
@@ -87,10 +90,11 @@ public class MNode implements Serializable {
   /**
    * delete a child
    */
+  @Override
   public void deleteChild(String name) throws DeleteFailedException {
     if (children != null && children.containsKey(name)) {
       // acquire the write lock of its child node.
-      Lock writeLock = (children.get(name)).lock.writeLock();
+      Lock writeLock = (children.get(name)).getWriteLock();
       if (writeLock.tryLock()) {
         children.remove(name);
         writeLock.unlock();
@@ -103,6 +107,7 @@ public class MNode implements Serializable {
   /**
    * delete the alias of a child
    */
+  @Override
   public void deleteAliasChild(String alias) throws DeleteFailedException {
     if (aliasChildren == null) {
       return;
@@ -118,8 +123,9 @@ public class MNode implements Serializable {
   /**
    * get the child with the name
    */
-  public MNode getChild(String name) {
-    MNode child = null;
+  @Override
+  public ISchemaNode getChild(String name) {
+    ISchemaNode child = null;
     if (children != null) {
       child = children.get(name);
     }
@@ -132,12 +138,13 @@ public class MNode implements Serializable {
   /**
    * get the count of all leaves whose ancestor is current node
    */
+  @Override
   public int getLeafCount() {
     if (children == null) {
       return 0;
     }
     int leafCount = 0;
-    for (MNode child : children.values()) {
+    for (ISchemaNode child : children.values()) {
       leafCount += child.getLeafCount();
     }
     return leafCount;
@@ -146,7 +153,8 @@ public class MNode implements Serializable {
   /**
    * add an alias
    */
-  public void addAlias(String alias, MNode child) {
+  @Override
+  public void addAlias(String alias, ISchemaNode child) {
     if (aliasChildren == null) {
       aliasChildren = new LinkedHashMap<>();
     }
@@ -156,6 +164,7 @@ public class MNode implements Serializable {
   /**
    * get full path
    */
+  @Override
   public String getFullPath() {
     if (fullPath != null) {
       return fullPath;
@@ -166,10 +175,10 @@ public class MNode implements Serializable {
 
   String concatFullPath() {
     StringBuilder builder = new StringBuilder(name);
-    MNode curr = this;
+    ISchemaNode curr = this;
     while (curr.getParent() != null) {
       curr = curr.getParent();
-      builder.insert(0, IoTDBConstant.PATH_SEPARATOR).insert(0, curr.name);
+      builder.insert(0, IoTDBConstant.PATH_SEPARATOR).insert(0, curr.getName());
     }
     return builder.toString();
   }
@@ -179,33 +188,40 @@ public class MNode implements Serializable {
     return this.getName();
   }
 
-  public MNode getParent() {
+  @Override
+  public ISchemaNode getParent() {
     return parent;
   }
 
-  public void setParent(MNode parent) {
+  @Override
+  public void setParent(ISchemaNode parent) {
     this.parent = parent;
   }
 
-  public Map<String, MNode> getChildren() {
+  @Override
+  public Map<String, ISchemaNode> getChildren() {
     if (children == null) {
       return new LinkedHashMap<>();
     }
     return children;
   }
 
+  @Override
   public String getName() {
     return name;
   }
 
+  @Override
   public void setName(String name) {
     this.name = name;
   }
 
-  public void setChildren(Map<String, MNode> children) {
+  @Override
+  public void setChildren(Map<String, ISchemaNode> children) {
     this.children = children;
   }
 
+  @Override
   public void serializeTo(BufferedWriter bw) throws IOException {
     serializeChildren(bw);
 
@@ -220,24 +236,36 @@ public class MNode implements Serializable {
     if (children == null) {
       return;
     }
-    for (Entry<String, MNode> entry : children.entrySet()) {
+    for (Entry<String, ISchemaNode> entry : children.entrySet()) {
       entry.getValue().serializeTo(bw);
     }
   }
 
+  @Override
   public void readLock() {
-    MNode node = this;
+    ISchemaNode node = this;
     while (node != null) {
-      node.lock.readLock().lock();
-      node = node.parent;
+      node.getReadLock().lock();
+      node = node.getParent();
     }
   }
 
+  @Override
   public void readUnlock() {
-    MNode node = this;
+    ISchemaNode node = this;
     while (node != null) {
-      node.lock.readLock().unlock();
-      node = node.parent;
+      node.getReadLock().unlock();
+      node = node.getParent();
     }
   }
+
+  @Override
+  public Lock getWriteLock() {
+    return lock.writeLock();
+  }
+
+  @Override
+  public Lock getReadLock() {
+    return lock.readLock();
+  }
 }
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/mnode/MeasurementMNode.java b/server/src/main/java/org/apache/iotdb/db/metadata/mnode/MeasurementMNode.java
index b31edc1..64b31ec 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/mnode/MeasurementMNode.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/mnode/MeasurementMNode.java
@@ -32,7 +32,7 @@ import org.apache.iotdb.tsfile.write.schema.MeasurementSchema;
 /**
  * Represents an MNode which has a Measurement or Sensor attached to it.
  */
-public class MeasurementMNode extends MNode {
+public class MeasurementMNode extends MNode implements IMeasurementMNode {
 
   private static final long serialVersionUID = -1199657856921206435L;
 
@@ -49,28 +49,31 @@ public class MeasurementMNode extends MNode {
   /**
    * @param alias alias of measurementName
    */
-  public MeasurementMNode(MNode parent, String measurementName, String alias, TSDataType dataType,
+  public MeasurementMNode(ISchemaNode parent, String measurementName, String alias, TSDataType dataType,
       TSEncoding encoding, CompressionType type, Map<String, String> props) {
     super(parent, measurementName);
     this.schema = new MeasurementSchema(measurementName, dataType, encoding, type, props);
     this.alias = alias;
   }
 
-  public MeasurementMNode(MNode parent, String measurementName, MeasurementSchema schema,
+  public MeasurementMNode(ISchemaNode parent, String measurementName, MeasurementSchema schema,
       String alias) {
     super(parent, measurementName);
     this.schema = schema;
     this.alias = alias;
   }
 
+  @Override
   public MeasurementSchema getSchema() {
     return schema;
   }
 
+  @Override
   public TimeValuePair getCachedLast() {
     return cachedLastValuePair;
   }
 
+  @Override
   public synchronized void updateCachedLast(
       TimeValuePair timeValuePair, boolean highPriorityUpdate, Long latestFlushedTime) {
     if (timeValuePair == null || timeValuePair.getValue() == null) {
@@ -96,26 +99,32 @@ public class MeasurementMNode extends MNode {
     return concatFullPath();
   }
 
+  @Override
   public void resetCache() {
     cachedLastValuePair = null;
   }
 
+  @Override
   public long getOffset() {
     return offset;
   }
 
+  @Override
   public void setOffset(long offset) {
     this.offset = offset;
   }
 
+  @Override
   public String getAlias() {
     return alias;
   }
 
+  @Override
   public void setAlias(String alias) {
     this.alias = alias;
   }
 
+  @Override
   public void setSchema(MeasurementSchema schema) {
     this.schema = schema;
   }
@@ -141,29 +150,4 @@ public class MeasurementMNode extends MNode {
     bw.newLine();
   }
 
-  /**
-   * deserialize MeasuremetMNode from string array
-   *
-   * @param nodeInfo node information array. For example: "2,s0,speed,2,2,1,year:2020;month:jan;,-1,0"
-   * representing: [0] nodeType [1] name [2] alias [3] TSDataType.ordinal() [4] TSEncoding.ordinal()
-   * [5] CompressionType.ordinal() [6] props [7] offset [8] children size
-   */
-  public static MeasurementMNode deserializeFrom(String[] nodeInfo) {
-    String name = nodeInfo[1];
-    String alias = nodeInfo[2].equals("") ? null : nodeInfo[2];
-    Map<String, String> props = new HashMap<>();
-    if (!nodeInfo[6].equals("")) {
-      for (String propInfo : nodeInfo[6].split(";")) {
-        props.put(propInfo.split(":")[0], propInfo.split(":")[1]);
-      }
-    }
-    MeasurementSchema schema = new MeasurementSchema(name,
-        TSDataType.deserialize(Short.valueOf(nodeInfo[3])),
-        TSEncoding.deserialize(Short.valueOf(nodeInfo[4])),
-        CompressionType.deserialize(Short.valueOf(nodeInfo[5])), props);
-    MeasurementMNode node = new MeasurementMNode(null, name, schema, alias);
-    node.setOffset(Long.valueOf(nodeInfo[7]));
-
-    return node;
-  }
 }
\ No newline at end of file
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/mnode/StorageGroupMNode.java b/server/src/main/java/org/apache/iotdb/db/metadata/mnode/StorageGroupMNode.java
index ce47e81..a1e0f30 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/mnode/StorageGroupMNode.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/mnode/StorageGroupMNode.java
@@ -22,7 +22,7 @@ import java.io.BufferedWriter;
 import java.io.IOException;
 import org.apache.iotdb.db.metadata.MetadataConstant;
 
-public class StorageGroupMNode extends MNode {
+public class StorageGroupMNode extends MNode implements IStorageGroupMNode {
 
   private static final long serialVersionUID = 7999036474525817732L;
 
@@ -32,15 +32,17 @@ public class StorageGroupMNode extends MNode {
    */
   private long dataTTL;
 
-  public StorageGroupMNode(MNode parent, String name, long dataTTL) {
+  public StorageGroupMNode(ISchemaNode parent, String name, long dataTTL) {
     super(parent, name);
     this.dataTTL = dataTTL;
   }
 
+  @Override
   public long getDataTTL() {
     return dataTTL;
   }
 
+  @Override
   public void setDataTTL(long dataTTL) {
     this.dataTTL = dataTTL;
   }
@@ -57,7 +59,4 @@ public class StorageGroupMNode extends MNode {
     bw.newLine();
   }
 
-  public static StorageGroupMNode deserializeFrom(String[] nodeInfo) {
-    return new StorageGroupMNode(null, nodeInfo[1], Long.valueOf(nodeInfo[2]));
-  }
 }
\ No newline at end of file
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/executor/PlanExecutor.java b/server/src/main/java/org/apache/iotdb/db/qp/executor/PlanExecutor.java
index c1f93fa..4978b0a 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/executor/PlanExecutor.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/executor/PlanExecutor.java
@@ -74,7 +74,8 @@ import org.apache.iotdb.db.exception.metadata.MetadataException;
 import org.apache.iotdb.db.exception.metadata.StorageGroupNotSetException;
 import org.apache.iotdb.db.exception.query.QueryProcessException;
 import org.apache.iotdb.db.metadata.ISchemaManager;
-import org.apache.iotdb.db.metadata.mnode.MNode;
+import org.apache.iotdb.db.metadata.mnode.ISchemaNode;
+import org.apache.iotdb.db.metadata.mnode.IStorageGroupMNode;
 import org.apache.iotdb.db.metadata.mnode.MeasurementMNode;
 import org.apache.iotdb.db.metadata.mnode.StorageGroupMNode;
 import org.apache.iotdb.db.qp.logical.Operator.OperatorType;
@@ -519,7 +520,7 @@ public class PlanExecutor implements IPlanExecutor {
     return IoTDB.metaManager.showTimeseries(plan, context);
   }
 
-  protected List<StorageGroupMNode> getAllStorageGroupNodes() {
+  protected List<IStorageGroupMNode> getAllStorageGroupNodes() {
     return IoTDB.metaManager.getAllStorageGroupNodes();
   }
 
@@ -530,9 +531,9 @@ public class PlanExecutor implements IPlanExecutor {
             Arrays.asList(TSDataType.TEXT, TSDataType.INT64));
     List<String> selectedSgs = showTTLPlan.getStorageGroups();
 
-    List<StorageGroupMNode> storageGroups = getAllStorageGroupNodes();
+    List<IStorageGroupMNode> storageGroups = getAllStorageGroupNodes();
     int timestamp = 0;
-    for (StorageGroupMNode mNode : storageGroups) {
+    for (IStorageGroupMNode mNode : storageGroups) {
       String sgName = mNode.getFullPath();
       if (!selectedSgs.isEmpty() && !selectedSgs.contains(sgName)) {
         continue;
@@ -752,7 +753,7 @@ public class PlanExecutor implements IPlanExecutor {
     Set<Path> registeredSeries = new HashSet<>();
     for (ChunkGroupMetadata chunkGroupMetadata : chunkGroupMetadataList) {
       String device = chunkGroupMetadata.getDevice();
-      MNode node = null;
+      ISchemaNode node = null;
       try {
         node = ISchemaManager.getDeviceNodeWithAutoCreateAndReadLock(device, true, sgLevel);
         for (ChunkMetadata chunkMetadata : chunkGroupMetadata.getChunkMetadataList()) {
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/physical/crud/InsertPlan.java b/server/src/main/java/org/apache/iotdb/db/qp/physical/crud/InsertPlan.java
index 36a1174..1fce9e8 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/physical/crud/InsertPlan.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/physical/crud/InsertPlan.java
@@ -21,7 +21,7 @@ package org.apache.iotdb.db.qp.physical.crud;
 
 import java.util.ArrayList;
 import java.util.List;
-import org.apache.iotdb.db.metadata.mnode.MNode;
+import org.apache.iotdb.db.metadata.mnode.ISchemaNode;
 import org.apache.iotdb.db.qp.logical.Operator;
 import org.apache.iotdb.db.qp.physical.PhysicalPlan;
 import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
@@ -35,7 +35,7 @@ abstract public class InsertPlan extends PhysicalPlan {
   protected MeasurementSchema[] schemas;
 
   // for updating last cache
-  private MNode deviceMNode;
+  private ISchemaNode deviceMNode;
 
   // record the failed measurements
   protected List<String> failedMeasurements;
@@ -85,11 +85,11 @@ abstract public class InsertPlan extends PhysicalPlan {
     return failedMeasurements == null ? 0 : failedMeasurements.size();
   }
 
-  public MNode getDeviceMNode() {
+  public ISchemaNode getDeviceMNode() {
     return deviceMNode;
   }
 
-  public void setDeviceMNode(MNode deviceMNode) {
+  public void setDeviceMNode(ISchemaNode deviceMNode) {
     this.deviceMNode = deviceMNode;
   }
 
diff --git a/server/src/main/java/org/apache/iotdb/db/query/dataset/AlignByDeviceDataSet.java b/server/src/main/java/org/apache/iotdb/db/query/dataset/AlignByDeviceDataSet.java
index e224a07..b40db48 100644
--- a/server/src/main/java/org/apache/iotdb/db/query/dataset/AlignByDeviceDataSet.java
+++ b/server/src/main/java/org/apache/iotdb/db/query/dataset/AlignByDeviceDataSet.java
@@ -29,7 +29,7 @@ import org.apache.iotdb.db.conf.IoTDBDescriptor;
 import org.apache.iotdb.db.exception.StorageEngineException;
 import org.apache.iotdb.db.exception.metadata.MetadataException;
 import org.apache.iotdb.db.exception.query.QueryProcessException;
-import org.apache.iotdb.db.metadata.mnode.MNode;
+import org.apache.iotdb.db.metadata.mnode.ISchemaNode;
 import org.apache.iotdb.db.qp.physical.crud.*;
 import org.apache.iotdb.db.qp.physical.crud.AlignByDevicePlan.MeasurementType;
 import org.apache.iotdb.db.query.context.QueryContext;
@@ -197,7 +197,7 @@ public class AlignByDeviceDataSet extends QueryDataSet {
 
   protected Set<String> getDeviceMeasurements(String device) throws IOException {
     try {
-      MNode deviceNode = IoTDB.metaManager.getNodeByPath(device);
+      ISchemaNode deviceNode = IoTDB.metaManager.getNodeByPath(device);
       return deviceNode.getChildren().keySet();
     } catch (MetadataException e) {
       throw new IOException("Cannot get node from " + device, e);
diff --git a/server/src/main/java/org/apache/iotdb/db/query/executor/LastQueryExecutor.java b/server/src/main/java/org/apache/iotdb/db/query/executor/LastQueryExecutor.java
index 7f03ce9..ff277e5 100644
--- a/server/src/main/java/org/apache/iotdb/db/query/executor/LastQueryExecutor.java
+++ b/server/src/main/java/org/apache/iotdb/db/query/executor/LastQueryExecutor.java
@@ -25,7 +25,7 @@ import org.apache.iotdb.db.engine.storagegroup.TsFileResource;
 import org.apache.iotdb.db.exception.StorageEngineException;
 import org.apache.iotdb.db.exception.metadata.MetadataException;
 import org.apache.iotdb.db.exception.query.QueryProcessException;
-import org.apache.iotdb.db.metadata.mnode.MeasurementMNode;
+import org.apache.iotdb.db.metadata.mnode.IMeasurementMNode;
 import org.apache.iotdb.db.qp.physical.crud.LastQueryPlan;
 import org.apache.iotdb.db.query.context.QueryContext;
 import org.apache.iotdb.db.query.control.QueryResourceManager;
@@ -121,9 +121,9 @@ public class LastQueryExecutor {
       throws IOException, QueryProcessException, StorageEngineException {
 
     // Retrieve last value from MNode
-    MeasurementMNode node = null;
+    IMeasurementMNode node = null;
     try {
-      node = (MeasurementMNode) IoTDB.metaManager.getNodeByPath(seriesPath.toString());
+      node = (IMeasurementMNode) IoTDB.metaManager.getNodeByPath(seriesPath.toString());
     } catch (MetadataException e) {
       TimeValuePair timeValuePair = IoTDB.metaManager.getLastCache(seriesPath.getFullPath());
       if (timeValuePair != null) {
diff --git a/server/src/test/java/org/apache/iotdb/db/engine/cache/ChunkMetadataCacheTest.java b/server/src/test/java/org/apache/iotdb/db/engine/cache/ChunkMetadataCacheTest.java
index a4b5825..2dd4ec8 100644
--- a/server/src/test/java/org/apache/iotdb/db/engine/cache/ChunkMetadataCacheTest.java
+++ b/server/src/test/java/org/apache/iotdb/db/engine/cache/ChunkMetadataCacheTest.java
@@ -32,9 +32,9 @@ import org.apache.iotdb.db.engine.storagegroup.TsFileProcessor;
 import org.apache.iotdb.db.engine.storagegroup.TsFileResource;
 import org.apache.iotdb.db.exception.WriteProcessException;
 import org.apache.iotdb.db.exception.query.QueryProcessException;
+import org.apache.iotdb.db.metadata.mnode.ISchemaNode;
 import org.apache.iotdb.db.metadata.mnode.MNode;
 import org.apache.iotdb.db.metadata.mnode.MeasurementMNode;
-import org.apache.iotdb.db.qp.physical.crud.InsertPlan;
 import org.apache.iotdb.db.qp.physical.crud.InsertRowPlan;
 import org.apache.iotdb.db.query.context.QueryContext;
 import org.apache.iotdb.db.query.control.FileReaderManager;
@@ -89,7 +89,7 @@ public class ChunkMetadataCacheTest {
     record.addTuple(DataPoint.getDataPoint(TSDataType.DOUBLE, measurementId3, String.valueOf(num)));
     record.addTuple(DataPoint.getDataPoint(TSDataType.BOOLEAN, measurementId4, "True"));
     InsertRowPlan insertRowPlan = new InsertRowPlan(record);
-    MNode mNode = new MNode(null, storageGroup);
+    ISchemaNode mNode = new MNode(null, storageGroup);
     mNode.addChild(measurementId0, new MeasurementMNode(null, null, null, null));
     mNode.addChild(measurementId1, new MeasurementMNode(null, null, null, null));
     mNode.addChild(measurementId2, new MeasurementMNode(null, null, null, null));
diff --git a/server/src/test/java/org/apache/iotdb/db/engine/modification/DeletionFileNodeTest.java b/server/src/test/java/org/apache/iotdb/db/engine/modification/DeletionFileNodeTest.java
index 79c74cf..eb0eb93 100644
--- a/server/src/test/java/org/apache/iotdb/db/engine/modification/DeletionFileNodeTest.java
+++ b/server/src/test/java/org/apache/iotdb/db/engine/modification/DeletionFileNodeTest.java
@@ -27,6 +27,7 @@ import org.apache.iotdb.db.engine.querycontext.ReadOnlyMemChunk;
 import org.apache.iotdb.db.exception.StorageEngineException;
 import org.apache.iotdb.db.exception.metadata.MetadataException;
 import org.apache.iotdb.db.exception.query.QueryProcessException;
+import org.apache.iotdb.db.metadata.mnode.ISchemaNode;
 import org.apache.iotdb.db.metadata.mnode.MNode;
 import org.apache.iotdb.db.metadata.mnode.MeasurementMNode;
 import org.apache.iotdb.db.qp.physical.crud.InsertRowPlan;
@@ -65,7 +66,7 @@ public class DeletionFileNodeTest {
   private static String[] measurements = new String[10];
   private TSDataType dataType = TSDataType.DOUBLE;
   private TSEncoding encoding = TSEncoding.PLAIN;
-  private MNode deviceMNode = null;
+  private ISchemaNode deviceMNode = null;
 
   static {
     for (int i = 0; i < 10; i++) {
diff --git a/server/src/test/java/org/apache/iotdb/db/engine/modification/DeletionQueryTest.java b/server/src/test/java/org/apache/iotdb/db/engine/modification/DeletionQueryTest.java
index 83222e9..687c599 100644
--- a/server/src/test/java/org/apache/iotdb/db/engine/modification/DeletionQueryTest.java
+++ b/server/src/test/java/org/apache/iotdb/db/engine/modification/DeletionQueryTest.java
@@ -23,6 +23,7 @@ import org.apache.iotdb.db.engine.StorageEngine;
 import org.apache.iotdb.db.exception.StorageEngineException;
 import org.apache.iotdb.db.exception.metadata.MetadataException;
 import org.apache.iotdb.db.exception.query.QueryProcessException;
+import org.apache.iotdb.db.metadata.mnode.ISchemaNode;
 import org.apache.iotdb.db.metadata.mnode.MNode;
 import org.apache.iotdb.db.metadata.mnode.MeasurementMNode;
 import org.apache.iotdb.db.qp.physical.crud.InsertRowPlan;
@@ -57,7 +58,7 @@ public class DeletionQueryTest {
   private TSDataType dataType = TSDataType.DOUBLE;
   private TSEncoding encoding = TSEncoding.PLAIN;
   private QueryRouter router = new QueryRouter();
-  private MNode deviceMNode = null;
+  private ISchemaNode deviceMNode = null;
 
   static {
     for (int i = 0; i < 10; i++) {
diff --git a/server/src/test/java/org/apache/iotdb/db/engine/storagegroup/StorageGroupProcessorTest.java b/server/src/test/java/org/apache/iotdb/db/engine/storagegroup/StorageGroupProcessorTest.java
index 380e99d..a9d4e33 100644
--- a/server/src/test/java/org/apache/iotdb/db/engine/storagegroup/StorageGroupProcessorTest.java
+++ b/server/src/test/java/org/apache/iotdb/db/engine/storagegroup/StorageGroupProcessorTest.java
@@ -29,15 +29,14 @@ import java.util.concurrent.atomic.AtomicLong;
 import org.apache.iotdb.db.conf.adapter.ActiveTimeSeriesCounter;
 import org.apache.iotdb.db.constant.TestConstant;
 import org.apache.iotdb.db.engine.MetadataManagerHelper;
-import org.apache.iotdb.db.engine.StorageEngine;
 import org.apache.iotdb.db.engine.flush.TsFileFlushPolicy;
 import org.apache.iotdb.db.engine.merge.manage.MergeManager;
 import org.apache.iotdb.db.engine.querycontext.QueryDataSource;
 import org.apache.iotdb.db.engine.querycontext.ReadOnlyMemChunk;
-import org.apache.iotdb.db.exception.StorageEngineException;
 import org.apache.iotdb.db.exception.StorageGroupProcessorException;
 import org.apache.iotdb.db.exception.WriteProcessException;
 import org.apache.iotdb.db.exception.query.QueryProcessException;
+import org.apache.iotdb.db.metadata.mnode.ISchemaNode;
 import org.apache.iotdb.db.metadata.mnode.MNode;
 import org.apache.iotdb.db.metadata.mnode.MeasurementMNode;
 import org.apache.iotdb.db.qp.physical.crud.InsertRowPlan;
@@ -65,7 +64,7 @@ public class StorageGroupProcessorTest {
   private StorageGroupProcessor processor;
   private QueryContext context = EnvironmentUtils.TEST_QUERY_CONTEXT;
   private AtomicLong mergeLock;
-  private MNode deviceMNode = null;
+  private ISchemaNode deviceMNode = null;
 
   @Before
   public void setUp() throws Exception {
@@ -180,7 +179,7 @@ public class StorageGroupProcessorTest {
     schemas[0] = new MeasurementSchema("s0", TSDataType.INT32, TSEncoding.PLAIN);
     schemas[1] = new MeasurementSchema("s1", TSDataType.INT64, TSEncoding.PLAIN);
 
-    MNode deviceMNode = new MNode(null, deviceId);
+    ISchemaNode deviceMNode = new MNode(null, deviceId);
     deviceMNode.addChild("s0", new MeasurementMNode(null, null, null, null));
     deviceMNode.addChild("s1", new MeasurementMNode(null, null, null, null));
 
diff --git a/server/src/test/java/org/apache/iotdb/db/engine/storagegroup/TTLTest.java b/server/src/test/java/org/apache/iotdb/db/engine/storagegroup/TTLTest.java
index fa0abb2..97199a0 100644
--- a/server/src/test/java/org/apache/iotdb/db/engine/storagegroup/TTLTest.java
+++ b/server/src/test/java/org/apache/iotdb/db/engine/storagegroup/TTLTest.java
@@ -32,12 +32,12 @@ import org.apache.iotdb.db.exception.WriteProcessException;
 import org.apache.iotdb.db.exception.metadata.MetadataException;
 import org.apache.iotdb.db.exception.query.OutOfTTLException;
 import org.apache.iotdb.db.exception.query.QueryProcessException;
+import org.apache.iotdb.db.metadata.mnode.ISchemaNode;
+import org.apache.iotdb.db.metadata.mnode.IStorageGroupMNode;
 import org.apache.iotdb.db.metadata.mnode.MNode;
 import org.apache.iotdb.db.metadata.mnode.MeasurementMNode;
-import org.apache.iotdb.db.metadata.mnode.StorageGroupMNode;
 import org.apache.iotdb.db.qp.Planner;
 import org.apache.iotdb.db.qp.executor.PlanExecutor;
-import org.apache.iotdb.db.qp.physical.crud.InsertPlan;
 import org.apache.iotdb.db.qp.physical.crud.InsertRowPlan;
 import org.apache.iotdb.db.qp.physical.sys.SetTTLPlan;
 import org.apache.iotdb.db.qp.physical.sys.ShowTTLPlan;
@@ -55,7 +55,6 @@ import org.apache.iotdb.tsfile.read.common.Path;
 import org.apache.iotdb.tsfile.read.common.RowRecord;
 import org.apache.iotdb.tsfile.read.query.dataset.QueryDataSet;
 import org.apache.iotdb.tsfile.read.reader.IBatchReader;
-import org.apache.iotdb.tsfile.write.record.TSRecord;
 import org.apache.iotdb.tsfile.write.schema.MeasurementSchema;
 import org.apache.thrift.TException;
 import org.junit.After;
@@ -78,7 +77,7 @@ public class TTLTest {
   private String g1s1 = sg1 + IoTDBConstant.PATH_SEPARATOR + s1;
   private long prevPartitionInterval;
 
-  private MNode deviceMNode = null;
+  private ISchemaNode deviceMNode = null;
 
   @Before
   public void setUp()
@@ -127,7 +126,7 @@ public class TTLTest {
 
     // normally set ttl
     IoTDB.metaManager.setTTL(sg1, ttl);
-    StorageGroupMNode mNode = IoTDB.metaManager.getStorageGroupNode(sg1);
+    IStorageGroupMNode mNode = IoTDB.metaManager.getStorageGroupNode(sg1);
     assertEquals(ttl, mNode.getDataTTL());
 
     // default ttl
diff --git a/server/src/test/java/org/apache/iotdb/db/integration/IoTDBLastIT.java b/server/src/test/java/org/apache/iotdb/db/integration/IoTDBLastIT.java
index def5957..dd9ea23 100644
--- a/server/src/test/java/org/apache/iotdb/db/integration/IoTDBLastIT.java
+++ b/server/src/test/java/org/apache/iotdb/db/integration/IoTDBLastIT.java
@@ -19,8 +19,8 @@
 package org.apache.iotdb.db.integration;
 
 import org.apache.iotdb.db.exception.metadata.MetadataException;
-import org.apache.iotdb.db.metadata.mnode.MNode;
-import org.apache.iotdb.db.metadata.mnode.MeasurementMNode;
+import org.apache.iotdb.db.metadata.mnode.IMeasurementMNode;
+import org.apache.iotdb.db.metadata.mnode.ISchemaNode;
 import org.apache.iotdb.db.service.IoTDB;
 import org.apache.iotdb.db.utils.EnvironmentUtils;
 import org.apache.iotdb.jdbc.Config;
@@ -128,8 +128,8 @@ public class IoTDBLastIT {
         }
       }
 
-      MeasurementMNode node =
-          (MeasurementMNode) IoTDB.metaManager.getNodeByPath("root.ln.wf01.wt01.temperature");
+      IMeasurementMNode node =
+          (IMeasurementMNode) IoTDB.metaManager.getNodeByPath("root.ln.wf01.wt01.temperature");
       node.resetCache();
 
       statement.execute(
@@ -189,8 +189,8 @@ public class IoTDBLastIT {
             DriverManager.getConnection("jdbc:iotdb://127.0.0.1:6667/", "root", "root");
         Statement statement = connection.createStatement()) {
 
-      MNode node = IoTDB.metaManager.getNodeByPath("root.ln.wf01.wt02.temperature");
-      ((MeasurementMNode) node).resetCache();
+      ISchemaNode node = IoTDB.metaManager.getNodeByPath("root.ln.wf01.wt02.temperature");
+      ((IMeasurementMNode) node).resetCache();
       boolean hasResultSet =
           statement.execute(
               "select last temperature,status,id from root.ln.wf01.wt02");
@@ -240,8 +240,8 @@ public class IoTDBLastIT {
         DriverManager.getConnection("jdbc:iotdb://127.0.0.1:6667/", "root", "root");
         Statement statement = connection.createStatement()) {
 
-      MNode node = IoTDB.metaManager.getNodeByPath("root.ln.wf01.wt03.temperature");
-      ((MeasurementMNode) node).resetCache();
+      ISchemaNode node = IoTDB.metaManager.getNodeByPath("root.ln.wf01.wt03.temperature");
+      ((IMeasurementMNode) node).resetCache();
 
       statement.execute("INSERT INTO root.ln.wf01.wt03(timestamp,status, id) values(500, false, 9)");
       statement.execute("flush");
@@ -288,8 +288,8 @@ public class IoTDBLastIT {
       statement.execute("INSERT INTO root.ln.wf01.wt04(timestamp,temperature) values(150,31.2)");
       statement.execute("flush");
 
-      MNode node = IoTDB.metaManager.getNodeByPath("root.ln.wf01.wt03.temperature");
-      ((MeasurementMNode) node).resetCache();
+      ISchemaNode node = IoTDB.metaManager.getNodeByPath("root.ln.wf01.wt03.temperature");
+      ((IMeasurementMNode) node).resetCache();
 
       boolean hasResultSet = statement.execute(
           "select last temperature from root.ln.wf01.wt04");
diff --git a/server/src/test/java/org/apache/iotdb/db/metadata/MManagerAdvancedTest.java b/server/src/test/java/org/apache/iotdb/db/metadata/MManagerAdvancedTest.java
index bdb9412..e7df3a9 100644
--- a/server/src/test/java/org/apache/iotdb/db/metadata/MManagerAdvancedTest.java
+++ b/server/src/test/java/org/apache/iotdb/db/metadata/MManagerAdvancedTest.java
@@ -19,8 +19,8 @@
 package org.apache.iotdb.db.metadata;
 
 import org.apache.iotdb.db.exception.metadata.MetadataException;
-import org.apache.iotdb.db.metadata.mnode.MNode;
-import org.apache.iotdb.db.metadata.mnode.MeasurementMNode;
+import org.apache.iotdb.db.metadata.mnode.IMeasurementMNode;
+import org.apache.iotdb.db.metadata.mnode.ISchemaNode;
 import org.apache.iotdb.db.service.IoTDB;
 import org.apache.iotdb.db.utils.EnvironmentUtils;
 import org.apache.iotdb.tsfile.common.conf.TSFileDescriptor;
@@ -128,8 +128,8 @@ public class MManagerAdvancedTest {
     mmanager.createTimeseries("root.vehicle.d2.s3", TSDataType.TEXT, TSEncoding.PLAIN,
         TSFileDescriptor.getInstance().getConfig().getCompressor(), Collections.emptyMap());
 
-    MNode node = mmanager.getNodeByPath("root.vehicle.d0");
-    Assert.assertEquals(TSDataType.INT32, ((MeasurementMNode) node.getChild("s0")).getSchema().getType());
+    ISchemaNode node = mmanager.getNodeByPath("root.vehicle.d0");
+    Assert.assertEquals(TSDataType.INT32, ((IMeasurementMNode) node.getChild("s0")).getSchema().getType());
 
     try {
       mmanager.getNodeByPath("root.vehicle.d100");
@@ -147,11 +147,11 @@ public class MManagerAdvancedTest {
     TimeValuePair tv1 = new TimeValuePair(1000, TsPrimitiveType.getByType(TSDataType.DOUBLE, 1.0));
     TimeValuePair tv2 = new TimeValuePair(2000, TsPrimitiveType.getByType(TSDataType.DOUBLE, 3.0));
     TimeValuePair tv3 = new TimeValuePair(1500, TsPrimitiveType.getByType(TSDataType.DOUBLE, 2.5));
-    MNode node = mmanager.getNodeByPath("root.vehicle.d2.s0");
-    ((MeasurementMNode)node).updateCachedLast(tv1, true, Long.MIN_VALUE);
-    ((MeasurementMNode)node).updateCachedLast(tv2, true, Long.MIN_VALUE);
-    Assert.assertEquals(tv2.getTimestamp(), ((MeasurementMNode)node).getCachedLast().getTimestamp());
-    ((MeasurementMNode)node).updateCachedLast(tv3, true, Long.MIN_VALUE);
-    Assert.assertEquals(tv2.getTimestamp(), ((MeasurementMNode)node).getCachedLast().getTimestamp());
+    ISchemaNode node = mmanager.getNodeByPath("root.vehicle.d2.s0");
+    ((IMeasurementMNode)node).updateCachedLast(tv1, true, Long.MIN_VALUE);
+    ((IMeasurementMNode)node).updateCachedLast(tv2, true, Long.MIN_VALUE);
+    Assert.assertEquals(tv2.getTimestamp(), ((IMeasurementMNode)node).getCachedLast().getTimestamp());
+    ((IMeasurementMNode)node).updateCachedLast(tv3, true, Long.MIN_VALUE);
+    Assert.assertEquals(tv2.getTimestamp(), ((IMeasurementMNode)node).getCachedLast().getTimestamp());
   }
 }
diff --git a/server/src/test/java/org/apache/iotdb/db/metadata/MManagerImproveTest.java b/server/src/test/java/org/apache/iotdb/db/metadata/MManagerImproveTest.java
index 86f77c8..1e5bb88 100644
--- a/server/src/test/java/org/apache/iotdb/db/metadata/MManagerImproveTest.java
+++ b/server/src/test/java/org/apache/iotdb/db/metadata/MManagerImproveTest.java
@@ -19,8 +19,8 @@
 package org.apache.iotdb.db.metadata;
 
 import org.apache.iotdb.db.exception.metadata.MetadataException;
-import org.apache.iotdb.db.metadata.mnode.MNode;
-import org.apache.iotdb.db.metadata.mnode.MeasurementMNode;
+import org.apache.iotdb.db.metadata.mnode.IMeasurementMNode;
+import org.apache.iotdb.db.metadata.mnode.ISchemaNode;
 import org.apache.iotdb.db.service.IoTDB;
 import org.apache.iotdb.db.utils.EnvironmentUtils;
 import org.apache.iotdb.tsfile.common.conf.TSFileDescriptor;
@@ -130,12 +130,12 @@ public class MManagerImproveTest {
   }
 
   private void doCacheTest(String deviceId, List<String> measurementList) throws MetadataException {
-    MNode node = null;
+    ISchemaNode node = null;
     try {
       node = ISchemaManager.getDeviceNodeWithAutoCreateAndReadLock(deviceId);
       for (String s : measurementList) {
         assertTrue(node.hasChild(s));
-        MeasurementMNode measurementNode = (MeasurementMNode) node.getChild(s);
+        IMeasurementMNode measurementNode = (IMeasurementMNode) node.getChild(s);
         TSDataType dataType = measurementNode.getSchema().getType();
         assertEquals(TSDataType.TEXT, dataType);
       }