}
boolean setNewIdKey = false;
boolean anyLocksDenied = false;
final DatabaseImpl db = getDatabase();
final EnvironmentImpl envImpl = db.getDbEnvironment();
for (int i = 0; i < getNEntries(); i++) {
/* KD and PD determine deletedness. */
if (!isEntryPendingDeleted(i) && !isEntryKnownDeleted(i)) {
continue;
}
/*
* We have to be able to lock the LN before we can compress the
* entry. If we can't, then skip over it.
*
* We must lock the LN even if isKnownDeleted is true, because
* locks protect the aborts. (Aborts may execute multiple
* operations, where each operation latches and unlatches. It's the
* LN lock that protects the integrity of the whole multi-step
* process.)
*
* For example, during abort, there may be cases where we have
* deleted and then added an LN during the same txn. This means
* that to undo/abort it, we first delete the LN (leaving
* knownDeleted set), and then add it back into the tree. We want
* to make sure the entry is in the BIN when we do the insert back
* in.
*/
final BasicLocker lockingTxn =
BasicLocker.createBasicLocker(envImpl);
/* Don't allow this short-lived lock to be preempted/stolen. */
lockingTxn.setPreemptable(false);
try {
/* Lock LSN. Can discard a NULL_LSN entry without locking. */
final long lsn = getLsn(i);
if (lsn != DbLsn.NULL_LSN) {
final LockResult lockRet = lockingTxn.nonBlockingLock
(lsn, LockType.READ, false /*jumpAheadOfWaiters*/, db);
if (lockRet.getLockGrant() == LockGrantType.DENIED) {
anyLocksDenied = true;
continue;
}
}
/* At this point, we know we can delete. */
if (Key.compareKeys(getKey(i), getIdentifierKey(),
getKeyComparator()) == 0) {
/*
* We're about to remove the entry with the idKey so the
* node will need a new idkey.
*/
setNewIdKey = true;
/*
* We think identifier keys are always in the first slot.
* However, this assertion fails in DatabaseTest. Needs
* futher investigation.
*/
//assert (i == 0) : i;
}
if (db.isDeferredWriteMode()) {
final LN ln = (LN) getTarget(i);
if (ln != null &&
ln.isDirty() &&
!DbLsn.isTransient(lsn)) {
if (db.isTemporary()) {
/*
* When a previously logged LN in a temporary DB is
* dirty, we can count the LSN of the last logged
* LN as obsolete without logging. There it no
* requirement for the dirty deleted LN to be
* durable past recovery. There is no danger of
* the last logged LN being accessed again (after
* log cleaning, for example), since temporary DBs
* do not survive recovery.
*/
if (localTracker != null) {
localTracker.countObsoleteNode
(lsn, ln.getGenericLogType(),
ln.getLastLoggedSize(), db);
} else {
envImpl.getLogManager().countObsoleteNode
(lsn, ln.getGenericLogType(),
ln.getLastLoggedSize(), db,
true /*countExact*/);
}
} else {