public boolean positionFirstOrLast(boolean first, DIN duplicateRoot)
throws DatabaseException {
assert assertCursorState(false) : dumpToString(true);
IN in = null;
boolean found = false;
try {
if (duplicateRoot == null) {
removeCursorBIN();
if (first) {
in = databaseImpl.getTree().getFirstNode(cacheMode);
} else {
in = databaseImpl.getTree().getLastNode(cacheMode);
}
if (in != null) {
assert (in instanceof BIN);
dupBin = null;
dupIndex = -1;
bin = (BIN) in;
index = (first ? 0 : (bin.getNEntries() - 1));
addCursor(bin);
TreeWalkerStatsAccumulator treeStatsAccumulator =
getTreeStatsAccumulator();
if (bin.getNEntries() == 0) {
/*
* An IN was found. Even if it's empty, let Cursor
* handle moving to the first non-deleted entry.
*/
found = true;
} else {
/*
* See if we need to descend further. If fetchTarget
* returns null, a deleted LN was cleaned.
*
* We do not need to fetch a known deleted entry. We
* do need to fetch to determine if this is a dup
* database into which we will descend further.
*/
Node n = null;
if (!bin.isEntryKnownDeleted(index) &&
duplicateRoot == null &&
databaseImpl.getSortedDuplicates()) {
n = bin.fetchTarget(index);
}
if (n != null && n.containsDuplicates()) {
DIN dupRoot = (DIN) n;
dupRoot.latch(cacheMode);
in.releaseLatch();
in = null;
found = positionFirstOrLast(first, dupRoot);
} else {
/*
* Even if the entry is deleted, just leave our
* position here and return.
*/
if (treeStatsAccumulator != null) {
if (bin.isEntryKnownDeleted(index) ||
bin.isEntryPendingDeleted(index) ||
(n != null && ((LN) n).isDeleted())) {
treeStatsAccumulator.
incrementDeletedLNCount();
} else {
treeStatsAccumulator.
incrementLNCount();
}
}
found = true;
}
}
}
} else {
removeCursorDBIN();
if (first) {
in = databaseImpl.getTree().
getFirstNode(duplicateRoot, cacheMode);
} else {
in = databaseImpl.getTree().
getLastNode(duplicateRoot, cacheMode);
}
if (in != null) {
/*
* An IN was found. Even if it's empty, let Cursor handle
* moving to the first non-deleted entry.
*/
/*
* assert (in instanceof DBIN);
* Will always be true since Tree.getFirst/LastNode always
* returns a DBIN.
*/
dupBin = (DBIN) in;
dupIndex = (first ? 0 : (dupBin.getNEntries() - 1));
addCursor(dupBin);
found = true;
}
}
status = CURSOR_INITIALIZED;
return found;
} catch (DatabaseException e) {
/* Release latch on error. */
if (in != null) {
in.releaseLatch();
}
throw e;
}
}