Пример #1
0
  /**
   * Something is wrong with this file. If there is no data in this file (the header is <= the file
   * header size) then move this last file aside and search the next "last" file. If the last file
   * does have data in it, return null and throw an exception back to the application, since we're
   * not sure what to do now.
   *
   * @param cause is a DatabaseException or ChecksumException.
   */
  private Long attemptToMoveBadFile(Exception cause)
      throws IOException, ChecksumException, DatabaseException {

    String fileName = fileManager.getFullFileNames(window.currentFileNum())[0];
    File problemFile = new File(fileName);

    if (problemFile.length() <= FileManager.firstLogEntryOffset()) {
      fileManager.clear(); // close all existing files
      /* Move this file aside. */
      Long lastNum = fileManager.getFollowingFileNum(window.currentFileNum(), false);
      if (!fileManager.renameFile(window.currentFileNum(), FileManager.BAD_SUFFIX)) {
        throw EnvironmentFailureException.unexpectedState(
            "Could not rename file: 0x" + Long.toHexString(window.currentFileNum()));
      }

      return lastNum;
    }
    /* There's data in this file, throw up to the app. */
    if (cause instanceof DatabaseException) {
      throw (DatabaseException) cause;
    }
    if (cause instanceof ChecksumException) {
      throw (ChecksumException) cause;
    }
    throw EnvironmentFailureException.unexpectedException(cause);
  }
Пример #2
0
  /**
   * Returns the SHA1 has associated with the file.
   *
   * @param file
   * @param length
   * @return
   * @throws IOException
   * @throws DatabaseException
   */
  static MessageDigest getSHA1Digest(File file, long length) throws IOException, DatabaseException {

    MessageDigest messageDigest = null;

    try {
      messageDigest = MessageDigest.getInstance("SHA1");
    } catch (NoSuchAlgorithmException e) {
      throw EnvironmentFailureException.unexpectedException(e);
    }
    final FileInputStream fileStream = new FileInputStream(file);
    try {
      ByteBuffer buffer = ByteBuffer.allocate(TRANSFER_BYTES);
      for (long bytes = length; bytes > 0; ) {
        int readSize = (int) Math.min(TRANSFER_BYTES, bytes);
        int readBytes = fileStream.read(buffer.array(), 0, readSize);
        if (readBytes == -1) {
          throw new IOException("Premature EOF. Was expecting: " + readSize);
        }
        messageDigest.update(buffer.array(), 0, readBytes);
        bytes -= readBytes;
      }
    } finally {
      fileStream.close();
    }
    return messageDigest;
  }
Пример #3
0
  public LogFileFeeder(FeederManager feederManager, SocketChannel channel)
      throws DatabaseException {
    super(feederManager.getEnvImpl(), "Log File Feeder");

    this.feederManager = feederManager;
    logger = feederManager.logger;
    this.namedChannel = new NamedChannel(channel, feederManager.nameIdPair);

    try {
      messageDigest = MessageDigest.getInstance("SHA1");
    } catch (NoSuchAlgorithmException e) {
      LoggerUtils.severe(
          logger,
          feederManager.getEnvImpl(),
          "The SHA1 algorithm was not made available " + "by the security provider");
      throw EnvironmentFailureException.unexpectedException(e);
    }
  }
Пример #4
0
  /**
   * Rollback the changes to this txn's write locked nodes up to but not including the entry at the
   * specified matchpoint. When we log a transactional entry, we record the LSN of the original,
   * before-this-transaction version as the abort LSN. This means that if there are multiple updates
   * to a given record in a single transaction, each update only references that original version
   * and its true predecessor.
   *
   * <p>This was done to streamline abort processing, so that an undo reverts directly to the
   * original version rather than stepping through all the intermediates. The intermediates are
   * skipped. However, undo to a matchpoint may need to stop at an intermediate point, so we need to
   * create a true chain of versions.
   *
   * <p>To do so, we read the transaction backwards from the last logged LSN to reconstruct a
   * transaction chain that links intermediate versions of records. For example, suppose our
   * transaction looks like this and that we are undoing up to LSN 250
   *
   * <p>lsn=100 node=A (version 1) lsn=200 node=B (version 1) <-- matchpointLsn lsn=300 node=C
   * (version 1) lsn=400 node=A (version 2) lsn=500 node=B (version 2) lsn=600 node=A (version 3)
   * lsn=700 node=A (version 4)
   *
   * <p>To setup the old versions, We walk from LSN 700 -> 100 700 (A) rolls back to 600 600 (A)
   * rolls back to 400 500 (B) rolls back to 200 400 (A) rolls back to 100 300 (C) rolls back to an
   * empty slot (NULL_LSN).
   *
   * <p>A partial rollback also requires resetting the lastLoggedLsn field, because these operations
   * are no longer in the btree and their on-disk entries are no longer valid.
   *
   * <p>Lastly, the appropriate write locks must be released.
   *
   * @param matchpointLsn the rollback should go up to but not include this LSN.
   */
  private void undoWrites(long matchpointLsn, List<Long> rollbackLsns) throws DatabaseException {

    /*
     * Generate a map of nodeId->List of intermediate LSNs for this node.
     * to re-create the transaction chain.
     */
    TreeLocation location = new TreeLocation();
    Long undoLsn = lastLoggedLsn;
    TxnChain chain = new TxnChain(undoLsn, id, matchpointLsn, undoDatabases, envImpl);

    try {
      while ((undoLsn != DbLsn.NULL_LSN) && DbLsn.compareTo(undoLsn, matchpointLsn) > 0) {

        UndoReader undo = new UndoReader(envImpl, undoLsn, undoDatabases);

        RevertInfo revertTo = chain.pop();

        logFinest(undoLsn, undo, revertTo);

        /*
         * When we undo this log entry, we've logically truncated
         * it from the log. Remove it from the btree and mark it
         * obsolete.
         */
        RecoveryManager.rollbackUndo(logger, Level.FINER, undo, revertTo, location, undoLsn);

        countObsoleteInexact(undoLsn, undo);
        rollbackLsns.add(undoLsn);

        /*
         * Move on to the previous log entry for this txn and update
         * what is considered to be the end of the transaction chain.
         */
        undoLsn = undo.logEntry.getUserTxn().getLastLsn();
        lastLoggedLsn = undoLsn;
      }

      /*
       * Correct the fields which hold LSN and VLSN state that may
       * now be changed.
       */
      lastApplied = chain.getLastValidVLSN();
      if (!updateLoggedForTxn()) {
        firstLoggedLsn = NULL_LSN;
      }

    } catch (DatabaseException e) {
      LoggerUtils.traceAndLogException(
          envImpl, "Txn", "undo", "For LSN=" + DbLsn.getNoFormatString(undoLsn), e);
      throw e;
    } catch (RuntimeException e) {
      throw EnvironmentFailureException.unexpectedException(
          "Txn undo for LSN=" + DbLsn.getNoFormatString(undoLsn), e);
    }

    if (lastLoggedLsn == DbLsn.NULL_LSN) {
      /*
       * The whole txn is rolled back, and it may not appear again. This
       * is the equivalent of an abort. Do any delete processing for an
       * abort which is needed.
       *
       * Set database state for deletes before releasing any write
       * locks.
       */
      setDeletedDatabaseState(false);
    }

    /* Clear any write locks that are no longer needed. */
    clearWriteLocks(chain.getRemainingLockedNodes());
  }