// try to read the last log record to see if it is a checkpoint
boolean checkpointFound = false;
try {
final Loggable lastLog = reader.lastEntry();
if (lastLog != null && lastLog.getLogType() == LogEntryTypes.CHECKPOINT) {
final Checkpoint checkpoint = (Checkpoint) lastLog;
// Found a checkpoint. To be sure it is indeed a valid checkpoint
// record, we compare the LSN stored in it with the current LSN.
if (checkpoint.getStoredLsn() == checkpoint.getLsn()) {
checkpointFound = true;
LOG.debug("Database is in clean state. Last checkpoint: " +
checkpoint.getDateString());
}
}
} catch (final LogException e) {
LOG.info("Reading last journal log entry failed: " + e.getMessage() + ". Will scan the log...");
// if an exception occurs at this point, the journal file is probably incomplete,
// which indicates a db crash
checkpointFound = false;
}
if (!checkpointFound) {
LOG.info("Unclean shutdown detected. Scanning journal...");
broker.getBrokerPool().reportStatus("Unclean shutdown detected. Scanning log...");
reader.position(1);
final Long2ObjectHashMap<Loggable> txnsStarted = new Long2ObjectHashMap<Loggable>();
Checkpoint lastCheckpoint = null;
long lastLsn = Lsn.LSN_INVALID;
Loggable next;
try {
final ProgressBar progress = new ProgressBar("Scanning journal ", last.length());
while ((next = reader.nextEntry()) != null) {
// LOG.debug(next.dump());
progress.set(Lsn.getOffset(next.getLsn()));
if (next.getLogType() == LogEntryTypes.TXN_START) {
// new transaction starts: add it to the transactions table
txnsStarted.put(next.getTransactionId(), next);
} else if (next.getLogType() == LogEntryTypes.TXN_ABORT) {
// transaction aborted: remove it from the transactions table
txnsStarted.remove(next.getTransactionId());
} else if (next.getLogType() == LogEntryTypes.CHECKPOINT) {
txnsStarted.clear();
lastCheckpoint = (Checkpoint) next;
}
lastLsn = next.getLsn();
}
} catch (final LogException e) {
if (LOG.isDebugEnabled()) {
LOG.debug("Caught exception while reading log", e);
}
LOG.info("Last readable journal log entry lsn: " + Lsn.dump(lastLsn));
}
// if the last checkpoint record is not the last record in the file
// we need a recovery.
if ((lastCheckpoint == null || lastCheckpoint.getLsn() != lastLsn) &&
txnsStarted.size() > 0) {
LOG.info("Dirty transactions: " + txnsStarted.size());
// starting recovery: reposition the log reader to the last checkpoint
if (lastCheckpoint == null)
{reader.position(1);}
else {
reader.position(lastCheckpoint.getLsn());
next = reader.nextEntry();
}
recoveryRun = true;
try {
LOG.info("Running recovery...");