* If there are cleaned files to be deleted, flush an extra level to
* write out the parents of cleaned nodes. This ensures that the node
* will contain the LSN of a cleaned files.
*/
boolean flushExtraLevel = false;
Cleaner cleaner = envImpl.getCleaner();
CheckpointStartCleanerState cleanerState =
cleaner.getFilesAtCheckpointStart();
if (!cleanerState.isEmpty()) {
flushExtraLevel = true;
}
lastCheckpointMillis = System.currentTimeMillis();
flushStats.resetPerRunCounters();
/* Get the next checkpoint id. */
checkpointId++;
nCheckpoints++;
boolean success = false;
boolean traced = false;
LogManager logManager = envImpl.getLogManager();
/* dirtyMap keeps track of the INs to be written out by the ckpt. */
DirtyINMap dirtyMap = new DirtyINMap(envImpl);
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;
synchronized (envImpl.getEvictor()) {
/* Log the checkpoint start. */
SingleItemEntry startEntry =
new SingleItemEntry(LogEntryType.LOG_CKPT_START,
new CheckpointStart(checkpointId,
invokingSource));
checkpointStart =
logManager.log(startEntry,
ReplicationContext.NO_REPLICATE);
/*
* Note the first active LSN point. The definition of
* firstActiveLsn is that all log entries for active
* transactions are equal to or after that LSN.
*/
firstActiveLsn = envImpl.getTxnManager().getFirstActiveLsn();
if (firstActiveLsn == DbLsn.NULL_LSN) {
firstActiveLsn = checkpointStart;
} else {
if (DbLsn.compareTo(checkpointStart, firstActiveLsn) < 0) {
firstActiveLsn = checkpointStart;
}
}
/*
* Find the set of dirty INs that must be logged. Update the
* highestFlushLevels volatile field so it will be seen by the
* evictor, before starting to flush dirty nodes.
*/
highestFlushLevels = dirtyMap.selectDirtyINsForCheckpoint
(flushAll, flushExtraLevel);
}
/*
* Add the dirty map to the memory budget, outside the evictor
* synchronization section.
*/
dirtyMap.addCostToMemoryBudget();
/* Call hook after dirty map creation and before flushing. */
TestHookExecute.doHookIfSet(beforeFlushHook);
/* Flush IN nodes. */
boolean allowDeltas = !config.getMinimizeRecoveryTime();
flushDirtyNodes(envImpl, dirtyMap, highestFlushLevels, allowDeltas,
checkpointStart, highPriority, flushStats);
/*
* Flush MapLNs if not already done by flushDirtyNodes. Only flush
* a database if it has not already been flushed since checkpoint
* start. Lastly, flush the DB mapping tree root.
*/
dirtyMap.flushMapLNs(checkpointStart);
dirtyMap.flushRoot(checkpointStart);
/*
* Flush replication information if necessary so that the VLSNIndex
* cache is flushed and is recoverable.
*/
envImpl.preCheckpointEndFlush();
/*
* Flush utilization info AFTER flushing IN nodes to reduce the
* inaccuracies caused by the sequence FileSummaryLN-LN-BIN.
*/
envImpl.getUtilizationProfile().flushFileUtilization
(envImpl.getUtilizationTracker().getTrackedFiles());
DbTree dbTree = envImpl.getDbTree();
boolean willDeleteFiles = !cleanerState.isEmpty();
CheckpointEnd ckptEnd = new CheckpointEnd
(invokingSource, checkpointStart, envImpl.getRootLsn(),
firstActiveLsn,
envImpl.getNodeSequence().getLastLocalNodeId(),
envImpl.getNodeSequence().getLastReplicatedNodeId(),
dbTree.getLastLocalDbId(), dbTree.getLastReplicatedDbId(),
envImpl.getTxnManager().getLastLocalTxnId(),
envImpl.getTxnManager().getLastReplicatedTxnId(),
checkpointId,
willDeleteFiles);
SingleItemEntry endEntry =
new SingleItemEntry(LogEntryType.LOG_CKPT_END, ckptEnd);
/*
* 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 /*fsyncRequired*/,
ReplicationContext.NO_REPLICATE);
lastCheckpointStart = checkpointStart;
success = true;
cleaner.updateFilesAtCheckpointEnd(cleanerState);
} catch (DatabaseException e) {
LoggerUtils.traceAndLogException(envImpl, "Checkpointer",
"doCheckpoint", "checkpointId=" +
checkpointId, e);