unlink(recoveryPath); /* ignore any error */
/*
- * As of 8.4 we no longer rename the recovery.conf file out of the
- * way until after we have performed a full checkpoint. This ensures
- * that any crash between now and the end of the checkpoint does not
- * attempt to restart from a WAL file that is no longer available to us.
- * As soon as we remove recovery.conf we lose our recovery_command and
- * cannot reaccess WAL files from the archive.
- */
+ * Rename the config file out of the way, so that we don't accidentally
+ * re-enter archive recovery mode in a subsequent crash. We have already
+ * restored all the WAL segments we need from the archive, and we trust
+ * that they are not going to go away even if we crash. (XXX: should
+ * we fsync() them all to ensure that?)
+ */
+ unlink(RECOVERY_COMMAND_DONE);
+ if (rename(RECOVERY_COMMAND_FILE, RECOVERY_COMMAND_DONE) != 0)
+ ereport(FATAL,
+ (errcode_for_file_access(),
+ errmsg("could not rename file \"%s\" to \"%s\": %m",
+ RECOVERY_COMMAND_FILE, RECOVERY_COMMAND_DONE)));
ereport(LOG,
(errmsg("archive recovery complete")));
}
/*
- * Prior to 8.4 we wrote a Shutdown Checkpoint at the end of recovery.
- * This could add minutes to the startup time, so we want bgwriter
- * to perform it. This then frees the Startup process to complete so we can
- * allow transactions and WAL inserts. We still write a checkpoint, but
- * it will be an online checkpoint. Online checkpoints have a redo
- * location that can be prior to the actual checkpoint record. So we want
- * to derive that redo location *before* we let anybody else write WAL,
- * otherwise we might miss some WAL records if we crash.
+ * If we had to replay any WAL records, request a checkpoint. This isn't
+ * strictly necessary: if we crash now, the recovery will simply restart
+ * from the same point where it started this time around (or from the
+ * last restartpoint). The control file is left in DB_IN_*_RECOVERY
+ * state; the first checkpoint will change that to DB_IN_PRODUCTION.
*/
if (performedRecovery)
{
-#ifdef DEADCODE
- XLogRecPtr redo;
-
- /*
- * We must grab the pointer before anybody writes WAL
- */
- redo = GetRedoLocationForCheckpoint();
-
- /*
- * Tell the bgwriter
- */
- SetRedoLocationForArchiveCheckpoint(redo);
-#endif
/*
* Okay, we can come up now. Allow others to write WAL.
*/
XLogCtl->SharedRecoveryProcessingMode = false;
- /*
- * Now request checkpoint
- */
- RequestCheckpoint(CHECKPOINT_FORCE | CHECKPOINT_IMMEDIATE);
+ RequestCheckpoint(CHECKPOINT_FORCE | CHECKPOINT_IMMEDIATE |
+ CHECKPOINT_STARTUP);
}
else
{
uint32 _logSeg;
TransactionId *inCommitXids;
int nInCommit;
- bool leavingArchiveRecovery = false;
/*
* Acquire CheckpointLock to ensure only one checkpoint happens at a time.
MemSet(&CheckpointStats, 0, sizeof(CheckpointStats));
CheckpointStats.ckpt_start_t = GetCurrentTimestamp();
- /*
- * Find out if this is the first checkpoint after archive recovery.
- */
- LWLockAcquire(ControlFileLock, LW_EXCLUSIVE);
- leavingArchiveRecovery = (ControlFile->state == DB_IN_ARCHIVE_RECOVERY);
- LWLockRelease(ControlFileLock);
-
/*
* Use a critical section to force system panic if we have trouble.
*/
checkPoint.ThisTimeLineID = ThisTimeLineID;
checkPoint.time = (pg_time_t) time(NULL);
-#ifdef DEADCODE
- if (leavingArchiveRecovery)
- checkPoint.redo = GetRedoLocationForArchiveCheckpoint();
- else
-#endif
- {
- /*
- * We must hold WALInsertLock while examining insert state to determine
- * the checkpoint REDO pointer.
- */
- LWLockAcquire(WALInsertLock, LW_EXCLUSIVE);
+ /*
+ * We must hold WALInsertLock while examining insert state to determine
+ * the checkpoint REDO pointer.
+ */
+ LWLockAcquire(WALInsertLock, LW_EXCLUSIVE);
- /*
- * If this isn't a shutdown or forced checkpoint, and we have not inserted
- * any XLOG records since the start of the last checkpoint, skip the
- * checkpoint. The idea here is to avoid inserting duplicate checkpoints
- * when the system is idle. That wastes log space, and more importantly it
- * exposes us to possible loss of both current and previous checkpoint
- * records if the machine crashes just as we're writing the update.
- * (Perhaps it'd make even more sense to checkpoint only when the previous
- * checkpoint record is in a different xlog page?)
- *
- * We have to make two tests to determine that nothing has happened since
- * the start of the last checkpoint: current insertion point must match
- * the end of the last checkpoint record, and its redo pointer must point
- * to itself.
- */
- if ((flags & (CHECKPOINT_IS_SHUTDOWN | CHECKPOINT_FORCE)) == 0)
+ /*
+ * If this isn't a shutdown or forced checkpoint, and we have not inserted
+ * any XLOG records since the start of the last checkpoint, skip the
+ * checkpoint. The idea here is to avoid inserting duplicate checkpoints
+ * when the system is idle. That wastes log space, and more importantly it
+ * exposes us to possible loss of both current and previous checkpoint
+ * records if the machine crashes just as we're writing the update.
+ * (Perhaps it'd make even more sense to checkpoint only when the previous
+ * checkpoint record is in a different xlog page?)
+ *
+ * We have to make two tests to determine that nothing has happened since
+ * the start of the last checkpoint: current insertion point must match
+ * the end of the last checkpoint record, and its redo pointer must point
+ * to itself.
+ */
+ if ((flags & (CHECKPOINT_IS_SHUTDOWN | CHECKPOINT_FORCE)) == 0)
+ {
+ XLogRecPtr curInsert;
+
+ INSERT_RECPTR(curInsert, Insert, Insert->curridx);
+ if (curInsert.xlogid == ControlFile->checkPoint.xlogid &&
+ curInsert.xrecoff == ControlFile->checkPoint.xrecoff +
+ MAXALIGN(SizeOfXLogRecord + sizeof(CheckPoint)) &&
+ ControlFile->checkPoint.xlogid ==
+ ControlFile->checkPointCopy.redo.xlogid &&
+ ControlFile->checkPoint.xrecoff ==
+ ControlFile->checkPointCopy.redo.xrecoff)
{
- XLogRecPtr curInsert;
-
- INSERT_RECPTR(curInsert, Insert, Insert->curridx);
- if (curInsert.xlogid == ControlFile->checkPoint.xlogid &&
- curInsert.xrecoff == ControlFile->checkPoint.xrecoff +
- MAXALIGN(SizeOfXLogRecord + sizeof(CheckPoint)) &&
- ControlFile->checkPoint.xlogid ==
- ControlFile->checkPointCopy.redo.xlogid &&
- ControlFile->checkPoint.xrecoff ==
- ControlFile->checkPointCopy.redo.xrecoff)
- {
- LWLockRelease(WALInsertLock);
- LWLockRelease(CheckpointLock);
- END_CRIT_SECTION();
- return;
- }
+ LWLockRelease(WALInsertLock);
+ LWLockRelease(CheckpointLock);
+ END_CRIT_SECTION();
+ return;
}
+ }
- /*
- * Compute new REDO record ptr = location of next XLOG record.
- *
- * NB: this is NOT necessarily where the checkpoint record itself will be,
- * since other backends may insert more XLOG records while we're off doing
- * the buffer flush work. Those XLOG records are logically after the
- * checkpoint, even though physically before it. Got that?
- */
- checkPoint.redo = GetRedoLocationForCheckpoint();
+ /*
+ * Compute new REDO record ptr = location of next XLOG record.
+ *
+ * NB: this is NOT necessarily where the checkpoint record itself will be,
+ * since other backends may insert more XLOG records while we're off doing
+ * the buffer flush work. Those XLOG records are logically after the
+ * checkpoint, even though physically before it. Got that?
+ */
+ checkPoint.redo = GetRedoLocationForCheckpoint();
- /*
- * Now we can release WAL insert lock, allowing other xacts to proceed
- * while we are flushing disk buffers.
- */
- LWLockRelease(WALInsertLock);
- }
+ /*
+ * Now we can release WAL insert lock, allowing other xacts to proceed
+ * while we are flushing disk buffers.
+ */
+ LWLockRelease(WALInsertLock);
/*
* If enabled, log checkpoint start. We postpone this until now so as not
LWLockRelease(ControlFileLock);
- if (leavingArchiveRecovery)
- {
- /*
- * Rename the config file out of the way, so that we don't accidentally
- * re-enter archive recovery mode in a subsequent crash. Prior to
- * 8.4 this step was performed at end of exitArchiveRecovery().
- */
- unlink(RECOVERY_COMMAND_DONE);
- if (rename(RECOVERY_COMMAND_FILE, RECOVERY_COMMAND_DONE) != 0)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not rename file \"%s\" to \"%s\": %m",
- RECOVERY_COMMAND_FILE, RECOVERY_COMMAND_DONE)));
- }
-
/* Update shared-memory copy of checkpoint XID/epoch */
{
/* use volatile pointer to prevent code rearrangement */