void redoInsert(InsertNode node) throws WriteProcessException {
    if (!node.hasValidMeasurements()) {
      return;
    }
    boolean isSingleDevice = !(node instanceof RelationalInsertTabletNode);
    if (tsFileResource != null && isSingleDevice) {
      // orders of insert node is guaranteed by storage engine, just check time in the file
      // the last chunk group may contain the same data with the logs, ignore such logs in seq file
      Optional<Long> lastEndTime = tsFileResource.getEndTime(node.getDeviceID());
      long minTimeInNode;
      if (node instanceof InsertRowNode) {
        minTimeInNode = ((InsertRowNode) node).getTime();
      } else {
        minTimeInNode = ((InsertTabletNode) node).getTimes()[0];
      }
      if (lastEndTime.isPresent() && lastEndTime.get() >= minTimeInNode) {
        return;
      }
    }

    int pointsInserted;
    if (node instanceof InsertRowNode) {
      if (node.isAligned()) {
        pointsInserted = recoveryMemTable.insertAlignedRow((InsertRowNode) node);
      } else {
        pointsInserted = recoveryMemTable.insert((InsertRowNode) node);
      }
    } else if (node instanceof RelationalInsertTabletNode) {
      pointsInserted = 0;
      RelationalInsertTabletNode relationalInsertTabletNode = (RelationalInsertTabletNode) node;
      List<Pair<IDeviceID, Integer>> deviceIndexPairs =
          relationalInsertTabletNode.splitByDevice(0, relationalInsertTabletNode.getRowCount());
      int start = 0;
      for (Pair<IDeviceID, Integer> pair : deviceIndexPairs) {
        IDeviceID deviceID = pair.getLeft();
        Optional<Long> endTimeInResource =
            tsFileResource == null ? Optional.empty() : tsFileResource.getEndTime(deviceID);
        long minTimeOfDevice = relationalInsertTabletNode.getTimes()[start];
        if (endTimeInResource.isPresent() && endTimeInResource.get() >= minTimeOfDevice) {
          start = pair.getRight();
          continue;
        }
        pointsInserted =
            recoveryMemTable.insertAlignedTablet(
                relationalInsertTabletNode, start, pair.getRight(), null);
        start = pair.getRight();
      }
    } else {
      if (node.isAligned()) {
        pointsInserted =
            recoveryMemTable.insertAlignedTablet(
                (InsertTabletNode) node, 0, ((InsertTabletNode) node).getRowCount(), null);
      } else {
        pointsInserted =
            recoveryMemTable.insertTablet(
                (InsertTabletNode) node, 0, ((InsertTabletNode) node).getRowCount());
      }
    }
    updatePointsInsertedMetric(node, pointsInserted);
  }
This class helps redo wal logs into a TsFile. Notice: You should update time map in {@link
TsFileResource} before using this class to avoid duplicated insertion and this class doesn't
guarantee concurrency safety.
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/recover/file/TsFilePlanRedoer.java