public Future<?> asyncClose() {
    flushQueryLock.writeLock().lock();
    logFlushQueryWriteLocked();
    try {
      if (logger.isDebugEnabled()) {
        if (workMemTable != null) {
          logger.debug(
              "{}: flush a working memtable in async close tsfile {}, memtable size: {}, tsfile "
                  + "size: {}, plan index: [{}, {}], progress index: {}",
              dataRegionName,
              tsFileResource.getTsFile().getAbsolutePath(),
              workMemTable.memSize(),
              tsFileResource.getTsFileSize(),
              workMemTable.getMinPlanIndex(),
              workMemTable.getMaxPlanIndex(),
              tsFileResource.getMaxProgressIndex());
        } else {
          logger.debug(
              "{}: flush a NotifyFlushMemTable in async close tsfile {}, tsfile size: {}",
              dataRegionName,
              tsFileResource.getTsFile().getAbsolutePath(),
              tsFileResource.getTsFileSize());
        }
      }

      if (shouldClose) {
        return CompletableFuture.completedFuture(null);
      }
      // when a flush thread serves this TsFileProcessor (because the processor is submitted by
      // registerTsFileProcessor()), the thread will seal the corresponding TsFile and
      // execute other cleanup works if "shouldClose == true and flushingMemTables is empty".

      // To ensure there must be a flush thread serving this processor after the field `shouldClose`
      // is set true, we need to generate a NotifyFlushMemTable as a signal task and submit it to
      // the FlushManager.

      // we have to add the memtable into flushingList first and then set the shouldClose tag.
      // see https://issues.apache.org/jira/browse/IOTDB-510
      IMemTable tmpMemTable = workMemTable == null ? new NotifyFlushMemTable() : workMemTable;

      try {
        PipeInsertionDataNodeListener.getInstance()
            .listenToTsFile(
                dataRegionInfo.getDataRegion().getDataRegionId(),
                dataRegionInfo.getDataRegion().getDatabaseName(),
                tsFileResource,
                false,
                tmpMemTable.isTotallyGeneratedByPipe());

        // When invoke closing TsFile after insert data to memTable, we shouldn't flush until invoke
        // flushing memTable in System module.
        Future<?> future = addAMemtableIntoFlushingList(tmpMemTable);
        shouldClose = true;
        return future;
      } catch (Exception e) {
        logger.error(
            "{}: {} async close failed, because",
            dataRegionName,
            tsFileResource.getTsFile().getName(),
            e);
      }
    } finally {
      flushQueryLock.writeLock().unlock();
      logFlushQueryWriteUnlocked();
    }
    return CompletableFuture.completedFuture(null);
  }
async close one tsfile, register and close it by another thread
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/TsFileProcessor.java