*/
private IN selectIN(INList inList, ScanIterator scanIter)
throws DatabaseException {
/* Find the best target in the next <nodesPerScan> nodes. */
IN target = null;
long targetGeneration = Long.MAX_VALUE;
int targetLevel = Integer.MAX_VALUE;
boolean targetDirty = true;
boolean envIsReadOnly = envImpl.isReadOnly();
int scanned = 0;
boolean wrapped = false;
while (scanned < nodesPerScan) {
if (scanIter.hasNext()) {
IN in = scanIter.next();
nNodesScannedThisRun++;
DatabaseImpl db = in.getDatabase();
/*
* We don't expect to see an IN with a database that has
* finished delete processing, because it would have been
* removed from the inlist during post-delete cleanup.
*/
if (db == null || db.isDeleteFinished()) {
String inInfo = " IN type=" + in.getLogType() + " id=" +
in.getNodeId() + " not expected on INList";
String errMsg = (db == null) ? inInfo :
"Database " + db.getDebugName() + " id=" + db.getId() +
inInfo;
throw new DatabaseException(errMsg);
}
/* Ignore if the db is in the middle of delete processing. */
if (db.isDeleted()) {
continue;
}
/*
* Don't evict the DatabaseImpl Id Mapping Tree (db 0), both
* for object identity reasons and because the id mapping tree
* should stay cached.
*/
if (db.getId().equals(DbTree.ID_DB_ID)) {
continue;
}
/*
* If this is a read only database and we have at least one
* target, skip any dirty INs (recovery dirties INs even in a
* read-only environment). We take at least one target so we
* don't loop endlessly if everything is dirty.
*/
if (envIsReadOnly && (target != null) && in.getDirty()) {
continue;
}
/*
* Only scan evictable or strippable INs. This prevents higher
* level INs from being selected for eviction, unless they are
* part of an unused tree.
*/
int evictType = in.getEvictionType();
if (evictType == IN.MAY_NOT_EVICT) {
continue;
}
/*
* This node is in the scanned node set. Select according to
* the configured eviction policy.
*/
if (evictByLruOnly) {
/*
* Select the node with the lowest generation number,
* irrespective of tree level or dirtyness.
*/
if (targetGeneration > in.getGeneration()) {
targetGeneration = in.getGeneration();
target = in;
}
} else {
/*
* Select first by tree level, then by dirtyness, then by
* generation/LRU.
*/
int level = normalizeLevel(in, evictType);
if (targetLevel != level) {
if (targetLevel > level) {
targetLevel = level;
targetDirty = in.getDirty();
targetGeneration = in.getGeneration();
target = in;
}
} else if (targetDirty != in.getDirty()) {
if (targetDirty) {
targetDirty = false;
targetGeneration = in.getGeneration();
target = in;
}
} else {
if (targetGeneration > in.getGeneration()) {
targetGeneration = in.getGeneration();
target = in;
}
}
}
scanned++;