*
* If no possible parent is found, the compressor may have deleted
* this item before we got to processing it.
*/
if (result.parent != null) {
IN parent = result.parent;
int parentLevel = parent.getLevel();
boolean mustLogParent = false;
/*
* If bottomLevelTarget is true, the parent IN contains bottom
* level BINs -- either DBINs or BINs depending on whether dups
* are configured or not. If dups are configured we cannot
* mask the level, since we do not want to select the parent of
* a BIN in the upper part of the tree. The masking is used to
* normalize the level for ordinary non-dup DBs and the mapping
* tree DB.
*/
boolean bottomLevelTarget = db.getSortedDuplicates() ?
(parentLevel == 2) :
((parentLevel & IN.LEVEL_MASK) == 2);
/*
* INs at the max flush level are always non-provisional and
* INs at the bottom level (when this is not also the max flush
* level) are always provisional. In between INs are
* provisional BEFORE_CKPT_END (see Provisional).
*
* Note that to determine whether this IN is at the
* maxFlushLevel, we check (parentLevel > maxFlushLevel)
* instead of (currentLevel >= maxFlushLevel). This handles
* the case where this IN is a DIN root, and the parent is a
* BIN that will not be flushed because the maxFlushLevel is
* less than IN.MAIN_LEVEL (0x10000). For example, this IN is
* a DIN root at level 2 and the maxFlushLevel is 3. [#16712]
*/
Provisional provisional;
if (parentLevel > maxFlushLevel) {
provisional = Provisional.NO;
} else if (bottomLevelTarget) {
provisional = Provisional.YES;
} else {
provisional = Provisional.BEFORE_CKPT_END;
}
/*
* Log a sub-tree when the target is at the bottom level and
* this is not a recursive call to flushIN during sub-tree
* logging.
*/
boolean logSubtree = bottomLevelTarget && allowLogSubtree;
/*
* Log sub-tree siblings with the latch held when highPriority
* is configured and this is not a DW DB. For a DW DB, dirty
* LNs are logged for each BIN. If we were to log a DW
* sub-tree with the parent latch held, the amount of logging
* may cause the latch to be held for too long a period.
*/
boolean logSiblingsWithParentLatchHeld =
logSubtree &&
highPriority &&
!db.isDurableDeferredWrite();
/*
* If we log siblings with the parent latch held, we log the
* target along with other siblings so we can perform a single
* multi-log call for all siblings.
*/
boolean logTargetWithOtherSiblings = false;
/*
* Map of node ID to parent index for each sibling to log. We
* must process the siblings in node ID order during multi-log,
* so that latching order is deterministic and only in one
* direction.
*/
SortedMap<Long,Integer> siblingsToLog = null;
try {
if (result.exactParentFound) {
/*
* If the child has already been evicted, don't
* refetch it.
*/
IN renewedTarget = (IN) parent.getTarget(result.index);
if (renewedTarget == null) {
/* nAlreadyEvictedThisRun++; -- for future */
mustLogParent |= true;
} else {
if (logSiblingsWithParentLatchHeld) {
logTargetWithOtherSiblings = true;
} else {
mustLogParent |= logSiblings
(envImpl, dirtyMap, parent,
Collections.singleton(result.index),
allowDeltas, checkpointStart,
highPriority, provisional, fstats,
localTracker);
}
}
} else {
/* result.exactParentFound was false. */
/* Do not flush children of the inexact parent. */
logSubtree = false;
if (result.childNotResident) {
/*
* But it was because the child wasn't resident.
* To be on the safe side, we'll put the parent
* into the dirty set to be logged when that level
* is processed.
*
* Only do this if the parent we found is at a
* higher level than the child. This ensures that
* the non-exact search does not find a sibling
* rather than a parent. [#11555]
*/
if (parentLevel > currentLevel) {
mustLogParent |= true;
}
/* nAlreadyEvictedThisRun++; -- for future. */
}
}
if (logSubtree) {
/*
* Create a map of node ID to parent index for each
* sibling we intend to log. Note that the dirty map
* does not contain targetRef (the sibling we're
* processing) because it was removed before calling
* this method, but it is added to the map below.
*
* A TreeMap (sorted map) is used so that siblings are
* latched in node ID order. A deterministic order is
* needed to avoid deadlocks, if siblings are latched
* in multiple threads in the future.
*/
siblingsToLog = new TreeMap<Long,Integer>();
for (int index = 0;
index < parent.getNEntries();
index += 1) {
Node child = parent.getTarget(index);
if (child != null) {
Long childId = child.getNodeId();
if ((logTargetWithOtherSiblings &&
targetRef.nodeId ==
childId.longValue()) ||
dirtyMap.containsNode
(child.getLevel(), childId)) {
siblingsToLog.put(childId, index);
}
}
}
if (logSiblingsWithParentLatchHeld) {
if (MULTI_LOG) {
mustLogParent |= logSiblings
(envImpl, dirtyMap, parent,
siblingsToLog.values(), allowDeltas,
checkpointStart, highPriority,
provisional, fstats, localTracker);
} else {
for (int index : siblingsToLog.values()) {
IN child = (IN) parent.getTarget(index);
CheckpointReference childRef =
(targetRef.nodeId ==
child.getNodeId()) ? targetRef :
dirtyMap.removeNode(child.getLevel(),
child.getNodeId());
assert childRef != null;
mustLogParent |= logSiblings
(envImpl, dirtyMap, parent,
Collections.singleton(index),
allowDeltas, checkpointStart,