Пример #1
0
  /*
   * A checksum error has been encountered.  Go to the start of this log file
   * and read forward until the lower side of the corrupted area has been
   * found.
   */
  @Override
  protected boolean resyncReader(long nextGoodRecordPostCorruption, boolean showCorruptedBounds)
      throws DatabaseException {

    LastFileReader reader = null;
    long tryReadBufferFileNum = DbLsn.getFileNumber(nextGoodRecordPostCorruption);

    while (tryReadBufferFileNum >= 0) {
      try {
        reader = new LastFileReader(envImpl, readBufferSize, Long.valueOf(tryReadBufferFileNum));
        break;
      } catch (ChecksumException e) {

        /*
         * We encountered a problem opening this file so skip to an
         * earlier file.
         */
        tryReadBufferFileNum--;
        continue;
      }
    }

    boolean switchedFiles =
        tryReadBufferFileNum != DbLsn.getFileNumber(nextGoodRecordPostCorruption);

    if (!switchedFiles) {

      /*
       * Read forward until a checksum fails.  This reader will not throw
       * an exception if a checksum error is hit -- it will just return
       * false.
       */
      while (reader.readNextEntry()) {}
    }

    long lastUsedLsn = reader.getLastValidLsn();
    long nextAvailableLsn = reader.getEndOfLog();
    if (showCorruptedBounds) {
      System.err.println("A checksum error was found in the log.");
      System.err.println("Corruption begins at LSN:\n   " + DbLsn.toString(nextAvailableLsn));
      System.err.println(
          "Last known good record before corruption is at LSN:\n   " + DbLsn.toString(lastUsedLsn));
      System.err.println(
          "Next known good record after corruption is at LSN:\n   "
              + DbLsn.toString(nextGoodRecordPostCorruption));
    }

    startLsn = lastUsedLsn;
    initStartingPosition(nextAvailableLsn, null);
    if (switchedFiles) {
      currentEntryPrevOffset = 0;
    }
    /* Indicate resync is permitted so don't throw exception. */
    return true;
  }
  /** Helper for determining the starting position and opening up a file at the desired location. */
  protected void initStartingPosition(long endOfFileLsn, Long ignoreSingleFileNumber) {
    eof = false;
    if (forward) {

      /*
       * Start off at the startLsn. If that's null, start at the
       * beginning of the log. If there are no log files, set eof.
       */
      if (startLsn != DbLsn.NULL_LSN) {
        window.initAtFileStart(startLsn);
      } else {
        Long firstNum = fileManager.getFirstFileNum();
        if (firstNum == null) {
          eof = true;
        } else {
          window.initAtFileStart(DbLsn.makeLsn(firstNum, 0));
        }
      }

      /*
       * After we read the first entry, the currentEntry will point here.
       */
      nextEntryOffset = window.getEndOffset();
    } else {

      /*
       * Make the read buffer look like it's positioned off the end of
       * the file. Initialize the first LSN we want to read. When
       * traversing the log backwards, we always start at the very end.
       */
      assert startLsn != DbLsn.NULL_LSN;
      window.initAtFileStart(endOfFileLsn);

      /*
       * currentEntryPrevOffset points to the entry we want to start out
       * reading when going backwards. If it's 0, the entry we want to
       * read is in a different file.
       */
      if (DbLsn.getFileNumber(startLsn) == DbLsn.getFileNumber(endOfFileLsn)) {
        currentEntryPrevOffset = DbLsn.getFileOffset(startLsn);
      } else {
        currentEntryPrevOffset = 0;
      }
      currentEntryOffset = DbLsn.getFileOffset(endOfFileLsn);
    }
  }
Пример #3
0
  /**
   * Returns whether a given obsolete LSN has already been counted in the utilization profile. If
   * true is returned, it should not be counted again, to prevent double-counting.
   */
  private boolean isObsoleteLsnAlreadyCounted(long oldLsn, long newLsn) {

    /* If the file summary follows the new LSN, it was already counted. */
    Long fileNum = new Long(DbLsn.getFileNumber(oldLsn));
    long fileSummaryLsn = DbLsn.longToLsn((Long) fileSummaryLsns.get(fileNum));
    int cmpFsLsnToNewLsn =
        (fileSummaryLsn != DbLsn.NULL_LSN) ? DbLsn.compareTo(fileSummaryLsn, newLsn) : -1;
    return (cmpFsLsnToNewLsn >= 0);
  }
