public void recover() throws WALRecoverException, StartupException {
    logger.info("Start recovering wal.");
    try {
      // collect wal nodes' information
      List<File> walNodeDirs = new ArrayList<>();
      for (String walDir : commonConfig.getWalDirs()) {
        File walDirFile = SystemFileFactory.INSTANCE.getFile(walDir);
        File[] nodeDirs = walDirFile.listFiles(File::isDirectory);
        if (nodeDirs == null) {
          continue;
        }
        for (File nodeDir : nodeDirs) {
          if (nodeDir.isDirectory()) {
            walNodeDirs.add(nodeDir);
          }
        }
      }
      // wait until all data regions have submitted their unsealed TsFiles,
      // which means walRecoverManger.addRecoverPerformer method won't be call anymore
      try {
        allDataRegionScannedLatch.await();
        if (allDataRegionScannedLatch.hasException()) {
          throw new DataRegionException(allDataRegionScannedLatch.getExceptionMessage());
        }
        hasStarted = true;
      } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
        throw new WALRecoverException("Fail to recover wal.", e);
      }
      logger.info(
          "Data regions have submitted all unsealed TsFiles, start recovering TsFiles in each wal node.");
      // recover each wal node's TsFiles
      if (!walNodeDirs.isEmpty()) {
        recoverThreadPool =
            IoTDBThreadPoolFactory.newCachedThreadPool(ThreadName.WAL_RECOVER.getName());
        CountDownLatch allNodesRecoveredLatch = new CountDownLatch(walNodeDirs.size());
        for (File walNodeDir : walNodeDirs) {
          recoverThreadPool.submit(new WALNodeRecoverTask(walNodeDir, allNodesRecoveredLatch));
        }

        try {
          allNodesRecoveredLatch.await();
        } catch (InterruptedException e) {
          Thread.currentThread().interrupt();
          throw new WALRecoverException("Fail to recover wal.", e);
        }
      }
      // deal with remaining TsFiles which don't have wal
      asyncRecoverLeftTsFiles();
    } catch (DataRegionException e) {
      throw new StartupException(e.getMessage());
    } catch (Exception e) {
      for (UnsealedTsFileRecoverPerformer recoverPerformer :
          absolutePath2RecoverPerformer.values()) {
        recoverPerformer.getRecoverListener().fail(e);
      }
    } finally {
      for (UnsealedTsFileRecoverPerformer recoverPerformer :
          absolutePath2RecoverPerformer.values()) {
        try {
          if (!recoverPerformer.canWrite()) {
            recoverPerformer.close();
          }
        } catch (Exception e) {
          // continue
        }
      }
      stop();
    }
    logger.info("Successfully recover all wal nodes.");
  }
First set allVsgScannedLatch, then call recover method.
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/recover/WALRecoverManager.java