try {
dupRoot = (DIN) n;
dupRoot.latch();
/* Lock the DupCountLN before logging any LNs. */
LockResult dclLockResult =
cursor.lockDupCountLN(dupRoot, LockType.WRITE);
/* The BIN/index may have changed during locking. */
bin = cursor.getBIN();
index = cursor.getIndex();
/*
* Do not proceed if duplicates are not allowed and there are
* one or more duplicates already present. Note that if the
* dup count is zero, we allow the insert.
*/
if (!allowDuplicates) {
DupCountLN dcl = (DupCountLN) dclLockResult.getLN();
if (dcl.getDupCount() > 0) {
return false;
}
}
/*
* Split the dup root if necessary. The dup root may have
* changed during locking above or by the split, so refetch it.
* In either case it will be latched.
*/
maybeSplitDuplicateRoot(bin, index);
dupRoot = (DIN) bin.fetchTarget(index);
/*
* Search the duplicate tree for the right place to insert this
* new record. Releases the latch on duplicateRoot. If the
* duplicateRoot got logged as a result of some splitting,
* update the BIN's LSN information. The SortedLSNTreeWalker
* relies on accurate LSNs in the in-memory tree.
*/
byte[] newLNKey = newLN.getData();
long previousLsn = dupRoot.getLastFullVersion();
try {
dupBin = (DBIN) searchSubTreeSplitsAllowed
(dupRoot, newLNKey, -1, true /*updateGeneration*/);
} catch (SplitRequiredException e) {
/*
* Shouldn't happen -- we have the DIN in the root of the
* dup tree latched during this insert, so there should be
* no possibility of being unable to insert a new entry
* into the DIN root of the dup tree.
*/
throw new DatabaseException(e) ;
}
long currentLsn = dupRoot.getLastFullVersion();
if (currentLsn != previousLsn) {
bin.updateEntry(index, currentLsn);
}
/* Release the BIN latch to increase concurrency. */
cursor.releaseBIN();
bin = null;
/* The search above released the dup root latch. */
dupRoot = null;
/*
* Try to insert a new reference object. If successful, we'll
* log the LN and update the LSN in the reference.
*/
ChildReference newLNRef =
new ChildReference(newLN, newLNKey, DbLsn.NULL_LSN);
int dupIndex = dupBin.insertEntry1(newLNRef);
if ((dupIndex & IN.INSERT_SUCCESS) != 0) {
/*
* Update the cursor to point to the entry that has been
* successfully inserted.
*/
dupIndex &= ~IN.INSERT_SUCCESS;
cursor.updateDBin(dupBin, dupIndex);
/* Log the new LN. */
long newLsn = DbLsn.NULL_LSN;
try {
newLsn = newLN.log
(env, database.getId(), key, DbLsn.NULL_LSN,
cursor.getLocker());
} finally {
if (newLsn == DbLsn.NULL_LSN) {
/* See Tree.insert for an explanation. */
dupBin.setKnownDeleted(dupIndex);
}
}
lnLock.setAbortLsn(DbLsn.NULL_LSN, true, true);
dupBin.setLsn(dupIndex, newLsn);
traceInsertDuplicate(Level.FINER,
database.getDbEnvironment(),
dupBin, newLN, newLsn, binNid);
successfulInsert = true;
} else {
/*
* The insert was not successful. Either this is a
* duplicate duplicate or there is an existing entry but
* that entry is deleted.
*/
dupIndex &= ~IN.EXACT_MATCH;
cursor.updateDBin(dupBin, dupIndex);
LN currentLN = (LN) dupBin.fetchTarget(dupIndex);
/* If an LN is present, lock it and check deleted-ness. */
boolean isDeleted = false;
LockResult currentLock = null;
if (currentLN == null) {
/* The LN was cleaned. */
isDeleted = true;
} else {
currentLock = cursor.lockLNDeletedAllowed
(currentLN, LockType.WRITE);
currentLN = currentLock.getLN();
/* The DBIN/index may have changed while locking. */
dupBin = cursor.getDupBIN();
dupIndex = cursor.getDupIndex();
if (dupBin.isEntryKnownDeleted(dupIndex) ||
currentLN == null ||
currentLN.isDeleted()) {
/* The current LN is deleted/cleaned. */
isDeleted = true;
}
}
if (isDeleted) {
/* See Tree.insert for an explanation. */
long abortLsn = dupBin.getLsn(dupIndex);
boolean abortKnownDeleted = true;
if (currentLN != null &&
currentLock.getLockGrant() ==
LockGrantType.EXISTING) {
long nodeId = currentLN.getNodeId();
Locker locker = cursor.getLocker();
WriteLockInfo info =
locker.getWriteLockInfo(nodeId);