/**
   * Reset the checksum validator and add the new header bytes. Assumes that the data buffer is
   * positioned just past the end of the invariant portion of the log entry header.
   *
   * @throws DatabaseException
   */
  private void startChecksum(ByteBuffer dataBuffer) throws ChecksumException {

    startChecksum(dataBuffer, true /* isChecksumTarget */);
  }
  /**
   * Variant of readNextEntry that throws FileNotFoundException and ChecksumException, rather than
   * wrapping them in an EnvironmentFailureException and invalidating the enviornment. This allows
   * users of this class (see cleaner.FileProcessor), and subclasses that override readNextEntry
   * (see ScavengerFileReader and LastFileReader), to handle these exceptions specially.
   */
  public final boolean readNextEntryAllowExceptions()
      throws FileNotFoundException, ChecksumException {

    boolean foundEntry = false;
    long savedCurrentEntryOffset = currentEntryOffset;
    long savedNextEntryOffset = nextEntryOffset;

    try {
      while ((!eof) && (!foundEntry)) {

        /* Read the invariant portion of the next header. */
        getLogEntryInReadBuffer();
        ByteBuffer dataBuffer = readData(LogEntryHeader.MIN_HEADER_SIZE, true); // collectData

        readBasicHeader(dataBuffer);

        boolean isTarget;
        boolean isChecksumTarget;
        boolean collectData;

        if (currentEntryHeader.isVariableLength()) {

          /*
           * For all variable length entries, init the checksum w/the
           * invariant portion of the header, before we know whether
           * the entry is a target for this reader.  This has
           * to be done before we read the variable portion of the
           * header, because readData() only guarantees that it
           * returns a dataBuffer that contains the next bytes that
           * are needed, and has no guarantee that it holds any bytes
           * that were previously read. The act of calling
           * readData() to obtain the optional portion may reset the
           * dataBuffer, and nudge the invariant part of the header
           * out of the buffer returned by readData()
           */
          startChecksum(dataBuffer);

          int optionalPortionLen = currentEntryHeader.getVariablePortionSize();

          /* Load the optional part of the header into a buffer. */
          dataBuffer = readData(optionalPortionLen, true);

          /*
           * Add to checksum while the buffer is positioned at
           * the start of the new bytes.
           */
          addToChecksum(dataBuffer, optionalPortionLen);

          /* Now read the optional bytes. */
          currentEntryHeader.readVariablePortion(dataBuffer);
        }

        /*
         * We've read the header of the next logrec. Move up our
         * offsets if we're moving forward. If we're moving
         * backwards, we set our offset before we read the header,
         * because we knew where the entry started.
         */
        if (forward) {
          currentEntryOffset = nextEntryOffset;
          nextEntryOffset +=
              currentEntryHeader.getSize()
                  + // header size
                  currentEntryHeader.getItemSize(); // item size
        }

        try {
          isTarget = isTargetEntry();

          isChecksumTarget = (isTarget || alwaysValidateChecksum);

          if (!currentEntryHeader.isVariableLength()) {
            startChecksum(dataBuffer, isChecksumTarget);
          }

          collectData = (isChecksumTarget && doChecksumOnRead) || isTarget;

          /*
           * Read in the body of the next entry. Note that even if
           * this isn't a targeted entry, we have to move the buffer
           * position along.
           */
          dataBuffer = readData(currentEntryHeader.getItemSize(), collectData);
        } catch (Throwable e) {
          if (forward) {
            currentEntryOffset = savedCurrentEntryOffset;
            nextEntryOffset = savedNextEntryOffset;
          }
          throw e;
        }

        /* Validate the log entry checksum. */
        validateChecksum(dataBuffer, isChecksumTarget);

        if (isTarget) {

          /*
           * For a target entry, call the subclass reader's
           * processEntry method to do whatever we need with the
           * entry.  It returns true if this entry is one that should
           * be returned.  Note that some entries, although targeted
           * and read, are not returned.
           */
          if (processEntry(dataBuffer)) {
            foundEntry = true;
            nRead++;
          }
        } else if (collectData) {

          /*
           * For a non-target entry that was validated, the buffer is
           * positioned at the start of the entry; skip over it.
           */
          skipEntry(dataBuffer);
        }
      }
    } catch (EOFException e) {
      eof = true;
    } catch (DatabaseException e) {
      eof = true;
      /* Report on error. */
      reportProblem(e);
      throw e;
    }

    return foundEntry;
  }