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

jackietien pushed a commit to branch research/auto-aligned
in repository https://gitbox.apache.org/repos/asf/iotdb.git


The following commit(s) were added to refs/heads/research/auto-aligned by this 
push:
     new e955d08  add autoaligned time series (#5012)
e955d08 is described below

commit e955d086e4f74c95cbca19e5330005609521e06d
Author: Chenguang Fang <[email protected]>
AuthorDate: Mon Feb 7 18:53:21 2022 +0800

    add autoaligned time series (#5012)
---
 .../org/apache/iotdb/db/qp/sql/IoTDBSqlLexer.g4    |   8 +
 .../org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4   |   8 +-
 .../iotdb/db/engine/flush/FlushGroupingEngine.java | 362 ++++++++++++++++++++
 .../iotdb/db/engine/flush/MemTableFlushTask.java   |  14 +-
 .../iotdb/db/engine/memtable/AbstractMemTable.java |  71 ++++
 .../memtable/AutoAlignedWritableMemChunk.java      | 367 +++++++++++++++++++++
 .../memtable/AutoAlignedWritableMemChunkGroup.java | 116 +++++++
 .../apache/iotdb/db/engine/memtable/IMemTable.java |   8 +
 .../db/engine/storagegroup/TsFileProcessor.java    |  67 +++-
 .../org/apache/iotdb/db/metadata/MManager.java     |  94 ++++--
 .../apache/iotdb/db/metadata/idtable/IDTable.java  |   9 +
 .../db/metadata/idtable/IDTableHashmapImpl.java    |  56 ++++
 .../db/metadata/idtable/entry/DeviceEntry.java     |   9 +
 .../db/metadata/idtable/entry/DiskSchemaEntry.java |  22 ++
 .../db/metadata/idtable/entry/SchemaEntry.java     |  31 ++
 .../iotdb/db/metadata/logfile/MLogWriter.java      |  27 +-
 .../iotdb/db/metadata/mnode/EntityMNode.java       |  12 +
 .../iotdb/db/metadata/mnode/IEntityMNode.java      |   4 +
 .../org/apache/iotdb/db/metadata/mtree/MTree.java  |  63 ++++
 .../apache/iotdb/db/qp/executor/PlanExecutor.java  |  13 +
 .../org/apache/iotdb/db/qp/logical/Operator.java   |   3 +-
 .../iotdb/db/qp/logical/crud/InsertOperator.java   |   8 +
 .../sys/CreateAutoAlignedTimeSeriesOperator.java   | 131 ++++++++
 .../apache/iotdb/db/qp/physical/PhysicalPlan.java  |  49 +--
 .../iotdb/db/qp/physical/crud/InsertPlan.java      |  10 +
 .../iotdb/db/qp/physical/crud/InsertRowPlan.java   |  23 ++
 .../sys/CreateAutoAlignedTimeSeriesPlan.java       | 267 +++++++++++++++
 .../apache/iotdb/db/qp/sql/IoTDBSqlVisitor.java    |  59 ++++
 .../db/utils/datastructure/AlignedTVList.java      |   4 +
 .../chunk/AutoAlignedChunkGroupWriterImpl.java     | 301 +++++++++++++++++
 .../write/chunk/AutoAlignedChunkWriterImpl.java    | 239 ++++++++++++++
 31 files changed, 2360 insertions(+), 95 deletions(-)

diff --git a/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlLexer.g4 
b/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlLexer.g4
index 024cf78..e703b12 100644
--- a/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlLexer.g4
+++ b/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlLexer.g4
@@ -85,6 +85,14 @@ ATTRIBUTES
     : A T T R I B U T E S
     ;
 
+AUTOALIGN
+    : A U T O A L I G N
+    ;
+
+AUTOALIGNED
+    : A U T O A L I G N E D
+    ;
+
 AUTOREGISTER
     : A U T O R E G I S T E R
     ;
diff --git a/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4 
b/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4
index 7a2e82f..201f271 100644
--- a/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4
+++ b/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4
@@ -81,6 +81,7 @@ createStorageGroup
 // Create Timeseries
 createTimeseries
     : CREATE ALIGNED TIMESERIES fullPath alignedMeasurements? 
#createAlignedTimeseries
+    | CREATE AUTOALIGNED TIMESERIES fullPath autoAlignedMeasurements? 
#createAutoAlignedTimeseries
     | CREATE TIMESERIES fullPath attributeClauses  #createNonAlignedTimeseries
     ;
 
@@ -89,6 +90,11 @@ alignedMeasurements
     (COMMA nodeNameWithoutWildcard attributeClauses)* RR_BRACKET
     ;
 
+autoAlignedMeasurements
+    : LR_BRACKET nodeNameWithoutWildcard attributeClauses
+    (COMMA nodeNameWithoutWildcard attributeClauses)* RR_BRACKET
+    ;
+
 // Create Schema Template
 createSchemaTemplate
     : CREATE SCHEMA? TEMPLATE templateName=identifier
@@ -431,7 +437,7 @@ timeInterval
 
 // Insert Statement
 insertStatement
-    : INSERT INTO prefixPath insertColumnsSpec ALIGNED? VALUES insertValuesSpec
+    : INSERT INTO prefixPath insertColumnsSpec ALIGNED? AUTOALIGNED? VALUES 
insertValuesSpec
     ;
 
 insertColumnsSpec
diff --git 
a/server/src/main/java/org/apache/iotdb/db/engine/flush/FlushGroupingEngine.java
 
b/server/src/main/java/org/apache/iotdb/db/engine/flush/FlushGroupingEngine.java
new file mode 100644
index 0000000..822f3fd
--- /dev/null
+++ 
b/server/src/main/java/org/apache/iotdb/db/engine/flush/FlushGroupingEngine.java
@@ -0,0 +1,362 @@
+/*
+ * 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.engine.flush;
+
+import org.apache.iotdb.db.utils.datastructure.AlignedTVList;
+import org.apache.iotdb.tsfile.utils.BitMap;
+import org.apache.iotdb.tsfile.write.schema.IMeasurementSchema;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import static org.apache.iotdb.db.rescon.PrimitiveArrayManager.ARRAY_SIZE;
+
+public class FlushGroupingEngine {
+  private static final Logger LOGGER = 
LoggerFactory.getLogger(MemTableFlushTask.class);
+
+  public static class ColumnGroup {
+    public ArrayList<Integer> columns;
+    public int maxGain = -1;
+    public int maxGainPosition = -1;
+    public long lastTimestampIdx;
+    public long startTimestampIdx;
+    public int timeSeriesLength; // number of exist timestamps, i.e., zeros in 
bitmap
+    public long interval;
+    public ArrayList<BitMap> bitmap;
+    public int size; // total length of the bitmap
+    public ArrayList<Integer> gains;
+
+    public ColumnGroup(
+        ArrayList<Integer> columns, int maxGain, ArrayList<BitMap> bitmap, int 
size, int GroupNum) {
+      this.columns = columns;
+      this.maxGain = maxGain;
+      this.bitmap = bitmap;
+      this.size = size;
+      this.gains = new ArrayList<>(Collections.nCopies(GroupNum, -1));
+      this.updateTimestampInfo();
+    }
+
+    public void updateTimestampInfo() {
+      int onesCount = 0;
+      this.startTimestampIdx = -1;
+      this.lastTimestampIdx = -1;
+      int bitmapSize = ARRAY_SIZE;
+      if (this.bitmap == null) {}
+
+      for (int i = 0; i < this.bitmap.size(); i++) {
+        if (this.bitmap.get(i) == null) {
+          if (this.startTimestampIdx == -1) {
+            this.startTimestampIdx = i * bitmapSize;
+          }
+          if (i * bitmapSize + bitmapSize - 1 < size) {
+            this.lastTimestampIdx = i * bitmapSize + bitmapSize - 1;
+          } else {
+            if (i * bitmapSize - 1 < size) {
+              this.lastTimestampIdx = size - 1;
+            }
+          }
+        } else {
+          BitMap bm = this.bitmap.get(i);
+          for (int j = 0; j < bm.getSize() / Byte.SIZE; j++) {
+            int onesNumber = countOnesForByte(bm.getByteArray()[j]);
+            if (this.startTimestampIdx == -1 && onesNumber != 8) {
+              this.startTimestampIdx = i * bitmapSize + j * 8 + 
firstZero(bm.getByteArray()[j]);
+            }
+            if (onesNumber != 8) {
+              if (i * bitmapSize + j * 8 + lastZero(bm.getByteArray()[j]) < 
size) {
+                this.lastTimestampIdx = i * bitmapSize + j * 8 + 
lastZero(bm.getByteArray()[j]);
+              }
+            }
+            onesCount += countOnesForByte(bm.getByteArray()[j]);
+          }
+        }
+      }
+      this.timeSeriesLength = this.size - onesCount;
+    }
+
+    public static ColumnGroup mergeColumnGroup(ColumnGroup g1, ColumnGroup g2) 
{
+      // merge bitmap
+      ArrayList<BitMap> newBitmap = new ArrayList<>();
+      for (int i = 0; i < g1.bitmap.size(); i++) {
+        int bitmapLength = ARRAY_SIZE;
+        byte[] bitmap = new byte[bitmapLength / Byte.SIZE + 1];
+        for (int j = 0; j < bitmap.length; j++) {
+          byte g1byte = 0;
+          if (g1.bitmap.get(i) != null) {
+            g1byte = g1.bitmap.get(i).getByteArray()[j];
+          }
+          byte g2byte = 0;
+          if (g2.bitmap.get(i) != null) {
+            g2byte = g2.bitmap.get(i).getByteArray()[j];
+          }
+          bitmap[j] = (byte) (g1byte & g2byte);
+        }
+        newBitmap.add(new BitMap(ARRAY_SIZE, bitmap));
+      }
+      // merge columns
+      ArrayList<Integer> newColumns = (ArrayList<Integer>) g1.columns.clone();
+      newColumns.addAll(g2.columns);
+
+      // update posIndex
+      return new ColumnGroup(newColumns, -1, newBitmap, g1.size, 
g1.gains.size() - 1);
+    }
+  }
+
+  /** autoaligned grouping method * */
+  public static void grouping(AlignedTVList dataList, List<IMeasurementSchema> 
schemaList) {
+    try {
+      if (dataList.getBitMaps() == null) {
+        return;
+      }
+
+      int timeSeriesNumber = dataList.getValues().size();
+      int size = dataList.rowCount();
+      ArrayList<ColumnGroup> columnGroups = new ArrayList<>();
+
+      if (timeSeriesNumber == 0) {
+        return;
+      }
+      if (timeSeriesNumber == 1) {
+        return;
+      }
+
+      // init posMap, maxGain, groupingResult
+      for (int i = 0; i < timeSeriesNumber; i++) {
+        ArrayList<Integer> newGroup = new ArrayList<>();
+        newGroup.add(i);
+        ArrayList<BitMap> bitmap = (ArrayList<BitMap>) 
dataList.getBitMaps().get(i);
+        if (bitmap == null) {
+          bitmap = new ArrayList<>();
+          for (int j = 0; j < dataList.getBitMaps().size(); j++) {
+            if (dataList.getBitMaps().get(j) != null) {
+              int sizeBitmap = dataList.getBitMaps().get(j).size();
+              for (int k = 0; k < sizeBitmap; k++) {
+                bitmap.add(null);
+              }
+            }
+          }
+        }
+        columnGroups.add(new ColumnGroup(newGroup, -1, bitmap, size, 
timeSeriesNumber));
+      }
+
+      // init gain matrix
+      for (int i = 0; i < timeSeriesNumber; i++) {
+        for (int j = i + 1; j < timeSeriesNumber; j++) {
+          int gain = computeGain(columnGroups.get(i), columnGroups.get(j), 
size);
+          columnGroups.get(i).gains.set(j, gain);
+          columnGroups.get(j).gains.set(i, gain);
+          if (columnGroups.get(i).maxGain < gain) {
+            columnGroups.get(i).maxGain = gain;
+            columnGroups.get(i).maxGainPosition = j;
+          }
+          if (columnGroups.get(j).maxGain < gain) {
+            columnGroups.get(j).maxGain = gain;
+            columnGroups.get(j).maxGainPosition = i;
+          }
+        }
+      }
+
+      while (true) {
+        /** merge * */
+
+        // find the main gain
+        int maxGainOfAll = -1;
+        int maxGainOfAllPos = -1;
+        for (int i = 0; i < columnGroups.size(); i++) {
+          if (columnGroups.get(i).maxGain > maxGainOfAll) {
+            maxGainOfAll = columnGroups.get(i).maxGain;
+            maxGainOfAllPos = i;
+          }
+        }
+        if (maxGainOfAll <= 0) {
+          break;
+        }
+
+        // merge the group, create a new group
+        int source = maxGainOfAllPos;
+        int target = columnGroups.get(source).maxGainPosition;
+
+        ColumnGroup newGroup =
+            ColumnGroup.mergeColumnGroup(columnGroups.get(source), 
columnGroups.get(target));
+
+        // remove the old groups
+        columnGroups.remove(target);
+        columnGroups.remove(source);
+
+        // load target into source
+        columnGroups.add(source, newGroup);
+
+        /** update * */
+
+        // update gains
+        // remove the target, and update the source
+        for (int i = 0; i < columnGroups.size(); i++) {
+          if (i != source) {
+            ColumnGroup g = columnGroups.get(i);
+            ColumnGroup gSource = columnGroups.get(source);
+            g.gains.remove(target);
+            int gain = computeGain(g, gSource, size);
+            g.gains.set(source, gain);
+            // update the maxgain in i
+            if ((g.maxGainPosition != source) && (g.maxGainPosition != 
target)) {
+              if (gain > g.maxGain) {
+                g.maxGain = gain;
+                g.maxGainPosition = source;
+              } else {
+                if (target < g.maxGainPosition) {
+                  g.maxGainPosition -= 1;
+                }
+              }
+            } else {
+              g.maxGain = gain;
+              g.maxGainPosition = source;
+              for (int j = 0; j < g.gains.size(); j++) {
+                if (g.gains.get(j) > g.maxGain) {
+                  g.maxGain = g.gains.get(j);
+                  g.maxGainPosition = j;
+                }
+              }
+            }
+            // update the maxgain and data in source
+            gSource.gains.set(i, gain);
+            if (gain > gSource.maxGain) {
+              gSource.maxGain = gain;
+              gSource.maxGainPosition = i;
+            }
+          }
+        }
+      }
+    } catch (Exception e) {
+      LOGGER.error(e.getMessage());
+    }
+  }
+
+  public static int computeOverlap(ArrayList<BitMap> col1, ArrayList<BitMap> 
col2, int size) {
+    int bitmapSize = ARRAY_SIZE;
+    int overlaps = 0;
+    for (int i = 0; i < col1.size(); i++) {
+      byte[] byteCol1 = null;
+      byte[] byteCol2 = null;
+      if (col1.get(i) != null) {
+        byteCol1 = col1.get(i).getByteArray();
+      }
+      if (col2.get(i) != null) {
+        byteCol2 = col2.get(i).getByteArray();
+      }
+      overlaps += computeOverlapForByte(byteCol1, byteCol2, bitmapSize);
+    }
+    int repeatOverlap = bitmapSize - (size % bitmapSize);
+    if (size % bitmapSize == 0) {
+      repeatOverlap = 0;
+    }
+    return overlaps - repeatOverlap;
+  }
+
+  public static int computeOverlapForByte(byte[] col1, byte[] col2, int size) {
+    if (col1 == null && col2 == null) {
+      return size;
+    }
+    int onesCount = 0;
+    if (col1 == null) {
+      for (int i = 0; i < size / Byte.SIZE; i++) {
+        onesCount += countOnesForByte(col2[i]);
+      }
+      return size - onesCount;
+    }
+    if (col2 == null) {
+      for (int i = 0; i < size / Byte.SIZE; i++) {
+        onesCount += countOnesForByte(col1[i]);
+      }
+      return size - onesCount;
+    }
+    for (int i = 0; i < size / Byte.SIZE; i++) {
+      onesCount += countOnesForByte((byte) (col1[i] | col2[i]));
+    }
+    return size - onesCount;
+  }
+
+  public static int computeGain(ColumnGroup g1, ColumnGroup g2, int size) {
+    int overlap = computeOverlap(g1.bitmap, g2.bitmap, size);
+    if (g1.columns.size() == 1 && g2.columns.size() == 1) {
+      // col - col
+      int gain = overlap * Long.SIZE - 2 * (g1.timeSeriesLength + 
g2.timeSeriesLength - overlap);
+      return gain;
+    }
+    if (g1.columns.size() == 1) {
+      // col - group
+      int m_s_a = g1.timeSeriesLength;
+      int n_g_a = g2.columns.size();
+      int m_g_a = g2.timeSeriesLength;
+      int gain = overlap * Long.SIZE + n_g_a * m_g_a - (n_g_a + 1) * (m_s_a + 
m_g_a - overlap);
+      return gain;
+    }
+    if (g2.columns.size() == 1) {
+      // group - col
+      int m_s_a = g2.timeSeriesLength;
+      int n_g_a = g1.columns.size();
+      int m_g_a = g1.timeSeriesLength;
+      int gain = overlap * Long.SIZE + n_g_a * m_g_a - (n_g_a + 1) * (m_s_a + 
m_g_a - overlap);
+      return gain;
+    }
+
+    // group - group
+    int n_g_a = g1.columns.size();
+    int m_g_a = g1.timeSeriesLength;
+    int n_g_b = g2.columns.size();
+    int m_g_b = g2.timeSeriesLength;
+
+    int gain = overlap * Long.SIZE + (n_g_a + n_g_b) * overlap - n_g_a * m_g_b 
- n_g_b * m_g_a;
+    return gain;
+  }
+
+  /** belows are some util functions* */
+  public static int countOnesForByte(byte x) {
+    return ((x >> 7) & 1)
+        + ((x >> 6) & 1)
+        + ((x >> 5) & 1)
+        + ((x >> 4) & 1)
+        + ((x >> 3) & 1)
+        + ((x >> 2) & 1)
+        + ((x >> 1) & 1)
+        + (x & 1);
+  }
+
+  public static int firstZero(byte x) {
+    for (int i = 0; i <= 7; i++) {
+      if (((x >> i) & 1) == 0) {
+        return i;
+      }
+    }
+    return -1;
+  }
+
+  public static int lastZero(byte x) {
+    for (int i = 7; i >= 0; i--) {
+      if (((x >> i) & 1) == 0) {
+        return i;
+      }
+    }
+    return -1;
+  }
+}
diff --git 
a/server/src/main/java/org/apache/iotdb/db/engine/flush/MemTableFlushTask.java 
b/server/src/main/java/org/apache/iotdb/db/engine/flush/MemTableFlushTask.java
index 3501db0..5eaaae8 100644
--- 
a/server/src/main/java/org/apache/iotdb/db/engine/flush/MemTableFlushTask.java
+++ 
b/server/src/main/java/org/apache/iotdb/db/engine/flush/MemTableFlushTask.java
@@ -21,23 +21,24 @@ package org.apache.iotdb.db.engine.flush;
 import org.apache.iotdb.db.conf.IoTDBConfig;
 import org.apache.iotdb.db.conf.IoTDBDescriptor;
 import org.apache.iotdb.db.engine.flush.pool.FlushSubTaskPoolManager;
-import org.apache.iotdb.db.engine.memtable.IMemTable;
-import org.apache.iotdb.db.engine.memtable.IWritableMemChunk;
-import org.apache.iotdb.db.engine.memtable.IWritableMemChunkGroup;
+import org.apache.iotdb.db.engine.memtable.*;
 import org.apache.iotdb.db.exception.runtime.FlushRunTimeException;
 import org.apache.iotdb.db.metadata.idtable.entry.IDeviceID;
 import org.apache.iotdb.db.rescon.SystemInfo;
 import org.apache.iotdb.db.service.metrics.Metric;
 import org.apache.iotdb.db.service.metrics.MetricsService;
 import org.apache.iotdb.db.service.metrics.Tag;
+import org.apache.iotdb.db.utils.datastructure.AlignedTVList;
 import org.apache.iotdb.metrics.config.MetricConfigDescriptor;
 import org.apache.iotdb.tsfile.write.chunk.IChunkWriter;
+import org.apache.iotdb.tsfile.write.schema.IMeasurementSchema;
 import org.apache.iotdb.tsfile.write.writer.RestorableTsFileIOWriter;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.io.IOException;
+import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
@@ -122,6 +123,13 @@ public class MemTableFlushTask {
         series.sortTvListForFlush();
         sortTime += System.currentTimeMillis() - startTime;
         encodingTaskQueue.put(series);
+        if (series instanceof AutoAlignedWritableMemChunk) {
+          /** perform our grouping strategy* */
+          List<IMeasurementSchema> schemaList =
+              ((AutoAlignedWritableMemChunk) series).getSchemaList();
+          AlignedTVList dataList = ((AutoAlignedWritableMemChunk) 
series).getList();
+          FlushGroupingEngine.grouping(dataList, schemaList);
+        }
       }
 
       encodingTaskQueue.put(new EndChunkGroupIoTask());
diff --git 
a/server/src/main/java/org/apache/iotdb/db/engine/memtable/AbstractMemTable.java
 
b/server/src/main/java/org/apache/iotdb/db/engine/memtable/AbstractMemTable.java
index 57116e9..d067312 100644
--- 
a/server/src/main/java/org/apache/iotdb/db/engine/memtable/AbstractMemTable.java
+++ 
b/server/src/main/java/org/apache/iotdb/db/engine/memtable/AbstractMemTable.java
@@ -136,6 +136,25 @@ public abstract class AbstractMemTable implements 
IMemTable {
     return memChunkGroup;
   }
 
+  private IWritableMemChunkGroup 
createAutoAlignedMemChunkGroupIfNotExistAndGet(
+      IDeviceID deviceId, List<IMeasurementSchema> schemaList) {
+    IWritableMemChunkGroup memChunkGroup =
+        memTableMap.computeIfAbsent(
+            deviceId,
+            k -> {
+              seriesNumber += schemaList.size();
+              totalPointsNumThreshold += ((long) avgSeriesPointNumThreshold) * 
schemaList.size();
+              return new AutoAlignedWritableMemChunkGroup(schemaList);
+            });
+    for (IMeasurementSchema schema : schemaList) {
+      if (!memChunkGroup.contains(schema.getMeasurementId())) {
+        seriesNumber++;
+        totalPointsNumThreshold += avgSeriesPointNumThreshold;
+      }
+    }
+    return memChunkGroup;
+  }
+
   @Override
   public void insert(InsertRowPlan insertRowPlan) {
     // if this insert plan isn't from storage engine (mainly from test), we 
should set a temp device
@@ -216,6 +235,47 @@ public abstract class AbstractMemTable implements 
IMemTable {
   }
 
   @Override
+  public void insertAutoAlignedRow(InsertRowPlan insertRowPlan) {
+    // if this insert plan isn't from storage engine, we should set a temp 
device id for it
+    if (insertRowPlan.getDeviceID() == null) {
+      insertRowPlan.setDeviceID(
+          
DeviceIDFactory.getInstance().getDeviceID(insertRowPlan.getDevicePath()));
+    }
+
+    updatePlanIndexes(insertRowPlan.getIndex());
+    String[] measurements = insertRowPlan.getMeasurements();
+    List<IMeasurementSchema> schemaList = new ArrayList<>();
+    List<TSDataType> dataTypes = new ArrayList<>();
+    for (int i = 0; i < insertRowPlan.getMeasurements().length; i++) {
+      if (measurements[i] == null) {
+        continue;
+      }
+      IMeasurementSchema schema = 
insertRowPlan.getMeasurementMNodes()[i].getSchema();
+      schemaList.add(schema);
+      dataTypes.add(schema.getType());
+    }
+    if (schemaList.isEmpty()) {
+      return;
+    }
+    memSize +=
+        MemUtils.getAlignedRecordsSize(dataTypes, insertRowPlan.getValues(), 
disableMemControl);
+    writeAutoAlignedRow(
+        insertRowPlan.getDeviceID(),
+        schemaList,
+        insertRowPlan.getTime(),
+        insertRowPlan.getValues());
+    int pointsInserted =
+        insertRowPlan.getMeasurements().length - 
insertRowPlan.getFailedMeasurementNumber();
+    totalPointsNum += pointsInserted;
+
+    if 
(MetricConfigDescriptor.getInstance().getMetricConfig().getEnableMetric()) {
+      MetricsService.getInstance()
+          .getMetricManager()
+          .count(pointsInserted, Metric.QUANTITY.toString(), 
Tag.NAME.toString(), METRIC_POINT_IN);
+    }
+  }
+
+  @Override
   public void insertTablet(InsertTabletPlan insertTabletPlan, int start, int 
end)
       throws WriteProcessException {
     updatePlanIndexes(insertTabletPlan.getIndex());
@@ -281,6 +341,17 @@ public abstract class AbstractMemTable implements 
IMemTable {
     memChunkGroup.write(insertTime, objectValue, schemaList);
   }
 
+  @Override
+  public void writeAutoAlignedRow(
+      IDeviceID deviceId,
+      List<IMeasurementSchema> schemaList,
+      long insertTime,
+      Object[] objectValue) {
+    IWritableMemChunkGroup memChunkGroup =
+        createAutoAlignedMemChunkGroupIfNotExistAndGet(deviceId, schemaList);
+    memChunkGroup.write(insertTime, objectValue, schemaList);
+  }
+
   @SuppressWarnings("squid:S3776") // high Cognitive Complexity
   @Override
   public void write(InsertTabletPlan insertTabletPlan, int start, int end) {
diff --git 
a/server/src/main/java/org/apache/iotdb/db/engine/memtable/AutoAlignedWritableMemChunk.java
 
b/server/src/main/java/org/apache/iotdb/db/engine/memtable/AutoAlignedWritableMemChunk.java
new file mode 100755
index 0000000..4070c84
--- /dev/null
+++ 
b/server/src/main/java/org/apache/iotdb/db/engine/memtable/AutoAlignedWritableMemChunk.java
@@ -0,0 +1,367 @@
+/*
+ * 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.engine.memtable;
+
+import org.apache.iotdb.db.utils.datastructure.AlignedTVList;
+import org.apache.iotdb.db.utils.datastructure.TVList;
+import org.apache.iotdb.tsfile.exception.write.UnSupportedDataTypeException;
+import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
+import org.apache.iotdb.tsfile.utils.Binary;
+import org.apache.iotdb.tsfile.utils.BitMap;
+import org.apache.iotdb.tsfile.utils.Pair;
+import org.apache.iotdb.tsfile.write.chunk.AutoAlignedChunkWriterImpl;
+import org.apache.iotdb.tsfile.write.chunk.IChunkWriter;
+import org.apache.iotdb.tsfile.write.schema.IMeasurementSchema;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public class AutoAlignedWritableMemChunk implements IWritableMemChunk {
+
+  private final Map<String, Integer> measurementIndexMap;
+  private final List<IMeasurementSchema> schemaList;
+  private AlignedTVList list;
+  private static final String UNSUPPORTED_TYPE = "Unsupported data type:";
+  private static final Logger LOGGER = 
LoggerFactory.getLogger(AutoAlignedWritableMemChunk.class);
+
+  public AutoAlignedWritableMemChunk(List<IMeasurementSchema> schemaList) {
+    this.measurementIndexMap = new LinkedHashMap<>();
+    List<TSDataType> dataTypeList = new ArrayList<>();
+    this.schemaList = schemaList;
+    for (int i = 0; i < schemaList.size(); i++) {
+      measurementIndexMap.put(schemaList.get(i).getMeasurementId(), i);
+      dataTypeList.add(schemaList.get(i).getType());
+    }
+    this.list = AlignedTVList.newAlignedList(dataTypeList);
+  }
+
+  public Set<String> getAllMeasurements() {
+    return measurementIndexMap.keySet();
+  }
+
+  public boolean containsMeasurement(String measurementId) {
+    return measurementIndexMap.containsKey(measurementId);
+  }
+
+  @Override
+  public void putLong(long t, long v) {
+    throw new UnSupportedDataTypeException(UNSUPPORTED_TYPE + 
TSDataType.VECTOR);
+  }
+
+  @Override
+  public void putInt(long t, int v) {
+    throw new UnSupportedDataTypeException(UNSUPPORTED_TYPE + 
TSDataType.VECTOR);
+  }
+
+  @Override
+  public void putFloat(long t, float v) {
+    throw new UnSupportedDataTypeException(UNSUPPORTED_TYPE + 
TSDataType.VECTOR);
+  }
+
+  @Override
+  public void putDouble(long t, double v) {
+    throw new UnSupportedDataTypeException(UNSUPPORTED_TYPE + 
TSDataType.VECTOR);
+  }
+
+  @Override
+  public void putBinary(long t, Binary v) {
+    throw new UnSupportedDataTypeException(UNSUPPORTED_TYPE + 
TSDataType.VECTOR);
+  }
+
+  @Override
+  public void putBoolean(long t, boolean v) {
+    throw new UnSupportedDataTypeException(UNSUPPORTED_TYPE + 
TSDataType.VECTOR);
+  }
+
+  @Override
+  public void putAlignedValue(long t, Object[] v, int[] columnIndexArray) {
+    list.putAlignedValue(t, v, columnIndexArray);
+  }
+
+  @Override
+  public void putLongs(long[] t, long[] v, BitMap bitMap, int start, int end) {
+    throw new UnSupportedDataTypeException(UNSUPPORTED_TYPE + 
TSDataType.VECTOR);
+  }
+
+  @Override
+  public void putInts(long[] t, int[] v, BitMap bitMap, int start, int end) {
+    throw new UnSupportedDataTypeException(UNSUPPORTED_TYPE + 
TSDataType.VECTOR);
+  }
+
+  @Override
+  public void putFloats(long[] t, float[] v, BitMap bitMap, int start, int 
end) {
+    throw new UnSupportedDataTypeException(UNSUPPORTED_TYPE + 
TSDataType.VECTOR);
+  }
+
+  @Override
+  public void putDoubles(long[] t, double[] v, BitMap bitMap, int start, int 
end) {
+    throw new UnSupportedDataTypeException(UNSUPPORTED_TYPE + 
TSDataType.VECTOR);
+  }
+
+  @Override
+  public void putBinaries(long[] t, Binary[] v, BitMap bitMap, int start, int 
end) {
+    throw new UnSupportedDataTypeException(UNSUPPORTED_TYPE + 
TSDataType.VECTOR);
+  }
+
+  @Override
+  public void putBooleans(long[] t, boolean[] v, BitMap bitMap, int start, int 
end) {
+    throw new UnSupportedDataTypeException(UNSUPPORTED_TYPE + 
TSDataType.VECTOR);
+  }
+
+  @Override
+  public void putAlignedValues(
+      long[] t, Object[] v, BitMap[] bitMaps, int[] columnIndexArray, int 
start, int end) {
+    list.putAlignedValues(t, v, bitMaps, columnIndexArray, start, end);
+  }
+
+  @Override
+  public void write(long insertTime, Object objectValue) {
+    throw new UnSupportedDataTypeException(UNSUPPORTED_TYPE + 
TSDataType.VECTOR);
+  }
+
+  @Override
+  public void writeAlignedValue(
+      long insertTime, Object[] objectValue, List<IMeasurementSchema> 
schemaList) {
+    int[] columnIndexArray = checkColumnsInInsertPlan(schemaList);
+    putAlignedValue(insertTime, objectValue, columnIndexArray);
+  }
+
+  @Override
+  public void write(
+      long[] times, Object valueList, BitMap bitMap, TSDataType dataType, int 
start, int end) {
+    throw new UnSupportedDataTypeException(UNSUPPORTED_TYPE + 
TSDataType.VECTOR);
+  }
+
+  @Override
+  public void writeAlignedValues(
+      long[] times,
+      Object[] valueList,
+      BitMap[] bitMaps,
+      List<IMeasurementSchema> schemaList,
+      int start,
+      int end) {
+    int[] columnIndexArray = checkColumnsInInsertPlan(schemaList);
+    putAlignedValues(times, valueList, bitMaps, columnIndexArray, start, end);
+  }
+
+  private int[] checkColumnsInInsertPlan(List<IMeasurementSchema> 
schemaListInInsertPlan) {
+    Map<String, Integer> measurementIdsInInsertPlan = new HashMap<>();
+    for (int i = 0; i < schemaListInInsertPlan.size(); i++) {
+      
measurementIdsInInsertPlan.put(schemaListInInsertPlan.get(i).getMeasurementId(),
 i);
+      if 
(!containsMeasurement(schemaListInInsertPlan.get(i).getMeasurementId())) {
+        this.measurementIndexMap.put(
+            schemaListInInsertPlan.get(i).getMeasurementId(), 
measurementIndexMap.size());
+        this.schemaList.add(schemaListInInsertPlan.get(i));
+        this.list.extendColumn(schemaListInInsertPlan.get(i).getType());
+      }
+    }
+    int[] columnIndexArray = new int[measurementIndexMap.size()];
+    measurementIndexMap.forEach(
+        (measurementId, i) -> {
+          columnIndexArray[i] = 
measurementIdsInInsertPlan.getOrDefault(measurementId, -1);
+        });
+    return columnIndexArray;
+  }
+
+  @Override
+  public TVList getTVList() {
+    return list;
+  }
+
+  @Override
+  public long count() {
+    return (long) list.rowCount() * measurementIndexMap.size();
+  }
+
+  public long alignedListSize() {
+    return list.rowCount();
+  }
+
+  @Override
+  public IMeasurementSchema getSchema() {
+    return null;
+  }
+
+  public List<IMeasurementSchema> getSchemaList() {
+    return schemaList;
+  }
+
+  public AlignedTVList getList() {
+    return list;
+  }
+
+  @Override
+  public TVList getSortedTvListForQuery() {
+    sortTVList();
+    // increase reference count
+    list.increaseReferenceCount();
+    return list;
+  }
+
+  @Override
+  public TVList getSortedTvListForQuery(List<IMeasurementSchema> schemaList) {
+    sortTVList();
+    // increase reference count
+    list.increaseReferenceCount();
+    List<Integer> columnIndexList = new ArrayList<>();
+    for (IMeasurementSchema measurementSchema : schemaList) {
+      columnIndexList.add(
+          
measurementIndexMap.getOrDefault(measurementSchema.getMeasurementId(), -1));
+    }
+    return list.getTvListByColumnIndex(columnIndexList);
+  }
+
+  private void sortTVList() {
+    // check reference count
+    if ((list.getReferenceCount() > 0 && !list.isSorted())) {
+      list = list.clone();
+    }
+
+    if (!list.isSorted()) {
+      list.sort();
+    }
+  }
+
+  @Override
+  public void sortTvListForFlush() {
+    sortTVList();
+  }
+
+  @Override
+  public int delete(long lowerBound, long upperBound) {
+    return list.delete(lowerBound, upperBound);
+  }
+
+  public Pair<Integer, Boolean> deleteDataFromAColumn(
+      long lowerBound, long upperBound, String measurementId) {
+    return list.delete(lowerBound, upperBound, 
measurementIndexMap.get(measurementId));
+  }
+
+  public void removeColumn(String measurementId) {
+    list.deleteColumn(measurementIndexMap.get(measurementId));
+    IMeasurementSchema schemaToBeRemoved = 
schemaList.get(measurementIndexMap.get(measurementId));
+    schemaList.remove(schemaToBeRemoved);
+    measurementIndexMap.clear();
+    for (int i = 0; i < schemaList.size(); i++) {
+      measurementIndexMap.put(schemaList.get(i).getMeasurementId(), i);
+    }
+  }
+
+  @Override
+  public IChunkWriter createIChunkWriter() {
+    return new AutoAlignedChunkWriterImpl(schemaList);
+  }
+
+  @Override
+  public void encode(IChunkWriter chunkWriter) {
+    AutoAlignedChunkWriterImpl autoAlignedChunkWriter = 
(AutoAlignedChunkWriterImpl) chunkWriter;
+    List<Integer> timeDuplicateAlignedRowIndexList = null;
+    for (int sortedRowIndex = 0; sortedRowIndex < list.rowCount(); 
sortedRowIndex++) {
+      long time = list.getTime(sortedRowIndex);
+
+      // skip duplicated data
+      if ((sortedRowIndex + 1 < list.rowCount() && (time == 
list.getTime(sortedRowIndex + 1)))) {
+        // record the time duplicated row index list for vector type
+        if (timeDuplicateAlignedRowIndexList == null) {
+          timeDuplicateAlignedRowIndexList = new ArrayList<>();
+          
timeDuplicateAlignedRowIndexList.add(list.getValueIndex(sortedRowIndex));
+        }
+        timeDuplicateAlignedRowIndexList.add(list.getValueIndex(sortedRowIndex 
+ 1));
+        continue;
+      }
+      List<TSDataType> dataTypes = list.getTsDataTypes();
+      int originRowIndex = list.getValueIndex(sortedRowIndex);
+      for (int columnIndex = 0; columnIndex < dataTypes.size(); columnIndex++) 
{
+        // write the time duplicated rows
+        if (timeDuplicateAlignedRowIndexList != null
+            && !timeDuplicateAlignedRowIndexList.isEmpty()) {
+          originRowIndex =
+              list.getValidRowIndexForTimeDuplicatedRows(
+                  timeDuplicateAlignedRowIndexList, columnIndex);
+        }
+        boolean isNull = list.isValueMarked(originRowIndex, columnIndex);
+        switch (dataTypes.get(columnIndex)) {
+          case BOOLEAN:
+            autoAlignedChunkWriter.write(
+                time, list.getBooleanByValueIndex(originRowIndex, 
columnIndex), isNull);
+            break;
+          case INT32:
+            autoAlignedChunkWriter.write(
+                time, list.getIntByValueIndex(originRowIndex, columnIndex), 
isNull);
+            break;
+          case INT64:
+            autoAlignedChunkWriter.write(
+                time, list.getLongByValueIndex(originRowIndex, columnIndex), 
isNull);
+            break;
+          case FLOAT:
+            autoAlignedChunkWriter.write(
+                time, list.getFloatByValueIndex(originRowIndex, columnIndex), 
isNull);
+            break;
+          case DOUBLE:
+            autoAlignedChunkWriter.write(
+                time, list.getDoubleByValueIndex(originRowIndex, columnIndex), 
isNull);
+            break;
+          case TEXT:
+            autoAlignedChunkWriter.write(
+                time, list.getBinaryByValueIndex(originRowIndex, columnIndex), 
isNull);
+            break;
+          default:
+            LOGGER.error(
+                "AlignedWritableMemChunk does not support data type: {}",
+                dataTypes.get(columnIndex));
+            break;
+        }
+      }
+      autoAlignedChunkWriter.write(time);
+      timeDuplicateAlignedRowIndexList = null;
+    }
+  }
+
+  @Override
+  public void release() {
+    if (list.getReferenceCount() == 0) {
+      list.clear();
+    }
+  }
+
+  @Override
+  public long getFirstPoint() {
+    if (list.rowCount() == 0) {
+      return Long.MAX_VALUE;
+    }
+    return getSortedTvListForQuery().getTimeValuePair(0).getTimestamp();
+  }
+
+  @Override
+  public long getLastPoint() {
+    if (list.rowCount() == 0) {
+      return Long.MIN_VALUE;
+    }
+    return getSortedTvListForQuery()
+        .getTimeValuePair(getSortedTvListForQuery().rowCount() - 1)
+        .getTimestamp();
+  }
+}
diff --git 
a/server/src/main/java/org/apache/iotdb/db/engine/memtable/AutoAlignedWritableMemChunkGroup.java
 
b/server/src/main/java/org/apache/iotdb/db/engine/memtable/AutoAlignedWritableMemChunkGroup.java
new file mode 100644
index 0000000..8801f82
--- /dev/null
+++ 
b/server/src/main/java/org/apache/iotdb/db/engine/memtable/AutoAlignedWritableMemChunkGroup.java
@@ -0,0 +1,116 @@
+/*
+ * 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.engine.memtable;
+
+import org.apache.iotdb.db.metadata.path.AlignedPath;
+import org.apache.iotdb.db.metadata.path.PartialPath;
+import org.apache.iotdb.tsfile.utils.BitMap;
+import org.apache.iotdb.tsfile.utils.Pair;
+import org.apache.iotdb.tsfile.write.schema.IMeasurementSchema;
+
+import java.util.*;
+
+public class AutoAlignedWritableMemChunkGroup implements 
IWritableMemChunkGroup {
+
+  private AutoAlignedWritableMemChunk memChunk;
+
+  public AutoAlignedWritableMemChunkGroup(List<IMeasurementSchema> schemaList) 
{
+    memChunk = new AutoAlignedWritableMemChunk(schemaList);
+  }
+
+  @Override
+  public void writeValues(
+      long[] times,
+      Object[] columns,
+      BitMap[] bitMaps,
+      List<IMeasurementSchema> schemaList,
+      int start,
+      int end) {
+    memChunk.writeAlignedValues(times, columns, bitMaps, schemaList, start, 
end);
+  }
+
+  @Override
+  public void release() {
+    memChunk.release();
+  }
+
+  @Override
+  public long count() {
+    return memChunk.count();
+  }
+
+  /**
+   * Check whether this MemChunkGroup contains a measurement. If a 
VECTOR_PLACEHOLDER passed from
+   * outer, always return true because AlignedMemChunkGroup existing.
+   */
+  @Override
+  public boolean contains(String measurement) {
+    // used for calculate memtable size
+    if (AlignedPath.VECTOR_PLACEHOLDER.equals(measurement)) {
+      return true;
+    }
+    return memChunk.containsMeasurement(measurement);
+  }
+
+  @Override
+  public void write(long insertTime, Object[] objectValue, 
List<IMeasurementSchema> schemaList) {
+    memChunk.writeAlignedValue(insertTime, objectValue, schemaList);
+  }
+
+  @Override
+  public Map<String, IWritableMemChunk> getMemChunkMap() {
+    if (memChunk.count() == 0) {
+      return Collections.emptyMap();
+    }
+    return Collections.singletonMap("", memChunk);
+  }
+
+  @Override
+  public int delete(
+      PartialPath originalPath, PartialPath devicePath, long startTimestamp, 
long endTimestamp) {
+    int deletedPointsNumber = 0;
+    Set<String> measurements = memChunk.getAllMeasurements();
+    List<String> columnsToBeRemoved = new ArrayList<>();
+    for (String measurement : measurements) {
+      PartialPath fullPath = devicePath.concatNode(measurement);
+      if (originalPath.matchFullPath(fullPath)) {
+        Pair<Integer, Boolean> deleteInfo =
+            memChunk.deleteDataFromAColumn(startTimestamp, endTimestamp, 
measurement);
+        deletedPointsNumber += deleteInfo.left;
+        if (Boolean.TRUE.equals(deleteInfo.right)) {
+          columnsToBeRemoved.add(measurement);
+        }
+      }
+    }
+    for (String columnToBeRemoved : columnsToBeRemoved) {
+      memChunk.removeColumn(columnToBeRemoved);
+    }
+    return deletedPointsNumber;
+  }
+
+  @Override
+  public long getCurrentTVListSize(String measurement) {
+    return memChunk.getTVList().rowCount();
+  }
+
+  public AutoAlignedWritableMemChunk getAlignedMemChunk() {
+    return memChunk;
+  }
+}
diff --git 
a/server/src/main/java/org/apache/iotdb/db/engine/memtable/IMemTable.java 
b/server/src/main/java/org/apache/iotdb/db/engine/memtable/IMemTable.java
index 69aeb47..0867197 100644
--- a/server/src/main/java/org/apache/iotdb/db/engine/memtable/IMemTable.java
+++ b/server/src/main/java/org/apache/iotdb/db/engine/memtable/IMemTable.java
@@ -57,6 +57,12 @@ public interface IMemTable {
       List<IMeasurementSchema> schemaList,
       long insertTime,
       Object[] objectValue);
+
+  void writeAutoAlignedRow(
+      IDeviceID deviceId,
+      List<IMeasurementSchema> schemaList,
+      long insertTime,
+      Object[] objectValue);
   /**
    * write data in the range [start, end). Null value in each column values 
will be replaced by the
    * subsequent non-null value, e.g., {1, null, 3, null, 5} will be {1, 3, 5, 
null, 5}
@@ -100,6 +106,8 @@ public interface IMemTable {
 
   void insertAlignedRow(InsertRowPlan insertRowPlan);
 
+  void insertAutoAlignedRow(InsertRowPlan insertRowPlan);
+
   /**
    * insert tablet into this memtable. The rows to be inserted are in the 
range [start, end). Null
    * value in each column values will be replaced by the subsequent non-null 
value, e.g., {1, null,
diff --git 
a/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/TsFileProcessor.java
 
b/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/TsFileProcessor.java
index 71eaef1..fda3d04 100644
--- 
a/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/TsFileProcessor.java
+++ 
b/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/TsFileProcessor.java
@@ -27,10 +27,7 @@ import org.apache.iotdb.db.engine.flush.FlushListener;
 import org.apache.iotdb.db.engine.flush.FlushManager;
 import org.apache.iotdb.db.engine.flush.MemTableFlushTask;
 import org.apache.iotdb.db.engine.flush.NotifyFlushMemTable;
-import org.apache.iotdb.db.engine.memtable.AlignedWritableMemChunk;
-import org.apache.iotdb.db.engine.memtable.AlignedWritableMemChunkGroup;
-import org.apache.iotdb.db.engine.memtable.IMemTable;
-import org.apache.iotdb.db.engine.memtable.PrimitiveMemTable;
+import org.apache.iotdb.db.engine.memtable.*;
 import org.apache.iotdb.db.engine.modification.Deletion;
 import org.apache.iotdb.db.engine.modification.Modification;
 import org.apache.iotdb.db.engine.querycontext.ReadOnlyMemChunk;
@@ -217,7 +214,9 @@ public class TsFileProcessor {
 
     long[] memIncrements = null;
     if (enableMemControl) {
-      if (insertRowPlan.isAligned()) {
+      if (insertRowPlan.isAutoAligned()) {
+        memIncrements = checkAutoAlignedMemCostAndAddToTspInfo(insertRowPlan);
+      } else if (insertRowPlan.isAligned()) {
         memIncrements = checkAlignedMemCostAndAddToTspInfo(insertRowPlan);
       } else {
         memIncrements = checkMemCostAndAddToTspInfo(insertRowPlan);
@@ -239,7 +238,9 @@ public class TsFileProcessor {
       }
     }
 
-    if (insertRowPlan.isAligned()) {
+    if (insertRowPlan.isAutoAligned()) {
+      workMemTable.insertAutoAlignedRow(insertRowPlan);
+    } else if (insertRowPlan.isAligned()) {
       workMemTable.insertAlignedRow(insertRowPlan);
     } else {
       workMemTable.insert(insertRowPlan);
@@ -384,6 +385,60 @@ public class TsFileProcessor {
     return new long[] {memTableIncrement, textDataIncrement, 
chunkMetadataIncrement};
   }
 
+  private long[] checkAutoAlignedMemCostAndAddToTspInfo(InsertRowPlan 
insertRowPlan)
+      throws WriteProcessException {
+    // memory of increased PrimitiveArray and TEXT values, e.g., add a 
long[128], add 128*8
+    long memTableIncrement = 0L;
+    long textDataIncrement = 0L;
+    long chunkMetadataIncrement = 0L;
+    AutoAlignedWritableMemChunk autoAlignedMemChunk = null;
+    // get device id
+    IDeviceID deviceID = null;
+    try {
+      deviceID = getDeviceID(insertRowPlan.getDevicePath().getFullPath());
+    } catch (IllegalPathException e) {
+      throw new WriteProcessException(e);
+    }
+
+    if (workMemTable.checkIfChunkDoesNotExist(deviceID, 
AlignedPath.VECTOR_PLACEHOLDER)) {
+      // ChunkMetadataIncrement
+      chunkMetadataIncrement +=
+          ChunkMetadata.calculateRamSize(AlignedPath.VECTOR_PLACEHOLDER, 
TSDataType.VECTOR)
+              * insertRowPlan.getDataTypes().length;
+      memTableIncrement += 
AlignedTVList.alignedTvListArrayMemCost(insertRowPlan.getDataTypes());
+    } else {
+      // here currentChunkPointNum >= 1
+      long currentChunkPointNum =
+          workMemTable.getCurrentTVListSize(deviceID, 
AlignedPath.VECTOR_PLACEHOLDER);
+      memTableIncrement +=
+          (currentChunkPointNum % PrimitiveArrayManager.ARRAY_SIZE) == 0
+              ? 
AlignedTVList.alignedTvListArrayMemCost(insertRowPlan.getDataTypes())
+              : 0;
+      autoAlignedMemChunk =
+          ((AutoAlignedWritableMemChunkGroup) 
workMemTable.getMemTableMap().get(deviceID))
+              .getAlignedMemChunk();
+    }
+    for (int i = 0; i < insertRowPlan.getDataTypes().length; i++) {
+      // skip failed Measurements
+      if (insertRowPlan.getDataTypes()[i] == null || 
insertRowPlan.getMeasurements()[i] == null) {
+        continue;
+      }
+      // extending the column of aligned mem chunk
+      if (autoAlignedMemChunk != null
+          && 
!autoAlignedMemChunk.containsMeasurement(insertRowPlan.getMeasurements()[i])) {
+        memTableIncrement +=
+            (autoAlignedMemChunk.alignedListSize() / 
PrimitiveArrayManager.ARRAY_SIZE + 1)
+                * insertRowPlan.getDataTypes()[i].getDataTypeSize();
+      }
+      // TEXT data mem size
+      if (insertRowPlan.getDataTypes()[i] == TSDataType.TEXT) {
+        textDataIncrement += MemUtils.getBinarySize((Binary) 
insertRowPlan.getValues()[i]);
+      }
+    }
+    updateMemoryInfo(memTableIncrement, chunkMetadataIncrement, 
textDataIncrement);
+    return new long[] {memTableIncrement, textDataIncrement, 
chunkMetadataIncrement};
+  }
+
   @SuppressWarnings("squid:S3776") // high Cognitive Complexity
   private long[] checkAlignedMemCostAndAddToTspInfo(InsertRowPlan 
insertRowPlan)
       throws WriteProcessException {
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 a56f57e..2bbf1ed 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
@@ -60,26 +60,7 @@ import org.apache.iotdb.db.qp.physical.PhysicalPlan;
 import org.apache.iotdb.db.qp.physical.crud.InsertPlan;
 import org.apache.iotdb.db.qp.physical.crud.InsertRowPlan;
 import org.apache.iotdb.db.qp.physical.crud.InsertTabletPlan;
-import org.apache.iotdb.db.qp.physical.sys.ActivateTemplatePlan;
-import org.apache.iotdb.db.qp.physical.sys.AppendTemplatePlan;
-import org.apache.iotdb.db.qp.physical.sys.AutoCreateDeviceMNodePlan;
-import org.apache.iotdb.db.qp.physical.sys.ChangeAliasPlan;
-import org.apache.iotdb.db.qp.physical.sys.ChangeTagOffsetPlan;
-import org.apache.iotdb.db.qp.physical.sys.CreateAlignedTimeSeriesPlan;
-import org.apache.iotdb.db.qp.physical.sys.CreateContinuousQueryPlan;
-import org.apache.iotdb.db.qp.physical.sys.CreateTemplatePlan;
-import org.apache.iotdb.db.qp.physical.sys.CreateTimeSeriesPlan;
-import org.apache.iotdb.db.qp.physical.sys.DeleteStorageGroupPlan;
-import org.apache.iotdb.db.qp.physical.sys.DeleteTimeSeriesPlan;
-import org.apache.iotdb.db.qp.physical.sys.DropContinuousQueryPlan;
-import org.apache.iotdb.db.qp.physical.sys.DropTemplatePlan;
-import org.apache.iotdb.db.qp.physical.sys.PruneTemplatePlan;
-import org.apache.iotdb.db.qp.physical.sys.SetStorageGroupPlan;
-import org.apache.iotdb.db.qp.physical.sys.SetTTLPlan;
-import org.apache.iotdb.db.qp.physical.sys.SetTemplatePlan;
-import org.apache.iotdb.db.qp.physical.sys.ShowDevicesPlan;
-import org.apache.iotdb.db.qp.physical.sys.ShowTimeSeriesPlan;
-import org.apache.iotdb.db.qp.physical.sys.UnsetTemplatePlan;
+import org.apache.iotdb.db.qp.physical.sys.*;
 import org.apache.iotdb.db.query.context.QueryContext;
 import org.apache.iotdb.db.query.dataset.ShowDevicesResult;
 import org.apache.iotdb.db.query.dataset.ShowTimeSeriesResult;
@@ -454,6 +435,11 @@ public class MManager {
             (CreateAlignedTimeSeriesPlan) plan;
         createAlignedTimeSeries(createAlignedTimeSeriesPlan);
         break;
+      case CREATE_AUTOALIGNED_TIMESERIES:
+        CreateAutoAlignedTimeSeriesPlan createAutoAlignedTimeSeriesPlan =
+            (CreateAutoAlignedTimeSeriesPlan) plan;
+        createAutoAlignedTimeSeries(createAutoAlignedTimeSeriesPlan);
+        break;
       case DELETE_TIMESERIES:
         DeleteTimeSeriesPlan deleteTimeSeriesPlan = (DeleteTimeSeriesPlan) 
plan;
         // cause we only has one path for one DeleteTimeSeriesPlan
@@ -720,6 +706,74 @@ public class MManager {
     }
   }
 
+  public void createAutoAlignedTimeSeries(
+      PartialPath prefixPath,
+      List<String> measurements,
+      List<TSDataType> dataTypes,
+      List<TSEncoding> encodings,
+      List<CompressionType> compressors)
+      throws MetadataException {
+    createAutoAlignedTimeSeries(
+        new CreateAutoAlignedTimeSeriesPlan(
+            prefixPath, measurements, dataTypes, encodings, compressors, 
null));
+  }
+
+  /**
+   * create aligned timeseries
+   *
+   * @param plan CreateAlignedTimeSeriesPlan
+   */
+  public void createAutoAlignedTimeSeries(CreateAutoAlignedTimeSeriesPlan plan)
+      throws MetadataException {
+    if (!allowToCreateNewSeries) {
+      throw new MetadataException(
+          "IoTDB system load is too large to create timeseries, "
+              + "please increase MAX_HEAP_SIZE in iotdb-env.sh/bat and 
restart");
+    }
+    try {
+      PartialPath prefixPath = plan.getPrefixPath();
+      List<String> measurements = plan.getMeasurements();
+      List<TSDataType> dataTypes = plan.getDataTypes();
+      List<TSEncoding> encodings = plan.getEncodings();
+
+      for (int i = 0; i < measurements.size(); i++) {
+        SchemaUtils.checkDataTypeWithEncoding(dataTypes.get(i), 
encodings.get(i));
+      }
+
+      ensureStorageGroup(prefixPath);
+
+      // create time series in MTree
+      mtree.createAutoAlignedTimeseries(
+          prefixPath,
+          measurements,
+          plan.getDataTypes(),
+          plan.getEncodings(),
+          plan.getCompressors());
+
+      // the cached mNode may be replaced by new entityMNode in mtree
+      mNodeCache.invalidate(prefixPath);
+
+      // update statistics and schemaDataTypeNumMap
+      totalSeriesNumber.addAndGet(measurements.size());
+      if (totalSeriesNumber.get() * ESTIMATED_SERIES_SIZE >= 
MTREE_SIZE_THRESHOLD) {
+        logger.warn("Current series number {} is too large...", 
totalSeriesNumber);
+        allowToCreateNewSeries = false;
+      }
+      // write log
+      if (!isRecovering) {
+        logWriter.createAutoAlignedTimeseries(plan);
+      }
+    } catch (IOException e) {
+      throw new MetadataException(e);
+    }
+
+    // update id table
+    if (config.isEnableIDTable()) {
+      IDTable idTable = 
IDTableManager.getInstance().getIDTable(plan.getPrefixPath());
+      idTable.createAutoAlignedTimeseries(plan);
+    }
+  }
+
   private void ensureStorageGroup(PartialPath path) throws MetadataException {
     try {
       mtree.getBelongedStorageGroup(path);
diff --git 
a/server/src/main/java/org/apache/iotdb/db/metadata/idtable/IDTable.java 
b/server/src/main/java/org/apache/iotdb/db/metadata/idtable/IDTable.java
index 5ab0d47..93a377d 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/idtable/IDTable.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/idtable/IDTable.java
@@ -33,6 +33,7 @@ import org.apache.iotdb.db.metadata.path.MeasurementPath;
 import org.apache.iotdb.db.metadata.path.PartialPath;
 import org.apache.iotdb.db.qp.physical.crud.InsertPlan;
 import org.apache.iotdb.db.qp.physical.sys.CreateAlignedTimeSeriesPlan;
+import org.apache.iotdb.db.qp.physical.sys.CreateAutoAlignedTimeSeriesPlan;
 import org.apache.iotdb.db.qp.physical.sys.CreateTimeSeriesPlan;
 import org.apache.iotdb.db.utils.TestOnly;
 import org.apache.iotdb.tsfile.read.TimeValuePair;
@@ -52,6 +53,14 @@ public interface IDTable {
   IoTDBConfig config = IoTDBDescriptor.getInstance().getConfig();
 
   /**
+   * create autoaligned timeseries
+   *
+   * @param plan create aligned timeseries plan
+   * @throws MetadataException if the device is not aligned, throw it
+   */
+  void createAutoAlignedTimeseries(CreateAutoAlignedTimeSeriesPlan plan) 
throws MetadataException;
+
+  /**
    * create aligned timeseries
    *
    * @param plan create aligned timeseries plan
diff --git 
a/server/src/main/java/org/apache/iotdb/db/metadata/idtable/IDTableHashmapImpl.java
 
b/server/src/main/java/org/apache/iotdb/db/metadata/idtable/IDTableHashmapImpl.java
index fb21776..b07dcab 100644
--- 
a/server/src/main/java/org/apache/iotdb/db/metadata/idtable/IDTableHashmapImpl.java
+++ 
b/server/src/main/java/org/apache/iotdb/db/metadata/idtable/IDTableHashmapImpl.java
@@ -35,6 +35,7 @@ import org.apache.iotdb.db.qp.physical.crud.InsertPlan;
 import org.apache.iotdb.db.qp.physical.crud.InsertRowPlan;
 import org.apache.iotdb.db.qp.physical.crud.InsertTabletPlan;
 import org.apache.iotdb.db.qp.physical.sys.CreateAlignedTimeSeriesPlan;
+import org.apache.iotdb.db.qp.physical.sys.CreateAutoAlignedTimeSeriesPlan;
 import org.apache.iotdb.db.qp.physical.sys.CreateTimeSeriesPlan;
 import org.apache.iotdb.db.service.IoTDB;
 import org.apache.iotdb.db.utils.TestOnly;
@@ -110,6 +111,34 @@ public class IDTableHashmapImpl implements IDTable {
   }
 
   /**
+   * create autoaligned timeseries
+   *
+   * @param plan create aligned timeseries plan
+   * @throws MetadataException if the device is not aligned, throw it
+   */
+  public synchronized void 
createAutoAlignedTimeseries(CreateAutoAlignedTimeSeriesPlan plan)
+      throws MetadataException {
+    DeviceEntry deviceEntry =
+        getDeviceEntryWithAutoAlignedCheck(plan.getPrefixPath().toString(), 
true);
+
+    for (int i = 0; i < plan.getMeasurements().size(); i++) {
+      PartialPath fullPath =
+          new PartialPath(plan.getPrefixPath().toString(), 
plan.getMeasurements().get(i));
+      SchemaEntry schemaEntry =
+          new SchemaEntry(
+              plan.getDataTypes().get(i),
+              plan.getEncodings().get(i),
+              plan.getCompressors().get(i),
+              deviceEntry.getDeviceID(),
+              fullPath,
+              true,
+              true,
+              IDiskSchemaManager);
+      deviceEntry.putSchemaEntry(plan.getMeasurements().get(i), schemaEntry);
+    }
+  }
+
+  /**
    * create timeseries
    *
    * @param plan create timeseries plan
@@ -388,6 +417,33 @@ public class IDTableHashmapImpl implements IDTable {
     return deviceEntry;
   }
 
+  private DeviceEntry getDeviceEntryWithAutoAlignedCheck(String deviceName, 
boolean isAutoAligned)
+      throws MetadataException {
+    IDeviceID deviceID = DeviceIDFactory.getInstance().getDeviceID(deviceName);
+    int slot = calculateSlot(deviceID);
+
+    DeviceEntry deviceEntry = idTables[slot].get(deviceID);
+    // new device
+    if (deviceEntry == null) {
+      deviceEntry = new DeviceEntry(deviceID);
+      deviceEntry.setAutoAligned(isAutoAligned);
+      idTables[slot].put(deviceID, deviceEntry);
+
+      return deviceEntry;
+    }
+
+    // check aligned
+    if (deviceEntry.isAligned() != isAutoAligned) {
+      throw new MetadataException(
+          String.format(
+              "Timeseries under path [%s]'s align value is [%b], which is not 
consistent with insert plan",
+              deviceName, deviceEntry.isAligned()));
+    }
+
+    // reuse device entry in map
+    return deviceEntry;
+  }
+
   /**
    * calculate slot that this deviceID should in
    *
diff --git 
a/server/src/main/java/org/apache/iotdb/db/metadata/idtable/entry/DeviceEntry.java
 
b/server/src/main/java/org/apache/iotdb/db/metadata/idtable/entry/DeviceEntry.java
index e5cbd90..7fbb35c 100644
--- 
a/server/src/main/java/org/apache/iotdb/db/metadata/idtable/entry/DeviceEntry.java
+++ 
b/server/src/main/java/org/apache/iotdb/db/metadata/idtable/entry/DeviceEntry.java
@@ -34,6 +34,7 @@ public class DeviceEntry {
   Map<String, SchemaEntry> measurementMap;
 
   boolean isAligned;
+  boolean isAutoAligned;
 
   // for managing last time
   // time partition -> last time
@@ -86,10 +87,18 @@ public class DeviceEntry {
     return isAligned;
   }
 
+  public boolean isAutoAligned() {
+    return isAutoAligned;
+  }
+
   public void setAligned(boolean aligned) {
     isAligned = aligned;
   }
 
+  public void setAutoAligned(boolean autoAligned) {
+    isAutoAligned = autoAligned;
+  }
+
   public IDeviceID getDeviceID() {
     return deviceID;
   }
diff --git 
a/server/src/main/java/org/apache/iotdb/db/metadata/idtable/entry/DiskSchemaEntry.java
 
b/server/src/main/java/org/apache/iotdb/db/metadata/idtable/entry/DiskSchemaEntry.java
index 556759b..bfb984e 100644
--- 
a/server/src/main/java/org/apache/iotdb/db/metadata/idtable/entry/DiskSchemaEntry.java
+++ 
b/server/src/main/java/org/apache/iotdb/db/metadata/idtable/entry/DiskSchemaEntry.java
@@ -50,6 +50,9 @@ public class DiskSchemaEntry {
   // whether this device is aligned
   public boolean isAligned;
 
+  // whether this device is autoaligned
+  public boolean isAutoAligned;
+
   // this entry's serialized size
   public transient long entrySize;
 
@@ -72,6 +75,25 @@ public class DiskSchemaEntry {
     this.isAligned = isAligned;
   }
 
+  public DiskSchemaEntry(
+      String deviceID,
+      String seriesKey,
+      String measurementName,
+      byte type,
+      byte encoding,
+      byte compressor,
+      boolean isAligned,
+      boolean isAutoAligned) {
+    this.deviceID = deviceID;
+    this.seriesKey = seriesKey;
+    this.measurementName = measurementName;
+    this.type = type;
+    this.encoding = encoding;
+    this.compressor = compressor;
+    this.isAligned = isAligned;
+    this.isAutoAligned = isAutoAligned;
+  }
+
   public int serialize(OutputStream outputStream) throws IOException {
     int byteLen = 0;
     byteLen += ReadWriteIOUtils.write(deviceID, outputStream);
diff --git 
a/server/src/main/java/org/apache/iotdb/db/metadata/idtable/entry/SchemaEntry.java
 
b/server/src/main/java/org/apache/iotdb/db/metadata/idtable/entry/SchemaEntry.java
index 77a07e1..f660979 100644
--- 
a/server/src/main/java/org/apache/iotdb/db/metadata/idtable/entry/SchemaEntry.java
+++ 
b/server/src/main/java/org/apache/iotdb/db/metadata/idtable/entry/SchemaEntry.java
@@ -109,6 +109,37 @@ public class SchemaEntry implements ILastCacheContainer {
     }
   }
 
+  public SchemaEntry(
+      TSDataType dataType,
+      TSEncoding encoding,
+      CompressionType compressionType,
+      IDeviceID deviceID,
+      PartialPath fullPath,
+      boolean isAligned,
+      boolean isAutoAligned,
+      IDiskSchemaManager IDiskSchemaManager) {
+    schema |= dataType.serialize();
+    schema |= (((long) encoding.serialize()) << 8);
+    schema |= (((long) compressionType.serialize()) << 16);
+
+    lastTime = Long.MIN_VALUE;
+
+    // write log file
+    if (config.isEnableIDTableLogFile()) {
+      DiskSchemaEntry diskSchemaEntry =
+          new DiskSchemaEntry(
+              deviceID.toStringID(),
+              fullPath.getFullPath(),
+              fullPath.getMeasurement(),
+              dataType.serialize(),
+              encoding.serialize(),
+              compressionType.serialize(),
+              isAligned,
+              isAutoAligned);
+      schema |= (IDiskSchemaManager.serialize(diskSchemaEntry) << 25);
+    }
+  }
+
   /**
    * get ts data type from long value of schema
    *
diff --git 
a/server/src/main/java/org/apache/iotdb/db/metadata/logfile/MLogWriter.java 
b/server/src/main/java/org/apache/iotdb/db/metadata/logfile/MLogWriter.java
index 303322d..fc347c1 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/logfile/MLogWriter.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/logfile/MLogWriter.java
@@ -25,27 +25,7 @@ import org.apache.iotdb.db.metadata.mnode.IMeasurementMNode;
 import org.apache.iotdb.db.metadata.mnode.IStorageGroupMNode;
 import org.apache.iotdb.db.metadata.path.PartialPath;
 import org.apache.iotdb.db.qp.physical.PhysicalPlan;
-import org.apache.iotdb.db.qp.physical.sys.ActivateTemplatePlan;
-import org.apache.iotdb.db.qp.physical.sys.AppendTemplatePlan;
-import org.apache.iotdb.db.qp.physical.sys.AutoCreateDeviceMNodePlan;
-import org.apache.iotdb.db.qp.physical.sys.ChangeAliasPlan;
-import org.apache.iotdb.db.qp.physical.sys.ChangeTagOffsetPlan;
-import org.apache.iotdb.db.qp.physical.sys.CreateAlignedTimeSeriesPlan;
-import org.apache.iotdb.db.qp.physical.sys.CreateContinuousQueryPlan;
-import org.apache.iotdb.db.qp.physical.sys.CreateTemplatePlan;
-import org.apache.iotdb.db.qp.physical.sys.CreateTimeSeriesPlan;
-import org.apache.iotdb.db.qp.physical.sys.DeleteStorageGroupPlan;
-import org.apache.iotdb.db.qp.physical.sys.DeleteTimeSeriesPlan;
-import org.apache.iotdb.db.qp.physical.sys.DropContinuousQueryPlan;
-import org.apache.iotdb.db.qp.physical.sys.DropTemplatePlan;
-import org.apache.iotdb.db.qp.physical.sys.MNodePlan;
-import org.apache.iotdb.db.qp.physical.sys.MeasurementMNodePlan;
-import org.apache.iotdb.db.qp.physical.sys.PruneTemplatePlan;
-import org.apache.iotdb.db.qp.physical.sys.SetStorageGroupPlan;
-import org.apache.iotdb.db.qp.physical.sys.SetTTLPlan;
-import org.apache.iotdb.db.qp.physical.sys.SetTemplatePlan;
-import org.apache.iotdb.db.qp.physical.sys.StorageGroupMNodePlan;
-import org.apache.iotdb.db.qp.physical.sys.UnsetTemplatePlan;
+import org.apache.iotdb.db.qp.physical.sys.*;
 import org.apache.iotdb.db.writelog.io.LogWriter;
 import org.apache.iotdb.tsfile.file.metadata.enums.CompressionType;
 import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
@@ -128,6 +108,11 @@ public class MLogWriter implements AutoCloseable {
     putLog(createAlignedTimeSeriesPlan);
   }
 
+  public void createAutoAlignedTimeseries(
+      CreateAutoAlignedTimeSeriesPlan createAutoAlignedTimeSeriesPlan) throws 
IOException {
+    putLog(createAutoAlignedTimeSeriesPlan);
+  }
+
   public void deleteTimeseries(DeleteTimeSeriesPlan deleteTimeSeriesPlan) 
throws IOException {
     putLog(deleteTimeSeriesPlan);
   }
diff --git 
a/server/src/main/java/org/apache/iotdb/db/metadata/mnode/EntityMNode.java 
b/server/src/main/java/org/apache/iotdb/db/metadata/mnode/EntityMNode.java
index 7bbb69d..62af863 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/mnode/EntityMNode.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/mnode/EntityMNode.java
@@ -37,6 +37,8 @@ public class EntityMNode extends InternalMNode implements 
IEntityMNode {
 
   private volatile boolean isAligned = false;
 
+  private volatile boolean isAutoAligned = false;
+
   private volatile Map<String, ILastCacheContainer> lastCacheMap = null;
 
   /**
@@ -111,10 +113,20 @@ public class EntityMNode extends InternalMNode implements 
IEntityMNode {
   }
 
   @Override
+  public boolean isAutoAligned() {
+    return isAutoAligned;
+  }
+
+  @Override
   public void setAligned(boolean isAligned) {
     this.isAligned = isAligned;
   }
 
+  @Override
+  public void setAutoAligned(boolean isAutoAligned) {
+    this.isAutoAligned = isAutoAligned;
+  }
+
   public ILastCacheContainer getLastCacheContainer(String measurementId) {
     checkLastCacheMap();
     return lastCacheMap.computeIfAbsent(measurementId, k -> new 
LastCacheContainer());
diff --git 
a/server/src/main/java/org/apache/iotdb/db/metadata/mnode/IEntityMNode.java 
b/server/src/main/java/org/apache/iotdb/db/metadata/mnode/IEntityMNode.java
index a6780cb..0f3885d 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/mnode/IEntityMNode.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/mnode/IEntityMNode.java
@@ -39,8 +39,12 @@ public interface IEntityMNode extends IMNode {
 
   boolean isAligned();
 
+  boolean isAutoAligned();
+
   void setAligned(boolean isAligned);
 
+  void setAutoAligned(boolean isAutoAligned);
+
   ILastCacheContainer getLastCacheContainer(String measurementId);
 
   Map<String, ILastCacheContainer> getTemplateLastCaches();
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/mtree/MTree.java 
b/server/src/main/java/org/apache/iotdb/db/metadata/mtree/MTree.java
index bddc4cf..fc56048 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/mtree/MTree.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/mtree/MTree.java
@@ -486,6 +486,69 @@ public class MTree implements Serializable {
     }
   }
 
+  /**
+   * Create aligned timeseries with full paths from root to one leaf node. 
Before creating
+   * timeseries, the * storage group should be set first, throw exception 
otherwise
+   *
+   * @param devicePath device path
+   * @param measurements measurements list
+   * @param dataTypes data types list
+   * @param encodings encodings list
+   * @param compressors compressor
+   */
+  public void createAutoAlignedTimeseries(
+      PartialPath devicePath,
+      List<String> measurements,
+      List<TSDataType> dataTypes,
+      List<TSEncoding> encodings,
+      List<CompressionType> compressors)
+      throws MetadataException {
+    MetaFormatUtils.checkSchemaMeasurementNames(measurements);
+    Pair<IMNode, Template> pair = checkAndAutoCreateInternalPath(devicePath);
+    IMNode cur = pair.left;
+    Template upperTemplate = pair.right;
+
+    // synchronize check and add, we need addChild and add Alias become atomic 
operation
+    // only write on mtree will be synchronized
+    synchronized (this) {
+      for (String measurement : measurements) {
+        if (cur.hasChild(measurement)) {
+          throw new PathAlreadyExistException(devicePath.getFullPath() + "." + 
measurement);
+        }
+      }
+
+      if (upperTemplate != null) {
+        for (String measurement : measurements) {
+          if (upperTemplate.getDirectNode(measurement) != null) {
+            throw new TemplateImcompatibeException(
+                devicePath.concatNode(measurement).getFullPath(), 
upperTemplate.getName());
+          }
+        }
+      }
+
+      if (cur.isEntity() && !cur.getAsEntityMNode().isAligned()) {
+        throw new AlignedTimeseriesException(
+            "Timeseries under this entity is not aligned, please use 
createTimeseries or change entity.",
+            devicePath.getFullPath());
+      }
+
+      IEntityMNode entityMNode = MNodeUtils.setToEntity(cur);
+      entityMNode.setAligned(true);
+      entityMNode.setAutoAligned(true);
+
+      for (int i = 0; i < measurements.size(); i++) {
+        IMeasurementMNode measurementMNode =
+            MeasurementMNode.getMeasurementMNode(
+                entityMNode,
+                measurements.get(i),
+                new MeasurementSchema(
+                    measurements.get(i), dataTypes.get(i), encodings.get(i), 
compressors.get(i)),
+                null);
+        entityMNode.addChild(measurements.get(i), measurementMNode);
+      }
+    }
+  }
+
   private Pair<IMNode, Template> checkAndAutoCreateInternalPath(PartialPath 
devicePath)
       throws MetadataException {
     String[] nodeNames = devicePath.getNodes();
diff --git 
a/server/src/main/java/org/apache/iotdb/db/qp/executor/PlanExecutor.java 
b/server/src/main/java/org/apache/iotdb/db/qp/executor/PlanExecutor.java
index 9540444..198631c 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/executor/PlanExecutor.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/executor/PlanExecutor.java
@@ -273,6 +273,8 @@ public class PlanExecutor implements IPlanExecutor {
         return createTimeSeries((CreateTimeSeriesPlan) plan);
       case CREATE_ALIGNED_TIMESERIES:
         return createAlignedTimeSeries((CreateAlignedTimeSeriesPlan) plan);
+      case CREATE_AUTOALIGNED_TIMESERIES:
+        return createAutoAlignedTimeSeries((CreateAutoAlignedTimeSeriesPlan) 
plan);
       case CREATE_MULTI_TIMESERIES:
         return createMultiTimeSeries((CreateMultiTimeSeriesPlan) plan);
       case ALTER_TIMESERIES:
@@ -1826,6 +1828,17 @@ public class PlanExecutor implements IPlanExecutor {
     return true;
   }
 
+  private boolean createAutoAlignedTimeSeries(
+      CreateAutoAlignedTimeSeriesPlan createAutoAlignedTimeSeriesPlan)
+      throws QueryProcessException {
+    try {
+      
IoTDB.metaManager.createAutoAlignedTimeSeries(createAutoAlignedTimeSeriesPlan);
+    } catch (MetadataException e) {
+      throw new QueryProcessException(e);
+    }
+    return true;
+  }
+
   @SuppressWarnings("squid:S3776") // high Cognitive Complexity
   private boolean createMultiTimeSeries(CreateMultiTimeSeriesPlan multiPlan)
       throws BatchProcessException {
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/logical/Operator.java 
b/server/src/main/java/org/apache/iotdb/db/qp/logical/Operator.java
index de439e9..4e8a7a8 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/logical/Operator.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/logical/Operator.java
@@ -194,6 +194,7 @@ public abstract class Operator {
     APPEND_TEMPLATE,
     DROP_TEMPLATE,
 
-    SHOW_QUERY_RESOURCE
+    SHOW_QUERY_RESOURCE,
+    CREATE_AUTOALIGNED_TIMESERIES
   }
 }
diff --git 
a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/InsertOperator.java 
b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/InsertOperator.java
index 99176c4..dc247d3 100644
--- 
a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/InsertOperator.java
+++ 
b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/InsertOperator.java
@@ -39,6 +39,7 @@ public class InsertOperator extends Operator {
   private List<String[]> valueLists;
 
   private boolean isAligned;
+  private boolean isAutoAligned;
 
   public InsertOperator(int tokenIntType) {
     super(tokenIntType);
@@ -85,6 +86,11 @@ public class InsertOperator extends Operator {
     isAligned = aligned;
   }
 
+  public void setAutoAligned(boolean autoAligned) {
+    isAligned = autoAligned;
+    isAutoAligned = autoAligned;
+  }
+
   @Override
   public PhysicalPlan generatePhysicalPlan(PhysicalGenerator generator)
       throws QueryProcessException {
@@ -99,6 +105,7 @@ public class InsertOperator extends Operator {
       InsertRowPlan insertRowPlan =
           new InsertRowPlan(device, times[0], measurementList, 
valueLists.get(0));
       insertRowPlan.setAligned(isAligned);
+      insertRowPlan.setAutoAligned(isAutoAligned);
       return insertRowPlan;
     }
     InsertRowsPlan insertRowsPlan = new InsertRowsPlan();
@@ -112,6 +119,7 @@ public class InsertOperator extends Operator {
       InsertRowPlan insertRowPlan =
           new InsertRowPlan(device, times[i], measurementList.clone(), 
valueLists.get(i));
       insertRowPlan.setAligned(isAligned);
+      insertRowPlan.setAutoAligned(isAutoAligned);
       insertRowsPlan.addOneInsertRowPlan(insertRowPlan, i);
     }
     return insertRowsPlan;
diff --git 
a/server/src/main/java/org/apache/iotdb/db/qp/logical/sys/CreateAutoAlignedTimeSeriesOperator.java
 
b/server/src/main/java/org/apache/iotdb/db/qp/logical/sys/CreateAutoAlignedTimeSeriesOperator.java
new file mode 100755
index 0000000..1f8072d
--- /dev/null
+++ 
b/server/src/main/java/org/apache/iotdb/db/qp/logical/sys/CreateAutoAlignedTimeSeriesOperator.java
@@ -0,0 +1,131 @@
+/*
+ * 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.qp.logical.sys;
+
+import org.apache.iotdb.db.exception.query.QueryProcessException;
+import org.apache.iotdb.db.exception.runtime.SQLParserException;
+import org.apache.iotdb.db.metadata.path.PartialPath;
+import org.apache.iotdb.db.qp.logical.Operator;
+import org.apache.iotdb.db.qp.physical.PhysicalPlan;
+import org.apache.iotdb.db.qp.physical.sys.CreateAutoAlignedTimeSeriesPlan;
+import org.apache.iotdb.db.qp.strategy.PhysicalGenerator;
+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 java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+public class CreateAutoAlignedTimeSeriesOperator extends Operator {
+
+  private PartialPath prefixPath;
+  private List<String> measurements = new ArrayList<>();
+  private List<TSDataType> dataTypes = new ArrayList<>();
+  private List<TSEncoding> encodings = new ArrayList<>();
+  private List<CompressionType> compressors = new ArrayList<>();
+  private List<String> aliasList = null;
+
+  public CreateAutoAlignedTimeSeriesOperator(int tokenIntType) {
+    super(tokenIntType);
+    operatorType = OperatorType.CREATE_ALIGNED_TIMESERIES;
+  }
+
+  public PartialPath getPrefixPath() {
+    return prefixPath;
+  }
+
+  public void setPrefixPath(PartialPath prefixPath) {
+    this.prefixPath = prefixPath;
+  }
+
+  public List<String> getMeasurements() {
+    return measurements;
+  }
+
+  public void setMeasurements(List<String> measurements) {
+    this.measurements = measurements;
+  }
+
+  public void addMeasurement(String measurement) {
+    this.measurements.add(measurement);
+  }
+
+  public List<TSDataType> getDataTypes() {
+    return dataTypes;
+  }
+
+  public void setDataTypes(List<TSDataType> dataTypes) {
+    this.dataTypes = dataTypes;
+  }
+
+  public void addDataType(TSDataType dataType) {
+    this.dataTypes.add(dataType);
+  }
+
+  public List<TSEncoding> getEncodings() {
+    return encodings;
+  }
+
+  public void setEncodings(List<TSEncoding> encodings) {
+    this.encodings = encodings;
+  }
+
+  public void addEncoding(TSEncoding encoding) {
+    this.encodings.add(encoding);
+  }
+
+  public List<CompressionType> getCompressors() {
+    return compressors;
+  }
+
+  public void setCompressors(List<CompressionType> compressors) {
+    this.compressors = compressors;
+  }
+
+  public void addCompressor(CompressionType compression) {
+    this.compressors.add(compression);
+  }
+
+  public List<String> getAliasList() {
+    return aliasList;
+  }
+
+  public void setAliasList(List<String> aliasList) {
+    this.aliasList = aliasList;
+  }
+
+  public void addAliasList(String alias) {
+    this.aliasList.add(alias);
+  }
+
+  @Override
+  public PhysicalPlan generatePhysicalPlan(PhysicalGenerator generator)
+      throws QueryProcessException {
+    Set<String> measurementSet = new HashSet<>(measurements);
+    if (measurementSet.size() < measurements.size()) {
+      throw new SQLParserException(
+          "the measurement under an aligned device is not allowed to have the 
same measurement name");
+    }
+
+    return new CreateAutoAlignedTimeSeriesPlan(
+        prefixPath, measurements, dataTypes, encodings, compressors, 
aliasList);
+  }
+}
diff --git 
a/server/src/main/java/org/apache/iotdb/db/qp/physical/PhysicalPlan.java 
b/server/src/main/java/org/apache/iotdb/db/qp/physical/PhysicalPlan.java
index 0267b03..c0df4de 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/physical/PhysicalPlan.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/physical/PhysicalPlan.java
@@ -30,48 +30,7 @@ import 
org.apache.iotdb.db.qp.physical.crud.InsertRowsOfOneDevicePlan;
 import org.apache.iotdb.db.qp.physical.crud.InsertRowsPlan;
 import org.apache.iotdb.db.qp.physical.crud.InsertTabletPlan;
 import org.apache.iotdb.db.qp.physical.crud.SelectIntoPlan;
-import org.apache.iotdb.db.qp.physical.sys.ActivateTemplatePlan;
-import org.apache.iotdb.db.qp.physical.sys.AlterTimeSeriesPlan;
-import org.apache.iotdb.db.qp.physical.sys.AppendTemplatePlan;
-import org.apache.iotdb.db.qp.physical.sys.AuthorPlan;
-import org.apache.iotdb.db.qp.physical.sys.AutoCreateDeviceMNodePlan;
-import org.apache.iotdb.db.qp.physical.sys.ChangeAliasPlan;
-import org.apache.iotdb.db.qp.physical.sys.ChangeTagOffsetPlan;
-import org.apache.iotdb.db.qp.physical.sys.ClearCachePlan;
-import org.apache.iotdb.db.qp.physical.sys.CreateAlignedTimeSeriesPlan;
-import org.apache.iotdb.db.qp.physical.sys.CreateContinuousQueryPlan;
-import org.apache.iotdb.db.qp.physical.sys.CreateFunctionPlan;
-import org.apache.iotdb.db.qp.physical.sys.CreateIndexPlan;
-import org.apache.iotdb.db.qp.physical.sys.CreateMultiTimeSeriesPlan;
-import org.apache.iotdb.db.qp.physical.sys.CreateSnapshotPlan;
-import org.apache.iotdb.db.qp.physical.sys.CreateTemplatePlan;
-import org.apache.iotdb.db.qp.physical.sys.CreateTimeSeriesPlan;
-import org.apache.iotdb.db.qp.physical.sys.CreateTriggerPlan;
-import org.apache.iotdb.db.qp.physical.sys.DataAuthPlan;
-import org.apache.iotdb.db.qp.physical.sys.DeleteStorageGroupPlan;
-import org.apache.iotdb.db.qp.physical.sys.DeleteTimeSeriesPlan;
-import org.apache.iotdb.db.qp.physical.sys.DropContinuousQueryPlan;
-import org.apache.iotdb.db.qp.physical.sys.DropFunctionPlan;
-import org.apache.iotdb.db.qp.physical.sys.DropIndexPlan;
-import org.apache.iotdb.db.qp.physical.sys.DropTemplatePlan;
-import org.apache.iotdb.db.qp.physical.sys.DropTriggerPlan;
-import org.apache.iotdb.db.qp.physical.sys.FlushPlan;
-import org.apache.iotdb.db.qp.physical.sys.LoadConfigurationPlan;
-import org.apache.iotdb.db.qp.physical.sys.LogPlan;
-import org.apache.iotdb.db.qp.physical.sys.MNodePlan;
-import org.apache.iotdb.db.qp.physical.sys.MeasurementMNodePlan;
-import org.apache.iotdb.db.qp.physical.sys.MergePlan;
-import org.apache.iotdb.db.qp.physical.sys.PruneTemplatePlan;
-import org.apache.iotdb.db.qp.physical.sys.SetStorageGroupPlan;
-import org.apache.iotdb.db.qp.physical.sys.SetSystemModePlan;
-import org.apache.iotdb.db.qp.physical.sys.SetTTLPlan;
-import org.apache.iotdb.db.qp.physical.sys.SetTemplatePlan;
-import org.apache.iotdb.db.qp.physical.sys.ShowDevicesPlan;
-import org.apache.iotdb.db.qp.physical.sys.ShowTimeSeriesPlan;
-import org.apache.iotdb.db.qp.physical.sys.StartTriggerPlan;
-import org.apache.iotdb.db.qp.physical.sys.StopTriggerPlan;
-import org.apache.iotdb.db.qp.physical.sys.StorageGroupMNodePlan;
-import org.apache.iotdb.db.qp.physical.sys.UnsetTemplatePlan;
+import org.apache.iotdb.db.qp.physical.sys.*;
 import org.apache.iotdb.db.qp.utils.EmptyOutputStream;
 import org.apache.iotdb.tsfile.utils.ReadWriteIOUtils;
 
@@ -328,6 +287,9 @@ public abstract class PhysicalPlan {
         case CREATE_ALIGNED_TIMESERIES:
           plan = new CreateAlignedTimeSeriesPlan();
           break;
+        case CREATE_AUTOALIGNED_TIMESERIES:
+          plan = new CreateAutoAlignedTimeSeriesPlan();
+          break;
         case DELETE_TIMESERIES:
           plan = new DeleteTimeSeriesPlan();
           break;
@@ -557,7 +519,8 @@ public abstract class PhysicalPlan {
     UNSET_TEMPLATE,
     APPEND_TEMPLATE,
     PRUNE_TEMPLATE,
-    DROP_TEMPLATE
+    DROP_TEMPLATE,
+    CREATE_AUTOALIGNED_TIMESERIES
   }
 
   public long getIndex() {
diff --git 
a/server/src/main/java/org/apache/iotdb/db/qp/physical/crud/InsertPlan.java 
b/server/src/main/java/org/apache/iotdb/db/qp/physical/crud/InsertPlan.java
index df71f87..809aa01 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/physical/crud/InsertPlan.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/physical/crud/InsertPlan.java
@@ -40,6 +40,8 @@ public abstract class InsertPlan extends PhysicalPlan {
   protected PartialPath devicePath;
 
   protected boolean isAligned;
+  protected boolean isAutoAligned;
+
   protected String[] measurements;
   // get from client
   protected TSDataType[] dataTypes;
@@ -115,10 +117,18 @@ public abstract class InsertPlan extends PhysicalPlan {
     return isAligned;
   }
 
+  public boolean isAutoAligned() {
+    return isAutoAligned;
+  }
+
   public void setAligned(boolean aligned) {
     isAligned = aligned;
   }
 
+  public void setAutoAligned(boolean autoAligned) {
+    isAutoAligned = autoAligned;
+  }
+
   public abstract long getMinTime();
 
   /**
diff --git 
a/server/src/main/java/org/apache/iotdb/db/qp/physical/crud/InsertRowPlan.java 
b/server/src/main/java/org/apache/iotdb/db/qp/physical/crud/InsertRowPlan.java
index ee263cc..848428f 100644
--- 
a/server/src/main/java/org/apache/iotdb/db/qp/physical/crud/InsertRowPlan.java
+++ 
b/server/src/main/java/org/apache/iotdb/db/qp/physical/crud/InsertRowPlan.java
@@ -114,6 +114,26 @@ public class InsertRowPlan extends InsertPlan {
     this.isAligned = isAligned;
   }
 
+  public InsertRowPlan(
+      PartialPath prefixPath,
+      long insertTime,
+      String[] measurementList,
+      ByteBuffer values,
+      boolean isAligned,
+      boolean isAutoAligned)
+      throws QueryProcessException {
+    super(Operator.OperatorType.INSERT);
+    this.time = insertTime;
+    this.devicePath = prefixPath;
+    this.measurements = measurementList;
+    this.dataTypes = new TSDataType[measurementList.length];
+    this.values = new Object[measurementList.length];
+    this.fillValues(values);
+    isNeedInferType = false;
+    this.isAligned = isAligned;
+    this.isAutoAligned = isAutoAligned;
+  }
+
   @TestOnly
   public InsertRowPlan(
       PartialPath prefixPath,
@@ -363,6 +383,7 @@ public class InsertRowPlan extends InsertPlan {
 
     stream.writeLong(index);
     stream.write((byte) (isAligned ? 1 : 0));
+    stream.write((byte) (isAutoAligned ? 1 : 0));
   }
 
   private void putValues(DataOutputStream outputStream) throws 
QueryProcessException, IOException {
@@ -513,6 +534,7 @@ public class InsertRowPlan extends InsertPlan {
     buffer.putLong(index);
 
     buffer.put((byte) (isAligned ? 1 : 0));
+    buffer.put((byte) (isAutoAligned ? 1 : 0));
   }
 
   @Override
@@ -542,6 +564,7 @@ public class InsertRowPlan extends InsertPlan {
     isNeedInferType = buffer.get() == 1;
     this.index = buffer.getLong();
     isAligned = buffer.get() == 1;
+    isAutoAligned = buffer.get() == 1;
   }
 
   @Override
diff --git 
a/server/src/main/java/org/apache/iotdb/db/qp/physical/sys/CreateAutoAlignedTimeSeriesPlan.java
 
b/server/src/main/java/org/apache/iotdb/db/qp/physical/sys/CreateAutoAlignedTimeSeriesPlan.java
new file mode 100755
index 0000000..2174900
--- /dev/null
+++ 
b/server/src/main/java/org/apache/iotdb/db/qp/physical/sys/CreateAutoAlignedTimeSeriesPlan.java
@@ -0,0 +1,267 @@
+/*
+ * 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.qp.physical.sys;
+
+import org.apache.iotdb.db.exception.metadata.IllegalPathException;
+import org.apache.iotdb.db.metadata.path.PartialPath;
+import org.apache.iotdb.db.qp.logical.Operator;
+import org.apache.iotdb.db.qp.physical.PhysicalPlan;
+import org.apache.iotdb.tsfile.file.metadata.enums.CompressionType;
+import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
+import org.apache.iotdb.tsfile.file.metadata.enums.TSEncoding;
+import org.apache.iotdb.tsfile.utils.ReadWriteIOUtils;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+public class CreateAutoAlignedTimeSeriesPlan extends PhysicalPlan {
+
+  private static final Logger logger =
+      LoggerFactory.getLogger(CreateAutoAlignedTimeSeriesPlan.class);
+
+  private PartialPath prefixPath;
+  private List<String> measurements;
+  private List<TSDataType> dataTypes;
+  private List<TSEncoding> encodings;
+  private List<CompressionType> compressors;
+  private List<String> aliasList;
+
+  public CreateAutoAlignedTimeSeriesPlan() {
+    super(Operator.OperatorType.CREATE_AUTOALIGNED_TIMESERIES);
+    canBeSplit = false;
+  }
+
+  public CreateAutoAlignedTimeSeriesPlan(
+      PartialPath prefixPath,
+      List<String> measurements,
+      List<TSDataType> dataTypes,
+      List<TSEncoding> encodings,
+      List<CompressionType> compressors,
+      List<String> aliasList) {
+    super(Operator.OperatorType.CREATE_AUTOALIGNED_TIMESERIES);
+    this.prefixPath = prefixPath;
+    this.measurements = measurements;
+    this.dataTypes = dataTypes;
+    this.encodings = encodings;
+    this.compressors = compressors;
+    this.aliasList = aliasList;
+    this.canBeSplit = false;
+  }
+
+  public PartialPath getPrefixPath() {
+    return prefixPath;
+  }
+
+  public void setPrefixPath(PartialPath prefixPath) {
+    this.prefixPath = prefixPath;
+  }
+
+  public List<String> getMeasurements() {
+    return measurements;
+  }
+
+  public void setMeasurements(List<String> measurements) {
+    this.measurements = measurements;
+  }
+
+  public List<TSDataType> getDataTypes() {
+    return dataTypes;
+  }
+
+  public void setDataTypes(List<TSDataType> dataTypes) {
+    this.dataTypes = dataTypes;
+  }
+
+  public List<TSEncoding> getEncodings() {
+    return encodings;
+  }
+
+  public void setEncodings(List<TSEncoding> encodings) {
+    this.encodings = encodings;
+  }
+
+  public List<CompressionType> getCompressors() {
+    return compressors;
+  }
+
+  public void setCompressors(List<CompressionType> compressor) {
+    this.compressors = compressors;
+  }
+
+  public List<String> getAliasList() {
+    return aliasList;
+  }
+
+  public void setAliasList(List<String> aliasList) {
+    this.aliasList = aliasList;
+  }
+
+  @Override
+  public String toString() {
+    return String.format(
+        "devicePath: %s, measurements: %s, dataTypes: %s, encodings: %s, 
compressions: %s",
+        prefixPath, measurements, dataTypes, encodings, compressors);
+  }
+
+  @Override
+  public List<PartialPath> getPaths() {
+    List<PartialPath> paths = new ArrayList<>();
+    for (String measurement : measurements) {
+      try {
+        paths.add(new PartialPath(prefixPath.getFullPath(), measurement));
+      } catch (IllegalPathException e) {
+        logger.error("Failed to get paths of CreateAutoAlignedTimeSeriesPlan. 
", e);
+      }
+    }
+    return paths;
+  }
+
+  @Override
+  public void serialize(DataOutputStream stream) throws IOException {
+    stream.writeByte((byte) 
PhysicalPlanType.CREATE_AUTOALIGNED_TIMESERIES.ordinal());
+    byte[] bytes = prefixPath.getFullPath().getBytes();
+    stream.writeInt(bytes.length);
+    stream.write(bytes);
+
+    ReadWriteIOUtils.write(measurements.size(), stream);
+    for (String measurement : measurements) {
+      ReadWriteIOUtils.write(measurement, stream);
+    }
+    for (TSDataType dataType : dataTypes) {
+      stream.write(dataType.ordinal());
+    }
+    for (TSEncoding encoding : encodings) {
+      stream.write(encoding.ordinal());
+    }
+    for (CompressionType compressor : compressors) {
+      stream.write(compressor.ordinal());
+    }
+
+    // alias
+    if (aliasList != null) {
+      stream.write(1);
+      for (String alias : aliasList) {
+        ReadWriteIOUtils.write(alias, stream);
+      }
+    } else {
+      stream.write(0);
+    }
+    stream.writeLong(index);
+  }
+
+  @Override
+  public void serializeImpl(ByteBuffer buffer) {
+    buffer.put((byte) 
PhysicalPlanType.CREATE_AUTOALIGNED_TIMESERIES.ordinal());
+    byte[] bytes = prefixPath.getFullPath().getBytes();
+    buffer.putInt(bytes.length);
+    buffer.put(bytes);
+
+    ReadWriteIOUtils.write(measurements.size(), buffer);
+    for (String measurement : measurements) {
+      ReadWriteIOUtils.write(measurement, buffer);
+    }
+    for (TSDataType dataType : dataTypes) {
+      buffer.put((byte) dataType.ordinal());
+    }
+    for (TSEncoding encoding : encodings) {
+      buffer.put((byte) encoding.ordinal());
+    }
+    for (CompressionType compressor : compressors) {
+      buffer.put((byte) compressor.ordinal());
+    }
+
+    // alias
+    if (aliasList != null) {
+      buffer.put((byte) 1);
+      for (String alias : aliasList) {
+        ReadWriteIOUtils.write(alias, buffer);
+      }
+    } else {
+      buffer.put((byte) 0);
+    }
+
+    buffer.putLong(index);
+  }
+
+  @Override
+  public void deserialize(ByteBuffer buffer) throws IllegalPathException {
+    int length = buffer.getInt();
+    byte[] bytes = new byte[length];
+    buffer.get(bytes);
+
+    prefixPath = new PartialPath(new String(bytes));
+    int size = ReadWriteIOUtils.readInt(buffer);
+    measurements = new ArrayList<>();
+    for (int i = 0; i < size; i++) {
+      measurements.add(ReadWriteIOUtils.readString(buffer));
+    }
+    dataTypes = new ArrayList<>();
+    for (int i = 0; i < size; i++) {
+      dataTypes.add(TSDataType.values()[buffer.get()]);
+    }
+    encodings = new ArrayList<>();
+    for (int i = 0; i < size; i++) {
+      encodings.add(TSEncoding.values()[buffer.get()]);
+    }
+    compressors = new ArrayList<>();
+    for (int i = 0; i < size; i++) {
+      compressors.add(CompressionType.values()[buffer.get()]);
+    }
+
+    // alias
+    if (buffer.get() == 1) {
+      aliasList = new ArrayList<>();
+      for (int i = 0; i < size; i++) {
+        aliasList.add(ReadWriteIOUtils.readString(buffer));
+      }
+    }
+
+    this.index = buffer.getLong();
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (o == null || getClass() != o.getClass()) {
+      return false;
+    }
+    CreateAutoAlignedTimeSeriesPlan that = (CreateAutoAlignedTimeSeriesPlan) o;
+
+    return Objects.equals(prefixPath, that.prefixPath)
+        && Objects.equals(measurements, that.measurements)
+        && Objects.equals(dataTypes, that.dataTypes)
+        && Objects.equals(encodings, that.encodings)
+        && Objects.equals(compressors, that.compressors);
+  }
+
+  @Override
+  public int hashCode() {
+    return Objects.hash(prefixPath, measurements, dataTypes, encodings, 
compressors);
+  }
+}
diff --git 
a/server/src/main/java/org/apache/iotdb/db/qp/sql/IoTDBSqlVisitor.java 
b/server/src/main/java/org/apache/iotdb/db/qp/sql/IoTDBSqlVisitor.java
index 97a0158..faeb0b2 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/sql/IoTDBSqlVisitor.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/sql/IoTDBSqlVisitor.java
@@ -223,6 +223,26 @@ public class IoTDBSqlVisitor extends 
IoTDBSqlParserBaseVisitor<Operator> {
     }
   }
 
+  @Override
+  public Operator visitCreateAutoAlignedTimeseries(
+      IoTDBSqlParser.CreateAutoAlignedTimeseriesContext ctx) {
+    CreateAutoAlignedTimeSeriesOperator createAutoAlignedTimeSeriesOperator =
+        new 
CreateAutoAlignedTimeSeriesOperator(SQLConstant.TOK_METADATA_CREATE);
+    
createAutoAlignedTimeSeriesOperator.setPrefixPath(parseFullPath(ctx.fullPath()));
+    parseAutoAlignedMeasurements(
+        ctx.autoAlignedMeasurements(), createAutoAlignedTimeSeriesOperator);
+    return createAutoAlignedTimeSeriesOperator;
+  }
+
+  public void parseAutoAlignedMeasurements(
+      IoTDBSqlParser.AutoAlignedMeasurementsContext ctx,
+      CreateAutoAlignedTimeSeriesOperator createAutoAlignedTimeSeriesOperator) 
{
+    for (int i = 0; i < ctx.nodeNameWithoutWildcard().size(); i++) {
+      
createAutoAlignedTimeSeriesOperator.addMeasurement(ctx.nodeNameWithoutWildcard(i).getText());
+      parseAttributeClauses(ctx.attributeClauses(i), 
createAutoAlignedTimeSeriesOperator);
+    }
+  }
+
   public void parseAttributeClauses(
       IoTDBSqlParser.AttributeClausesContext ctx,
       CreateTimeSeriesOperator createTimeSeriesOperator) {
@@ -394,6 +414,44 @@ public class IoTDBSqlVisitor extends 
IoTDBSqlParserBaseVisitor<Operator> {
     }
   }
 
+  public void parseAttributeClauses(
+      IoTDBSqlParser.AttributeClausesContext ctx,
+      CreateAutoAlignedTimeSeriesOperator createAutoAlignedTimeSeriesOperator) 
{
+    if (ctx.alias() != null) {
+      throw new SQLParserException("create aligned timeseries: alias is not 
supported yet.");
+    }
+
+    String dataTypeString = ctx.dataType.getText().toUpperCase();
+    TSDataType dataType = TSDataType.valueOf(dataTypeString);
+    createAutoAlignedTimeSeriesOperator.addDataType(dataType);
+
+    TSEncoding encoding = 
IoTDBDescriptor.getInstance().getDefaultEncodingByType(dataType);
+    if (Objects.nonNull(ctx.encoding)) {
+      String encodingString = ctx.encoding.getText().toUpperCase();
+      encoding = TSEncoding.valueOf(encodingString);
+    }
+    createAutoAlignedTimeSeriesOperator.addEncoding(encoding);
+
+    CompressionType compressor = 
TSFileDescriptor.getInstance().getConfig().getCompressor();
+    if (ctx.compressor != null) {
+      String compressorString = ctx.compressor.getText().toUpperCase();
+      compressor = CompressionType.valueOf(compressorString);
+    }
+    createAutoAlignedTimeSeriesOperator.addCompressor(compressor);
+
+    if (ctx.propertyClause(0) != null) {
+      throw new SQLParserException("create aligned timeseries: property is not 
supported yet.");
+    }
+
+    if (ctx.tagClause() != null) {
+      throw new SQLParserException("create aligned timeseries: tag is not 
supported yet.");
+    }
+
+    if (ctx.attributeClause() != null) {
+      throw new SQLParserException("create aligned timeseries: attribute is 
not supported yet.");
+    }
+  }
+
   // Create Timeseries Of Schema Template
 
   @Override
@@ -1599,6 +1657,7 @@ public class IoTDBSqlVisitor extends 
IoTDBSqlParserBaseVisitor<Operator> {
     boolean isTimeDefault = parseInsertColumnSpec(ctx.insertColumnsSpec(), 
insertOp);
     parseInsertValuesSpec(ctx.insertValuesSpec(), insertOp, isTimeDefault);
     insertOp.setAligned(ctx.ALIGNED() != null);
+    insertOp.setAutoAligned(ctx.AUTOALIGNED() != null);
     return insertOp;
   }
 
diff --git 
a/server/src/main/java/org/apache/iotdb/db/utils/datastructure/AlignedTVList.java
 
b/server/src/main/java/org/apache/iotdb/db/utils/datastructure/AlignedTVList.java
index c91348f..5f1d408 100644
--- 
a/server/src/main/java/org/apache/iotdb/db/utils/datastructure/AlignedTVList.java
+++ 
b/server/src/main/java/org/apache/iotdb/db/utils/datastructure/AlignedTVList.java
@@ -148,6 +148,10 @@ public class AlignedTVList extends TVList {
     return getAlignedValueByValueIndex(valueIndex, null, floatPrecision, 
encodingList);
   }
 
+  public List<List<BitMap>> getBitMaps() {
+    return this.bitMaps;
+  }
+
   public TsPrimitiveType getAlignedValue(
       List<Integer> timeDuplicatedIndexList,
       Integer floatPrecision,
diff --git 
a/tsfile/src/main/java/org/apache/iotdb/tsfile/write/chunk/AutoAlignedChunkGroupWriterImpl.java
 
b/tsfile/src/main/java/org/apache/iotdb/tsfile/write/chunk/AutoAlignedChunkGroupWriterImpl.java
new file mode 100644
index 0000000..16a51ec
--- /dev/null
+++ 
b/tsfile/src/main/java/org/apache/iotdb/tsfile/write/chunk/AutoAlignedChunkGroupWriterImpl.java
@@ -0,0 +1,301 @@
+/*
+ * 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.tsfile.write.chunk;
+
+import org.apache.iotdb.tsfile.common.conf.TSFileDescriptor;
+import org.apache.iotdb.tsfile.common.constant.TsFileConstant;
+import org.apache.iotdb.tsfile.encoding.encoder.Encoder;
+import org.apache.iotdb.tsfile.encoding.encoder.TSEncodingBuilder;
+import org.apache.iotdb.tsfile.exception.write.UnSupportedDataTypeException;
+import org.apache.iotdb.tsfile.exception.write.WriteProcessException;
+import org.apache.iotdb.tsfile.file.metadata.enums.CompressionType;
+import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
+import org.apache.iotdb.tsfile.file.metadata.enums.TSEncoding;
+import org.apache.iotdb.tsfile.utils.Binary;
+import org.apache.iotdb.tsfile.write.record.Tablet;
+import org.apache.iotdb.tsfile.write.record.datapoint.DataPoint;
+import org.apache.iotdb.tsfile.write.schema.MeasurementSchema;
+import org.apache.iotdb.tsfile.write.writer.TsFileIOWriter;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.util.*;
+
+public class AutoAlignedChunkGroupWriterImpl implements IChunkGroupWriter {
+  private static final Logger LOG = 
LoggerFactory.getLogger(AutoAlignedChunkGroupWriterImpl.class);
+
+  private final String deviceId;
+
+  // measurementID -> ValueChunkWriter
+  private Map<String, ValueChunkWriter> valueChunkWriterMap = new 
LinkedHashMap<>();
+
+  private TimeChunkWriter timeChunkWriter;
+
+  private Set<String> writenMeasurementSet = new HashSet<>();
+
+  private long lastTime = -1;
+
+  public AutoAlignedChunkGroupWriterImpl(String deviceId) {
+    this.deviceId = deviceId;
+    String timeMeasurementId = "";
+    CompressionType compressionType = 
TSFileDescriptor.getInstance().getConfig().getCompressor();
+    TSEncoding tsEncoding =
+        
TSEncoding.valueOf(TSFileDescriptor.getInstance().getConfig().getTimeEncoder());
+    TSDataType timeType = 
TSFileDescriptor.getInstance().getConfig().getTimeSeriesDataType();
+    Encoder encoder = 
TSEncodingBuilder.getEncodingBuilder(tsEncoding).getEncoder(timeType);
+    timeChunkWriter = new TimeChunkWriter(timeMeasurementId, compressionType, 
tsEncoding, encoder);
+  }
+
+  @Override
+  public void tryToAddSeriesWriter(MeasurementSchema measurementSchema) {
+    if 
(!valueChunkWriterMap.containsKey(measurementSchema.getMeasurementId())) {
+      ValueChunkWriter valueChunkWriter =
+          new ValueChunkWriter(
+              measurementSchema.getMeasurementId(),
+              measurementSchema.getCompressor(),
+              measurementSchema.getType(),
+              measurementSchema.getEncodingType(),
+              measurementSchema.getValueEncoder());
+      valueChunkWriterMap.put(measurementSchema.getMeasurementId(), 
valueChunkWriter);
+      tryToAddEmptyPageAndData(valueChunkWriter);
+    }
+  }
+
+  @Override
+  public void tryToAddSeriesWriter(List<MeasurementSchema> measurementSchemas) 
{
+    for (MeasurementSchema schema : measurementSchemas) {
+      if (!valueChunkWriterMap.containsKey(schema.getMeasurementId())) {
+        ValueChunkWriter valueChunkWriter =
+            new ValueChunkWriter(
+                schema.getMeasurementId(),
+                schema.getCompressor(),
+                schema.getType(),
+                schema.getEncodingType(),
+                schema.getValueEncoder());
+        valueChunkWriterMap.put(schema.getMeasurementId(), valueChunkWriter);
+        tryToAddEmptyPageAndData(valueChunkWriter);
+      }
+    }
+  }
+
+  @Override
+  public int write(long time, List<DataPoint> data) throws 
WriteProcessException, IOException {
+    checkIsHistoryData("", time);
+
+    for (DataPoint point : data) {
+      writenMeasurementSet.add(point.getMeasurementId());
+      boolean isNull = point.getValue() == null;
+      ValueChunkWriter valueChunkWriter = 
valueChunkWriterMap.get(point.getMeasurementId());
+      switch (point.getType()) {
+        case BOOLEAN:
+          valueChunkWriter.write(time, (boolean) point.getValue(), isNull);
+          break;
+        case INT32:
+          valueChunkWriter.write(time, (int) point.getValue(), isNull);
+          break;
+        case INT64:
+          valueChunkWriter.write(time, (long) point.getValue(), isNull);
+          break;
+        case FLOAT:
+          valueChunkWriter.write(time, (float) point.getValue(), isNull);
+          break;
+        case DOUBLE:
+          valueChunkWriter.write(time, (double) point.getValue(), isNull);
+          break;
+        case TEXT:
+          valueChunkWriter.write(time, (Binary) point.getValue(), isNull);
+          break;
+        default:
+          throw new UnSupportedDataTypeException(
+              String.format("Data type %s is not supported.", 
point.getType()));
+      }
+    }
+    writeEmptyDataInOneRow(time);
+    timeChunkWriter.write(time);
+    lastTime = time;
+    if (checkPageSizeAndMayOpenANewPage()) {
+      writePageToPageBuffer();
+    }
+    return 1;
+  }
+
+  @Override
+  public int write(Tablet tablet) throws WriteProcessException, IOException {
+    int pointCount = 0;
+    List<MeasurementSchema> measurementSchemas = tablet.getSchemas();
+    for (int row = 0; row < tablet.rowSize; row++) {
+      long time = tablet.timestamps[row];
+      checkIsHistoryData("", time);
+      for (int columnIndex = 0; columnIndex < measurementSchemas.size(); 
columnIndex++) {
+        
writenMeasurementSet.add(measurementSchemas.get(columnIndex).getMeasurementId());
+        boolean isNull = false;
+        // check isNull by bitMap in tablet
+        if (tablet.bitMaps != null
+            && tablet.bitMaps[columnIndex] != null
+            && !tablet.bitMaps[columnIndex].isMarked(row)) {
+          isNull = true;
+        }
+        ValueChunkWriter valueChunkWriter =
+            
valueChunkWriterMap.get(measurementSchemas.get(columnIndex).getMeasurementId());
+        switch (measurementSchemas.get(columnIndex).getType()) {
+          case BOOLEAN:
+            valueChunkWriter.write(time, ((boolean[]) 
tablet.values[columnIndex])[row], isNull);
+            break;
+          case INT32:
+            valueChunkWriter.write(time, ((int[]) 
tablet.values[columnIndex])[row], isNull);
+            break;
+          case INT64:
+            valueChunkWriter.write(time, ((long[]) 
tablet.values[columnIndex])[row], isNull);
+            break;
+          case FLOAT:
+            valueChunkWriter.write(time, ((float[]) 
tablet.values[columnIndex])[row], isNull);
+            break;
+          case DOUBLE:
+            valueChunkWriter.write(time, ((double[]) 
tablet.values[columnIndex])[row], isNull);
+            break;
+          case TEXT:
+            valueChunkWriter.write(time, ((Binary[]) 
tablet.values[columnIndex])[row], isNull);
+            break;
+          default:
+            throw new UnSupportedDataTypeException(
+                String.format(
+                    "Data type %s is not supported.",
+                    measurementSchemas.get(columnIndex).getType()));
+        }
+      }
+      writeEmptyDataInOneRow(time);
+      timeChunkWriter.write(time);
+      lastTime = time;
+      if (checkPageSizeAndMayOpenANewPage()) {
+        writePageToPageBuffer();
+      }
+      pointCount++;
+    }
+    return pointCount;
+  }
+
+  @Override
+  public long flushToFileWriter(TsFileIOWriter tsfileWriter) throws 
IOException {
+    LOG.debug("start flush device id:{}", deviceId);
+    // make sure all the pages have been compressed into buffers, so that we 
can get correct
+    // groupWriter.getCurrentChunkGroupSize().
+    sealAllChunks();
+    long currentChunkGroupSize = getCurrentChunkGroupSize();
+    timeChunkWriter.writeToFileWriter(tsfileWriter);
+    for (ValueChunkWriter valueChunkWriter : valueChunkWriterMap.values()) {
+      valueChunkWriter.writeToFileWriter(tsfileWriter);
+    }
+    return currentChunkGroupSize;
+  }
+
+  @Override
+  public long updateMaxGroupMemSize() {
+    long bufferSize = timeChunkWriter.estimateMaxSeriesMemSize();
+    for (ValueChunkWriter valueChunkWriter : valueChunkWriterMap.values()) {
+      bufferSize += valueChunkWriter.estimateMaxSeriesMemSize();
+    }
+    return bufferSize;
+  }
+
+  @Override
+  public long getCurrentChunkGroupSize() {
+    long size = timeChunkWriter.getCurrentChunkSize();
+    for (ValueChunkWriter valueChunkWriter : valueChunkWriterMap.values()) {
+      size += valueChunkWriter.getCurrentChunkSize();
+    }
+    return size;
+  }
+
+  public void tryToAddEmptyPageAndData(ValueChunkWriter valueChunkWriter) {
+    // add empty page
+    for (int i = 0; i < timeChunkWriter.getNumOfPages(); i++) {
+      valueChunkWriter.writeEmptyPageToPageBuffer();
+    }
+
+    // add empty data of currentPage
+    for (long i = 0; i < 
timeChunkWriter.getPageWriter().getStatistics().getCount(); i++) {
+      valueChunkWriter.write(0, 0, true);
+    }
+  }
+
+  private void writeEmptyDataInOneRow(long time) {
+    for (Map.Entry<String, ValueChunkWriter> entry : 
valueChunkWriterMap.entrySet()) {
+      if (!writenMeasurementSet.contains(entry.getKey())) {
+        entry.getValue().write(time, 0, true);
+      }
+    }
+    writenMeasurementSet.clear();
+  }
+
+  /**
+   * check occupied memory size, if it exceeds the PageSize threshold, 
construct a page and put it
+   * to pageBuffer
+   */
+  private boolean checkPageSizeAndMayOpenANewPage() {
+    if (timeChunkWriter.checkPageSizeAndMayOpenANewPage()) {
+      return true;
+    }
+    for (ValueChunkWriter writer : valueChunkWriterMap.values()) {
+      if (writer.checkPageSizeAndMayOpenANewPage()) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  private void writePageToPageBuffer() {
+    timeChunkWriter.writePageToPageBuffer();
+    for (ValueChunkWriter valueChunkWriter : valueChunkWriterMap.values()) {
+      valueChunkWriter.writePageToPageBuffer();
+    }
+  }
+
+  private void sealAllChunks() {
+    timeChunkWriter.sealCurrentPage();
+    for (ValueChunkWriter valueChunkWriter : valueChunkWriterMap.values()) {
+      valueChunkWriter.sealCurrentPage();
+    }
+  }
+
+  private void checkIsHistoryData(String measurementId, long time) throws 
WriteProcessException {
+    if (time <= lastTime) {
+      throw new WriteProcessException(
+          "Not allowed to write out-of-order data in timeseries "
+              + deviceId
+              + TsFileConstant.PATH_SEPARATOR
+              + measurementId
+              + ", time should later than "
+              + lastTime);
+    }
+  }
+
+  public List<String> getMeasurements() {
+    return new ArrayList<>(valueChunkWriterMap.keySet());
+  }
+
+  public Long getLastTime() {
+    return this.lastTime;
+  }
+
+  public void setLastTime(Long lastTime) {
+    this.lastTime = lastTime;
+  }
+}
diff --git 
a/tsfile/src/main/java/org/apache/iotdb/tsfile/write/chunk/AutoAlignedChunkWriterImpl.java
 
b/tsfile/src/main/java/org/apache/iotdb/tsfile/write/chunk/AutoAlignedChunkWriterImpl.java
new file mode 100644
index 0000000..7bb2e4d
--- /dev/null
+++ 
b/tsfile/src/main/java/org/apache/iotdb/tsfile/write/chunk/AutoAlignedChunkWriterImpl.java
@@ -0,0 +1,239 @@
+/*
+ * 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.tsfile.write.chunk;
+
+import org.apache.iotdb.tsfile.common.conf.TSFileDescriptor;
+import org.apache.iotdb.tsfile.encoding.encoder.Encoder;
+import org.apache.iotdb.tsfile.encoding.encoder.TSEncodingBuilder;
+import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
+import org.apache.iotdb.tsfile.file.metadata.enums.TSEncoding;
+import org.apache.iotdb.tsfile.utils.Binary;
+import org.apache.iotdb.tsfile.utils.TsPrimitiveType;
+import org.apache.iotdb.tsfile.write.schema.IMeasurementSchema;
+import org.apache.iotdb.tsfile.write.schema.VectorMeasurementSchema;
+import org.apache.iotdb.tsfile.write.writer.TsFileIOWriter;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+
+public class AutoAlignedChunkWriterImpl implements IChunkWriter {
+
+  private final TimeChunkWriter timeChunkWriter;
+  private final List<ValueChunkWriter> valueChunkWriterList;
+  private int valueIndex;
+
+  /** @param schema schema of this measurement */
+  public AutoAlignedChunkWriterImpl(VectorMeasurementSchema schema) {
+    timeChunkWriter =
+        new TimeChunkWriter(
+            schema.getMeasurementId(),
+            schema.getCompressor(),
+            schema.getTimeTSEncoding(),
+            schema.getTimeEncoder());
+
+    List<String> valueMeasurementIdList = schema.getSubMeasurementsList();
+    List<TSDataType> valueTSDataTypeList = 
schema.getSubMeasurementsTSDataTypeList();
+    List<TSEncoding> valueTSEncodingList = 
schema.getSubMeasurementsTSEncodingList();
+    List<Encoder> valueEncoderList = schema.getSubMeasurementsEncoderList();
+
+    valueChunkWriterList = new ArrayList<>(valueMeasurementIdList.size());
+    for (int i = 0; i < valueMeasurementIdList.size(); i++) {
+      valueChunkWriterList.add(
+          new ValueChunkWriter(
+              valueMeasurementIdList.get(i),
+              schema.getCompressor(),
+              valueTSDataTypeList.get(i),
+              valueTSEncodingList.get(i),
+              valueEncoderList.get(i)));
+    }
+
+    this.valueIndex = 0;
+  }
+
+  public AutoAlignedChunkWriterImpl(List<IMeasurementSchema> schemaList) {
+    TSEncoding timeEncoding =
+        
TSEncoding.valueOf(TSFileDescriptor.getInstance().getConfig().getTimeEncoder());
+    TSDataType timeType = 
TSFileDescriptor.getInstance().getConfig().getTimeSeriesDataType();
+    timeChunkWriter =
+        new TimeChunkWriter(
+            "",
+            schemaList.get(0).getCompressor(),
+            timeEncoding,
+            
TSEncodingBuilder.getEncodingBuilder(timeEncoding).getEncoder(timeType));
+
+    valueChunkWriterList = new ArrayList<>(schemaList.size());
+    for (int i = 0; i < schemaList.size(); i++) {
+      valueChunkWriterList.add(
+          new ValueChunkWriter(
+              schemaList.get(i).getMeasurementId(),
+              schemaList.get(i).getCompressor(),
+              schemaList.get(i).getType(),
+              schemaList.get(i).getEncodingType(),
+              schemaList.get(i).getValueEncoder()));
+    }
+
+    this.valueIndex = 0;
+  }
+
+  public void write(long time, int value, boolean isNull) {
+    valueChunkWriterList.get(valueIndex++).write(time, value, isNull);
+  }
+
+  public void write(long time, long value, boolean isNull) {
+    valueChunkWriterList.get(valueIndex++).write(time, value, isNull);
+  }
+
+  public void write(long time, boolean value, boolean isNull) {
+    valueChunkWriterList.get(valueIndex++).write(time, value, isNull);
+  }
+
+  public void write(long time, float value, boolean isNull) {
+    valueChunkWriterList.get(valueIndex++).write(time, value, isNull);
+  }
+
+  public void write(long time, double value, boolean isNull) {
+    valueChunkWriterList.get(valueIndex++).write(time, value, isNull);
+  }
+
+  public void write(long time, Binary value, boolean isNull) {
+    valueChunkWriterList.get(valueIndex++).write(time, value, isNull);
+  }
+
+  public void write(long time, TsPrimitiveType[] points) {
+    valueIndex = 0;
+    for (TsPrimitiveType point : points) {
+      ValueChunkWriter writer = valueChunkWriterList.get(valueIndex++);
+      switch (writer.getDataType()) {
+        case INT64:
+          writer.write(time, point != null ? point.getLong() : Long.MAX_VALUE, 
point == null);
+          break;
+        case INT32:
+          writer.write(time, point != null ? point.getInt() : 
Integer.MAX_VALUE, point == null);
+          break;
+        case FLOAT:
+          writer.write(time, point != null ? point.getFloat() : 
Float.MAX_VALUE, point == null);
+          break;
+        case DOUBLE:
+          writer.write(time, point != null ? point.getDouble() : 
Double.MAX_VALUE, point == null);
+          break;
+        case BOOLEAN:
+          writer.write(time, point != null ? point.getBoolean() : false, point 
== null);
+          break;
+        case TEXT:
+          writer.write(
+              time,
+              point != null ? point.getBinary() : new 
Binary("".getBytes(StandardCharsets.UTF_8)),
+              point == null);
+          break;
+      }
+    }
+    write(time);
+  }
+
+  public void write(long time) {
+    valueIndex = 0;
+    timeChunkWriter.write(time);
+    if (checkPageSizeAndMayOpenANewPage()) {
+      writePageToPageBuffer();
+    }
+  }
+
+  /**
+   * check occupied memory size, if it exceeds the PageSize threshold, 
construct a page and put it
+   * to pageBuffer
+   */
+  private boolean checkPageSizeAndMayOpenANewPage() {
+    if (timeChunkWriter.checkPageSizeAndMayOpenANewPage()) {
+      return true;
+    }
+    for (ValueChunkWriter writer : valueChunkWriterList) {
+      if (writer.checkPageSizeAndMayOpenANewPage()) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  private void writePageToPageBuffer() {
+    timeChunkWriter.writePageToPageBuffer();
+    for (ValueChunkWriter valueChunkWriter : valueChunkWriterList) {
+      valueChunkWriter.writePageToPageBuffer();
+    }
+  }
+
+  @Override
+  public void writeToFileWriter(TsFileIOWriter tsfileWriter) throws 
IOException {
+    timeChunkWriter.writeToFileWriter(tsfileWriter);
+    for (ValueChunkWriter valueChunkWriter : valueChunkWriterList) {
+      valueChunkWriter.writeToFileWriter(tsfileWriter);
+    }
+  }
+
+  @Override
+  public long estimateMaxSeriesMemSize() {
+    long estimateMaxSeriesMemSize = timeChunkWriter.estimateMaxSeriesMemSize();
+    for (ValueChunkWriter valueChunkWriter : valueChunkWriterList) {
+      estimateMaxSeriesMemSize += valueChunkWriter.estimateMaxSeriesMemSize();
+    }
+    return estimateMaxSeriesMemSize;
+  }
+
+  public long getSerializedChunkSize() {
+    long currentChunkSize = timeChunkWriter.getCurrentChunkSize();
+    for (ValueChunkWriter valueChunkWriter : valueChunkWriterList) {
+      currentChunkSize += valueChunkWriter.getCurrentChunkSize();
+    }
+    return currentChunkSize;
+  }
+
+  @Override
+  public void sealCurrentPage() {
+    timeChunkWriter.sealCurrentPage();
+    for (ValueChunkWriter valueChunkWriter : valueChunkWriterList) {
+      valueChunkWriter.sealCurrentPage();
+    }
+  }
+
+  @Override
+  public void clearPageWriter() {
+    timeChunkWriter.clearPageWriter();
+    for (ValueChunkWriter valueChunkWriter : valueChunkWriterList) {
+      valueChunkWriter.clearPageWriter();
+    }
+  }
+
+  /** Used for compaction to control the target chunk size. */
+  public boolean checkIsChunkSizeOverThreshold(long threshold) {
+    if (timeChunkWriter.estimateMaxSeriesMemSize() > threshold) {
+      return true;
+    }
+    for (ValueChunkWriter valueChunkWriter : valueChunkWriterList) {
+      if (valueChunkWriter.estimateMaxSeriesMemSize() > threshold) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  public TSDataType getCurrentValueChunkType() {
+    return valueChunkWriterList.get(valueIndex).getDataType();
+  }
+}

Reply via email to