cursor.updateBin(bin, duplicateEntryIndex);
if (n != null) {
bin.releaseLatch();
}
Locker locker = cursor.getLocker();
LockResult currentLock = null;
while (n != null) {
/*
* Write lock instead of read lock to avoid upgrade issues.
* There's a good chance that we'll need it for write
* anyway.
*/
currentLock = locker.lock
(currentLN.getNodeId(), LockType.WRITE, database);
bin = cursor.latchBIN();
duplicateEntryIndex = cursor.getIndex();
n = bin.fetchTarget(duplicateEntryIndex);
if (n == null) {
currentLN = null;
break;
}
if (n == currentLN ||
dupCount != -1) {
break;
} else {
/*
* We should consider releasing the lock on currentLN
* here. However, it may be been locked from a prior
* operation in this transaction.
*/
if (n instanceof LN) {
currentLN = (LN) n;
dupCount = -1;
} else {
DIN duplicateRoot = (DIN) n;
currentLN = (DupCountLN)
duplicateRoot.getDupCountLNRef().
fetchTarget(database, duplicateRoot);
dupCount = ((DupCountLN) currentLN).getDupCount();
}
bin.releaseLatch();
}
}
/*
* If the ref is knownDeleted (DupCountLN's can't be deleted or
* knownDeleted), or the LN that it points to is not a
* DupCountLN and the data in it is deleted, then we substitute
* the argument LN for it.
*
* dupCount == -1 means there is no dup tree here.
*
* If fetchTarget returns null, a deleted LN was cleaned.
*/
boolean isDeleted = false;
if (bin.isEntryKnownDeleted(duplicateEntryIndex)) {
isDeleted = true;
} else if (dupCount == -1) {
LN existingLN = (LN) bin.fetchTarget(duplicateEntryIndex);
if (existingLN == null || existingLN.isDeleted()) {
isDeleted = true;
}
}
if (isDeleted) {
/*
* Set the abort LSN to that of the lock held on the
* current LN, if the current LN was previously locked by
* this txn. This is needed when we change the node ID of
* this slot.
*
* If reusing a slot with an deleted LN deleted in a prior
* transaction (the LockGrantType is NEW or UPGRADE),
* always set abortKnownDeleted=true. It may be that the
* existing slot is PENDING_DELETED, but we restore to
* KNOWN_DELETED in the event of an abort.
*/
long abortLsn = bin.getLsn(duplicateEntryIndex);
boolean abortKnownDeleted = true;
if (currentLN != null &&
currentLock.getLockGrant() == LockGrantType.EXISTING) {
long nodeId = currentLN.getNodeId();
abortLsn = locker.getAbortLsn(nodeId);
abortKnownDeleted =
locker.getAbortKnownDeleted(nodeId);
}