long firstActiveLsn = info.firstActiveLsn;
long lastUsedLsn = info.lastUsedLsn;
long endOfFileLsn = info.nextAvailableLsn;
/* Set up a reader to pick up target log entries from the log. */
LNFileReader reader =
new LNFileReader(env, readBufferSize, lastUsedLsn,
false, endOfFileLsn, firstActiveLsn, null);
Iterator iter = lnTypes.iterator();
while (iter.hasNext()) {
LogEntryType lnType = (LogEntryType) iter.next();
reader.addTargetType(lnType);
}
Map countedFileSummaries = new HashMap(); // TxnNodeId -> file number
Set countedAbortLsnNodes = new HashSet(); // set of TxnNodeId
DbTree dbMapTree = env.getDbMapTree();
TreeLocation location = new TreeLocation();
try {
/*
* Iterate over the target LNs and commit records, constructing
* tree.
*/
while (reader.readNextEntry()) {
if (reader.isLN()) {
/* Get the txnId from the log entry. */
Long txnId = reader.getTxnId();
/*
* If this node is not in a committed txn, examine it to
* see if it should be undone.
*/
if (!committedTxnIds.contains(txnId)) {
/*
* Invoke the evictor to reduce memory consumption.
*/
env.invokeEvictor();
LN ln = reader.getLN();
long logLsn = reader.getLastLsn();
long abortLsn = reader.getAbortLsn();
boolean abortKnownDeleted =
reader.getAbortKnownDeleted();
DatabaseId dbId = reader.getDatabaseId();
DatabaseImpl db = dbMapTree.getDb(dbId);
/* Database may be null if it's been deleted. */
if (db != null) {
ln.postFetchInit(db, logLsn);
try {
undo(detailedTraceLevel,
db,
location,
ln,
reader.getKey(),
reader.getDupTreeKey(),
logLsn,
abortLsn,
abortKnownDeleted,
info,
true);
} finally {
if (location.bin != null) {
location.bin.releaseLatchIfOwner();
}
}
/* Undo utilization info. */
TxnNodeId txnNodeId =
new TxnNodeId(reader.getNodeId(),
txnId.longValue());
undoUtilizationInfo(ln, logLsn, abortLsn,
abortKnownDeleted,
txnNodeId,
countedFileSummaries,
countedAbortLsnNodes);
/*
* Add any db that we encounter LN's for because
* they'll be part of the in-memory tree and
* therefore should be included in the INList
* rebuild.
*/
inListRebuildDbIds.add(dbId);
}
}
} else if (reader.isPrepare()) {
/*
* The entry just read is a prepare record. There should
* be no lock conflicts during recovery, but just in case
* there are, we set the locktimeout to 0.
*/
long prepareId = reader.getTxnPrepareId();
Long prepareIdL = new Long(prepareId);
if (!committedTxnIds.contains(prepareIdL) &&
!abortedTxnIds.contains(prepareIdL)) {
TransactionConfig txnConf = new TransactionConfig();
Txn preparedTxn = new Txn(env, txnConf, prepareId);
preparedTxn.setLockTimeout(0);
preparedTxns.put(prepareIdL, preparedTxn);
env.getTxnManager().registerXATxn
(reader.getTxnPrepareXid(), preparedTxn, true);
Tracer.trace(Level.INFO, env,
"Found unfinished prepare record: id: " +
reader.getTxnPrepareId() +
" Xid: " + reader.getTxnPrepareXid());
}
} else if (reader.isAbort()) {
/* The entry just read is an abort record. */
abortedTxnIds.add(new Long(reader.getTxnAbortId()));
} else {
/* The entry just read is a commit record. */
committedTxnIds.add(new Long(reader.getTxnCommitId()));
}
}
info.nRepeatIteratorReads += reader.getNRepeatIteratorReads();
} catch (Exception e) {
traceAndThrowException(reader.getLastLsn(), "undoLNs", e);
}
}