/** * 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); }
/** * 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; }
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); } }
/** * 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()); }