CreateRestartPoint(int flags)
{
	XLogRecPtr	lastCheckPointRecPtr;
	CheckPoint	lastCheckPoint;
	XLogSegNo	_logSegNo;
	TimestampTz xtime;

	/* use volatile pointer to prevent code rearrangement */
	volatile XLogCtlData *xlogctl = XLogCtl;

	/*
	 * Acquire CheckpointLock to ensure only one restartpoint or checkpoint
	 * happens at a time.
	 */
	LWLockAcquire(CheckpointLock, LW_EXCLUSIVE);

	/* Get a local copy of the last safe checkpoint record. */
	SpinLockAcquire(&xlogctl->info_lck);
	lastCheckPointRecPtr = xlogctl->lastCheckPointRecPtr;
	lastCheckPoint = xlogctl->lastCheckPoint;
	SpinLockRelease(&xlogctl->info_lck);

	/*
	 * Check that we're still in recovery mode. It's ok if we exit recovery
	 * mode after this check, the restart point is valid anyway.
	 */
	if (!RecoveryInProgress())
	{
		ereport(DEBUG2,
			  (errmsg("skipping restartpoint, recovery has already ended")));
		LWLockRelease(CheckpointLock);
		return false;
	}

	/*
	 * If the last checkpoint record we've replayed is already our last
	 * restartpoint, we can't perform a new restart point. We still update
	 * minRecoveryPoint in that case, so that if this is a shutdown restart
	 * point, we won't start up earlier than before. That's not strictly
	 * necessary, but when hot standby is enabled, it would be rather weird if
	 * the database opened up for read-only connections at a point-in-time
	 * before the last shutdown. Such time travel is still possible in case of
	 * immediate shutdown, though.
	 *
	 * We don't explicitly advance minRecoveryPoint when we do create a
	 * restartpoint. It's assumed that flushing the buffers will do that as a
	 * side-effect.
	 */
	if (XLogRecPtrIsInvalid(lastCheckPointRecPtr) ||
		lastCheckPoint.redo <= ControlFile->checkPointCopy.redo)
	{
		ereport(DEBUG2,
				(errmsg("skipping restartpoint, already performed at %X/%X",
						(uint32) (lastCheckPoint.redo >> 32),
						(uint32) lastCheckPoint.redo)));

		UpdateMinRecoveryPoint(InvalidXLogRecPtr, true);
		if (flags & CHECKPOINT_IS_SHUTDOWN)
		{
			LWLockAcquire(ControlFileLock, LW_EXCLUSIVE);
			ControlFile->state = DB_SHUTDOWNED_IN_RECOVERY;
			ControlFile->time = (pg_time_t) time(NULL);
			UpdateControlFile();
			LWLockRelease(ControlFileLock);
		}
		LWLockRelease(CheckpointLock);
		return false;
	}

	/*
	 * Update the shared RedoRecPtr so that the startup process can calculate
	 * the number of segments replayed since last restartpoint, and request a
	 * restartpoint if it exceeds checkpoint_segments.
	 *
	 * Like in CreateCheckPoint(), hold off insertions to update it, although
	 * during recovery this is just pro forma, because no WAL insertions are
	 * happening.
	 */
	WALInsertSlotAcquire(true);
	xlogctl->Insert.RedoRecPtr = lastCheckPoint.redo;
	WALInsertSlotRelease();

	/* Also update the info_lck-protected copy */
	SpinLockAcquire(&xlogctl->info_lck);
	xlogctl->RedoRecPtr = lastCheckPoint.redo;
	SpinLockRelease(&xlogctl->info_lck);

	/*
	 * Prepare to accumulate statistics.
	 *
	 * Note: because it is possible for log_checkpoints to change while a
	 * checkpoint proceeds, we always accumulate stats, even if
	 * log_checkpoints is currently off.
	 */
	MemSet(&CheckpointStats, 0, sizeof(CheckpointStats));
	CheckpointStats.ckpt_start_t = GetCurrentTimestamp();

	if (log_checkpoints)
		LogCheckpointStart(flags, true);

	CheckPointGuts(lastCheckPoint.redo, flags);

	/*
	 * Select point at which we can truncate the xlog, which we base on the
	 * prior checkpoint's earliest info.
	 */
	XLByteToSeg(ControlFile->checkPointCopy.redo, _logSegNo);

	/*
	 * Update pg_control, using current time.  Check that it still shows
	 * IN_ARCHIVE_RECOVERY state and an older checkpoint, else do nothing;
	 * this is a quick hack to make sure nothing really bad happens if somehow
	 * we get here after the end-of-recovery checkpoint.
	 */
	LWLockAcquire(ControlFileLock, LW_EXCLUSIVE);
	if (ControlFile->state == DB_IN_ARCHIVE_RECOVERY &&
		ControlFile->checkPointCopy.redo < lastCheckPoint.redo)
	{
		ControlFile->prevCheckPoint = ControlFile->checkPoint;
		ControlFile->checkPoint = lastCheckPointRecPtr;
		ControlFile->checkPointCopy = lastCheckPoint;
		ControlFile->time = (pg_time_t) time(NULL);
		if (flags & CHECKPOINT_IS_SHUTDOWN)
			ControlFile->state = DB_SHUTDOWNED_IN_RECOVERY;
		UpdateControlFile();
	}
	LWLockRelease(ControlFileLock);

	/*
	 * Due to an historical accident multixact truncations are not WAL-logged,
	 * but just performed everytime the mxact horizon is increased. So, unless
	 * we explicitly execute truncations on a standby it will never clean out
	 * /pg_multixact which obviously is bad, both because it uses space and
	 * because we can wrap around into pre-existing data...
	 *
	 * We can only do the truncation here, after the UpdateControlFile()
	 * above, because we've now safely established a restart point, that
	 * guarantees we will not need need to access those multis.
	 *
	 * It's probably worth improving this.
	 */
	TruncateMultiXact(lastCheckPoint.oldestMulti);

	/*
	 * Delete old log files (those no longer needed even for previous
	 * checkpoint/restartpoint) to prevent the disk holding the xlog from
	 * growing full.
	 */
	if (_logSegNo)
	{
		XLogRecPtr	receivePtr;
		XLogRecPtr	replayPtr;
		TimeLineID	replayTLI;
		XLogRecPtr	endptr;

		/*
		 * Get the current end of xlog replayed or received, whichever is
		 * later.
		 */
		receivePtr = GetWalRcvWriteRecPtr(NULL, NULL);
		replayPtr = GetXLogReplayRecPtr(&replayTLI);
		endptr = (receivePtr < replayPtr) ? replayPtr : receivePtr;

		KeepLogSeg(endptr, &_logSegNo);
		_logSegNo--;

		/*
		 * Try to recycle segments on a useful timeline. If we've been promoted
		 * since the beginning of this restartpoint, use the new timeline
		 * chosen at end of recovery (RecoveryInProgress() sets ThisTimeLineID
		 * in that case). If we're still in recovery, use the timeline we're
		 * currently replaying.
		 *
		 * There is no guarantee that the WAL segments will be useful on the
		 * current timeline; if recovery proceeds to a new timeline right
		 * after this, the pre-allocated WAL segments on this timeline will
		 * not be used, and will go wasted until recycled on the next
		 * restartpoint. We'll live with that.
		 */
		if (RecoveryInProgress())
			ThisTimeLineID = replayTLI;

		RemoveOldXlogFiles(_logSegNo, endptr);

		/*
		 * Make more log segments if needed.  (Do this after recycling old log
		 * segments, since that may supply some of the needed files.)
		 */
		PreallocXlogFiles(endptr);

		/*
		 * ThisTimeLineID is normally not set when we're still in recovery.
		 * However, recycling/preallocating segments above needed
		 * ThisTimeLineID to determine which timeline to install the segments
		 * on. Reset it now, to restore the normal state of affairs for
		 * debugging purposes.
		 */
		if (RecoveryInProgress())
			ThisTimeLineID = 0;
	}

	/*
	 * Truncate pg_subtrans if possible.  We can throw away all data before
	 * the oldest XMIN of any running transaction.	No future transaction will
	 * attempt to reference any pg_subtrans entry older than that (see Asserts
	 * in subtrans.c).	When hot standby is disabled, though, we mustn't do
	 * this because StartupSUBTRANS hasn't been called yet.
	 */
	if (EnableHotStandby)
		TruncateSUBTRANS(GetOldestXmin(true, false));

	/* Real work is done, but log and update before releasing lock. */
	LogCheckpointEnd(true);

	xtime = GetLatestXTime();
	ereport((log_checkpoints ? LOG : DEBUG2),
			(errmsg("recovery restart point at %X/%X",
		 (uint32) (lastCheckPoint.redo >> 32), (uint32) lastCheckPoint.redo),
		   xtime ? errdetail("last completed transaction was at log time %s",
							 timestamptz_to_str(xtime)) : 0));

	LWLockRelease(CheckpointLock);

	/*
	 * Finally, execute archive_cleanup_command, if any.
	 */
	if (XLogCtl->archiveCleanupCommand[0])
		ExecuteRecoveryCommand(XLogCtl->archiveCleanupCommand,
							   "archive_cleanup_command",
							   false);

	return true;
}
CreateRestartPoint(int flags)
{
	XLogRecPtr	lastCheckPointRecPtr;
	CheckPoint	lastCheckPoint;
	XLogSegNo	_logSegNo;
	TimestampTz xtime;

	 
	volatile XLogCtlData *xlogctl = XLogCtl;

	 
	LWLockAcquire(CheckpointLock, LW_EXCLUSIVE);

	 
	SpinLockAcquire(&xlogctl->info_lck);
	lastCheckPointRecPtr = xlogctl->lastCheckPointRecPtr;
	lastCheckPoint = xlogctl->lastCheckPoint;
	SpinLockRelease(&xlogctl->info_lck);

	 
	if (!RecoveryInProgress())
	{
		ereport(DEBUG2,
			  (errmsg("skipping restartpoint, recovery has already ended")));
		LWLockRelease(CheckpointLock);
		return false;
	}

	 
	if (XLogRecPtrIsInvalid(lastCheckPointRecPtr) ||
		lastCheckPoint.redo <= ControlFile->checkPointCopy.redo)
	{
		ereport(DEBUG2,
				(errmsg("skipping restartpoint, already performed at %X/%X",
						(uint32) (lastCheckPoint.redo >> 32),
						(uint32) lastCheckPoint.redo)));

		UpdateMinRecoveryPoint(InvalidXLogRecPtr, true);
		if (flags & CHECKPOINT_IS_SHUTDOWN)
		{
			LWLockAcquire(ControlFileLock, LW_EXCLUSIVE);
			ControlFile->state = DB_SHUTDOWNED_IN_RECOVERY;
			ControlFile->time = (pg_time_t) time(NULL);
			UpdateControlFile();
			LWLockRelease(ControlFileLock);
		}
		LWLockRelease(CheckpointLock);
		return false;
	}

	 
	WALInsertSlotAcquire(true);
	xlogctl->Insert.RedoRecPtr = lastCheckPoint.redo;
	WALInsertSlotRelease();

	 
	SpinLockAcquire(&xlogctl->info_lck);
	xlogctl->RedoRecPtr = lastCheckPoint.redo;
	SpinLockRelease(&xlogctl->info_lck);

	 
	MemSet(&CheckpointStats, 0, sizeof(CheckpointStats));
	CheckpointStats.ckpt_start_t = GetCurrentTimestamp();

	if (log_checkpoints)
		LogCheckpointStart(flags, true);

	CheckPointGuts(lastCheckPoint.redo, flags);

	 
	XLByteToSeg(ControlFile->checkPointCopy.redo, _logSegNo);

	 
	LWLockAcquire(ControlFileLock, LW_EXCLUSIVE);
	if (ControlFile->state == DB_IN_ARCHIVE_RECOVERY &&
		ControlFile->checkPointCopy.redo < lastCheckPoint.redo)
	{
		ControlFile->prevCheckPoint = ControlFile->checkPoint;
		ControlFile->checkPoint = lastCheckPointRecPtr;
		ControlFile->checkPointCopy = lastCheckPoint;
		ControlFile->time = (pg_time_t) time(NULL);
		if (flags & CHECKPOINT_IS_SHUTDOWN)
			ControlFile->state = DB_SHUTDOWNED_IN_RECOVERY;
		UpdateControlFile();
	}
	LWLockRelease(ControlFileLock);

	 
	TruncateMultiXact(lastCheckPoint.oldestMulti);

	 
	if (_logSegNo)
	{
		XLogRecPtr	receivePtr;
		XLogRecPtr	replayPtr;
		TimeLineID	replayTLI;
		XLogRecPtr	endptr;

		 
		receivePtr = GetWalRcvWriteRecPtr(NULL, NULL);
		replayPtr = GetXLogReplayRecPtr(&replayTLI);
		endptr = (receivePtr < replayPtr) ? replayPtr : receivePtr;

		KeepLogSeg(endptr, &_logSegNo);
		_logSegNo--;

		 
		if (RecoveryInProgress())
			ThisTimeLineID = replayTLI;

		RemoveOldXlogFiles(_logSegNo, endptr);

		 
		PreallocXlogFiles(endptr);

		 
		if (RecoveryInProgress())
			ThisTimeLineID = 0;
	}

	 
	if (EnableHotStandby)
		TruncateSUBTRANS(GetOldestXmin(true, false));

	 
	LogCheckpointEnd(true);

	xtime = GetLatestXTime();
	ereport((log_checkpoints ? LOG : DEBUG2),
			(errmsg("recovery restart point at %X/%X",
		 (uint32) (lastCheckPoint.redo >> 32), (uint32) lastCheckPoint.redo),
		   xtime ? errdetail("last completed transaction was at log time %s",
							 timestamptz_to_str(xtime)) : 0));

	LWLockRelease(CheckpointLock);

	 
	if (XLogCtl->archiveCleanupCommand[0])
		ExecuteRecoveryCommand(XLogCtl->archiveCleanupCommand,
							   "archive_cleanup_command",
							   false);

	return true;
}