/*
     * Assume that the window is properly positioned. Try to fill the read
     * buffer with data from this file handle, starting at the location
     * indicated by the starting offset field. If this file contains more
     * data, return true. If this file doesn't contain more data, return
     * false.
     *
     * In all cases, leave the the read buffer pointing at the target
     * offset and in a state that's ready to support reads, even if there
     * is nothing in the buffer. Note that the target offset, which may not
     * be the same as starting offset.
     * @return true if more data was read, false if not.
     */
    protected boolean fillFromFile(FileHandle fileHandle, long targetOffset)
        throws DatabaseException {

      boolean foundData = false;
      readBuffer.clear();
      if (fileManager.readFromFile(
          fileHandle.getFile(),
          readBuffer,
          startOffset,
          fileHandle.getFileNum(),
          false /* dataKnownToBeInFile */)) {
        foundData = true;
        nReadOperations += 1;
        /*
         * Ensure that fileNum and logVersion are in sync.  setFileNum
         * handles changes in the file number.  But we must also update
         * the logVersion here to handle the first read after we
         * initialize fileNum and logVersion is unknown.
         */
        logVersion = fileHandle.getLogVersion();
      }

      /*
       * In all cases, setup read buffer for valid reading. If the buffer
       * has no data, it will be positioned at the beginning, and will be
       * able to correctly return the fact that there is no data present.
       */

      endOffset = startOffset + threadSafeBufferPosition(readBuffer);
      threadSafeBufferFlip(readBuffer);
      threadSafeBufferPosition(readBuffer, (int) (targetOffset - startOffset));
      return foundData;
    }
    /*
     * Reposition to the specified file, and fill starting at
     * startOffset. Position the window's buffer to point at the log entry
     * indicated by targetOffset
     */
    public void slideAndFill(
        long windowfileNum, long windowStartOffset, long targetOffset, boolean forward)
        throws ChecksumException, FileNotFoundException, DatabaseException {

      FileHandle fileHandle = fileManager.getFileHandle(windowfileNum);
      try {
        startOffset = windowStartOffset;
        setFileNum(windowfileNum, fileHandle.getLogVersion());
        boolean foundData = fillFromFile(fileHandle, targetOffset);

        /*
         * When reading backwards, we need to guarantee there is no log
         * gap, throws out an EnvironmentFailreException if it exists.
         */
        if (!foundData && !forward) {
          throw EnvironmentFailureException.unexpectedState(
              "Detected a log file gap when reading backwards. "
                  + "Target position = "
                  + DbLsn.getNoFormatString(DbLsn.makeLsn(windowfileNum, targetOffset))
                  + " starting position = "
                  + DbLsn.getNoFormatString(DbLsn.makeLsn(windowfileNum, windowStartOffset))
                  + " end position = "
                  + DbLsn.getNoFormatString(DbLsn.makeLsn(windowfileNum, endOffset)));
        }
      } finally {
        fileHandle.release();
      }
    }
    /**
     * Fill up the read buffer with more data, moving along to the following file (next largest
     * number) if needed.
     *
     * @return true if the fill moved us to a new file.
     */
    protected boolean fillNext(boolean singleFile, int bytesNeeded)
        throws ChecksumException, FileNotFoundException, EOFException, DatabaseException {

      adjustReadBufferSize(bytesNeeded);

      FileHandle fileHandle = null;
      try {
        /* Get a file handle to read in more log. */
        fileHandle = fileManager.getFileHandle(fileNum);

        /*
         * Check to see if we've come to the end of the file.  If so,
         * get the next file.
         */
        startOffset = endOffset;
        if (fillFromFile(fileHandle, startOffset)) {
          /*
           * Successfully filled the read buffer, but didn't move to
           * a new file.
           */
          return false;
        }

        /* This file is done -- can we read in the next file? */
        if (singleFile) {
          throw new EOFException("Single file only");
        }

        Long nextFile = fileManager.getFollowingFileNum(fileNum, true /* forward */);

        if (nextFile == null) {
          throw new EOFException();
        }

        fileHandle.release();
        fileHandle = null;
        fileHandle = fileManager.getFileHandle(nextFile);
        setFileNum(nextFile, fileHandle.getLogVersion());
        startOffset = 0;
        fillFromFile(fileHandle, 0);
        return true;
      } finally {
        if (fileHandle != null) {
          fileHandle.release();
        }
      }
    }