@Override
  protected void readWALEntries(WALEntryStream entryStream, WALEntryBatch batch)
    throws InterruptedException {
    Path currentPath = entryStream.getCurrentPath();
    long positionBefore = entryStream.getPosition();
    for (;;) {
      Entry entry = entryStream.peek();
      boolean doFiltering = true;
      if (firstCellInEntryBeforeFiltering == null) {
        assert !entry.getEdit().isEmpty() : "should not write empty edits";
        // Used to locate the region record in meta table. In WAL we only have the table name and
        // encoded region name which can not be mapping to region name without scanning all the
        // records for a table, so we need a start key, just like what we have done at client side
        // when locating a region. For the markers, we will use the start key of the region as the
        // row key for the edit. And we need to do this before filtering since all the cells may
        // be filtered out, especially that for the markers.
        firstCellInEntryBeforeFiltering = entry.getEdit().getCells().get(0);
      } else {
        // if this is not null then we know that the entry has already been filtered.
        doFiltering = false;
      }

      if (doFiltering) {
        entry = filterEntry(entry);
      }
      if (entry != null) {
        int sleepMultiplier = 1;
        try {
          if (!checker.canPush(entry, firstCellInEntryBeforeFiltering)) {
            if (batch.getLastWalPosition() > positionBefore) {
              // we have something that can push, break
              break;
            } else {
              checker.waitUntilCanPush(entry, firstCellInEntryBeforeFiltering);
            }
          }
        } catch (IOException e) {
          LOG.warn("failed to check whether we can push the WAL entries", e);
          if (batch.getLastWalPosition() > positionBefore) {
            // we have something that can push, break
            break;
          }
          sleepMultiplier = sleep(sleepMultiplier);
        }
        // arrive here means we can push the entry, record the last sequence id
        batch.setLastSeqId(Bytes.toString(entry.getKey().getEncodedRegionName()),
          entry.getKey().getSequenceId());
        // actually remove the entry.
        removeEntryFromStream(entryStream, batch);
        if (addEntryToBatch(batch, entry)) {
          break;
        }
      } else {
        // actually remove the entry.
        removeEntryFromStream(entryStream, batch);
      }
      WALEntryStream.HasNext hasNext = entryStream.hasNext();
      // always return if we have switched to a new file.
      if (switched(entryStream, currentPath)) {
        batch.setEndOfFile(true);
        break;
      }
      if (hasNext != WALEntryStream.HasNext.YES) {
        // For hasNext other than YES, it is OK to just retry.
        // As for RETRY and RETRY_IMMEDIATELY, the correct action is to retry, and for NO, it will
        // return NO again when you call the method next time, so it is OK to just return here and
        // let the loop in the upper layer to call hasNext again.
        break;
      }
    }
  }
WAL reader for a serial replication peer.
hbase-server/src/main/java/org/apache/hadoop/hbase/replication/regionserver/SerialReplicationSourceWALReader.java