try {
Set alreadyUndone = new HashSet();
TreeLocation location = new TreeLocation();
while (undoLsn != DbLsn.NULL_LSN) {
LNLogEntry undoEntry =
(LNLogEntry) logManager.getLogEntry(undoLsn);
LN undoLN = undoEntry.getLN();
nodeId = new Long(undoLN.getNodeId());
/*
* Only process this if this is the first time we've seen this
* node. All log entries for a given node have the same
* abortLsn, so we don't need to undo it multiple times.
*/
if (!alreadyUndone.contains(nodeId)) {
alreadyUndone.add(nodeId);
DatabaseId dbId = undoEntry.getDbId();
DatabaseImpl db = (DatabaseImpl) undoDatabases.get(dbId);
undoLN.postFetchInit(db, undoLsn);
long abortLsn = undoEntry.getAbortLsn();
boolean abortKnownDeleted =
undoEntry.getAbortKnownDeleted();
try {
RecoveryManager.undo(Level.FINER,
db,
location,
undoLN,
undoEntry.getKey(),
undoEntry.getDupKey(),
undoLsn,
abortLsn,
abortKnownDeleted,
null, false);
} finally {
if (location.bin != null) {
location.bin.releaseLatchIfOwner();
}
}
/*
* The LN undone is counted as obsolete if it was not
* deleted.
*/
if (!undoLN.isDeleted()) {
logManager.countObsoleteNode(undoLsn, null);
}
}
/* Move on to the previous log entry for this txn. */
undoLsn = undoEntry.getUserTxn().getLastLsn();
}
} catch (DatabaseException e) {
Tracer.trace(envImpl, "Txn", "undo",
"for node=" + nodeId + " LSN=" +
DbLsn.getNoFormatString(undoLsn), e);