@Override
    public boolean hasNext() {
      if (itr != null && itr.hasNext()) {
        return true;
      }

      // clear outdated iterator
      insertNodes.clear();
      itr = null;
      if (filesToSearch == null || currentFileIndex >= filesToSearch.length - 1) {
        needUpdatingFilesToSearch = true;
      }

      // update files to search
      if (needUpdatingFilesToSearch) {
        updateFilesToSearch();
        if (needUpdatingFilesToSearch) {
          logger.debug(
              "update file to search failed, the next search index is {}", nextSearchIndex);
          return false;
        }
      }

      // find file contains search index
      while (WALFileUtils.parseStatusCode(filesToSearch[currentFileIndex].getName())
          == WALFileStatus.CONTAINS_NONE_SEARCH_INDEX) {
        currentFileIndex++;
        if (currentFileIndex >= filesToSearch.length - 1) {
          needUpdatingFilesToSearch = true;
          return false;
        }
      }

      /* ------ find all nodes from all wal file ------ */

      AtomicReference<List<IConsensusRequest>> tmpNodes = new AtomicReference<>(new ArrayList<>());
      AtomicBoolean notFirstFile = new AtomicBoolean(false);
      AtomicBoolean hasCollectedSufficientData = new AtomicBoolean(false);

      // try to collect current tmpNodes to insertNodes, return true if successfully collect an
      // insert node
      Runnable tryToCollectInsertNodeAndBumpIndex =
          () -> {
            if (!tmpNodes.get().isEmpty()) {
              insertNodes.add(new IndexedConsensusRequest(nextSearchIndex, tmpNodes.get()));
              tmpNodes.set(new ArrayList<>());
              nextSearchIndex++;
              if (notFirstFile.get()) {
                hasCollectedSufficientData.set(true);
              }
            }
          };

      COLLECT_FILE_LOOP:
      for (; currentFileIndex < filesToSearch.length - 1; currentFileIndex++) {
        // cannot find any in this file, so all slices of last plan node are found
        if (WALFileUtils.parseStatusCode(filesToSearch[currentFileIndex].getName())
            == WALFileStatus.CONTAINS_NONE_SEARCH_INDEX) {
          tryToCollectInsertNodeAndBumpIndex.run();
          continue;
        }
        try (WALByteBufReader walByteBufReader =
            new WALByteBufReader(filesToSearch[currentFileIndex])) {
          while (walByteBufReader.hasNext()) {
            ByteBuffer buffer = walByteBufReader.next();
            WALEntryType type = WALEntryType.valueOf(buffer.get());
            if (type.needSearch()) {
              // see WALInfoEntry#serialize, entry type + memtable id + plan node type
              buffer.position(WALInfoEntry.FIXED_SERIALIZED_SIZE + PlanNodeType.BYTES);
              final long currentWalEntryIndex = buffer.getLong();
              buffer.clear();
              if (currentWalEntryIndex == -1) {
                // WAL entry of targetIndex has been fully collected, so put them into insertNodes
                tryToCollectInsertNodeAndBumpIndex.run();
              } else if (currentWalEntryIndex < nextSearchIndex) {
                // WAL entry is outdated, do nothing, continue to see next WAL entry
              } else if (currentWalEntryIndex == nextSearchIndex) {
                tmpNodes.get().add(new IoTConsensusRequest(buffer));
              } else {
                // currentWalEntryIndex > targetIndex
                // WAL entry of targetIndex has been fully collected, put them into insertNodes
                tryToCollectInsertNodeAndBumpIndex.run();
                if (currentWalEntryIndex != nextSearchIndex) {
                  logger.warn(
                      "The search index of next WAL entry should be {}, but actually it's {}",
                      nextSearchIndex,
                      currentWalEntryIndex);
                  nextSearchIndex = currentWalEntryIndex;
                }
                tmpNodes.get().add(new IoTConsensusRequest(buffer));
              }
            } else {
              tryToCollectInsertNodeAndBumpIndex.run();
            }
            if (hasCollectedSufficientData.get()) {
              break COLLECT_FILE_LOOP;
            }
          }
        } catch (Exception e) {
          brokenFileId = WALFileUtils.parseVersionId(filesToSearch[currentFileIndex].getName());
          logger.error(
              "Fail to read wal from wal file {}, skip this file.",
              filesToSearch[currentFileIndex],
              e);
        }
        notFirstFile.set(true);
      }

      // update file index and version id
      if (currentFileIndex >= filesToSearch.length - 1) {
        needUpdatingFilesToSearch = true;
      }

      // update iterator
      if (!insertNodes.isEmpty()) {
        itr = insertNodes.listIterator();
        return true;
      }
      return false;
    }
last broken wal file's version id
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/node/WALNode.java