long logLsn)
throws DatabaseException {
/* Check if inClone is the root. */
if (inClone.isDbRoot()) {
IN rootIN = isRoot(tree, db, inClone, logLsn);
if (rootIN == null) {
/*
* inClone is a root, but no longer in use. Return now, because
* a call to tree.getParentNode will return something
* unexpected since it will try to find a parent.
*/
return null;
} else {
return rootIN;
}
}
/* It's not the root. Can we find it, and if so, is it current? */
inClone.latch(Cleaner.UPDATE_GENERATION);
SearchResult result = null;
try {
result = tree.getParentINForChildIN
(inClone,
true, // requireExactMatch
Cleaner.UPDATE_GENERATION,
inClone.getLevel(),
null); // trackingList
if (!result.exactParentFound) {
return null;
}
/* Note that treeLsn may be for a BINDelta, see below. */
long treeLsn = result.parent.getLsn(result.index);
/*
* The IN in the tree is a never-written IN for a DW db so the IN
* in the file is obsolete. [#15588]
*/
if (treeLsn == DbLsn.NULL_LSN) {
return null;
}
/*
* If tree and log LSNs are equal, then we've found the exact IN we
* read from the log. We know the treeLsn is not for a BINDelta,
* because it is equal to LSN of the IN (or BIN) we read from the
* log. To avoid a fetch, we can place the inClone in the tree if
* it is not already resident.
*/
if (treeLsn == logLsn) {
IN in = (IN) result.parent.getTarget(result.index);
if (in == null) {
in = inClone;
in.postFetchInit(db, logLsn);
result.parent.updateNode
(result.index, in, null /*lnSlotKey*/);
}
in.latch(Cleaner.UPDATE_GENERATION);
return in;
}
/*
* If the tree and log LSNs are unequal, then we must get the full
* version LSN in case the tree LSN is actually for a BINDelta.
* The simplest way to do that is to fetch the IN in the tree.
*
* A potential optimization is to fetch the delta first and then
* reconstitute the BIN using the inClone if the delta's
* lastFullVersion is equal to the log LSN. This avoids fetching
* the inClone we have in hand, or a later full version that does
* not need migration.
*/
if (inClone.isBIN()) {
/*
* getParentINForChildIN takes exclusive latches above, so we
* use fetchTargetWithExclusiveLatch.
*/
final IN in = (IN) result.parent.fetchTargetWithExclusiveLatch
(result.index);
treeLsn = in.getLastFullVersion();
}
/* Now compare LSNs, since we know treeLsn is the full version. */
final int compareVal = DbLsn.compareTo(treeLsn, logLsn);
if (compareVal > 0) {
/* Log entry is obsolete. */
return null;
}
/*
* Log entry is same or newer than what's in the tree.
* getParentINForChildIN takes exclusive latches above, so we use
* fetchTargetWithExclusiveLatch.
*/
final IN in = (IN) result.parent.fetchTargetWithExclusiveLatch
(result.index);
in.latch(Cleaner.UPDATE_GENERATION);
return in;
} finally {
if ((result != null) && (result.exactParentFound)) {
result.parent.releaseLatch();
}