private void reportProblem(Exception e) {

    StringBuilder sb = new StringBuilder();
    sb.append("Halted log file reading at file 0x")
        .append(Long.toHexString(window.currentFileNum()))
        .append(" offset 0x")
        .append(Long.toHexString(nextEntryOffset))
        .append(" offset(decimal)=")
        .append(nextEntryOffset)
        .append(" prev=0x")
        .append(Long.toHexString(currentEntryPrevOffset));

    if (currentEntryHeader != null) {
      LogEntryType problemType = LogEntryType.findType(currentEntryHeader.getType());
      sb.append(":\nentry=")
          .append(problemType)
          .append("type=")
          .append(currentEntryHeader.getType())
          .append(",version=")
          .append(currentEntryHeader.getVersion())
          .append(")\nprev=0x")
          .append(Long.toHexString(currentEntryPrevOffset))
          .append("\nsize=")
          .append(currentEntryHeader.getItemSize())
          .append("\nNext entry should be at 0x")
          .append(
              Long.toHexString(
                  nextEntryOffset
                      + currentEntryHeader.getSize()
                      + currentEntryHeader.getItemSize()));
    }

    LoggerUtils.traceAndLogException(envImpl, "FileReader", "readNextEntry", sb.toString(), e);
  }
  /**
   * 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;
  }
Пример #3
0
 /** Returns the total size (including header) of the last entry read. */
 public int getLastEntrySize() {
   return currentEntryHeader.getSize() + currentEntryHeader.getItemSize();
 }