checkpointId++;
nCheckpoints++;
boolean success = false;
boolean traced = false;
int dirtyMapMemSize = 0;
MemoryBudget mb = envImpl.getMemoryBudget();
try {
/*
* Eviction can run during checkpoint as long as it follows the
* same rules for using provisional logging and for propagating
* logging of the checkpoint dirty set up the tree. We have to lock
* out the evictor after the logging of checkpoint start until
* we've selected the dirty set and decided on the highest level to
* be flushed. See SR 11163, 11349.
*/
long checkpointStart = DbLsn.NULL_LSN;
long firstActiveLsn = DbLsn.NULL_LSN;
SortedMap dirtyMap = null;
synchronized (envImpl.getEvictor()) {
/* Log the checkpoint start. */
CheckpointStart startEntry =
new CheckpointStart(checkpointId, invokingSource);
checkpointStart = logManager.log(startEntry);
/*
* Remember the first active LSN -- before this position in the
* log, there are no active transactions at this point in time.
*/
firstActiveLsn = envImpl.getTxnManager().getFirstActiveLsn();
if (firstActiveLsn == DbLsn.NULL_LSN) {
firstActiveLsn = checkpointStart;
} else {
if (DbLsn.compareTo(checkpointStart, firstActiveLsn) < 0) {
firstActiveLsn = checkpointStart;
}
}
/* Find the dirty set. */
dirtyMap = selectDirtyINs(flushAll, flushExtraLevel);
}
/* Add each level's references to the budget. */
int totalSize = 0;
for (Iterator i = dirtyMap.values().iterator(); i.hasNext();) {
Set nodeSet = (Set) i.next();
int size = nodeSet.size() *
MemoryBudget.CHECKPOINT_REFERENCE_SIZE;
totalSize += size;
dirtyMapMemSize += size;
}
mb.updateMiscMemoryUsage(totalSize);
/* Flush IN nodes. */
boolean allowDeltas = !config.getMinimizeRecoveryTime();
flushDirtyNodes(dirtyMap, flushAll, allowDeltas,
flushExtraLevel, checkpointStart);
/*
* Flush utilization info AFTER flushing IN nodes to reduce the
* inaccuracies caused by the sequence FileSummaryLN-LN-BIN.
*/
flushUtilizationInfo();
CheckpointEnd endEntry =
new CheckpointEnd(invokingSource,
checkpointStart,
envImpl.getRootLsn(),
firstActiveLsn,
Node.getLastId(),
envImpl.getDbMapTree().getLastDbId(),
envImpl.getTxnManager().getLastTxnId(),
checkpointId);
/*
* Log checkpoint end and update state kept about the last
* checkpoint location. Send a trace message *before* the
* checkpoint end log entry. This is done so that the normal trace
* message doesn't affect the time-based isRunnable() calculation,
* which only issues a checkpoint if a log record has been written
* since the last checkpoint.
*/
trace(envImpl, invokingSource, true);
traced = true;
/*
* Always flush to ensure that cleaned files are not referenced,
* and to ensure that this checkpoint is not wasted if we crash.
*/
lastCheckpointEnd =
logManager.logForceFlush(endEntry,
true); // fsync required
lastFirstActiveLsn = firstActiveLsn;
lastCheckpointStart = checkpointStart;
/*
* Reset the highestFlushLevel so evictor activity knows there's no
* further requirement for provisional logging. SR 11163.
*/
highestFlushLevel = IN.MIN_LEVEL;
success = true;
if (cleaner != null && cleanerFiles != null) {
cleaner.updateFilesAtCheckpointEnd(cleanerFiles);
}
} catch (DatabaseException e) {
Tracer.trace(envImpl, "Checkpointer", "doCheckpoint",
"checkpointId=" + checkpointId, e);
throw e;
} finally {
mb.updateMiscMemoryUsage(0 - dirtyMapMemSize);
if (!traced) {
trace(envImpl, invokingSource, success);
}
}
}