throws DatabaseException {
boolean ret = false;
boolean setNewIdKey = false;
boolean anyLocksDenied = false;
DatabaseImpl db = getDatabase();
BasicLocker lockingTxn = new BasicLocker(db.getDbEnvironment());
try {
for (int i = 0; i < getNEntries(); i++) {
/*
* 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.
*/
boolean deleteEntry = false;
long obsoleteLsn = DbLsn.NULL_LSN;
if (binRef == null ||
isEntryPendingDeleted(i) ||
isEntryKnownDeleted(i) ||
binRef.hasDeletedKey(new Key(getKey(i)))) {
Node n = null;
if (canFetch) {
n = fetchTarget(i);
} else {
n = getTarget(i);
if (n == null) {
/* Punt, we don't know the state of this child. */
continue;
}
}
if (n == null) {
/* Cleaner deleted the log file. Compress this LN. */
deleteEntry = true;
} else if (isEntryKnownDeleted(i)) {
LockGrantType lockRet =
lockingTxn.nonBlockingReadLock(n.getNodeId(), db);
if (lockRet == LockGrantType.DENIED) {
anyLocksDenied = true;
continue;
}
deleteEntry = true;
} else {
if (!n.containsDuplicates()) {
LN ln = (LN) n;
LockGrantType lockRet =
lockingTxn.nonBlockingReadLock(ln.getNodeId(),
db);
if (lockRet == LockGrantType.DENIED) {
anyLocksDenied = true;
continue;
}
if (ln.isDeleted()) {
deleteEntry = true;
}
}
}
if (deleteEntry && n instanceof LN) {
obsoleteLsn = getLsn(i);
}
/* Remove key from BINReference in case we requeue it. */
if (binRef != null) {
binRef.removeDeletedKey(new Key(getKey(i)));
}
}
/* At this point, we know we can delete. */
if (deleteEntry) {
Comparator userComparisonFcn = getKeyComparator();
boolean entryIsIdentifierKey =
(userComparisonFcn == null ?
Key.compareKeys(getKey(i), getIdentifierKey()) :
userComparisonFcn.compare
(getKey(i), getIdentifierKey()))
== 0;
if (entryIsIdentifierKey) {
/*
* We're about to remove the entry with the idKey so
* the node will need a new idkey.
*/
setNewIdKey = true;
}
boolean deleteSuccess = deleteEntry(i, true);
assert deleteSuccess;
/*
* Since we're deleting the current entry, bump the current
* index back down one.
*/
i--;
}
}
} finally {
if (lockingTxn != null) {
lockingTxn.operationEnd();
}
}
if (anyLocksDenied && binRef != null) {
db.getDbEnvironment().addToCompressorQueue(binRef, false);
ret = true;
}
if (getNEntries() != 0 && setNewIdKey) {
setIdentifierKey(getKey(0));