Пример #4
0
  void setPosition(long startLsn)
      throws ChecksumException, FileNotFoundException, DatabaseException {

    if (startLsn == DbLsn.NULL_LSN) {
      return;
    }

    /*
     * An assertion: a reposition should never make the reader lose ground.
     */
    if (forward) {
      if (DbLsn.compareTo(getLastLsn(), startLsn) > 0) {
        throw EnvironmentFailureException.unexpectedState(
            "Feeder forward scanning should not be repositioned to "
                + " a position earlier than the current position. Current"
                + " lsn = "
                + DbLsn.getNoFormatString(getLastLsn())
                + " reposition = "
                + DbLsn.getNoFormatString(startLsn));
      }
    } else {
      if (DbLsn.compareTo(getLastLsn(), startLsn) < 0) {
        throw EnvironmentFailureException.unexpectedState(
            "Feeder backward scanning should not be repositioned to "
                + " a position later than the current position. Current"
                + " lsn = "
                + DbLsn.getNoFormatString(getLastLsn())
                + " reposition = "
                + DbLsn.getNoFormatString(startLsn));
      }
    }

    long fileNum = DbLsn.getFileNumber(startLsn);
    long offset = DbLsn.getFileOffset(startLsn);

    if (window.containsLsn(fileNum, offset)) {
      window.positionBuffer(offset);
    } else {
      window.slideAndFill(fileNum, offset, offset);
    }

    if (forward) {
      nextEntryOffset = offset;
    } else {
      currentEntryPrevOffset = offset;
    }
    nReposition++;
  }
