You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iotdb.apache.org by ji...@apache.org on 2019/11/05 12:14:22 UTC

[incubator-iotdb] 01/01: refactor MGraph

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

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

commit f6be8aab3b15fe2da46766797cadf357821bfdb7
Author: jt2594838 <jt...@163.com>
AuthorDate: Tue Nov 5 20:13:54 2019 +0800

    refactor MGraph
---
 .../apache/iotdb/jdbc/IoTDBDatabaseMetadata.java   |   4 +-
 .../apache/iotdb/jdbc/IoTDBMetadataResultSet.java  |   4 +-
 .../iotdb/jdbc/IoTDBDatabaseMetadataTest.java      |  12 +-
 .../org/apache/iotdb/jdbc/IoTDBStatementTest.java  |   8 +-
 .../org/apache/iotdb/db/engine/StorageEngine.java  |   3 +-
 .../java/org/apache/iotdb/db/metadata/MGraph.java  | 207 +++-------
 .../org/apache/iotdb/db/metadata/MManager.java     | 212 +---------
 .../java/org/apache/iotdb/db/metadata/MTree.java   | 425 +++++++--------------
 .../org/apache/iotdb/db/metadata/MetaUtils.java    |  74 +++-
 .../org/apache/iotdb/db/metadata/Metadata.java     | 125 ------
 .../apache/iotdb/db/metadata/MetadataConstant.java |  27 --
 .../iotdb/db/metadata/MetadataOperationType.java   |  20 +-
 .../java/org/apache/iotdb/db/metadata/PTree.java   |  33 +-
 .../org/apache/iotdb/db/service/TSServiceImpl.java |  19 +-
 .../db/sync/receiver/transfer/SyncServiceImpl.java |   3 +-
 .../sync/sender/transfer/DataTransferManager.java  |   6 +-
 .../org/apache/iotdb/db/utils/SchemaUtils.java     |  54 ++-
 .../iotdb/db/engine/storagegroup/TTLTest.java      |  15 +-
 .../iotdb/db/integration/IoTDBQuotedPathIT.java    | 106 ++---
 .../apache/iotdb/db/integration/IoTDBTtlIT.java    |  20 +-
 .../org/apache/iotdb/db/metadata/MGraphTest.java   |  37 +-
 .../iotdb/db/metadata/MManagerAdvancedTest.java    |  18 +-
 .../iotdb/db/metadata/MManagerImproveTest.java     |  40 +-
 .../org/apache/iotdb/db/metadata/MTreeTest.java    |  78 ++--
 .../org/apache/iotdb/db/metadata/MetadataTest.java |  88 -----
 service-rpc/rpc-changelist.md                      |   3 +-
 service-rpc/src/main/thrift/rpc.thrift             |   7 +-
 .../tsfile/common/constant/TsFileConstant.java     |   2 +-
 .../org/apache/iotdb/tsfile/read/common/Path.java  |   2 +-
 29 files changed, 532 insertions(+), 1120 deletions(-)

diff --git a/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBDatabaseMetadata.java b/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBDatabaseMetadata.java
index c88aac9..561604b 100644
--- a/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBDatabaseMetadata.java
+++ b/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBDatabaseMetadata.java
@@ -113,7 +113,7 @@ public class IoTDBDatabaseMetadata implements DatabaseMetaData {
           } catch (IoTDBRPCException e) {
             throw new IoTDBSQLException(e.getMessage(), resp.getStatus());
           }
-          Set<String> showStorageGroup = resp.getStorageGroups();
+          List<String> showStorageGroup = resp.getStorageGroups();
           return new IoTDBMetadataResultSet(showStorageGroup, MetadataType.STORAGE_GROUP);
         } catch (TException e) {
           throw new TException("Connection error when fetching storage group metadata", e);
@@ -128,7 +128,7 @@ public class IoTDBDatabaseMetadata implements DatabaseMetaData {
           } catch (IoTDBRPCException e) {
             throw new IoTDBSQLException(e.getMessage(), resp.getStatus());
           }
-          List<List<String>> showTimeseriesList = resp.getTimeseriesList();
+          List<List<String>> showTimeseriesList = resp.getTimeseriesInfoList();
           return new IoTDBMetadataResultSet(showTimeseriesList, MetadataType.TIMESERIES);
         } catch (TException e) {
           throw new TException("Connection error when fetching timeseries metadata", e);
diff --git a/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBMetadataResultSet.java b/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBMetadataResultSet.java
index c1e319a..4c70cd0 100644
--- a/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBMetadataResultSet.java
+++ b/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBMetadataResultSet.java
@@ -69,13 +69,13 @@ public class IoTDBMetadataResultSet extends IoTDBQueryResultSet {
         columnItr = columns.iterator();
         break;
       case STORAGE_GROUP:
-        Set<String> storageGroupSet = (Set<String>) object;
+        List<String> storageGroupSet = (List<String>) object;
         colCount = 1;
         showLabels = new String[]{"Storage Group"};
         columnItr = storageGroupSet.iterator();
         break;
       case DEVICES:
-        Set<String> devicesSet = (Set<String>) object;
+        List<String> devicesSet = (List<String>) object;
         colCount = 1;
         showLabels = new String[]{"Device"};
         columnItr = devicesSet.iterator();
diff --git a/jdbc/src/test/java/org/apache/iotdb/jdbc/IoTDBDatabaseMetadataTest.java b/jdbc/src/test/java/org/apache/iotdb/jdbc/IoTDBDatabaseMetadataTest.java
index 43f79e2..5903294 100644
--- a/jdbc/src/test/java/org/apache/iotdb/jdbc/IoTDBDatabaseMetadataTest.java
+++ b/jdbc/src/test/java/org/apache/iotdb/jdbc/IoTDBDatabaseMetadataTest.java
@@ -271,7 +271,7 @@ public class IoTDBDatabaseMetadataTest {
   @SuppressWarnings("resource")
   @Test
   public void device() {
-    Set<String> devicesSet = new HashSet<>();
+    List<String> devicesSet = new ArrayList<>();
     devicesSet.add("root.vehicle.d0");
 
     when(fetchMetadataResp.getDevices()).thenReturn(devicesSet);
@@ -332,7 +332,7 @@ public class IoTDBDatabaseMetadataTest {
       }
     });
 
-    when(fetchMetadataResp.getTimeseriesList()).thenReturn(tsList);
+    when(fetchMetadataResp.getTimeseriesInfoList()).thenReturn(tsList);
 
     String standard = "Timeseries,Storage Group,DataType,Encoding,\n"
         + "root.vehicle.d0.s0,root.vehicle,INT32,RLE,\n"
@@ -376,7 +376,7 @@ public class IoTDBDatabaseMetadataTest {
       }
     });
 
