*/
long checkpointStart = DbLsn.NULL_LSN;
long firstActiveLsn = DbLsn.NULL_LSN;
/* 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. This is the starting point for
* replaying LNs during recovery and will be stored in the CkptEnd
* entry.
*
* Use the checkpointStart as the firstActiveLsn if firstActiveLsn
* is null, meaning that no txns are active.
*
* The current value must be retrieved from TxnManager after
* logging CkptStart. If it were instead retrieved before logging
* CkptStart, the following failure could occur. [#20270]
*
* ... getFirstActiveLsn returns NULL_LSN, will use 200 CkptStart
* 100 LN-A in Txn-1
* 200 CkptStart
* 300 BIN-B refers to 100 LN-A
* 400 CkptEnd
* ... Crash and recover. Recovery does not undo 100 LN-A.
* ... Txn-1 is uncommitted, yet 100 LN-A takes effect.
*/
firstActiveLsn = envImpl.getTxnManager().getFirstActiveLsn();
if (firstActiveLsn == DbLsn.NULL_LSN) {
firstActiveLsn = checkpointStart;
}
/*
* In a replicated system, the checkpointer will be flushing out
* the VLSNIndex, which is HA metadata. Check that the in-memory
* version encompasses all metadata up to the point of the
* CheckpointStart record. This is no-op for non-replicated
* systems. [#19754]
*/
envImpl.awaitVLSNConsistency();
/* Find the set of dirty INs that must be logged. */
checkpointDirtyMap.selectDirtyINsForCheckpoint();
/* Call hook after dirty map creation and before flushing. */
TestHookExecute.doHookIfSet(beforeFlushHook);
/* Flush IN nodes. */
flushDirtyNodes(envImpl, checkpointDirtyMap, 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.
*/
checkpointDirtyMap.flushMapLNs(checkpointStart);
checkpointDirtyMap.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, cleaner.getLogSummary());
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