Пример #5
0
  public void testFlipFile() throws Throwable {

    /*
     * The setUp() method opens a standalone FileManager, but in this test
     * case we need a regular Environment.  On Windows, we can't lock the
     * file range twice in FileManager.lockEnvironment, so we must close
     * the standalone FileManager here before opening a regular
     * environment.
     */
    fileManager.clear();
    fileManager.close();
    fileManager = null;

    EnvironmentConfig envConfig = TestUtils.initEnvConfig();
    envConfig.setAllowCreate(true);
    envConfig.setTransactional(true);
    Environment env = new Environment(envHome, envConfig);
    EnvironmentImpl envImpl = DbInternal.envGetEnvironmentImpl(env);
    FileManager fileManager = envImpl.getFileManager();

    DatabaseConfig dbConfig = new DatabaseConfig();
    dbConfig.setAllowCreate(true);
    Database exampleDb = env.openDatabase(null, "simpleDb", dbConfig);

    assertEquals("Should have 0 as current file", 0L, fileManager.getCurrentFileNum());
    long flipLsn = envImpl.forceLogFileFlip();
    assertEquals("LSN should be 1 post-flip", 1L, DbLsn.getFileNumber(flipLsn));
    DatabaseEntry key = new DatabaseEntry();
    DatabaseEntry data = new DatabaseEntry();
    key.setData("key".getBytes());
    data.setData("data".getBytes());
    exampleDb.put(null, key, data);
    assertEquals("Should have 1 as last file", 1L, fileManager.getCurrentFileNum());
    exampleDb.close();
    env.close();
  }
 /*
  * Position this window at this LSN, but leave it empty, it has no data
  * yet.
  */
 public void initAtFileStart(long startLsn) {
   setFileNum(DbLsn.getFileNumber(startLsn), LogEntryType.UNKNOWN_FILE_HEADER_VERSION);
   startOffset = DbLsn.getFileOffset(startLsn);
   endOffset = startOffset;
 }
  /**
   * Ensure that the next target is in the window. The default behavior is that the next target is
   * the next previous entry.
   *
   * @throws DatabaseException
   */
  protected void setBackwardPosition()
      throws ChecksumException, FileNotFoundException, EOFException, DatabaseException {

    /*
     * currentEntryPrevOffset is the entry before the current entry.
     * currentEntryOffset is the entry we just read (or the end of the
     * file if we're starting out.
     */
    if ((currentEntryPrevOffset != 0) && window.containsOffset(currentEntryPrevOffset)) {

      /* The next log entry has passed the start LSN. */
      long nextLsn = DbLsn.makeLsn(window.currentFileNum(), currentEntryPrevOffset);
      if (finishLsn != DbLsn.NULL_LSN) {
        if (DbLsn.compareTo(nextLsn, finishLsn) == -1) {
          throw new EOFException(
              "finish="
                  + DbLsn.getNoFormatString(finishLsn)
                  + "next="
                  + DbLsn.getNoFormatString(nextLsn));
        }
      }

      /* This log entry starts in this buffer, just reposition. */
      window.positionBuffer(currentEntryPrevOffset);
    } else {

      /*
       * The start of the log entry is not in this read buffer so
       * we must fill the buffer again.
       *
       * 1) The target log entry is in a different file from the
       * current window's file. Move the window to the previous
       * file and start the read from the target LSN.
       *
       * 2) The target log entry is the same file but the log entry
       * is larger than the read chunk size. Start the next read
       * buffer from the target LSN. It's going to take multiple
       * reads to get the log entry, and we might as well get as
       * much as possible.
       *
       * 3) In the same file, and the log entry fits within one
       * read buffer. Try to position the next buffer chunk so the
       * target entry is held within the buffer, all the way at the
       * end. That way, since we're reading backwards, there will be
       * more buffered data available for following reads.
       */
      long nextFile;
      long nextWindowStart;
      long nextTarget;

      if (currentEntryPrevOffset == 0) {
        /* Case 1: Go to another file. */
        currentEntryPrevOffset = fileManager.getFileHeaderPrevOffset(window.currentFileNum());

        Long prevFileNum = fileManager.getFollowingFileNum(window.currentFileNum(), false);
        if (prevFileNum == null) {
          throw new EOFException("No file following " + window.currentFileNum());
        }

        /*
         *  Check finishLSN  before proceeding, in case we should stop
         *  the search before attempting to set the file reader to a
         *  position in the previous file. In  [#22407] we threw a
         *  spurious EFE complaining that we cannot read backwards over
         *  a cleaned file because the previous file had  been cleaned
         *  away.
         */
        if (finishLsn != DbLsn.NULL_LSN && prevFileNum < DbLsn.getFileNumber(finishLsn)) {
          throw new EOFException(
              "finish="
                  + DbLsn.getNoFormatString(finishLsn)
                  + " nextFile=0x"
                  + Long.toHexString(prevFileNum));
        }

        if (window.currentFileNum() - prevFileNum.longValue() != 1) {
          handleGapInBackwardsScan(prevFileNum);
        }

        nextFile = prevFileNum;
        nextWindowStart = currentEntryPrevOffset;
        nextTarget = currentEntryPrevOffset;
      } else if ((currentEntryOffset - currentEntryPrevOffset) > window.capacity()) {

        /*
         * Case 2: The entry is in the same file, but is bigger
         * than one buffer. Position it at the front of the buffer.
         */
        nextFile = window.currentFileNum();
        nextWindowStart = currentEntryPrevOffset;
        nextTarget = currentEntryPrevOffset;
      } else {

        /*
         * Case 3: In same file, but not in this buffer. The target
         * entry will fit in one buffer.
         */
        nextFile = window.currentFileNum();
        long newPosition = currentEntryOffset - window.capacity();
        nextWindowStart = (newPosition < 0) ? 0 : newPosition;
        nextTarget = currentEntryPrevOffset;
      }

      /* The next log entry has passed the start LSN. */
      long nextLsn = DbLsn.makeLsn(nextFile, currentEntryPrevOffset);
      if (finishLsn != DbLsn.NULL_LSN) {
        if (DbLsn.compareTo(nextLsn, finishLsn) == -1) {
          throw new EOFException(
              "finish="
                  + DbLsn.getNoFormatString(finishLsn)
                  + " next="
                  + DbLsn.getNoFormatString(nextLsn));
        }
      }

      window.slideAndFill(nextFile, nextWindowStart, nextTarget, forward);
    }

    /* The current entry will start at this offset. */
    currentEntryOffset = currentEntryPrevOffset;
  }