-    when(fetchMetadataResp.getTimeseriesList()).thenReturn(tsList);
+    when(fetchMetadataResp.getTimeseriesInfoList()).thenReturn(tsList);
 
     String standard = "DataType,\n" + "INT32,\n";
     try (ResultSet resultSet = databaseMetaData
@@ -403,9 +403,9 @@ public class IoTDBDatabaseMetadataTest {
   @SuppressWarnings("resource")
   @Test
   public void ShowStorageGroup() {
-    Set<String> sgSet = new HashSet<>();
-    sgSet.add("root.vehicle");
-    when(fetchMetadataResp.getStorageGroups()).thenReturn(sgSet);
+    List<String> sgList = new ArrayList<>();
+    sgList.add("root.vehicle");
+    when(fetchMetadataResp.getStorageGroups()).thenReturn(sgList);
 
     String standard = "Storage Group,\n" + "root.vehicle,\n";
     try (ResultSet resultSet = databaseMetaData
diff --git a/jdbc/src/test/java/org/apache/iotdb/jdbc/IoTDBStatementTest.java b/jdbc/src/test/java/org/apache/iotdb/jdbc/IoTDBStatementTest.java
index 5953fde..6cba428 100644
--- a/jdbc/src/test/java/org/apache/iotdb/jdbc/IoTDBStatementTest.java
+++ b/jdbc/src/test/java/org/apache/iotdb/jdbc/IoTDBStatementTest.java
@@ -28,9 +28,7 @@ import java.sql.ResultSetMetaData;
 import java.sql.SQLException;
 import java.time.ZoneId;
 import java.util.ArrayList;
-import java.util.HashSet;
 import java.util.List;
-import java.util.Set;
 import org.apache.iotdb.rpc.TSStatusCode;
 import org.apache.iotdb.service.rpc.thrift.TSFetchMetadataReq;
 import org.apache.iotdb.service.rpc.thrift.TSFetchMetadataResp;
@@ -109,7 +107,7 @@ public class IoTDBStatementTest {
             + "root.vehicle.d0.s0,root.vehicle,INT32,RLE,\n"
             + "root.vehicle.d0.s1,root.vehicle,INT64,RLE,\n"
             + "root.vehicle.d0.s2,root.vehicle,FLOAT,RLE,\n";
-    when(fetchMetadataResp.getTimeseriesList()).thenReturn(tsList);
+    when(fetchMetadataResp.getTimeseriesInfoList()).thenReturn(tsList);
     boolean res = stmt.execute("show timeseries");
     assertTrue(res);
     try (ResultSet resultSet = stmt.getResultSet()) {
@@ -166,7 +164,7 @@ public class IoTDBStatementTest {
         + "root.vehicle.d0.s0,root.vehicle,INT32,RLE,\n"
         + "root.vehicle.d0.s1,root.vehicle,INT64,RLE,\n"
         + "root.vehicle.d0.s2,root.vehicle,FLOAT,RLE,\n";
-    when(fetchMetadataResp.getTimeseriesList()).thenReturn(tsList);
+    when(fetchMetadataResp.getTimeseriesInfoList()).thenReturn(tsList);
     boolean res = stmt.execute("show timeseries root.vehicle.d0");
     assertTrue(res);
     try (ResultSet resultSet = stmt.getResultSet()) {
@@ -193,7 +191,7 @@ public class IoTDBStatementTest {
   @Test
   public void testExecuteSQL3() throws SQLException {
     IoTDBStatement stmt = new IoTDBStatement(connection, client, sessHandle, zoneID);
-    Set<String> sgSet = new HashSet<>();
+    List<String> sgSet = new ArrayList<>();
     sgSet.add("root.vehicle");
     when(fetchMetadataResp.getStorageGroups()).thenReturn(sgSet);
     String standard = "Storage Group,\nroot.vehicle,\n";
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 db41982..b2b5868 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
@@ -28,7 +28,6 @@ import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.Callable;
 import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
@@ -179,7 +178,7 @@ public class StorageEngine implements IService {
                 storageGroupName, Thread.currentThread().getId());
             processor = new StorageGroupProcessor(systemDir, storageGroupName);
             processor.setDataTTL(
-                MManager.getInstance().getNodeByPathWithCheck(storageGroupName).getDataTTL());
+                MManager.getInstance().getNodeInStorageGroup(storageGroupName).getDataTTL());
             processorMap.put(storageGroupName, processor);
           }
         }
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/MGraph.java b/server/src/main/java/org/apache/iotdb/db/metadata/MGraph.java
index b0618be..d12c0ed 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/MGraph.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/MGraph.java
@@ -18,18 +18,14 @@
  */
 package org.apache.iotdb.db.metadata;
 
-import java.io.Serializable;
 import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
+import org.apache.iotdb.db.conf.IoTDBConstant;
 import org.apache.iotdb.db.exception.MetadataErrorException;
 import org.apache.iotdb.db.exception.PathErrorException;
 import org.apache.iotdb.db.exception.StorageGroupException;
-import org.apache.iotdb.tsfile.common.conf.TSFileDescriptor;
 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;
@@ -38,10 +34,9 @@ import org.apache.iotdb.tsfile.write.schema.MeasurementSchema;
 /**
  * Metadata Graph consists of one {@code MTree} and several {@code PTree}.
  */
-public class MGraph implements Serializable {
+public class MGraph {
 
-  private static final long serialVersionUID = 8214849219614352834L;
-  private static final String DOUB_SEPARATOR = "\\.";
+  private static final String ESCAPED_SEPARATOR = "\\.";
   private static final String TIME_SERIES_INCORRECT = "Timeseries's root is not Correct. RootName: ";
   private MTree mtree;
   private HashMap<String, PTree> ptreeMap;
@@ -55,7 +50,7 @@ public class MGraph implements Serializable {
    * Add a {@code PTree} to current {@code MGraph}.
    */
   void addAPTree(String ptreeRootName) throws MetadataErrorException {
-    if (MetadataConstant.ROOT.equalsIgnoreCase(ptreeRootName)) {
+    if (IoTDBConstant.PATH_ROOT.equalsIgnoreCase(ptreeRootName)) {
       throw new MetadataErrorException("Property Tree's root name should not be 'root'");
     }
     PTree ptree = new PTree(ptreeRootName, mtree);
@@ -63,29 +58,14 @@ public class MGraph implements Serializable {
   }
 
   /**
-   * this is just for compatibility
-   */
-  public void addPathToMTree(String path, String dataType, String encoding)
-      throws PathErrorException {
-    TSDataType tsDataType = TSDataType.valueOf(dataType);
-    TSEncoding tsEncoding = TSEncoding.valueOf(encoding);
-    CompressionType compressionType = CompressionType.valueOf(TSFileDescriptor.getInstance().getConfig().getCompressor());
-    addPathToMTree(path, tsDataType, tsEncoding, compressionType,
-        Collections.emptyMap());
-  }
-
-  /**
    * Add a seriesPath to Metadata Tree.
    *
    * @param path Format: root.node.(node)*
    */
   public void addPathToMTree(String path, TSDataType dataType, TSEncoding encoding,
       CompressionType compressor, Map<String, String> props) throws PathErrorException {
-    String[] nodes = MetaUtils.getNodeNames(path, DOUB_SEPARATOR);
-    if (nodes.length == 0) {
-      throw new PathErrorException("Timeseries is null");
-    }
-    mtree.addTimeseriesPath(path, dataType, encoding, compressor, props);
+    String[] nodes = MetaUtils.getNodeNames(path);
+    mtree.addTimeseriesPath(nodes, dataType, encoding, compressor, props);
   }
 
   /**
@@ -99,14 +79,12 @@ public class MGraph implements Serializable {
    * Add a seriesPath to {@code PTree}.
    */
   void addPathToPTree(String path) throws PathErrorException {
-    String[] nodes = MetaUtils.getNodeNames(path, DOUB_SEPARATOR);
-    if (nodes.length == 0) {
-      throw new PathErrorException("Timeseries is null.");
-    }
+    String[] nodes = MetaUtils.getNodeNames(path);
+
     String rootName = nodes[0];
     if (ptreeMap.containsKey(rootName)) {
       PTree ptree = ptreeMap.get(rootName);
-      ptree.addPath(path);
+      ptree.addPath(nodes);
     } else {
       throw new PathErrorException(TIME_SERIES_INCORRECT + rootName);
     }
@@ -118,10 +96,8 @@ public class MGraph implements Serializable {
    * @param path a seriesPath belongs to MTree or PTree
    */
   String deletePath(String path) throws PathErrorException {
-    String[] nodes = MetaUtils.getNodeNames(path, DOUB_SEPARATOR);
-    if (nodes.length == 0) {
-      throw new PathErrorException("Timeseries is null");
-    }
+    String[] nodes = MetaUtils.getNodeNames(path);
+
     String rootName = nodes[0];
     if (mtree.getRoot().getName().equals(rootName)) {
       return mtree.deletePath(path);
@@ -137,24 +113,26 @@ public class MGraph implements Serializable {
   /**
    * Link a {@code MNode} to a {@code PNode} in current PTree.
    */
-  void linkMNodeToPTree(String path, String mpath) throws PathErrorException {
-    String ptreeName = MetaUtils.getNodeNames(path, DOUB_SEPARATOR)[0];
-    if (!ptreeMap.containsKey(ptreeName)) {
-      throw new PathErrorException("Error: PTree Path Not Correct. Path: " + path);
+  void linkMNodeToPTree(String pPath, String mPath) throws PathErrorException {
+    String[] pNodes = MetaUtils.getNodeNames(pPath);
+    String pRootName = pNodes[0];
+    if (!ptreeMap.containsKey(pRootName)) {
+      throw new PathErrorException("Error: PTree Path Not Correct. Path: " + pPath);
     } else {
-      ptreeMap.get(ptreeName).linkMNode(path, mpath);
+      ptreeMap.get(pRootName).linkMNode(pNodes, mPath);
     }
   }
 
   /**
    * Unlink a {@code MNode} from a {@code PNode} in current PTree.
    */
-  void unlinkMNodeFromPTree(String path, String mpath) throws PathErrorException {
-    String ptreeName = MetaUtils.getNodeNames(path, DOUB_SEPARATOR)[0];
-    if (!ptreeMap.containsKey(ptreeName)) {
-      throw new PathErrorException("Error: PTree Path Not Correct. Path: " + path);
+  void unlinkMNodeFromPTree(String pPath, String mPath) throws PathErrorException {
+    String[] pNodes = MetaUtils.getNodeNames(pPath);
+    String pRootName = pNodes[0];
+    if (!ptreeMap.containsKey(pRootName)) {
+      throw new PathErrorException("Error: PTree Path Not Correct. Path: " + pPath);
     } else {
-      ptreeMap.get(ptreeName).unlinkMNode(path, mpath);
+      ptreeMap.get(pRootName).unlinkMNode(pNodes, mPath);
     }
   }
 
@@ -175,8 +153,9 @@ public class MGraph implements Serializable {
   void deleteStorageGroup(String path) throws PathErrorException {
     mtree.deleteStorageGroup(path);
   }
+
   /**
-   * Check whether the input path is storage group for current Metadata Tree or not.
+   * Check whether the input path is a storage group in current Metadata Tree or not.
    *
    * @param path Format: root.node.(node)*
    * @apiNote :for cluster
@@ -191,13 +170,14 @@ public class MGraph implements Serializable {
    * Regular expression in this method is formed by the amalgamation of seriesPath and the character
    * '*'.
    *
-   * @return A HashMap whose Keys are separated by the storage file name.
+   * @return A HashMap whose Keys are the storage group names.
    */
   HashMap<String, List<String>> getAllPathGroupByStorageGroup(String path)
       throws PathErrorException {
-    String rootName = MetaUtils.getNodeNames(path, DOUB_SEPARATOR)[0];
+    String[] nodes = MetaUtils.getNodeNames(path);
+    String rootName = nodes[0];
     if (mtree.getRoot().getName().equals(rootName)) {
-      return mtree.getAllPath(path);
+      return mtree.getAllPath(nodes);
     } else if (ptreeMap.containsKey(rootName)) {
       PTree ptree = ptreeMap.get(rootName);
       return ptree.getAllLinkedPath(path);
@@ -211,11 +191,14 @@ public class MGraph implements Serializable {
 
   /**
    * function for getting all timeseries paths under the given seriesPath.
+   * @return each list in the returned list consists of 4 strings: full path, storage group, data
+   *   type and encoding of a timeseries
    */
-  List<List<String>> getShowTimeseriesPath(String path) throws PathErrorException {
-    String rootName = MetaUtils.getNodeNames(path, DOUB_SEPARATOR)[0];
+  List<List<String>> getTimeseriesInfo(String path) throws PathErrorException {
+    String[] nodes = MetaUtils.getNodeNames(path);
+    String rootName = nodes[0];
     if (mtree.getRoot().getName().equals(rootName)) {
-      return mtree.getShowTimeseriesPath(path);
+      return mtree.getTimeseriesInfo(nodes);
     } else if (ptreeMap.containsKey(rootName)) {
       throw new PathErrorException(
           "PTree is not involved in the execution of the sql 'show timeseries " + path + "'");
@@ -223,56 +206,16 @@ public class MGraph implements Serializable {
     throw new PathErrorException(TIME_SERIES_INCORRECT + rootName);
   }
 
-  /**
-   * Get all deviceId type in current Metadata Tree.
-   *
-   * @return a HashMap contains all distinct deviceId type separated by deviceId Type
-   */
-  Map<String, List<MeasurementSchema>> getSchemaForAllType() throws PathErrorException {
-    Map<String, List<MeasurementSchema>> res = new HashMap<>();
-    List<String> typeList = mtree.getAllType();
-    for (String type : typeList) {
-      res.put(type, getSchemaForOneType("root." + type));
-    }
-    return res;
-  }
-
-  private ArrayList<String> getDeviceForOneType(String type) throws PathErrorException {
-    return mtree.getDeviceForOneType(type);
-  }
-
-  /**
-   * Get all delta objects group by deviceId type.
-   */
-  private Map<String, List<String>> getDeviceForAllType() throws PathErrorException {
-    Map<String, List<String>> res = new HashMap<>();
-    ArrayList<String> types = mtree.getAllType();
-    for (String type : types) {
-      res.put(type, getDeviceForOneType(type));
-    }
-    return res;
-  }
-
-  /**
-   * Get the full Metadata info.
-   *
-   * @return A {@code Metadata} instance which stores all metadata info
-   */
-  public Metadata getMetadata() throws PathErrorException {
-    Map<String, List<String>> deviceIdMap = getDeviceForAllType();
-    return new Metadata(deviceIdMap);
-  }
-
   List<String> getAllStorageGroupNames() {
     return mtree.getAllStorageGroupList();
   }
 
-  Set<String> getAllDevices() throws SQLException {
+  List<String> getAllDevices() {
     return mtree.getAllDevices();
   }
 
-  List<String> getNodesList(String schemaPattern, int nodeLevel) throws SQLException {
-    return mtree.getNodesList(schemaPattern, nodeLevel);
+  List<String> getNodesList(String prefixPath, int nodeLevel) throws SQLException {
+    return mtree.getNodesList(prefixPath, nodeLevel);
   }
 
   List<String> getLeafNodePathInNextLevel(String path) throws PathErrorException {
@@ -280,43 +223,24 @@ public class MGraph implements Serializable {
   }
 
   /**
-   * Get all ColumnSchemas for given delta object type.
-   *
-   * @param path A seriesPath represented one Delta object
-   * @return a list contains all column schema
-   */
-  ArrayList<MeasurementSchema> getSchemaForOneType(String path) throws PathErrorException {
-    return mtree.getSchemaForOneType(path);
-  }
-
-  /**
    * Get all ColumnSchemas for the storage group seriesPath.
    *
    * @param path the Path in a storage group
-   * @return ArrayList<'   ColumnSchema   '> The list of the schema
+   * @return List<'   ColumnSchema   '> The list of the schema
    */
-  ArrayList<MeasurementSchema> getSchemaInOneStorageGroup(String path) {
+  List<MeasurementSchema> getSchemaInOneStorageGroup(String path) {
     return mtree.getSchemaForOneStorageGroup(path);
   }
 
-  Map<String, MeasurementSchema> getSchemaMapForOneFileNode(String path) {
+  Map<String, MeasurementSchema> getSchemaMapInStorageGroup(String path) {
     return mtree.getSchemaMapForOneStorageGroup(path);
   }
 
-  Map<String, Integer> getNumSchemaMapForOneFileNode(String path) {
+  Map<String, Integer> getNumSchemaMapInStorageGroup(String path) {
     return mtree.getNumSchemaMapForOneFileNode(path);
   }
 
   /**
-   * Calculate the count of storage-group nodes included in given seriesPath.
-   *
-   * @return The total count of storage-group nodes.
-   */
-  int getFileCountForOneType(String path) throws PathErrorException {
-    return mtree.getFileCountForOneType(path);
-  }
-
-  /**
    * Get the file name for given seriesPath Notice: This method could be called if and only if the
    * seriesPath includes one node whose {@code isStorageGroup} is true.
    */
@@ -346,16 +270,14 @@ public class MGraph implements Serializable {
     return mtree.isPathExist(path);
   }
 
-  boolean pathExist(MNode node, String path) {
-    return mtree.isPathExist(node, path);
-  }
-
-  MNode getNodeByPath(String path) throws PathErrorException {
-    return mtree.getNode(path);
-  }
-
-  MNode getNodeByPathWithCheck(String path) throws PathErrorException, StorageGroupException {
-      return mtree.getNodeByPathWithStorageGroupCheck(path);
+  /**
+   *
+   * @param path
+   * @return an MNode corresponding to path
+   * @throws PathErrorException if the path does not exist or does not belong to a storage group.
+   */
+  MNode getNodeInStorageGroup(String path) throws PathErrorException {
+      return mtree.getNodeInStorageGroup(path);
   }
 
   /**
@@ -366,19 +288,6 @@ public class MGraph implements Serializable {
     return mtree.getSchemaForOnePath(path);
   }
 
-  MeasurementSchema getSchemaForOnePath(MNode node, String path) throws PathErrorException {
-    return mtree.getSchemaForOnePath(node, path);
-  }
-
-  MeasurementSchema getSchemaForOnePathWithCheck(MNode node, String path)
-      throws PathErrorException {
-    return mtree.getSchemaForOnePathWithCheck(node, path);
-  }
-
-  MeasurementSchema getSchemaForOnePathWithCheck(String path) throws PathErrorException {
-    return mtree.getSchemaForOnePathWithCheck(path);
-  }
-
   /**
    * functions for converting the mTree to a readable string in json format.
    */
@@ -388,21 +297,13 @@ public class MGraph implements Serializable {
   }
 
   /**
-   * combine multiple metadata in string format
-   */
-  static String combineMetadataInStrings(String[] metadataArray) {
-    return MTree.combineMetadataInStrings(metadataArray);
-  }
-
-  /**
    * @return storage group name -> the series number
    */
-  Map<String, Integer> countSeriesNumberInEachStorageGroup() throws PathErrorException {
+  Map<String, Integer> countSeriesNumberInEachStorageGroup() {
     Map<String, Integer> res = new HashMap<>();
-    List<String> storageGroups = this.getAllStorageGroupNames();
-    for (String sg : storageGroups) {
-      MNode node = mtree.getNode(sg);
-      res.put(sg, node.getLeafCount());
+    List<MNode> storageGroups = getAllStorageGroupNodes();
+    for (MNode sg : storageGroups) {
+      res.put(sg.getFullPath(), sg.getLeafCount());
     }
     return res;
   }
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 3102d7c..5678b9f 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
@@ -62,9 +62,10 @@ import org.slf4j.LoggerFactory;
  */
 public class MManager {
 
+  public static final String METADATA_LOG = "mlog.txt";
   private static final Logger logger = LoggerFactory.getLogger(MManager.class);
   private static final String DOUB_SEPARATOR = "\\.";
-  private static final String ROOT_NAME = MetadataConstant.ROOT;
+  private static final String ROOT_NAME = IoTDBConstant.PATH_ROOT;
   private static final String TIME_SERIES_TREE_HEADER = "===  Timeseries Tree  ===\n\n";
 
   // the lock for read/insert
@@ -96,7 +97,7 @@ public class MManager {
         logger.info("create system folder {} failed.", systemFolder.getAbsolutePath());
       }
     }
-    logFilePath = schemaDir + File.separator + MetadataConstant.METADATA_LOG;
+    logFilePath = schemaDir + File.separator + METADATA_LOG;
     writeToLog = false;
 
     int cacheSize = IoTDBDescriptor.getInstance().getConfig().getmManagerCacheSize();
@@ -121,8 +122,8 @@ public class MManager {
       @Override
       public MNode loadObjectByKey(String key) throws CacheException {
         try {
-          return getNodeByPathWithCheck(key);
-        } catch (PathErrorException | StorageGroupException e) {
+          return getNodeInStorageGroup(key);
+        } catch (PathErrorException e) {
           throw new CacheException(e);
         }
       }
@@ -373,7 +374,7 @@ public class MManager {
   }
 
   /**
-   * path will be added to mgraph with no check
+   * path will be added to MGraph with no check
    */
   private void addPathToMTreeInternal(String path, TSDataType dataType, TSEncoding encoding,
       CompressionType compressor, Map<String, String> props)
@@ -778,82 +779,11 @@ public class MManager {
   }
 
   /**
-   * function for getting series type.
-   */
-  public TSDataType getSeriesType(MNode node, String fullPath) throws PathErrorException {
-
-    lock.readLock().lock();
-    try {
-      return getSchemaForOnePath(node, fullPath).getType();
-    } finally {
-      lock.readLock().unlock();
-    }
-  }
-
-  /**
-   * function for getting series type with check.
-   */
-  TSDataType getSeriesTypeWithCheck(MNode node, String fullPath) throws PathErrorException {
-
-    lock.readLock().lock();
-    try {
-      return getSchemaForOnePathWithCheck(node, fullPath).getType();
-    } finally {
-      lock.readLock().unlock();
-    }
-  }
-
-  /**
-   * unction for getting series type with check.
-   */
-  TSDataType getSeriesTypeWithCheck(String fullPath) throws PathErrorException {
-
-    lock.readLock().lock();
-    try {
-      return getSchemaForOnePathWithCheck(fullPath).getType();
-    } finally {
-      lock.readLock().unlock();
-    }
-  }
-
-  /**
-   * Get all device type in current Metadata Tree.
-   *
-   * @return a HashMap contains all distinct device type separated by device Type
-   */
-  // future feature
-  @SuppressWarnings("unused")
-  public Map<String, List<MeasurementSchema>> getSchemaForAllType() throws PathErrorException {
-
-    lock.readLock().lock();
-    try {
-      return mgraph.getSchemaForAllType();
-    } finally {
-      lock.readLock().unlock();
-    }
-  }
-
-  /**
-   * Get the full Metadata info.
-   *
-   * @return A {@code Metadata} instance which stores all metadata info
-   */
-  public Metadata getMetadata() throws PathErrorException {
-
-    lock.readLock().lock();
-    try {
-      return mgraph.getMetadata();
-    } finally {
-      lock.readLock().unlock();
-    }
-  }
-
-  /**
    * Get the full devices info.
    *
    * @return A HashSet instance which stores all devices info
    */
-  public Set<String> getAllDevices() throws SQLException {
+  public List<String> getAllDevices() {
 
     lock.readLock().lock();
     try {
@@ -879,21 +809,6 @@ public class MManager {
   }
 
   /**
-   * @param path A seriesPath represented one Delta object
-   * @return a list contains all column schema
-   * @deprecated Get all MeasurementSchemas for given delta object type.
-   */
-  @Deprecated
-  public List<MeasurementSchema> getSchemaForOneType(String path) throws PathErrorException {
-    lock.readLock().lock();
-    try {
-      return mgraph.getSchemaForOneType(path);
-    } finally {
-      lock.readLock().unlock();
-    }
-  }
-
-  /**
    * Get all MeasurementSchemas for the storage group seriesPath.
    */
   public List<MeasurementSchema> getSchemaForStorageGroup(String path) {
@@ -912,7 +827,7 @@ public class MManager {
 
     lock.readLock().lock();
     try {
-      return mgraph.getSchemaMapForOneFileNode(path);
+      return mgraph.getSchemaMapInStorageGroup(path);
     } finally {
       lock.readLock().unlock();
     }
@@ -925,24 +840,7 @@ public class MManager {
 
     lock.readLock().lock();
     try {
-      return mgraph.getNumSchemaMapForOneFileNode(path);
-    } finally {
-      lock.readLock().unlock();
-    }
-  }
-
-  /**
-   * Calculate the count of storage-group nodes included in given seriesPath.
-   *
-   * @return The total count of storage-group nodes.
-   */
-  // future feature
-  @SuppressWarnings("unused")
-  public int getFileCountForOneType(String path) throws PathErrorException {
-
-    lock.readLock().lock();
-    try {
-      return mgraph.getFileCountForOneType(path);
+      return mgraph.getNumSchemaMapInStorageGroup(path);
     } finally {
       lock.readLock().unlock();
     }
@@ -1075,22 +973,10 @@ public class MManager {
   /**
    * function for getting all timeseries paths under the given seriesPath.
    */
-  public List<List<String>> getShowTimeseriesPath(String path) throws PathErrorException {
+  public List<List<String>> getTimeseriesInfo(String path) throws PathErrorException {
     lock.readLock().lock();
     try {
-      return mgraph.getShowTimeseriesPath(path);
-    } finally {
-      lock.readLock().unlock();
-    }
-  }
-
-  /**
-   * function for getting leaf node path in the next level of given seriesPath.
-   */
-  List<String> getLeafNodePathInNextLevel(String path) throws PathErrorException {
-    lock.readLock().lock();
-    try {
-      return mgraph.getLeafNodePathInNextLevel(path);
+      return mgraph.getTimeseriesInfo(path);
     } finally {
       lock.readLock().unlock();
     }
@@ -1110,31 +996,6 @@ public class MManager {
   }
 
   /**
-   * function for checking whether the path exists.
-   */
-  boolean pathExist(MNode node, String path) {
-
-    lock.readLock().lock();
-    try {
-      return mgraph.pathExist(node, path);
-    } finally {
-      lock.readLock().unlock();
-    }
-  }
-
-  /**
-   * function for getting node by path.
-   */
-  MNode getNodeByPath(String path) throws PathErrorException {
-    lock.readLock().lock();
-    try {
-      return mgraph.getNodeByPath(path);
-    } finally {
-      lock.readLock().unlock();
-    }
-  }
-
-  /**
    * function for getting node by deviceId from cache.
    */
   public MNode getNodeByDeviceIdFromCache(String deviceId) throws CacheException, PathErrorException {
@@ -1171,12 +1032,13 @@ public class MManager {
   }
 
   /**
-   * function for getting node by path with check.
+   * function for getting a node in a storage group by path. If the path does not belong to a
+   * storage group, PathErrorException will rise.
    */
-  public MNode getNodeByPathWithCheck(String path) throws PathErrorException, StorageGroupException {
+  public MNode getNodeInStorageGroup(String path) throws PathErrorException {
     lock.readLock().lock();
     try {
-      return mgraph.getNodeByPathWithCheck(path);
+      return mgraph.getNodeInStorageGroup(path);
     } finally {
       lock.readLock().unlock();
     }
@@ -1197,46 +1059,6 @@ public class MManager {
   }
 
   /**
-   * function for getting schema for one path.
-   */
-  private MeasurementSchema getSchemaForOnePath(MNode node, String path) throws PathErrorException {
-
-    lock.readLock().lock();
-    try {
-      return mgraph.getSchemaForOnePath(node, path);
-    } finally {
-      lock.readLock().unlock();
-    }
-  }
-
-  /**
-   * function for getting schema for one path with check.
-   */
-  private MeasurementSchema getSchemaForOnePathWithCheck(MNode node, String path)
-      throws PathErrorException {
-
-    lock.readLock().lock();
-    try {
-      return mgraph.getSchemaForOnePathWithCheck(node, path);
-    } finally {
-      lock.readLock().unlock();
-    }
-  }
-
-  /**
-   * function for getting schema for one path with check.
-   */
-  private MeasurementSchema getSchemaForOnePathWithCheck(String path) throws PathErrorException {
-
-    lock.readLock().lock();
-    try {
-      return mgraph.getSchemaForOnePathWithCheck(path);
-    } finally {
-      lock.readLock().unlock();
-    }
-  }
-
-  /**
    * Check whether given seriesPath contains a MNode whose {@code MNode.isStorageGroup} is true.
    */
   public boolean checkFileLevel(List<Path> path) throws StorageGroupException {
@@ -1316,7 +1138,7 @@ public class MManager {
    */
   String getStorageGroupNameByAutoLevel(String fullPath, int level)
       throws PathErrorException {
-    String[] nodeNames = MetaUtils.getNodeNames(fullPath, DOUB_SEPARATOR);
+    String[] nodeNames = MetaUtils.getNodeNames(fullPath);
     StringBuilder storageGroupName = new StringBuilder(nodeNames[0]);
     if (nodeNames.length < level || !storageGroupName.toString().equals(ROOT_NAME)) {
       throw new PathErrorException(String.format("Timeseries %s is not right.", fullPath));
@@ -1399,7 +1221,7 @@ public class MManager {
   public void setTTL(String storageGroup, long dataTTL) throws PathErrorException, IOException {
     lock.writeLock().lock();
     try {
-      MNode sgNode = getNodeByPath(storageGroup);
+      MNode sgNode = getNodeInStorageGroup(storageGroup);
       if (!sgNode.isStorageGroup()) {
         throw new NotStorageGroupException(storageGroup);
       }
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 92e6f2e..431375b 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/MTree.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/MTree.java
@@ -18,25 +18,22 @@
  */
 package org.apache.iotdb.db.metadata;
 
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.JSONObject;
-import com.alibaba.fastjson.serializer.SerializerFeature;
+import static org.apache.iotdb.tsfile.common.constant.TsFileConstant.PATH_SEPARATOR;
+import static org.apache.iotdb.tsfile.common.constant.TsFileConstant.PATH_SEPARATOR_NO_REGEX;
 
-import java.io.Serializable;
+import com.alibaba.fastjson.JSONObject;
 import java.sql.SQLException;
+import java.util.ArrayDeque;
 import java.util.ArrayList;
+import java.util.Deque;
 import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
-import java.util.Stack;
+import org.apache.iotdb.db.conf.IoTDBConstant;
 import org.apache.iotdb.db.conf.IoTDBDescriptor;
 import org.apache.iotdb.db.exception.PathErrorException;
 import org.apache.iotdb.db.exception.StorageGroupException;
-import org.apache.iotdb.db.qp.constant.SQLConstant;
-import org.apache.iotdb.tsfile.common.constant.TsFileConstant;
+import org.apache.iotdb.db.utils.SchemaUtils;
 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;
@@ -45,10 +42,8 @@ import org.apache.iotdb.tsfile.write.schema.MeasurementSchema;
 /**
  * The hierarchical struct of the Metadata Tree is implemented in this class.
  */
-public class MTree implements Serializable {
+public class MTree {
 
-  private static final long serialVersionUID = -4200394435237291964L;
-  private static final String PATH_SEPARATOR = "\\.";
   private static final String NO_CHILD_ERROR = "Timeseries is not correct. Node[%s] "
           + "doesn't have child named:%s";
   private static final String NOT_LEAF_NODE = "Timeseries %s is not the leaf node";
@@ -63,12 +58,13 @@ public class MTree implements Serializable {
   /**
    * function for adding timeseries.It should check whether seriesPath exists.
    */
-  void addTimeseriesPath(String timeseriesPath, TSDataType dataType, TSEncoding encoding,
+  void addTimeseriesPath(String[] nodeNames, TSDataType dataType, TSEncoding encoding,
       CompressionType compressor, Map<String, String> props) throws PathErrorException {
-      String[] nodeNames = MetaUtils.getNodeNames(timeseriesPath, PATH_SEPARATOR);
     if (nodeNames.length <= 1 || !nodeNames[0].equals(root.getName())) {
-      throw new PathErrorException(String.format("Timeseries %s is not right.", timeseriesPath));
+      throw new PathErrorException(String.format("Timeseries %s is not right.",
+          String.join(PATH_SEPARATOR, nodeNames)));
     }
+
     MNode cur = findLeafParent(nodeNames);
     String levelPath = cur.getDataFileName();
 
@@ -79,8 +75,8 @@ public class MTree implements Serializable {
     leaf.setDataFileName(levelPath);
     if (cur.isLeaf()) {
       throw new PathErrorException(
-              String.format("The Node [%s] is left node, the timeseries %s can't be created",
-                      cur.getName(), timeseriesPath));
+          String.format("The Node [%s] is left node, the timeseries %s can't be created",
+              cur.getName(), String.join(PATH_SEPARATOR, nodeNames)));
     }
     cur.addChild(nodeNames[nodeNames.length - 1], leaf);
   }
@@ -89,7 +85,7 @@ public class MTree implements Serializable {
    * function for adding deviceId
    */
   MNode addDeviceId(String deviceId) throws PathErrorException {
-    String[] nodeNames = MetaUtils.getNodeNames(deviceId, PATH_SEPARATOR);
+    String[] nodeNames = MetaUtils.getNodeNames(deviceId);
     if (nodeNames.length <= 1 || !nodeNames[0].equals(root.getName())) {
       throw new PathErrorException(String.format("Timeseries %s is not right.", deviceId));
     }
@@ -138,7 +134,12 @@ public class MTree implements Serializable {
    * @param path -seriesPath not necessarily the whole seriesPath (possibly a prefix of a sequence)
    */
   boolean isPathExist(String path) {
-    String[] nodeNames = nodeNames = MetaUtils.getNodeNames(path, PATH_SEPARATOR);
+    String[] nodeNames;
+    try {
+      nodeNames = MetaUtils.getNodeNames(path);
+    } catch (PathErrorException e) {
+      return false;
+    }
     MNode cur = root;
     int i = 0;
     while (i < nodeNames.length - 1) {
@@ -162,7 +163,12 @@ public class MTree implements Serializable {
    * function for checking whether the given path exists under the given mNode.
    */
   boolean isPathExist(MNode node, String path) {
-    String[] nodeNames = MetaUtils.getNodeNames(path, PATH_SEPARATOR);
+    String[] nodeNames;
+    try {
+      nodeNames = MetaUtils.getNodeNames(path);
+    } catch (PathErrorException e) {
+      return false;
+    }
     if (nodeNames.length < 1) {
       return true;
     }
@@ -193,7 +199,7 @@ public class MTree implements Serializable {
    * make sure check seriesPath before setting storage group.
    */
   public void setStorageGroup(String path) throws StorageGroupException {
-    String[] nodeNames = MetaUtils.getNodeNames(path, PATH_SEPARATOR);
+    String[] nodeNames = path.split(PATH_SEPARATOR_NO_REGEX);
     MNode cur = root;
     if (nodeNames.length <= 1 || !nodeNames[0].equals(root.getName())) {
       throw new StorageGroupException(
@@ -236,7 +242,7 @@ public class MTree implements Serializable {
     }
     cur.getParent().deleteChild(cur.getName());
     cur = cur.getParent();
-    while (cur != null && !MetadataConstant.ROOT.equals(cur.getName()) && cur.getChildren().size() == 0) {
+    while (cur != null && !IoTDBConstant.PATH_ROOT.equals(cur.getName()) && cur.getChildren().size() == 0) {
       cur.getParent().deleteChild(cur.getName());
       cur = cur.getParent();
     }
@@ -250,7 +256,7 @@ public class MTree implements Serializable {
    * @apiNote :for cluster
    */
   boolean checkStorageGroup(String path) {
-    String[] nodeNames = MetaUtils.getNodeNames(path, PATH_SEPARATOR);
+    String[] nodeNames = path.split(PATH_SEPARATOR_NO_REGEX);
     MNode cur = root;
     if (nodeNames.length <= 1 || !nodeNames[0].equals(root.getName())) {
       return false;
@@ -285,7 +291,7 @@ public class MTree implements Serializable {
    *             node.
    */
   String deletePath(String path) throws PathErrorException {
-    String[] nodes = MetaUtils.getNodeNames(path, PATH_SEPARATOR);
+    String[] nodes = MetaUtils.getNodeNames(path);
     if (nodes.length == 0 || !nodes[0].equals(getRoot().getName())) {
       throw new PathErrorException("Timeseries %s is not correct." + path);
     }
@@ -307,7 +313,7 @@ public class MTree implements Serializable {
     }
     cur.getParent().deleteChild(cur.getName());
     cur = cur.getParent();
-    while (cur != null && !MetadataConstant.ROOT.equals(cur.getName()) && cur.getChildren().size() == 0) {
+    while (cur != null && !IoTDBConstant.PATH_ROOT.equals(cur.getName()) && cur.getChildren().size() == 0) {
       if (cur.isStorageGroup()) {
         dataFileName = cur.getDataFileName();
         return dataFileName;
@@ -328,93 +334,21 @@ public class MTree implements Serializable {
     return leaf.getSchema();
   }
 
-  MeasurementSchema getSchemaForOnePath(MNode node, String path) throws PathErrorException {
-    MNode leaf = getLeafByPath(node, path);
-    return leaf.getSchema();
-  }
-
-  MeasurementSchema getSchemaForOnePathWithCheck(MNode node, String path)
-          throws PathErrorException {
-    MNode leaf = getLeafByPathWithCheck(node, path);
-    return leaf.getSchema();
-  }
-
-  MeasurementSchema getSchemaForOnePathWithCheck(String path) throws PathErrorException {
-    MNode leaf = getLeafByPathWithCheck(path);
-    return leaf.getSchema();
-  }
-
   private MNode getLeafByPath(String path) throws PathErrorException {
-    getNode(path);
-    String[] node = MetaUtils.getNodeNames(path, PATH_SEPARATOR);
-    MNode cur = getRoot();
-    for (int i = 1; i < node.length; i++) {
-      cur = cur.getChild(node[i]);
-    }
-    if (!cur.isLeaf()) {
+    MNode lastNode = getNode(path);
+    if (!lastNode.isLeaf()) {
       throw new PathErrorException(String.format(NOT_LEAF_NODE, path));
     }
-    return cur;
-  }
-
-  private MNode getLeafByPath(MNode node, String path) throws PathErrorException {
-    String[] nodes = MetaUtils.getNodeNames(path, PATH_SEPARATOR);
-    MNode cur = node.getChild(nodes[0]);
-    for (int i = 1; i < nodes.length; i++) {
-      cur = cur.getChild(nodes[i]);
-    }
-    if (!cur.isLeaf()) {
-      throw new PathErrorException(String.format(NOT_LEAF_NODE, path));
-    }
-    return cur;
-  }
-
-  private MNode getLeafByPathWithCheck(MNode node, String path) throws PathErrorException {
-    String[] nodes = MetaUtils.getNodeNames(path, PATH_SEPARATOR);
-    if (nodes.length < 1 || !node.hasChild(nodes[0])) {
-      throw new PathErrorException(String.format(SERIES_NOT_CORRECT, path));
-    }
-
-    MNode cur = node.getChild(nodes[0]);
-    for (int i = 1; i < nodes.length; i++) {
-      if (!cur.hasChild(nodes[i])) {
-        throw new PathErrorException(
-                String.format(NO_CHILD_ERROR, cur.getName(), nodes[i]));
-      }
-      cur = cur.getChild(nodes[i]);
-    }
-    if (!cur.isLeaf()) {
-      throw new PathErrorException(String.format(NOT_LEAF_NODE, path));
-    }
-    return cur;
-  }
-
-  private MNode getLeafByPathWithCheck(String path) throws PathErrorException {
-    String[] nodes = MetaUtils.getNodeNames(path, PATH_SEPARATOR);
-    if (nodes.length < 2 || !nodes[0].equals(getRoot().getName())) {
-      throw new PathErrorException(String.format(SERIES_NOT_CORRECT, path));
-    }
-
-    MNode cur = getRoot();
-    for (int i = 1; i < nodes.length; i++) {
-      if (!cur.hasChild(nodes[i])) {
-        throw new PathErrorException(
-                String.format(NO_CHILD_ERROR, cur.getName(), nodes[i]));
-      }
-      cur = cur.getChild(nodes[i]);
-    }
-    if (!cur.isLeaf()) {
-      throw new PathErrorException(String.format(NOT_LEAF_NODE, path));
-    }
-    return cur;
+    return lastNode;
   }
 
   /**
-   * function for getting node by path with file level check.
+   * function for getting a node by path in a storage group. PathErrorException will rise if the
+   * path does not belong to a storage group.
    */
-  MNode getNodeByPathWithStorageGroupCheck(String path) throws PathErrorException, StorageGroupException {
+  MNode getNodeInStorageGroup(String path) throws PathErrorException {
     boolean storageGroupChecked = false;
-    String[] nodes = MetaUtils.getNodeNames(path, PATH_SEPARATOR);
+    String[] nodes = MetaUtils.getNodeNames(path);
     if (nodes.length < 2 || !nodes[0].equals(getRoot().getName())) {
       throw new PathErrorException(String.format(SERIES_NOT_CORRECT, path));
     }
@@ -423,7 +357,7 @@ public class MTree implements Serializable {
     for (int i = 1; i < nodes.length; i++) {
       if (!cur.hasChild(nodes[i])) {
         if (!storageGroupChecked) {
-          throw new StorageGroupException("Storage group is not set for current seriesPath:" + path);
+          throw new PathErrorException("Storage group is not set for current seriesPath:" + path);
         }
         throw new PathErrorException(String.format(NO_CHILD_ERROR, cur.getName(), nodes[i]));
       }
@@ -435,7 +369,7 @@ public class MTree implements Serializable {
     }
 
     if (!storageGroupChecked) {
-      throw new StorageGroupException("Storage group is not set for current seriesPath:" + path);
+      throw new PathErrorException("Storage group is not set for current seriesPath:" + path);
     }
     return cur;
   }
@@ -446,7 +380,7 @@ public class MTree implements Serializable {
    * @return last node in given seriesPath
    */
   MNode getNode(String path) throws PathErrorException {
-    String[] nodes = MetaUtils.getNodeNames(path, PATH_SEPARATOR);
+    String[] nodes = MetaUtils.getNodeNames(path);
     if (nodes.length < 2 || !nodes[0].equals(getRoot().getName())) {
       throw new PathErrorException(String.format(SERIES_NOT_CORRECT, path));
     }
@@ -461,7 +395,7 @@ public class MTree implements Serializable {
   }
 
   private void checkPath(MNode node, String path) throws PathErrorException {
-    String[] nodes = MetaUtils.getNodeNames(path, PATH_SEPARATOR);
+    String[] nodes = MetaUtils.getNodeNames(path);
     if (nodes.length < 1) {
       return;
     }
@@ -481,7 +415,12 @@ public class MTree implements Serializable {
    * @return String storage group seriesPath
    */
   String getStorageGroupNameByPath(String path) throws StorageGroupException {
-    String[] nodes = MetaUtils.getNodeNames(path, PATH_SEPARATOR);
+    String[] nodes;
+    try {
+      nodes = MetaUtils.getNodeNames(path);
+    } catch (PathErrorException e) {
+      throw new StorageGroupException(e);
+    }
     MNode cur = getRoot();
     for (int i = 1; i < nodes.length; i++) {
       if (cur == null) {
@@ -506,7 +445,7 @@ public class MTree implements Serializable {
    */
   List<String> getAllFileNamesByPath(String pathReg) throws PathErrorException {
     ArrayList<String> fileNames = new ArrayList<>();
-    String[] nodes = MetaUtils.getNodeNames(pathReg, PATH_SEPARATOR);
+    String[] nodes = MetaUtils.getNodeNames(pathReg);
     if (nodes.length == 0 || !nodes[0].equals(getRoot().getName())) {
       throw new PathErrorException(String.format(SERIES_NOT_CORRECT, pathReg));
     }
@@ -547,7 +486,12 @@ public class MTree implements Serializable {
    * function for getting file name by path.
    */
   String getStorageGroupNameByPath(MNode node, String path) throws StorageGroupException {
-    String[] nodes = MetaUtils.getNodeNames(path, PATH_SEPARATOR);
+    String[] nodes;
+    try {
+      nodes = MetaUtils.getNodeNames(path);
+    } catch (PathErrorException e) {
+      throw new StorageGroupException(e);
+    }
     MNode cur = node.getChild(nodes[0]);
     for (int i = 1; i < nodes.length; i++) {
       if (cur == null) {
@@ -571,7 +515,7 @@ public class MTree implements Serializable {
    * seriesPath is not storage group seriesPath
    */
   boolean checkFileNameByPath(String path) {
-    String[] nodes = MetaUtils.getNodeNames(path, PATH_SEPARATOR);
+    String[] nodes = path.split(PATH_SEPARATOR_NO_REGEX);
     MNode cur = getRoot();
     for (int i = 1; i <= nodes.length; i++) {
       if (cur == null) {
@@ -592,10 +536,15 @@ public class MTree implements Serializable {
    * @return A HashMap whose Keys are separated by the storage file name.
    */
   HashMap<String, List<String>> getAllPath(String pathReg) throws PathErrorException {
+    String[] nodes = MetaUtils.getNodeNames(pathReg);
+    return getAllPath(nodes);
+  }
+
+  HashMap<String, List<String>> getAllPath(String[] nodes) throws PathErrorException {
     HashMap<String, List<String>> paths = new HashMap<>();
-    String[] nodes = MetaUtils.getNodeNames(pathReg, PATH_SEPARATOR);
     if (nodes.length == 0 || !nodes[0].equals(getRoot().getName())) {
-      throw new PathErrorException(String.format(SERIES_NOT_CORRECT, pathReg));
+      throw new PathErrorException(String.format(SERIES_NOT_CORRECT, String.join(PATH_SEPARATOR,
+       nodes)));
     }
     findPath(getRoot(), nodes, 1, "", paths);
     return paths;
@@ -608,7 +557,7 @@ public class MTree implements Serializable {
    */
   List<MNode> getAllStorageGroupNodes() {
     List<MNode> ret = new ArrayList<>();
-    Stack<MNode> nodeStack = new Stack<>();
+    Deque<MNode> nodeStack = new ArrayDeque<>();
     nodeStack.add(getRoot());
     while (!nodeStack.isEmpty()) {
       MNode current = nodeStack.pop();
@@ -623,14 +572,16 @@ public class MTree implements Serializable {
 
   /**
    * function for getting all timeseries paths under the given seriesPath.
+   * @return each list in the returned list consists of 4 strings: full path, storage group, data
+   * type and encoding of a timeseries
    */
-  List<List<String>> getShowTimeseriesPath(String pathReg) throws PathErrorException {
+  List<List<String>> getTimeseriesInfo(String[] nodes) throws PathErrorException {
     List<List<String>> res = new ArrayList<>();
-    String[] nodes = MetaUtils.getNodeNames(pathReg, PATH_SEPARATOR);
     if (nodes.length == 0 || !nodes[0].equals(getRoot().getName())) {
-      throw new PathErrorException(String.format(SERIES_NOT_CORRECT, pathReg));
+      throw new PathErrorException(String.format(SERIES_NOT_CORRECT, String.join(PATH_SEPARATOR,
+       nodes)));
     }
-    findPath(getRoot(), nodes, 1, "", res);
+    retrieveTimeseriesInfo(getRoot(), nodes, 1, "", res);
     return res;
   }
 
@@ -663,49 +614,6 @@ public class MTree implements Serializable {
   }
 
   /**
-   * Calculate the count of storage-level nodes included in given seriesPath.
-   *
-   * @return The total count of storage-level nodes.
-   */
-  int getFileCountForOneType(String path) throws PathErrorException {
-    String[] nodes = MetaUtils.getNodeNames(path, PATH_SEPARATOR);
-    if (nodes.length != 2 || !nodes[0].equals(getRoot().getName()) || !getRoot()
-            .hasChild(nodes[1])) {
-      throw new PathErrorException(
-              "Timeseries must be " + getRoot().getName()
-                      + ". X (X is one of the nodes of root's children)");
-    }
-    return getFileCountForOneNode(getRoot().getChild(nodes[1]));
-  }
-
-  private int getFileCountForOneNode(MNode node) {
-
-    if (node.isStorageGroup()) {
-      return 1;
-    }
-    int sum = 0;
-    if (!node.isLeaf()) {
-      for (MNode child : node.getChildren().values()) {
-        sum += getFileCountForOneNode(child);
-      }
-    }
-    return sum;
-  }
-
-  /**
-   * Get all device type in current Metadata Tree.
-   *
-   * @return a list contains all distinct device type
-   */
-  ArrayList<String> getAllType() {
-    ArrayList<String> res = new ArrayList<>();
-    if (getRoot() != null) {
-      res.addAll(getRoot().getChildren().keySet());
-    }
-    return res;
-  }
-
-  /**
    * Get all storage groups in current Metadata Tree.
    *
    * @return a list contains all distinct storage groups
@@ -734,30 +642,27 @@ public class MTree implements Serializable {
    *
    * @return a list contains all distinct devices
    */
-  Set<String> getAllDevices() {
-    HashSet<String> devices = new HashSet<>();
-    MNode node;
-    if ((node = getRoot()) != null) {
-      findDevices(node, SQLConstant.ROOT, devices);
-    }
-    return new LinkedHashSet<>(devices);
-  }
+  List<String> getAllDevices() {
+    List<String> devices = new ArrayList<>();
+    Deque<MNode> nodeStack = new ArrayDeque<>();
+    nodeStack.addLast(root);
 
-  private void findDevices(MNode node, String path, HashSet<String> res) {
-    if (node == null) {
-      return;
-    }
-    if (node.isLeaf()) {
-      res.add(path);
-      return;
-    }
-    for (MNode child : node.getChildren().values()) {
-      if (child.isLeaf()) {
-        res.add(path);
-      } else {
-        findDevices(child, path + "." + child.toString(), res);
+    while (!nodeStack.isEmpty()) {
+      MNode current = nodeStack.removeFirst();
+      boolean currentAdded = false;
+      if (current.hasChildren()) {
+        for (MNode child : current.getChildren().values()) {
+          if (child.isLeaf() && !currentAdded) {
+            devices.add(current.getFullPath());
+            currentAdded = true;
+          } else if (!child.isLeaf()) {
+            nodeStack.addLast(child);
+          }
+        }
       }
     }
+
+    return devices;
   }
 
   /**
@@ -765,40 +670,54 @@ public class MTree implements Serializable {
    *
    * @return a list contains all nodes at the given level
    */
-  List<String> getNodesList(String schemaPattern, int nodeLevel) throws SQLException {
-    List<String> res = new ArrayList<>();
-    String[] nodes = MetaUtils.getNodeNames(schemaPattern, PATH_SEPARATOR);
-    MNode node;
-    if ((node = getRoot()) != null) {
-      if (nodes[0].equals("root")) {
-        for (int i = 1; i < nodes.length; i++) {
-          if (node.getChild(nodes[i]) != null) {
-            node = node.getChild(nodes[i]);
-          } else {
-            throw new SQLException(nodes[i - 1] + " does not have the child node " + nodes[i]);
-          }
+  List<String> getNodesList(String prefixPath, int nodeLevel) throws SQLException {
+    String[] nodes = prefixPath.split(PATH_SEPARATOR_NO_REGEX);
+
+    if (nodes[0].equals(IoTDBConstant.PATH_ROOT)) {
+      MNode node = getRoot();
+      for (int i = 1; i < nodes.length; i++) {
+        if (node.getChild(nodes[i]) != null) {
+          node = node.getChild(nodes[i]);
+        } else {
+          throw new SQLException(nodes[i - 1] + " does not have the child node " + nodes[i]);
         }
-        findNodes(node, schemaPattern, res, nodeLevel - (nodes.length - 1));
-      } else {
-        throw new SQLException("Incorrect root node " + nodes[0] + " selected");
       }
+      return findNodes(node, prefixPath, nodeLevel - (nodes.length - 1));
+    } else {
+      throw new SQLException("Incorrect root node " + nodes[0] + " selected");
     }
-    return res;
   }
 
-  private void findNodes(MNode node, String path, List<String> res, int targetLevel) {
-    if (node == null) {
-      return;
-    }
-    if (targetLevel == 0) {
-      res.add(path);
-      return;
-    }
-    if (node.hasChildren()) {
-      for (MNode child : node.getChildren().values()) {
-        findNodes(child, path + "." + child.toString(), res, targetLevel - 1);
+  private List<String> findNodes(MNode node, String path, int targetLevel) {
+    List<String> res = new ArrayList<>();
+
+    Deque<MNode> nodeStack = new ArrayDeque<>();
+    nodeStack.addLast(node);
+
+    int currLevelCnt = 1;
+    int nextLevelCnt = 0;
+    while (targetLevel > 0) {
+      MNode current = nodeStack.removeFirst();
+      currLevelCnt--;
+      if (current.hasChildren()) {
+        for (MNode child : current.getChildren().values()) {
+          nodeStack.addLast(child);
+          // these children are added to the next level
+          nextLevelCnt++;
+        }
+      }
+      if (currLevelCnt == 0) {
+        // current level has exhausted, start the next level
+        targetLevel--;
+        currLevelCnt = nextLevelCnt;
+        nextLevelCnt = 0;
       }
     }
+
+    while (!nodeStack.isEmpty()) {
+      res.add(nodeStack.removeFirst().getFullPath());
+    }
+    return res;
   }
 
   /**
@@ -828,31 +747,12 @@ public class MTree implements Serializable {
   }
 
   /**
-   * Get all ColumnSchemas for given delta object type.
-   *
-   * @param path A seriesPath represented one Delta object
-   * @return a list contains all column schema
-   */
-  ArrayList<MeasurementSchema> getSchemaForOneType(String path) throws PathErrorException {
-    String[] nodes = MetaUtils.getNodeNames(path, PATH_SEPARATOR);
-    if (nodes.length != 2 || !nodes[0].equals(getRoot().getName()) || !getRoot()
-            .hasChild(nodes[1])) {
-      throw new PathErrorException(
-              "Timeseries must be " + getRoot().getName()
-                      + ". X (X is one of the nodes of root's children)");
-    }
-    HashMap<String, MeasurementSchema> leafMap = new HashMap<>();
-    putLeafToLeafMap(getRoot().getChild(nodes[1]), leafMap);
-    return new ArrayList<>(leafMap.values());
-  }
-
-  /**
    * Get all ColumnSchemas for the storage group seriesPath.
    *
    * @return ArrayList<ColumnSchema> The list of the schema
    */
-  ArrayList<MeasurementSchema> getSchemaForOneStorageGroup(String path) {
-    String[] nodes = MetaUtils.getNodeNames(path, PATH_SEPARATOR);
+  List<MeasurementSchema> getSchemaForOneStorageGroup(String path) {
+    String[] nodes = path.split(PATH_SEPARATOR_NO_REGEX);
     HashMap<String, MeasurementSchema> leafMap = new HashMap<>();
     MNode cur = getRoot();
     for (int i = 1; i < nodes.length; i++) {
@@ -867,7 +767,7 @@ public class MTree implements Serializable {
    * function for getting schema map for one storage group.
    */
   Map<String, MeasurementSchema> getSchemaMapForOneStorageGroup(String path) {
-    String[] nodes = MetaUtils.getNodeNames(path, PATH_SEPARATOR);
+    String[] nodes = path.split(PATH_SEPARATOR_NO_REGEX);
     MNode cur = getRoot();
     for (int i = 1; i < nodes.length; i++) {
       cur = cur.getChild(nodes[i]);
@@ -879,7 +779,7 @@ public class MTree implements Serializable {
    * function for getting num schema map for one file node.
    */
   Map<String, Integer> getNumSchemaMapForOneFileNode(String path) {
-    String[] nodes = MetaUtils.getNodeNames(path, PATH_SEPARATOR);
+    String[] nodes = path.split(PATH_SEPARATOR_NO_REGEX);
     MNode cur = getRoot();
     for (int i = 1; i < nodes.length; i++) {
       cur = cur.getChild(nodes[i]);
@@ -905,7 +805,7 @@ public class MTree implements Serializable {
       if (nodes.length <= idx) {
         String fileName = node.getDataFileName();
         String nodeName;
-        if (node.getName().contains(TsFileConstant.PATH_SEPARATOR)) {
+        if (node.getName().contains(PATH_SEPARATOR)) {
           nodeName = "\"" + node + "\"";
         } else {
           nodeName = "" + node;
@@ -935,8 +835,10 @@ public class MTree implements Serializable {
 
   /*
    * Iterate through MTree to fetch metadata info of all leaf nodes under the given seriesPath
+   * the full path,storage group,resultDataType,encoding of each timeseries will be put into a
+   * list and the list will be added into res
    */
-  private void findPath(MNode node, String[] nodes, int idx, String parent,
+  private void retrieveTimeseriesInfo(MNode node, String[] nodes, int idx, String parent,
                         List<List<String>> res) {
     if (node.isLeaf()) {
       if (nodes.length <= idx) {
@@ -960,11 +862,11 @@ public class MTree implements Serializable {
 
     if (!("*").equals(nodeReg)) {
       if (node.hasChild(nodeReg)) {
-        findPath(node.getChild(nodeReg), nodes, idx + 1, parent + node.getName() + ".", res);
+        retrieveTimeseriesInfo(node.getChild(nodeReg), nodes, idx + 1, parent + node.getName() + ".", res);
       }
     } else {
       for (MNode child : node.getChildren().values()) {
-        findPath(child, nodes, idx + 1, parent + node.getName() + ".", res);
+        retrieveTimeseriesInfo(child, nodes, idx + 1, parent + node.getName() + ".", res);
       }
     }
   }
@@ -982,12 +884,9 @@ public class MTree implements Serializable {
 
   @Override
   public String toString() {
-    return jsonToString(toJson());
+    return SchemaUtils.jsonToString(toJson());
   }
 
-  private static String jsonToString(JSONObject jsonObject) {
-    return JSON.toJSONString(jsonObject, SerializerFeature.PrettyFormat);
-  }
 
   private JSONObject toJson() {
     JSONObject jsonObject = new JSONObject();
@@ -1015,46 +914,4 @@ public class MTree implements Serializable {
     return root;
   }
 
-  /**
-   * combine multiple metadata in string format
-   */
-  static String combineMetadataInStrings(String[] metadataStrs) {
-    JSONObject[] jsonObjects = new JSONObject[metadataStrs.length];
-    for (int i = 0; i < jsonObjects.length; i++) {
-      jsonObjects[i] = JSONObject.parseObject(metadataStrs[i]);
-    }
-
-    JSONObject root = jsonObjects[0];
-    for (int i = 1; i < jsonObjects.length; i++) {
-      root = combineJSONObjects(root, jsonObjects[i]);
-    }
-    return jsonToString(root);
-  }
-
-  private static JSONObject combineJSONObjects(JSONObject a, JSONObject b) {
-    JSONObject res = new JSONObject();
-
-    Set<String> retainSet = new HashSet<>(a.keySet());
-    retainSet.retainAll(b.keySet());
-    Set<String> aCha = new HashSet<>(a.keySet());
-    Set<String> bCha = new HashSet<>(b.keySet());
-    aCha.removeAll(retainSet);
-    bCha.removeAll(retainSet);
-    for (String key : aCha) {
-      res.put(key, a.getJSONObject(key));
-    }
-    for (String key : bCha) {
-      res.put(key, b.get(key));
-    }
-    for (String key : retainSet) {
-      Object v1 = a.get(key);
-      Object v2 = b.get(key);
-      if (v1 instanceof JSONObject && v2 instanceof JSONObject) {
-        res.put(key, combineJSONObjects((JSONObject) v1, (JSONObject) v2));
-      } else {
-        res.put(key, v1);
-      }
-    }
-    return res;
-  }
 }
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/MetaUtils.java b/server/src/main/java/org/apache/iotdb/db/metadata/MetaUtils.java
index 6899c2f..0dc1ac2 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/MetaUtils.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/MetaUtils.java
@@ -18,27 +18,69 @@
  */
 package org.apache.iotdb.db.metadata;
 
-public class MetaUtils {
-  public static String[] getNodeNames(String path, String separator) {
-    String[] nodeNames;
+import static org.apache.iotdb.tsfile.common.constant.TsFileConstant.PATH_SEPARATOR_NO_REGEX;
+
+import org.apache.iotdb.db.exception.PathErrorException;
+
+class MetaUtils {
+
+  private MetaUtils() {
+    // util class
+  }
+
+  static String[] getNodeNames(String path) throws PathErrorException {
     path = path.trim();
-    if (path.contains("\"") || path.contains("\'")) {
-      String[] deviceAndMeasurement;
-      if (path.contains("\"")) {
-        deviceAndMeasurement = path.split("\"");
-      } else {
-        deviceAndMeasurement = path.split("\'");
+
+    int firstSingleQuotePos = -1;
+    int firstDoubleQuotePos = -1;
+    for (int i = 0; i < path.length(); i++) {
+      if (firstSingleQuotePos == -1 && path.charAt(i) == '\'') {
+        firstSingleQuotePos = i;
+      }
+      if (firstDoubleQuotePos == -1 && path.charAt(i) == '\"') {
+        firstDoubleQuotePos = i;
       }
-      String device = deviceAndMeasurement[0];
-      String measurement = deviceAndMeasurement[1];
-      String[] deviceNodeName = device.split(separator);
-      int nodeNumber = deviceNodeName.length + 1;
+    }
+
+    if (firstDoubleQuotePos != -1 && firstSingleQuotePos != -1) {
+      throw new PathErrorException("Path contains both \" and \': " + path);
+    }
+
+    return getNodeNames(path, firstSingleQuotePos, firstDoubleQuotePos);
+  }
+
+  private static String[] getNodeNames(String path, int firstSingleQuotePos,
+      int firstDoubleQuotePos) throws PathErrorException {
+    String[] nodeNames;
+
+    if (firstSingleQuotePos != -1 && path.charAt(path.length() - 1) != '\'' ||
+        firstDoubleQuotePos != -1 && path.charAt(path.length() - 1) != '\"') {
+      throw new PathErrorException("Path contains but not ends with \' or \": " + path);
+    } else if (firstDoubleQuotePos == -1 && firstSingleQuotePos == -1) {
+      return path.split(PATH_SEPARATOR_NO_REGEX);
+    }
+
+    String device = null;
+    String measurement;
+    int quotePos = firstDoubleQuotePos != -1 ? firstDoubleQuotePos :
+        firstSingleQuotePos;
+    if (quotePos == 0) {
+      measurement = path;
+    } else {
+      device = path.substring(0, quotePos - 1);
+      measurement = path.substring(quotePos + 1, path.length() - 1);
+    }
+
+    if (device == null) {
+      nodeNames = new String[]{measurement};
+    } else {
+      String[] deviceNodeNames = device.split(PATH_SEPARATOR_NO_REGEX);
+      int nodeNumber = deviceNodeNames.length + 1;
       nodeNames = new String[nodeNumber];
-      System.arraycopy(deviceNodeName, 0, nodeNames, 0, nodeNumber - 1);
+      System.arraycopy(deviceNodeNames, 0, nodeNames, 0, nodeNumber - 1);
       nodeNames[nodeNumber - 1] = measurement;
-    } else {
-      nodeNames = path.split(separator);
     }
+
     return nodeNames;
   }
 }
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/Metadata.java b/server/src/main/java/org/apache/iotdb/db/metadata/Metadata.java
deleted file mode 100644
index ee59a2a..0000000
--- a/server/src/main/java/org/apache/iotdb/db/metadata/Metadata.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.iotdb.db.metadata;
-
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Objects;
-import java.util.Set;
-
-/**
- * This class stores all the metadata info for every deviceId and every timeseries.
- */
-public class Metadata implements Serializable {
-
-  private Map<String, List<String>> deviceIdMap;
-
-  public Metadata(Map<String, List<String>> deviceIdMap) {
-    this.deviceIdMap = deviceIdMap;
-  }
-
-  public Map<String, List<String>> getDeviceMap() {
-    return deviceIdMap;
-  }
-
-  /**
-   * combine multiple metadatas
-   */
-  public static Metadata combineMetadatas(Metadata[] metadatas) {
-    Map<String, List<String>> deviceIdMap = new HashMap<>();
-
-    if (metadatas == null || metadatas.length == 0) {
-      return new Metadata(deviceIdMap);
-    }
-
-    for (int i = 0; i < metadatas.length; i++) {
-      Map<String, List<String>> subDeviceIdMap = metadatas[i].deviceIdMap;
-      for (Entry<String, List<String>> entry : subDeviceIdMap.entrySet()) {
-        List<String> list = deviceIdMap.getOrDefault(entry.getKey(), new ArrayList<>());
-        list.addAll(entry.getValue());
-
-        if (!deviceIdMap.containsKey(entry.getKey())) {
-          deviceIdMap.put(entry.getKey(), list);
-        }
-      }
-      metadatas[i] = null;
-    }
-
-    return new Metadata(deviceIdMap);
-  }
-
-  @Override
-  public String toString() {
-    return deviceIdMap.toString();
-  }
-
-  @Override
-  public boolean equals(Object obj) {
-    if(this == obj){
-      return true;
-    }
-    if(obj == null){
-      return false;
-    }
-    if(this.getClass() != obj.getClass()){
-      return false;
-    }
-
-    Metadata metadata = (Metadata) obj;
-    return deviceIdMapEquals(deviceIdMap, metadata.deviceIdMap);
-  }
-
-  @Override
-  public int hashCode() {
-    return Objects.hash(deviceIdMap);
-  }
-
-  /**
-   * only used to check if deviceIdMap is equal to another deviceIdMap
-   */
-  private boolean deviceIdMapEquals(Map<String, List<String>> map1, Map<String, List<String>> map2) {
-    if (!map1.keySet().equals(map2.keySet())) {
-      return false;
-    }
-
-    for (Entry<String, List<String>> entry : map1.entrySet()) {
-      List list1 = entry.getValue();
-      List list2 = map2.get(entry.getKey());
-
-      if (!listEquals(list1, list2)) {
-        return false;
-      }
-    }
-    return true;
-  }
-
-  private boolean listEquals(List list1, List list2) {
-    Set set1 = new HashSet();
-    set1.addAll(list1);
-    Set set2 = new HashSet();
-    set2.addAll(list2);
-
-    return set1.equals(set2);
-  }
-}
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/MetadataConstant.java b/server/src/main/java/org/apache/iotdb/db/metadata/MetadataConstant.java
deleted file mode 100644
index 13bb74f..0000000
--- a/server/src/main/java/org/apache/iotdb/db/metadata/MetadataConstant.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.iotdb.db.metadata;
-
-public class MetadataConstant {
-  private MetadataConstant(){
-    //allowed to do nothing
-  }
-  public static final String ROOT = "root";
-  public static final String METADATA_LOG = "mlog.txt";
-}
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/MetadataOperationType.java b/server/src/main/java/org/apache/iotdb/db/metadata/MetadataOperationType.java
index dce3523..4b8574e 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/MetadataOperationType.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/MetadataOperationType.java
@@ -24,16 +24,16 @@ public class MetadataOperationType {
     //allowed to do nothing
   }
 
-  public static final String ADD_PATH_TO_MTREE = "0";
-  public static final String DELETE_PATH_FROM_MTREE = "1";
-  public static final String SET_STORAGE_GROUP_TO_MTREE = "2";
-  public static final String ADD_A_PTREE = "3";
-  public static final String ADD_A_PATH_TO_PTREE = "4";
-  public static final String DELETE_PATH_FROM_PTREE = "5";
-  public static final String LINK_MNODE_TO_PTREE = "6";
-  public static final String UNLINK_MNODE_FROM_PTREE = "7";
+  static final String ADD_PATH_TO_MTREE = "0";
+  static final String DELETE_PATH_FROM_MTREE = "1";
+  static final String SET_STORAGE_GROUP_TO_MTREE = "2";
+  static final String ADD_A_PTREE = "3";
+  static final String ADD_A_PATH_TO_PTREE = "4";
+  static final String DELETE_PATH_FROM_PTREE = "5";
+  static final String LINK_MNODE_TO_PTREE = "6";
+  static final String UNLINK_MNODE_FROM_PTREE = "7";
   public static final String ADD_INDEX_TO_PATH = "8";
   public static final String DELETE_INDEX_FROM_PATH = "9";
-  public static final String SET_TTL = "10";
-  public static final String DELETE_STORAGE_GROUP_FROM_MTREE = "11";
+  static final String SET_TTL = "10";
+  static final String DELETE_STORAGE_GROUP_FROM_MTREE = "11";
 }
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/PTree.java b/server/src/main/java/org/apache/iotdb/db/metadata/PTree.java
index 1faf3c5..32faa5a 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/PTree.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/PTree.java
@@ -18,6 +18,8 @@
  */
 package org.apache.iotdb.db.metadata;
 
+import static org.apache.iotdb.tsfile.common.constant.TsFileConstant.PATH_SEPARATOR;
+
 import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -45,17 +47,12 @@ public class PTree implements Serializable {
   /**
    * Add a seriesPath to current PTree
    *
-   * @return The count of new added {@code PNode} TODO: unused
    * @throws PathErrorException
    */
-  int addPath(String path) throws PathErrorException {
-    int addCount = 0;
-    if (getRoot() == null) {
-      throw new PathErrorException("Root Node is null, Please initialize root first");
-    }
-    String[] nodes = MetaUtils.getNodeNames(path, "\\.");
+  void addPath(String[] nodes) throws PathErrorException {
     if (nodes.length <= 1 || !nodes[0].equals(getRoot().getName())) {
-      throw new PathErrorException("Input seriesPath not exist. Path: " + path);
+      throw new PathErrorException("Input seriesPath not exist. Path: "
+          + String.join(PATH_SEPARATOR, nodes));
     }
 
     PNode cur = getRoot();
@@ -63,18 +60,16 @@ public class PTree implements Serializable {
     for (i = 1; i < nodes.length - 1; i++) {
       if (!cur.hasChild(nodes[i])) {
         cur.addChild(nodes[i], new PNode(nodes[i], cur, false));
-        addCount++;
       }
       cur = cur.getChild(nodes[i]);
     }
     if (cur.hasChild(nodes[i])) {
-      throw new PathErrorException("Path already exists. Path: " + path);
+      throw new PathErrorException("Path already exists. Path: "
+          + String.join(PATH_SEPARATOR, nodes));
     } else {
       PNode node = new PNode(nodes[i], cur, true);
       cur.addChild(node.getName(), node);
-      addCount++;
     }
-    return addCount;
   }
 
   /**
@@ -83,7 +78,7 @@ public class PTree implements Serializable {
    * @throws PathErrorException
    */
   void deletePath(String path) throws PathErrorException {
-    String[] nodes = MetaUtils.getNodeNames(path, "\\.");
+    String[] nodes = MetaUtils.getNodeNames(path);
     if (nodes.length == 0 || !nodes[0].equals(getRoot().getName())) {
       throw new PathErrorException("Path not correct. Path:" + path);
     }
@@ -103,10 +98,9 @@ public class PTree implements Serializable {
    *
    * @throws PathErrorException
    */
-  void linkMNode(String pTreePath, String mTreePath) throws PathErrorException {
+  void linkMNode(String[] pTreeNodes, String mTreePath) throws PathErrorException {
     List<String> paths = mTree.getAllPathInList(mTreePath);
-    String[] nodes = MetaUtils.getNodeNames(pTreePath, "\\.");
-    PNode leaf = getLeaf(getRoot(), nodes, 0);
+    PNode leaf = getLeaf(getRoot(), pTreeNodes, 0);
     for (String p : paths) {
       leaf.linkMPath(p);
     }
@@ -117,10 +111,9 @@ public class PTree implements Serializable {
    *
    * @throws PathErrorException
    */
-  void unlinkMNode(String pTreePath, String mTreePath) throws PathErrorException {
+  void unlinkMNode(String[] pTreeNodes, String mTreePath) throws PathErrorException {
     List<String> paths = mTree.getAllPathInList(mTreePath);
-    String[] nodes = MetaUtils.getNodeNames(pTreePath, "\\.");
-    PNode leaf = getLeaf(getRoot(), nodes, 0);
+    PNode leaf = getLeaf(getRoot(), pTreeNodes, 0);
     for (String p : paths) {
       leaf.unlinkMPath(p);
     }
@@ -153,7 +146,7 @@ public class PTree implements Serializable {
    */
   HashMap<String, List<String>> getAllLinkedPath(String path)
       throws PathErrorException {
-    String[] nodes = MetaUtils.getNodeNames(path, "\\.");
+    String[] nodes = MetaUtils.getNodeNames(path);
     PNode leaf = getLeaf(getRoot(), nodes, 0);
     HashMap<String, List<String>> res = new HashMap<>();
 
diff --git a/server/src/main/java/org/apache/iotdb/db/service/TSServiceImpl.java b/server/src/main/java/org/apache/iotdb/db/service/TSServiceImpl.java
index 11f1d0b..07c7fd9 100644
--- a/server/src/main/java/org/apache/iotdb/db/service/TSServiceImpl.java
+++ b/server/src/main/java/org/apache/iotdb/db/service/TSServiceImpl.java
@@ -306,24 +306,19 @@ public class TSServiceImpl implements TSIService.Iface, ServerContext {
     try {
       switch (req.getType()) {
         case "SHOW_TIMESERIES":
-          String path = req.getColumnPath();
-          List<List<String>> timeseriesList = getTimeSeriesForPath(path);
-          resp.setTimeseriesList(timeseriesList);
+          resp.setTimeseriesInfoList(getTimeSeriesInfo(req.getColumnPath()));
           status = new TSStatus(getStatus(TSStatusCode.SUCCESS_STATUS));
           break;
         case "SHOW_STORAGE_GROUP":
-          Set<String> storageGroups = new HashSet<>(getAllStorageGroups());
-          resp.setStorageGroups(storageGroups);
+          resp.setStorageGroups(getAllStorageGroups());
           status = new TSStatus(getStatus(TSStatusCode.SUCCESS_STATUS));
           break;
         case "METADATA_IN_JSON":
-          String metadataInJson = getMetadataInString();
-          resp.setMetadataInJson(metadataInJson);
+          resp.setMetadataInJson(getMetadataInString());
           status = new TSStatus(getStatus(TSStatusCode.SUCCESS_STATUS));
           break;
         case "SHOW_DEVICES":
-          Set<String> devices = getAllDevices();
-          resp.setDevices(devices);
+          resp.setDevices(getAllDevices());
           status = new TSStatus(getStatus(TSStatusCode.SUCCESS_STATUS));
           break;
         case "COLUMN":
@@ -380,13 +375,13 @@ public class TSServiceImpl implements TSIService.Iface, ServerContext {
     return MManager.getInstance().getAllStorageGroupNames();
   }
 
-  private Set<String> getAllDevices() throws SQLException {
+  private List<String> getAllDevices() {
     return MManager.getInstance().getAllDevices();
   }
 
-  private List<List<String>> getTimeSeriesForPath(String path)
+  private List<List<String>> getTimeSeriesInfo(String path)
       throws PathErrorException {
-    return MManager.getInstance().getShowTimeseriesPath(path);
+    return MManager.getInstance().getTimeseriesInfo(path);
   }
 
   private String getMetadataInString() {
diff --git a/server/src/main/java/org/apache/iotdb/db/sync/receiver/transfer/SyncServiceImpl.java b/server/src/main/java/org/apache/iotdb/db/sync/receiver/transfer/SyncServiceImpl.java
index 9401c1a..e1a8dc5 100644
--- a/server/src/main/java/org/apache/iotdb/db/sync/receiver/transfer/SyncServiceImpl.java
+++ b/server/src/main/java/org/apache/iotdb/db/sync/receiver/transfer/SyncServiceImpl.java
@@ -37,7 +37,6 @@ import org.apache.iotdb.db.exception.MetadataErrorException;
 import org.apache.iotdb.db.exception.PathErrorException;
 import org.apache.iotdb.db.exception.SyncDeviceOwnerConflictException;
 import org.apache.iotdb.db.metadata.MManager;
-import org.apache.iotdb.db.metadata.MetadataConstant;
 import org.apache.iotdb.db.sync.conf.SyncConstant;
 import org.apache.iotdb.db.sync.receiver.load.FileLoader;
 import org.apache.iotdb.db.sync.receiver.load.FileLoaderManager;
@@ -222,7 +221,7 @@ public class SyncServiceImpl implements SyncService.Iface {
             .format("MD5 of the sender is differ from MD5 of the receiver of the file %s.",
                 currentFile.get().getAbsolutePath()));
       } else {
-        if (currentFile.get().getName().endsWith(MetadataConstant.METADATA_LOG)) {
+        if (currentFile.get().getName().endsWith(MManager.METADATA_LOG)) {
           loadMetadata();
         } else {
           if (!currentFile.get().getName().endsWith(TsFileResource.RESOURCE_SUFFIX)) {
diff --git a/server/src/main/java/org/apache/iotdb/db/sync/sender/transfer/DataTransferManager.java b/server/src/main/java/org/apache/iotdb/db/sync/sender/transfer/DataTransferManager.java
index 2354305..34963ce 100644
--- a/server/src/main/java/org/apache/iotdb/db/sync/sender/transfer/DataTransferManager.java
+++ b/server/src/main/java/org/apache/iotdb/db/sync/sender/transfer/DataTransferManager.java
@@ -47,7 +47,7 @@ import org.apache.iotdb.db.conf.IoTDBDescriptor;
 import org.apache.iotdb.db.engine.storagegroup.TsFileResource;
 import org.apache.iotdb.db.exception.SyncConnectionException;
 import org.apache.iotdb.db.exception.SyncDeviceOwnerConflictException;
-import org.apache.iotdb.db.metadata.MetadataConstant;
+import org.apache.iotdb.db.metadata.MManager;
 import org.apache.iotdb.db.sync.conf.SyncConstant;
 import org.apache.iotdb.db.sync.conf.SyncSenderConfig;
 import org.apache.iotdb.db.sync.conf.SyncSenderDescriptor;
@@ -330,7 +330,7 @@ public class DataTransferManager implements IDataTransferManager {
       return;
     }
     int retryCount = 0;
-    serviceClient.initSyncData(MetadataConstant.METADATA_LOG);
+    serviceClient.initSyncData(MManager.METADATA_LOG);
     while (true) {
       if (retryCount > config.getMaxNumOfSyncFileRetry()) {
         throw new SyncConnectionException(String
@@ -645,7 +645,7 @@ public class DataTransferManager implements IDataTransferManager {
 
   private File getSchemaLogFile() {
     return new File(IoTDBDescriptor.getInstance().getConfig().getSchemaDir(),
-        MetadataConstant.METADATA_LOG);
+        MManager.METADATA_LOG);
   }
 
   private static class InstanceHolder {
diff --git a/server/src/main/java/org/apache/iotdb/db/utils/SchemaUtils.java b/server/src/main/java/org/apache/iotdb/db/utils/SchemaUtils.java
index 6ce9d4c..3444a4f 100644
--- a/server/src/main/java/org/apache/iotdb/db/utils/SchemaUtils.java
+++ b/server/src/main/java/org/apache/iotdb/db/utils/SchemaUtils.java
@@ -18,7 +18,12 @@
  */
 package org.apache.iotdb.db.utils;
 
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.serializer.SerializerFeature;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 import org.apache.iotdb.db.metadata.MManager;
 import org.apache.iotdb.tsfile.exception.write.WriteProcessException;
 import org.apache.iotdb.tsfile.write.schema.Schema;
@@ -47,11 +52,58 @@ public class SchemaUtils {
    * @param schemaList the schema of the columns in this file.
    * @return a Schema contains the provided schemas.
    */
-  public static Schema getSchemaFromColumnSchema(List<MeasurementSchema> schemaList) {
+  private static Schema getSchemaFromColumnSchema(List<MeasurementSchema> schemaList) {
     Schema schema = new Schema();
     for (MeasurementSchema measurementSchema : schemaList) {
       schema.registerMeasurement(measurementSchema);
     }
     return schema;
   }
+
+  /**
+   * combine multiple metadata in string format
+   */
+  public static String combineMetadataInStrings(String[] metadataStrs) {
+    JSONObject[] jsonObjects = new JSONObject[metadataStrs.length];
+    for (int i = 0; i < jsonObjects.length; i++) {
+      jsonObjects[i] = JSONObject.parseObject(metadataStrs[i]);
+    }
+
+    JSONObject root = jsonObjects[0];
+    for (int i = 1; i < jsonObjects.length; i++) {
+      root = combineJSONObjects(root, jsonObjects[i]);
+    }
+    return jsonToString(root);
+  }
+
+  public static String jsonToString(JSONObject jsonObject) {
+    return JSON.toJSONString(jsonObject, SerializerFeature.PrettyFormat);
+  }
+
+  private static JSONObject combineJSONObjects(JSONObject a, JSONObject b) {
+    JSONObject res = new JSONObject();
+
+    Set<String> retainSet = new HashSet<>(a.keySet());
+    retainSet.retainAll(b.keySet());
+    Set<String> aCha = new HashSet<>(a.keySet());
+    Set<String> bCha = new HashSet<>(b.keySet());
+    aCha.removeAll(retainSet);
+    bCha.removeAll(retainSet);
+    for (String key : aCha) {
+      res.put(key, a.getJSONObject(key));
+    }
+    for (String key : bCha) {
+      res.put(key, b.get(key));
+    }
+    for (String key : retainSet) {
+      Object v1 = a.get(key);
+      Object v2 = b.get(key);
+      if (v1 instanceof JSONObject && v2 instanceof JSONObject) {
+        res.put(key, combineJSONObjects((JSONObject) v1, (JSONObject) v2));
+      } else {
+        res.put(key, v1);
+      }
+    }
+    return res;
+  }
 }
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 4bcbcc0..b50061b 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
@@ -39,7 +39,6 @@ import org.apache.iotdb.db.exception.PathErrorException;
 import org.apache.iotdb.db.exception.ProcessorException;
 import org.apache.iotdb.db.exception.StartupException;
 import org.apache.iotdb.db.exception.StorageEngineException;
-import org.apache.iotdb.db.exception.StorageGroupException;
 import org.apache.iotdb.db.exception.qp.QueryProcessorException;
 import org.apache.iotdb.db.metadata.MManager;
 import org.apache.iotdb.db.metadata.MNode;
@@ -98,7 +97,7 @@ public class TTLTest {
   }
 
   @Test
-  public void testSetMetaTTL() throws IOException, PathErrorException, StorageGroupException {
+  public void testSetMetaTTL() throws IOException, PathErrorException {
     // exception is expected when setting ttl to a non-exist storage group
     boolean caught = false;
     try {
@@ -110,11 +109,11 @@ public class TTLTest {
 
     // normally set ttl
     MManager.getInstance().setTTL(sg1, ttl);
-    MNode mNode = MManager.getInstance().getNodeByPathWithCheck(sg1);
+    MNode mNode = MManager.getInstance().getNodeInStorageGroup(sg1);
     assertEquals(ttl, mNode.getDataTTL());
 
     // default ttl
-    mNode = MManager.getInstance().getNodeByPathWithCheck(sg2);
+    mNode = MManager.getInstance().getNodeInStorageGroup(sg2);
     assertEquals(Long.MAX_VALUE, mNode.getDataTTL());
   }
 
@@ -282,12 +281,12 @@ public class TTLTest {
     QueryProcessExecutor executor = new QueryProcessExecutor();
     QueryDataSet queryDataSet = executor.processQuery(plan, EnvironmentUtils.TEST_QUERY_CONTEXT);
     RowRecord rowRecord = queryDataSet.next();
-    assertEquals(sg2, rowRecord.getFields().get(0).getStringValue());
-    assertEquals("null", rowRecord.getFields().get(1).getStringValue());
-
-    rowRecord = queryDataSet.next();
     assertEquals(sg1, rowRecord.getFields().get(0).getStringValue());
     assertEquals(ttl, rowRecord.getFields().get(1).getLongV());
+
+    rowRecord = queryDataSet.next();
+    assertEquals(sg2, rowRecord.getFields().get(0).getStringValue());
+    assertEquals("null", rowRecord.getFields().get(1).getStringValue());
   }
 
   @Test
diff --git a/server/src/test/java/org/apache/iotdb/db/integration/IoTDBQuotedPathIT.java b/server/src/test/java/org/apache/iotdb/db/integration/IoTDBQuotedPathIT.java
index a2dd289..ba6a8dc 100644
--- a/server/src/test/java/org/apache/iotdb/db/integration/IoTDBQuotedPathIT.java
+++ b/server/src/test/java/org/apache/iotdb/db/integration/IoTDBQuotedPathIT.java
@@ -52,64 +52,64 @@ public class IoTDBQuotedPathIT {
 
   @Test
   public void test() throws SQLException {
-    Connection connection = DriverManager
-            .getConnection(Config.IOTDB_URL_PREFIX + "127.0.0.1:6667/", "root",
-                    "root");
-    Statement statement = connection.createStatement();
+    try (Connection connection = DriverManager
+        .getConnection(Config.IOTDB_URL_PREFIX + "127.0.0.1:6667/", "root",
+            "root");
+        Statement statement = connection.createStatement()) {
+      String[] exp = new String[]{
+          "1509465600000,true",
+          "1509465600001,true",
+          "1509465600002,false",
+          "1509465600003,false"
+      };
+      statement.execute("SET STORAGE GROUP TO root.ln.wf01.wt01");
+      statement.execute("CREATE TIMESERIES root.ln.wf01.wt01.\"status.2.3\" WITH DATATYPE=BOOLEAN, ENCODING=PLAIN");
+      statement.execute("INSERT INTO root.ln.wf01.wt01(timestamp,\"status.2.3\") values(1509465600000,true)");
+      statement.execute("INSERT INTO root.ln.wf01.wt01(timestamp,\'status.2.3\') values(1509465600001,true)");
+      statement.execute("INSERT INTO root.ln.wf01.wt01(timestamp,\"status.2.3\") values(1509465600002,false)");
+      statement.execute("INSERT INTO root.ln.wf01.wt01(timestamp,\'status.2.3\') values(1509465600003,false)");
+      statement.execute("SET STORAGE GROUP TO root.ln.wf01.wt02");
+      statement.execute("CREATE TIMESERIES root.ln.wf01.wt02.\"abd\" WITH DATATYPE=BOOLEAN, ENCODING=PLAIN");
+      statement.execute("CREATE TIMESERIES root.ln.wf01.wt02.\"asf.asd.sdf\" WITH DATATYPE=BOOLEAN, ENCODING=PLAIN");
+      statement.execute("CREATE TIMESERIES root.ln.wf01.wt02.\"asd12\" WITH DATATYPE=BOOLEAN, ENCODING=PLAIN");
+      boolean hasResultSet = statement.execute("SELECT * FROM root.ln.wf01.wt01");
 
-    String[] exp = new String[]{
-            "1509465600000,true",
-            "1509465600001,true",
-            "1509465600002,false",
-            "1509465600003,false"
-    };
-    statement.execute("SET STORAGE GROUP TO root.ln.wf01.wt01");
-    statement.execute("CREATE TIMESERIES root.ln.wf01.wt01.\"status.2.3\" WITH DATATYPE=BOOLEAN, ENCODING=PLAIN");
-    statement.execute("INSERT INTO root.ln.wf01.wt01(timestamp,\"status.2.3\") values(1509465600000,true)");
-    statement.execute("INSERT INTO root.ln.wf01.wt01(timestamp,\'status.2.3\') values(1509465600001,true)");
-    statement.execute("INSERT INTO root.ln.wf01.wt01(timestamp,\"status.2.3\") values(1509465600002,false)");
-    statement.execute("INSERT INTO root.ln.wf01.wt01(timestamp,\'status.2.3\') values(1509465600003,false)");
-    statement.execute("SET STORAGE GROUP TO root.ln.wf01.wt02");
-    statement.execute("CREATE TIMESERIES root.ln.wf01.wt02.\"abd\" WITH DATATYPE=BOOLEAN, ENCODING=PLAIN");
-    statement.execute("CREATE TIMESERIES root.ln.wf01.wt02.\"asf.asd.sdf\" WITH DATATYPE=BOOLEAN, ENCODING=PLAIN");
-    statement.execute("CREATE TIMESERIES root.ln.wf01.wt02.\"asd12\" WITH DATATYPE=BOOLEAN, ENCODING=PLAIN");
-    boolean hasResultSet = statement.execute("SELECT * FROM root.ln.wf01.wt01");
+      assertTrue(hasResultSet);
+      int cnt;
+      ArrayList<String> ans = new ArrayList<>();
+      ResultSet resultSet = statement.getResultSet();
+      cnt = 0;
+      while (resultSet.next()) {
+        String result = resultSet.getString(TIMESTAMP_STR) + "," + resultSet.getString(2);
+        ans.add(result);
+        cnt++;
+      }
 
-    assertTrue(hasResultSet);
-    int cnt;
-    ArrayList<String> ans = new ArrayList<>();
-    ResultSet resultSet = statement.getResultSet();
-    cnt = 0;
-    while (resultSet.next()) {
-      String result = resultSet.getString(TIMESTAMP_STR) + "," + resultSet.getString(2);
-      ans.add(result);
-      cnt++;
-    }
+      for (int i = 0; i < ans.size(); i++) {
+        assertEquals(exp[i], ans.get(i));
+      }
 
-    for (int i = 0; i < ans.size(); i++) {
-      assertEquals(exp[i], ans.get(i));
-    }
+      hasResultSet = statement.execute("SELECT  * FROM root.ln.wf01.wt01 WHERE \'status.2.3\' = false");
+      assertTrue(hasResultSet);
+      exp = new String[]{
+          "1509465600002,false",
+          "1509465600003,false"
+      };
+      ans = new ArrayList<>();
+      resultSet = statement.getResultSet();
+      cnt = 0;
+      while (resultSet.next()) {
+        String result = resultSet.getString(TIMESTAMP_STR) + "," + resultSet.getString(2);
+        ans.add(result);
+        cnt++;
+      }
 
-    hasResultSet = statement.execute("SELECT  * FROM root.ln.wf01.wt01 WHERE \'status.2.3\' = false");
-    assertTrue(hasResultSet);
-    exp = new String[]{
-            "1509465600002,false",
-            "1509465600003,false"
-    };
-    ans = new ArrayList<>();
-    resultSet = statement.getResultSet();
-    cnt = 0;
-    while (resultSet.next()) {
-      String result = resultSet.getString(TIMESTAMP_STR) + "," + resultSet.getString(2);
-      ans.add(result);
-      cnt++;
-    }
+      for (int i = 0; i < exp.length; i++) {
+        assertEquals(exp[i], ans.get(i));
+      }
+      statement.execute("DELETE FROM root.ln.wf01.wt01.\"status.2.3\" WHERE time < 1509465600001");
+      statement.execute("DELETE TIMESERIES root.ln.wf01.wt01.\"status.2.3\"");
 
-    for (int i = 0; i < exp.length; i++) {
-      assertEquals(exp[i], ans.get(i));
     }
-    statement.execute("DELETE FROM root.ln.wf01.wt01.\"status.2.3\" WHERE time < 1509465600001");
-    statement.execute("DELETE TIMESERIES root.ln.wf01.wt01.\"status.2.3\"");
-
   }
 }
diff --git a/server/src/test/java/org/apache/iotdb/db/integration/IoTDBTtlIT.java b/server/src/test/java/org/apache/iotdb/db/integration/IoTDBTtlIT.java
index f7c0f2e..11b54c9 100644
--- a/server/src/test/java/org/apache/iotdb/db/integration/IoTDBTtlIT.java
+++ b/server/src/test/java/org/apache/iotdb/db/integration/IoTDBTtlIT.java
@@ -22,6 +22,7 @@ package org.apache.iotdb.db.integration;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import java.sql.DriverManager;
 import java.sql.ResultSet;
@@ -62,7 +63,7 @@ public class IoTDBTtlIT {
         .getConnection(Config.IOTDB_URL_PREFIX + "127.0.0.1:6667/", "root", "root");
         Statement statement = connection.createStatement()) {
       try {
-        statement.execute("SET TTL TO root.TTL_SG1 1000");
+        statement.execute("SET TTL TO root.TTL_SG1 1200");
       } catch (SQLException e) {
         assertEquals(TSStatusCode.EXECUTE_STATEMENT_ERROR.getStatusCode(), e.getErrorCode());
       }
@@ -76,6 +77,7 @@ public class IoTDBTtlIT {
       statement.execute("CREATE TIMESERIES root.TTL_SG1.s1 WITH DATATYPE=INT64,ENCODING=PLAIN");
       try {
         statement.execute("SET TTL TO root.TTL_SG1.s1 1000");
+        fail("Exception uncaught");
       } catch (SQLException e) {
         assertEquals(TSStatusCode.NOT_A_STORAGE_GROUP_ERROR.getStatusCode(), e.getErrorCode());
       }
@@ -150,22 +152,22 @@ public class IoTDBTtlIT {
       statement.execute("SET STORAGE GROUP TO root.group2");
 
       String result = doQuery(statement, "SHOW ALL TTL", 2);
-      assertEquals("root.group2,null\n"
-          + "root.group1,null\n", result);
+      assertEquals("root.group1,null\n"
+          + "root.group2,null\n", result);
       result = doQuery(statement, "SHOW TTL ON root.group1", 2);
       assertEquals("root.group1,null\n", result);
 
       statement.execute("SET TTL TO root.group1 10000");
       result = doQuery(statement, "SHOW ALL TTL", 2);
-      assertEquals("root.group2,null\n"
-          + "root.group1,10000\n", result);
+      assertEquals("root.group1,10000\n"
+          + "root.group2,null\n", result);
       result = doQuery(statement, "SHOW TTL ON root.group1", 2);
       assertEquals("root.group1,10000\n", result);
 
       statement.execute("UNSET TTL TO root.group1");
       result = doQuery(statement, "SHOW ALL TTL", 2);
-      assertEquals("root.group2,null\n"
-          + "root.group1,null\n", result);
+      assertEquals("root.group1,null\n"
+          + "root.group2,null\n", result);
       result = doQuery(statement, "SHOW TTL ON root.group1", 2);
       assertEquals("root.group1,null\n", result);
     }
@@ -196,8 +198,8 @@ public class IoTDBTtlIT {
       statement.execute("SET STORAGE GROUP TO root.group2");
 
       String result = doQuery(statement, "SHOW ALL TTL", 2);
-      assertEquals("root.group2,10000\n"
-          + "root.group1,10000\n", result);
+      assertEquals("root.group1,10000\n" + "root.group2,10000\n"
+          , result);
     } finally {
       IoTDBDescriptor.getInstance().getConfig().setDefaultTTL(Long.MAX_VALUE);
     }
diff --git a/server/src/test/java/org/apache/iotdb/db/metadata/MGraphTest.java b/server/src/test/java/org/apache/iotdb/db/metadata/MGraphTest.java
index cc830ad..fc4bb0b 100644
--- a/server/src/test/java/org/apache/iotdb/db/metadata/MGraphTest.java
+++ b/server/src/test/java/org/apache/iotdb/db/metadata/MGraphTest.java
@@ -20,9 +20,14 @@ package org.apache.iotdb.db.metadata;
 
 import static org.junit.Assert.*;
 
+import java.util.Collections;
 import org.apache.iotdb.db.exception.PathErrorException;
 import org.apache.iotdb.db.exception.StorageGroupException;
 import org.apache.iotdb.db.utils.EnvironmentUtils;
+import org.apache.iotdb.db.utils.SchemaUtils;
+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.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -47,32 +52,42 @@ public class MGraphTest {
     MGraph root3 = new MGraph("root");
     try {
       root.setStorageGroup("root.a.d0");
-      root.addPathToMTree("root.a.d0.s0", "INT32", "RLE");
-      root.addPathToMTree("root.a.d0.s1", "INT32", "RLE");
+      root.addPathToMTree("root.a.d0.s0", TSDataType.INT32, TSEncoding.RLE,
+          CompressionType.UNCOMPRESSED,Collections.emptyMap());
+      root.addPathToMTree("root.a.d0.s1", TSDataType.INT32, TSEncoding.RLE,
+          CompressionType.UNCOMPRESSED,Collections.emptyMap());
 
       root.setStorageGroup("root.a.d1");
-      root.addPathToMTree("root.a.d1.s0", "INT32", "RLE");
-      root.addPathToMTree("root.a.d1.s1", "INT32", "RLE");
+      root.addPathToMTree("root.a.d1.s0", TSDataType.INT32, TSEncoding.RLE,
+          CompressionType.UNCOMPRESSED,Collections.emptyMap());
+      root.addPathToMTree("root.a.d1.s1", TSDataType.INT32, TSEncoding.RLE,
+          CompressionType.UNCOMPRESSED,Collections.emptyMap());
 
       root.setStorageGroup("root.a.b.d0");
-      root.addPathToMTree("root.a.b.d0.s0", "INT32", "RLE");
+      root.addPathToMTree("root.a.b.d0.s0", TSDataType.INT32, TSEncoding.RLE,
+          CompressionType.UNCOMPRESSED,Collections.emptyMap());
 
       root1.setStorageGroup("root.a.d0");
-      root1.addPathToMTree("root.a.d0.s0", "INT32", "RLE");
-      root1.addPathToMTree("root.a.d0.s1", "INT32", "RLE");
+      root1.addPathToMTree("root.a.d0.s0", TSDataType.INT32, TSEncoding.RLE,
+          CompressionType.UNCOMPRESSED,Collections.emptyMap());
+      root1.addPathToMTree("root.a.d0.s1", TSDataType.INT32, TSEncoding.RLE,
+          CompressionType.UNCOMPRESSED,Collections.emptyMap());
 
       root2.setStorageGroup("root.a.d1");
-      root2.addPathToMTree("root.a.d1.s0", "INT32", "RLE");
-      root2.addPathToMTree("root.a.d1.s1", "INT32", "RLE");
+      root2.addPathToMTree("root.a.d1.s0", TSDataType.INT32, TSEncoding.RLE,
+          CompressionType.UNCOMPRESSED,Collections.emptyMap());
+      root2.addPathToMTree("root.a.d1.s1", TSDataType.INT32, TSEncoding.RLE,
+          CompressionType.UNCOMPRESSED,Collections.emptyMap());
 
       root3.setStorageGroup("root.a.b.d0");
-      root3.addPathToMTree("root.a.b.d0.s0", "INT32", "RLE");
+      root3.addPathToMTree("root.a.b.d0.s0", TSDataType.INT32, TSEncoding.RLE,
+          CompressionType.UNCOMPRESSED,Collections.emptyMap());
 
       String[] metadatas = new String[3];
       metadatas[0] = root1.toString();
       metadatas[1] = root2.toString();
       metadatas[2] = root3.toString();
-      assertEquals(MGraph.combineMetadataInStrings(metadatas), root.toString());
+      assertEquals(SchemaUtils.combineMetadataInStrings(metadatas), root.toString());
     } catch (PathErrorException | StorageGroupException e) {
       e.printStackTrace();
       fail(e.getMessage());
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 e34674d..28d629d 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
@@ -114,30 +114,16 @@ public class MManagerAdvancedTest {
     Assert.assertNull(
         mmanager.checkPathStorageGroupAndGetDataType("root.vehicle.d0.s100").getDataType());
 
-    MNode node = mmanager.getNodeByPath("root.vehicle.d0");
+    MNode node = mmanager.getNodeInStorageGroup("root.vehicle.d0");
     Assert.assertEquals(TSDataType.INT32, node.getChild("s0").getSchema().getType());
 
     try {
-      mmanager.getNodeByPath("root.vehicle.d100");
+      mmanager.getNodeInStorageGroup("root.vehicle.d100");
       fail();
     } catch (PathErrorException e) {
       // ignore
     }
   }
 
-  @Test
-  public void testGetNextLevelPath()
-      throws PathErrorException, IOException, StorageGroupException {
-    mmanager.addPathToMTree("root.vehicle.d2.s0", "DOUBLE", "RLE");
-    mmanager.addPathToMTree("root.vehicle.d2.s1", "BOOLEAN", "PLAIN");
-    mmanager.addPathToMTree("root.vehicle.d2.s2.g0", "TEXT", "PLAIN");
-    mmanager.addPathToMTree("root.vehicle.d2.s3", "TEXT", "PLAIN");
-
-    List<String> paths = mmanager.getLeafNodePathInNextLevel("root.vehicle.d2");
-    Assert.assertEquals(3, paths.size());
-
-    paths = mmanager.getLeafNodePathInNextLevel("root.vehicle.d2.s2");
-    Assert.assertEquals(1, paths.size());
-  }
 
 }
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 9e4eead..571b89c 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
@@ -146,39 +146,12 @@ public class MManagerImproveTest {
   }
 
   private void doPathLoopOnceTest(String deviceId, List<String> measurementList)
-      throws PathErrorException, StorageGroupException {
+      throws StorageGroupException {
     for (String measurement : measurementList) {
       String path = deviceId + "." + measurement;
       List<Path> paths = new ArrayList<>();
       paths.add(new Path(path));
       assertTrue(mManager.checkFileLevel(paths));
-      TSDataType dataType = mManager.getSeriesTypeWithCheck(path);
-      assertEquals(TSDataType.TEXT, dataType);
-    }
-  }
-
-  private void doDealdeviceIdOnceTest(String deviceId, List<String> measurementList)
-      throws PathErrorException, StorageGroupException {
-    boolean isFileLevelChecked;
-    List<Path> tempList = new ArrayList<>();
-    tempList.add(new Path(deviceId));
-    try {
-      isFileLevelChecked = mManager.checkFileLevel(tempList);
-    } catch (StorageGroupException e) {
-      isFileLevelChecked = false;
-    }
-    MNode node = mManager.getNodeByPath(deviceId);
-
-    for (String measurement : measurementList) {
-      assertTrue(mManager.pathExist(node, measurement));
-      List<Path> paths = new ArrayList<>();
-      paths.add(new Path(measurement));
-      if (!isFileLevelChecked) {
-        isFileLevelChecked = mManager.checkFileLevel(node, paths);
-      }
-      assertTrue(isFileLevelChecked);
-      TSDataType dataType = mManager.getSeriesType(node, measurement);
-      assertEquals(TSDataType.TEXT, dataType);
     }
   }
 
@@ -201,15 +174,13 @@ public class MManagerImproveTest {
     } catch (StorageGroupException e) {
       isFileLevelChecked = false;
     }
-    MNode node = mManager.getNodeByPathWithCheck(deviceId);
+    MNode node = mManager.getNodeInStorageGroup(deviceId);
 
     for (String measurement : measurementList) {
       if (!isFileLevelChecked) {
         isFileLevelChecked = mManager.checkFileLevelWithCheck(node, measurement);
       }
       assertTrue(isFileLevelChecked);
-      TSDataType dataType = mManager.getSeriesTypeWithCheck(node, measurement);
-      assertEquals(TSDataType.TEXT, dataType);
     }
   }
 
@@ -255,13 +226,6 @@ public class MManagerImproveTest {
 
     startTime = System.currentTimeMillis();
     for (String deviceId : deviceIdList) {
-      doDealdeviceIdOnceTest(deviceId, measurementList);
-    }
-    endTime = System.currentTimeMillis();
-    logger.debug("deal deviceId once:\t" + (endTime - startTime));
-
-    startTime = System.currentTimeMillis();
-    for (String deviceId : deviceIdList) {
       doRemoveListTest(deviceId, measurementList);
     }
     endTime = System.currentTimeMillis();
diff --git a/server/src/test/java/org/apache/iotdb/db/metadata/MTreeTest.java b/server/src/test/java/org/apache/iotdb/db/metadata/MTreeTest.java
index 465da84..c51f099 100644
--- a/server/src/test/java/org/apache/iotdb/db/metadata/MTreeTest.java
+++ b/server/src/test/java/org/apache/iotdb/db/metadata/MTreeTest.java
@@ -30,6 +30,7 @@ import java.util.Map;
 import org.apache.iotdb.db.exception.PathErrorException;
 import org.apache.iotdb.db.exception.StorageGroupException;
 import org.apache.iotdb.db.utils.EnvironmentUtils;
+import org.apache.iotdb.db.utils.SchemaUtils;
 import org.apache.iotdb.tsfile.common.conf.TSFileDescriptor;
 import org.apache.iotdb.tsfile.file.metadata.enums.CompressionType;
 import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
@@ -55,14 +56,16 @@ public class MTreeTest {
   public void testAddLeftNodePath() {
     MTree root = new MTree("root");
     try {
-      root.addTimeseriesPath("root.laptop.d1.s1", TSDataType.INT32, TSEncoding.RLE, CompressionType.valueOf
+      root.addTimeseriesPath(MetaUtils.getNodeNames("root.laptop.d1.s1"),
+          TSDataType.INT32, TSEncoding.RLE, CompressionType.valueOf
           (TSFileDescriptor.getInstance().getConfig().getCompressor()), Collections.EMPTY_MAP);
     } catch (PathErrorException e) {
       e.printStackTrace();
       fail(e.getMessage());
     }
     try {
-      root.addTimeseriesPath("root.laptop.d1.s1.b", TSDataType.INT32, TSEncoding.RLE, CompressionType.valueOf
+      root.addTimeseriesPath(MetaUtils.getNodeNames("root.laptop.d1.s1.b"),
+          TSDataType.INT32, TSEncoding.RLE, CompressionType.valueOf
           (TSFileDescriptor.getInstance().getConfig().getCompressor()), Collections.EMPTY_MAP);
     } catch (PathErrorException e) {
       Assert.assertEquals(
@@ -78,7 +81,8 @@ public class MTreeTest {
     assertTrue(root.isPathExist(path1));
     assertFalse(root.isPathExist("root.laptop.d1"));
     try {
-      root.addTimeseriesPath("root.laptop.d1.s1", TSDataType.INT32, TSEncoding.RLE, CompressionType.valueOf
+      root.addTimeseriesPath(MetaUtils.getNodeNames("root.laptop.d1.s1"),
+          TSDataType.INT32, TSEncoding.RLE, CompressionType.valueOf
           (TSFileDescriptor.getInstance().getConfig().getCompressor()), Collections.EMPTY_MAP);
     } catch (PathErrorException e1) {
       fail(e1.getMessage());
@@ -87,7 +91,8 @@ public class MTreeTest {
     assertTrue(root.isPathExist("root.laptop"));
     assertFalse(root.isPathExist("root.laptop.d1.s2"));
     try {
-      root.addTimeseriesPath("aa.bb.cc", TSDataType.INT32, TSEncoding.RLE, CompressionType.valueOf
+      root.addTimeseriesPath(MetaUtils.getNodeNames("aa.bb.cc"),
+          TSDataType.INT32, TSEncoding.RLE, CompressionType.valueOf
           (TSFileDescriptor.getInstance().getConfig().getCompressor()), Collections.EMPTY_MAP);
     } catch (PathErrorException e) {
       Assert.assertEquals(String.format("Timeseries %s is not right.", "aa.bb.cc"), e.getMessage());
@@ -101,21 +106,26 @@ public class MTreeTest {
       assertFalse(root.isPathExist("root.a.d0"));
       assertFalse(root.checkFileNameByPath("root.a.d0"));
       root.setStorageGroup("root.a.d0");
-      root.addTimeseriesPath("root.a.d0.s0", TSDataType.INT32, TSEncoding.RLE, CompressionType.valueOf
+      root.addTimeseriesPath(MetaUtils.getNodeNames("root.a.d0.s0"),
+          TSDataType.INT32, TSEncoding.RLE, CompressionType.valueOf
           (TSFileDescriptor.getInstance().getConfig().getCompressor()), Collections.EMPTY_MAP);
-      root.addTimeseriesPath("root.a.d0.s1", TSDataType.INT32, TSEncoding.RLE, CompressionType.valueOf
+      root.addTimeseriesPath(MetaUtils.getNodeNames("root.a.d0.s1"),
+          TSDataType.INT32, TSEncoding.RLE, CompressionType.valueOf
           (TSFileDescriptor.getInstance().getConfig().getCompressor()), Collections.EMPTY_MAP);
 
       assertFalse(root.isPathExist("root.a.d1"));
       assertFalse(root.checkFileNameByPath("root.a.d1"));
       root.setStorageGroup("root.a.d1");
-      root.addTimeseriesPath("root.a.d1.s0", TSDataType.INT32, TSEncoding.RLE, CompressionType.valueOf
+      root.addTimeseriesPath(MetaUtils.getNodeNames("root.a.d1.s0"),
+          TSDataType.INT32, TSEncoding.RLE, CompressionType.valueOf
           (TSFileDescriptor.getInstance().getConfig().getCompressor()), Collections.EMPTY_MAP);
-      root.addTimeseriesPath("root.a.d1.s1", TSDataType.INT32, TSEncoding.RLE, CompressionType.valueOf
+      root.addTimeseriesPath(MetaUtils.getNodeNames("root.a.d1.s1"),
+          TSDataType.INT32, TSEncoding.RLE, CompressionType.valueOf
           (TSFileDescriptor.getInstance().getConfig().getCompressor()), Collections.EMPTY_MAP);
 
       root.setStorageGroup("root.a.b.d0");
-      root.addTimeseriesPath("root.a.b.d0.s0", TSDataType.INT32, TSEncoding.RLE, CompressionType.valueOf
+      root.addTimeseriesPath(MetaUtils.getNodeNames("root.a.b.d0.s0"),
+          TSDataType.INT32, TSEncoding.RLE,CompressionType.valueOf
           (TSFileDescriptor.getInstance().getConfig().getCompressor()), Collections.EMPTY_MAP);
 
     } catch (PathErrorException | StorageGroupException e1) {
@@ -148,42 +158,52 @@ public class MTreeTest {
     MTree root3 = new MTree("root");
     try {
       root.setStorageGroup("root.a.d0");
-      root.addTimeseriesPath("root.a.d0.s0", TSDataType.INT32, TSEncoding.RLE, CompressionType.valueOf
+      root.addTimeseriesPath(MetaUtils.getNodeNames("root.a.d0.s0"),
+          TSDataType.INT32, TSEncoding.RLE,CompressionType.valueOf
           (TSFileDescriptor.getInstance().getConfig().getCompressor()), Collections.EMPTY_MAP);
-      root.addTimeseriesPath("root.a.d0.s1", TSDataType.INT32, TSEncoding.RLE, CompressionType.valueOf
+      root.addTimeseriesPath(MetaUtils.getNodeNames("root.a.d0.s1"),
+          TSDataType.INT32, TSEncoding.RLE, CompressionType.valueOf
           (TSFileDescriptor.getInstance().getConfig().getCompressor()), Collections.EMPTY_MAP);
 
       root.setStorageGroup("root.a.d1");
-      root.addTimeseriesPath("root.a.d1.s0", TSDataType.INT32, TSEncoding.RLE, CompressionType.valueOf
+      root.addTimeseriesPath(MetaUtils.getNodeNames("root.a.d1.s0"),
+          TSDataType.INT32, TSEncoding.RLE, CompressionType.valueOf
           (TSFileDescriptor.getInstance().getConfig().getCompressor()), Collections.EMPTY_MAP);
-      root.addTimeseriesPath("root.a.d1.s1", TSDataType.INT32, TSEncoding.RLE, CompressionType.valueOf
+      root.addTimeseriesPath(MetaUtils.getNodeNames("root.a.d1.s1"),
+          TSDataType.INT32, TSEncoding.RLE, CompressionType.valueOf
           (TSFileDescriptor.getInstance().getConfig().getCompressor()), Collections.EMPTY_MAP);
 
       root.setStorageGroup("root.a.b.d0");
-      root.addTimeseriesPath("root.a.b.d0.s0", TSDataType.INT32, TSEncoding.RLE, CompressionType.valueOf
+      root.addTimeseriesPath(MetaUtils.getNodeNames("root.a.b.d0.s0"),
+          TSDataType.INT32, TSEncoding.RLE, CompressionType.valueOf
           (TSFileDescriptor.getInstance().getConfig().getCompressor()), Collections.EMPTY_MAP);
 
       root1.setStorageGroup("root.a.d0");
-      root1.addTimeseriesPath("root.a.d0.s0", TSDataType.INT32, TSEncoding.RLE, CompressionType.valueOf
+      root1.addTimeseriesPath(MetaUtils.getNodeNames("root.a.d0.s0"),
+          TSDataType.INT32, TSEncoding.RLE, CompressionType.valueOf
           (TSFileDescriptor.getInstance().getConfig().getCompressor()), Collections.EMPTY_MAP);
-      root1.addTimeseriesPath("root.a.d0.s1", TSDataType.INT32, TSEncoding.RLE, CompressionType.valueOf
+      root1.addTimeseriesPath(MetaUtils.getNodeNames("root.a.d0.s1"),
+          TSDataType.INT32, TSEncoding.RLE, CompressionType.valueOf
           (TSFileDescriptor.getInstance().getConfig().getCompressor()), Collections.EMPTY_MAP);
 
       root2.setStorageGroup("root.a.d1");
-      root2.addTimeseriesPath("root.a.d1.s0", TSDataType.INT32, TSEncoding.RLE, CompressionType.valueOf
+      root2.addTimeseriesPath(MetaUtils.getNodeNames("root.a.d1.s0"),
+          TSDataType.INT32, TSEncoding.RLE, CompressionType.valueOf
           (TSFileDescriptor.getInstance().getConfig().getCompressor()), Collections.EMPTY_MAP);
-      root2.addTimeseriesPath("root.a.d1.s1", TSDataType.INT32, TSEncoding.RLE, CompressionType.valueOf
+      root2.addTimeseriesPath(MetaUtils.getNodeNames("root.a.d1.s1"),
+          TSDataType.INT32, TSEncoding.RLE, CompressionType.valueOf
           (TSFileDescriptor.getInstance().getConfig().getCompressor()), Collections.EMPTY_MAP);
 
       root3.setStorageGroup("root.a.b.d0");
-      root3.addTimeseriesPath("root.a.b.d0.s0", TSDataType.INT32, TSEncoding.RLE, CompressionType.valueOf
+      root3.addTimeseriesPath(MetaUtils.getNodeNames("root.a.b.d0.s0"),
+          TSDataType.INT32, TSEncoding.RLE, CompressionType.valueOf
           (TSFileDescriptor.getInstance().getConfig().getCompressor()), Collections.EMPTY_MAP);
 
       String[] metadataStrs = new String[3];
       metadataStrs[0] = root1.toString();
       metadataStrs[1] = root2.toString();
       metadataStrs[2] = root3.toString();
-      assertEquals(MTree.combineMetadataInStrings(metadataStrs), root.toString());
+      assertEquals(SchemaUtils.combineMetadataInStrings(metadataStrs), root.toString());
     } catch (PathErrorException | StorageGroupException e) {
       e.printStackTrace();
       fail(e.getMessage());
@@ -226,16 +246,20 @@ public class MTreeTest {
 
     try {
       assertEquals("root.laptop.d1", root.getStorageGroupNameByPath("root.laptop.d1.s0"));
-      root.addTimeseriesPath("root.laptop.d1.s0", TSDataType.INT32, TSEncoding.RLE, CompressionType.valueOf
+      root.addTimeseriesPath(MetaUtils.getNodeNames("root.laptop.d1.s0"),
+          TSDataType.INT32, TSEncoding.RLE, CompressionType.valueOf
           (TSFileDescriptor.getInstance().getConfig().getCompressor()), Collections.EMPTY_MAP);
       assertEquals("root.laptop.d1", root.getStorageGroupNameByPath("root.laptop.d1.s1"));
-      root.addTimeseriesPath("root.laptop.d1.s1", TSDataType.INT32, TSEncoding.RLE, CompressionType.valueOf
+      root.addTimeseriesPath(MetaUtils.getNodeNames("root.laptop.d1.s1"),
+          TSDataType.INT32, TSEncoding.RLE, CompressionType.valueOf
           (TSFileDescriptor.getInstance().getConfig().getCompressor()), Collections.EMPTY_MAP);
       assertEquals("root.laptop.d2", root.getStorageGroupNameByPath("root.laptop.d2.s0"));
-      root.addTimeseriesPath("root.laptop.d2.s0", TSDataType.INT32, TSEncoding.RLE, CompressionType.valueOf
+      root.addTimeseriesPath(MetaUtils.getNodeNames("root.laptop.d2.s0"),
+          TSDataType.INT32, TSEncoding.RLE, CompressionType.valueOf
           (TSFileDescriptor.getInstance().getConfig().getCompressor()), Collections.EMPTY_MAP);
       assertEquals("root.laptop.d2", root.getStorageGroupNameByPath("root.laptop.d2.s1"));
-      root.addTimeseriesPath("root.laptop.d2.s1", TSDataType.INT32, TSEncoding.RLE, CompressionType.valueOf
+      root.addTimeseriesPath(MetaUtils.getNodeNames("root.laptop.d2.s1"),
+          TSDataType.INT32, TSEncoding.RLE, CompressionType.valueOf
           (TSFileDescriptor.getInstance().getConfig().getCompressor()), Collections.EMPTY_MAP);
     } catch (PathErrorException | StorageGroupException e) {
       e.printStackTrace();
@@ -292,8 +316,10 @@ public class MTreeTest {
     try {
       root.setStorageGroup("root.laptop.d1");
       root.setStorageGroup("root.laptop.d2");
-      root.addTimeseriesPath("root.laptop.d1.s1", TSDataType.INT32, TSEncoding.PLAIN, CompressionType.GZIP, null);
-      root.addTimeseriesPath("root.laptop.d1.s1", TSDataType.INT32, TSEncoding.PLAIN, CompressionType.GZIP, null);
+      root.addTimeseriesPath(MetaUtils.getNodeNames("root.laptop.d1.s1"),
+          TSDataType.INT32, TSEncoding.PLAIN, CompressionType.GZIP, null);
+      root.addTimeseriesPath(MetaUtils.getNodeNames("root.laptop.d1.s1"),
+          TSDataType.INT32, TSEncoding.PLAIN, CompressionType.GZIP, null);
 
       List<String> list = new ArrayList<>();
 
diff --git a/server/src/test/java/org/apache/iotdb/db/metadata/MetadataTest.java b/server/src/test/java/org/apache/iotdb/db/metadata/MetadataTest.java
deleted file mode 100644
index 3d21e65..0000000
--- a/server/src/test/java/org/apache/iotdb/db/metadata/MetadataTest.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.iotdb.db.metadata;
-
-import static org.junit.Assert.*;
-
-import java.io.IOException;
-import org.apache.iotdb.db.exception.MetadataErrorException;
-import org.apache.iotdb.db.exception.PathErrorException;
-import org.apache.iotdb.db.exception.StorageGroupException;
-import org.apache.iotdb.db.utils.EnvironmentUtils;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-public class MetadataTest {
-
-  @Before
-  public void setUp() throws Exception {
-    EnvironmentUtils.envSetUp();
-  }
-
-  @After
-  public void tearDown() throws Exception {
-    EnvironmentUtils.cleanEnv();
-  }
-
-  @Test
-  public void testCombineMetadatas() {
-    MManager manager = MManager.getInstance();
-
-    try {
-      manager.setStorageGroupToMTree("root.t.d1");
-      manager.addPathToMTree("root.t.d1.s0", "INT32", "RLE");
-      manager.addPathToMTree("root.t.d1.s1", "DOUBLE", "RLE");
-      manager.setStorageGroupToMTree("root.t.d2");
-      manager.addPathToMTree("root.t.d2.s1", "DOUBLE", "RLE");
-      Metadata metadata1 = manager.getMetadata();
-
-      manager.clear();
-
-      manager.setStorageGroupToMTree("root.t.d3");
-      manager.addPathToMTree("root.t.d3.s1", "DOUBLE", "RLE");
-      manager.addPathToMTree("root.t.d3.s2", "TEXT", "RLE");
-      manager.setStorageGroupToMTree("root.t1.d1");
-      manager.addPathToMTree("root.t1.d1.s1", "DOUBLE", "RLE");
-      manager.addPathToMTree("root.t1.d1.s2", "TEXT", "RLE");
-      Metadata metadata2 = manager.getMetadata();
-
-      manager.clear();
-
-      manager.setStorageGroupToMTree("root.t.d1");
-      manager.addPathToMTree("root.t.d1.s0", "INT32", "RLE");
-      manager.addPathToMTree("root.t.d1.s1", "DOUBLE", "RLE");
-      manager.setStorageGroupToMTree("root.t.d2");
-      manager.addPathToMTree("root.t.d2.s1", "DOUBLE", "RLE");
-      manager.setStorageGroupToMTree("root.t.d3");
-      manager.addPathToMTree("root.t.d3.s1", "DOUBLE", "RLE");
-      manager.addPathToMTree("root.t.d3.s2", "TEXT", "RLE");
-      manager.setStorageGroupToMTree("root.t1.d1");
-      manager.addPathToMTree("root.t1.d1.s1", "DOUBLE", "RLE");
-      manager.addPathToMTree("root.t1.d1.s2", "TEXT", "RLE");
-      Metadata metadata = manager.getMetadata();
-
-      Metadata combineMetadata = Metadata.combineMetadatas(new Metadata[]{metadata1, metadata2});
-      assertTrue(metadata.equals(combineMetadata));
-    } catch (PathErrorException | IOException | MetadataErrorException | StorageGroupException e) {
-      e.printStackTrace();
-      fail(e.getMessage());
-    }
-  }
-}
\ No newline at end of file
diff --git a/service-rpc/rpc-changelist.md b/service-rpc/rpc-changelist.md
index c66a7c4..56abce7 100644
--- a/service-rpc/rpc-changelist.md
+++ b/service-rpc/rpc-changelist.md
@@ -72,6 +72,7 @@ Last Updated on October 27th, 2019 by Lei Rui.
 | Rename some fields in TSFetchMetadataResp: ~~ColumnsList~~ to columnsList, ~~showTimeseriesList~~ to timeseriesList, ~~showStorageGroups~~ to storageGroups | Zesong Sun             |
 | Change struct TSQueryDataSet to eliminate row-wise rpc writing | Lei Rui                |
 | Add optional i32 timeseriesNum in TSFetchMetadataResp        | Jack Tsai              |
-
+| Rename timeseriesList in TSFetchMetadataResp to timeseriesInfoList          | Tian Jiang   |
+| Change the type of devices and storageGroups in TSFetchMetadataResp to List | Tian Jiang   |
 
 
diff --git a/service-rpc/src/main/thrift/rpc.thrift b/service-rpc/src/main/thrift/rpc.thrift
index 0e1186f..03681f2 100644
--- a/service-rpc/src/main/thrift/rpc.thrift
+++ b/service-rpc/src/main/thrift/rpc.thrift
@@ -179,9 +179,10 @@ struct TSFetchMetadataResp{
 		3: optional list<string> columnsList
 		4: optional i32 timeseriesNum
 		5: optional string dataType
-		6: optional list<list<string>> timeseriesList
-		7: optional set<string> storageGroups
-		8: optional set<string> devices
+		// each list contains the full path, storage group, data type and encoding of a timeseries
+		6: optional list<list<string>> timeseriesInfoList
+		7: optional list<string> storageGroups
+		8: optional list<string> devices
 		9: optional list<string> nodesList
 		10: optional map<string, string> nodeTimeseriesNum
 }
diff --git a/tsfile/src/main/java/org/apache/iotdb/tsfile/common/constant/TsFileConstant.java b/tsfile/src/main/java/org/apache/iotdb/tsfile/common/constant/TsFileConstant.java
index 479bd8e..cbe190c 100644
--- a/tsfile/src/main/java/org/apache/iotdb/tsfile/common/constant/TsFileConstant.java
+++ b/tsfile/src/main/java/org/apache/iotdb/tsfile/common/constant/TsFileConstant.java
@@ -25,7 +25,7 @@ public class TsFileConstant {
   public static final String TSFILE_CONF = "TSFILE_CONF";
   public static final String PATH_ROOT = "root";
   public static final String PATH_SEPARATOR = ".";
-  public static final String PATH_SEPARATER_NO_REGEX = "\\.";
+  public static final String PATH_SEPARATOR_NO_REGEX = "\\.";
   public static final String DEFAULT_DELTA_TYPE = "default_delta_type";
 
   private TsFileConstant(){}
diff --git a/tsfile/src/main/java/org/apache/iotdb/tsfile/read/common/Path.java b/tsfile/src/main/java/org/apache/iotdb/tsfile/read/common/Path.java
index c91b75e..feb65d1 100644
--- a/tsfile/src/main/java/org/apache/iotdb/tsfile/read/common/Path.java
+++ b/tsfile/src/main/java/org/apache/iotdb/tsfile/read/common/Path.java
@@ -110,7 +110,7 @@ public class Path implements Serializable {
       measurement = subStrs[1];
       fullPath = pathSc;
     } else {
-      StringContainer sc = new StringContainer(pathSc.split(TsFileConstant.PATH_SEPARATER_NO_REGEX), TsFileConstant.PATH_SEPARATOR);
+      StringContainer sc = new StringContainer(pathSc.split(TsFileConstant.PATH_SEPARATOR_NO_REGEX), TsFileConstant.PATH_SEPARATOR);
       if (sc.size() <= 1) {
         device = "";
         fullPath = measurement = sc.toString();