public IMeasurementMNode<IMemMNode> createTimeSeries(
      final PartialPath path,
      final TSDataType dataType,
      final TSEncoding encoding,
      final CompressionType compressor,
      final Map<String, String> props,
      final String alias,
      final boolean withMerge)
      throws MetadataException {
    final String[] nodeNames = path.getNodes();
    if (nodeNames.length <= 2) {
      throw new IllegalPathException(path.getFullPath());
    }
    MetaFormatUtils.checkTimeseries(path);
    final PartialPath devicePath = path.getDevicePath();
    final IMemMNode deviceParent = checkAndAutoCreateInternalPath(devicePath);

    // synchronize check and add, we need addChild and add Alias become atomic operation
    // only write on mTree will be synchronized
    synchronized (this) {
      final IMemMNode device = checkAndAutoCreateDeviceNode(devicePath.getTailNode(), deviceParent);

      MetaFormatUtils.checkTimeseriesProps(path.getFullPath(), props);

      final String leafName = path.getMeasurement();

      if (!withMerge && alias != null && device.hasChild(alias)) {
        throw new AliasAlreadyExistException(path.getFullPath(), alias);
      }

      if (device.hasChild(leafName)) {
        final IMemMNode node = device.getChild(leafName);
        if (node.isMeasurement()) {
          final IMeasurementMNode<IMemMNode> measurementNode = node.getAsMeasurementMNode();
          if (measurementNode.isPreDeleted()) {
            throw new MeasurementInBlackListException(path);
          } else if (!withMerge || measurementNode.getDataType() != dataType) {
            // Report conflict if the types are different
            throw new MeasurementAlreadyExistException(
                path.getFullPath(), node.getAsMeasurementMNode().getMeasurementPath());
          } else {
            // Return null iff we should merge the time series with the existing one
            return null;
          }
        } else {
          throw new PathAlreadyExistException(path.getFullPath());
        }
      }

      if (device.isDevice()
          && device.getAsDeviceMNode().isAlignedNullable() != null
          && device.getAsDeviceMNode().isAligned()) {
        throw new AlignedTimeseriesException(
            "time series under this device is aligned, please use createAlignedTimeseries or change device.",
            device.getFullPath());
      }

      final IDeviceMNode<IMemMNode> entityMNode;
      if (device.isDevice()) {
        entityMNode = device.getAsDeviceMNode();
      } else {
        entityMNode = store.setToEntity(device);
      }

      // create a non-aligned time series
      if (entityMNode.isAlignedNullable() == null) {
        entityMNode.setAligned(false);
      }

      final IMeasurementMNode<IMemMNode> measurementMNode =
          nodeFactory.createMeasurementMNode(
              entityMNode,
              leafName,
              new MeasurementSchema(leafName, dataType, encoding, compressor, props),
              alias);

      store.addChild(entityMNode.getAsMNode(), leafName, measurementMNode.getAsMNode());

      // link alias to LeafMNode
      if (alias != null) {
        entityMNode.addAlias(alias, measurementMNode);
      }

      return measurementMNode;
    }
  }
Create a time series with a full path from root to leaf node. Before creating a time series,
the database should be set first, throw exception otherwise

@param path time series path
@param dataType data type
@param encoding encoding
@param compressor compressor
@param props props
@param alias alias of measurement
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/mtree/impl/mem/MTreeBelowSGMemoryImpl.java