BIN bin,
int index,
DIN parentDIN)
throws DatabaseException {
LN ln = info.getLN();
byte[] key = info.getKey();
byte[] dupKey = info.getDupKey();
DatabaseImpl db = bin.getDatabase();
boolean isDupCountLN = parentDIN != null;
/* Status variables are used to generate debug tracing info. */
boolean obsolete = false; // The LN is no longer in use.
boolean migrated = false; // The LN was in use and is migrated.
boolean lockDenied = false;// The LN lock was denied.
boolean completed = false; // This method completed.
long nodeId = ln.getNodeId();
BasicLocker locker = null;
try {
Tree tree = db.getTree();
assert tree != null;
/*
* If the tree and log LSNs are equal, then we can be fairly
* certain that the log entry is current; in that case, it is
* wasteful to lock the LN here -- it is better to lock only once
* during lazy migration. But if the tree and log LSNs differ, it
* is likely that another thread has updated or deleted the LN and
* the log LSN is now obsolete; in this case we can avoid dirtying
* the BIN by checking for obsoleteness here, which requires
* locking. The latter case can occur frequently if trackDetail is
* false.
*
* 1. If the LSN in the tree and in the log are the same, we will
* attempt to migrate it.
*
* 2. If the LSN in the tree is < the LSN in the log, the log entry
* is obsolete, because this LN has been rolled back to a previous
* version by a txn that aborted.
*
* 3. If the LSN in the tree is > the LSN in the log, the log entry
* is obsolete, because the LN was advanced forward by some
* now-committed txn.
*/
if (treeLsn != logLsn) {
/*
* Check to see whether the LN being migrated is locked
* elsewhere. Do that by attempting to lock it. We can hold
* the latch on the BIN (and DIN) since we always attempt to
* acquire a non-blocking read lock. Holding the latch ensures
* that the INs won't change underneath us because of splits or
* eviction.
*/
locker = new BasicLocker(env);
LockResult lockRet = locker.nonBlockingLock
(nodeId, LockType.READ, db);
if (lockRet.getLockGrant() == LockGrantType.DENIED) {
/*
* LN is currently locked by another Locker, so we can't
* assume anything about the value of the LSN in the bin.
*/
nLNsLockedThisRun++;
lockDenied = true;
} else {
/* The LN is obsolete and can be purged. */
nLNsDeadThisRun++;
obsolete = true;
}
}
if (!obsolete && !lockDenied) {
/*
* Set the migrate flag and dirty the parent IN. The evictor
* or checkpointer will migrate the LN later.
*
* Then set the target node so it does not have to be fetched
* when it is migrated, if the tree and log LSNs are equal and
* the target is not resident. We must call postFetchInit to
* initialize MapLNs that have not been fully initialized yet
* [#13191].
*/
if (isDupCountLN) {
ChildReference dclRef = parentDIN.getDupCountLNRef();
dclRef.setMigrate(true);
parentDIN.setDirty(true);
if (treeLsn == logLsn && dclRef.getTarget() == null) {
ln.postFetchInit(db, logLsn);
parentDIN.updateDupCountLN(ln);
}
} else {
bin.setMigrate(index, true);
bin.setDirty(true);
if (treeLsn == logLsn && bin.getTarget(index) == null) {
ln.postFetchInit(db, logLsn);
bin.updateEntry(index, ln);
}
/*
* If the generation is zero, we fetched this BIN just for