bool SharedRecoveryProcessingMode;
/*
- * This is somewhat similar to RedoRecPtr. It's the location of the
- * most recent checkpoint record we've seen in the WAL replay.
- * (ignoring records that are not safe to use as restartpoints because
- * a resource manager returned false in rm_safe_restartpoint())
+ * During recovery, we keep a copy of the latest checkpoint record
+ * here. It's used by the background writer when it wants to create
+ * a restartpoint.
+ *
+ * is info_lck spinlock a bit too light-weight to protect this?
*/
- XLogRecPtr RestartRedoPtr;
- CheckPoint restartPoint; /* XXX is info_lck spinlock a bit too light-weight to protect this? */
- XLogRecPtr ReadRecPtr; /* last read pointer during recovery */
+ XLogRecPtr lastCheckPointPtr;
+ CheckPoint lastCheckPoint;
slock_t info_lck; /* locks shared variables shown above */
} XLogCtlData;
}
#endif
- /*
- * Advertise new read pointer.
- */
- {
- /* use volatile pointer to prevent code rearrangement */
- volatile XLogCtlData *xlogctl = XLogCtl;
-
- SpinLockAcquire(&xlogctl->info_lck);
- xlogctl->ReadRecPtr = record->xl_prev;
- SpinLockRelease(&xlogctl->info_lck);
- }
-
/*
* Have we reached our recovery target?
*/
/*
* Have we reached our safe starting point? If so, we can
- * signal Postmaster to enter consistent recovery mode.
+ * signal postmaster to enter consistent recovery mode.
*
* There are two points in the log we must pass. The first is
* the minRecoveryPoint, which is the LSN at the time the
* base backup was taken that we are about to rollfoward from.
* If recovery has ever crashed or was stopped there is
- * another point also: minSafeStartPoint, which we know the
+ * another point also: minSafeStartPoint, which is the
* latest LSN that recovery could have reached prior to crash.
*/
if (!reachedSafeStartPoint &&
volatile XLogCtlData *xlogctl = XLogCtl;
XLogRecPtr recptr;
- if (IsRecoveryProcessingMode())
- {
- SpinLockAcquire(&xlogctl->info_lck);
- recptr = xlogctl->LogwrtRqst.Write;
- SpinLockRelease(&xlogctl->info_lck);
- }
- else
- {
- SpinLockAcquire(&xlogctl->info_lck);
- recptr = xlogctl->ReadRecPtr;
- SpinLockRelease(&xlogctl->info_lck);
- }
+ SpinLockAcquire(&xlogctl->info_lck);
+ recptr = xlogctl->LogwrtRqst.Write;
+ SpinLockRelease(&xlogctl->info_lck);
return recptr;
}
}
/*
- * Set a recovery restart point if appropriate
- *
- * This is similar to CreateCheckPoint, but is used during WAL recovery
- * to establish a point from which recovery can roll forward without
- * replaying the entire recovery log. This function is called each time
- * a checkpoint record is read from XLOG; it must determine whether a
- * restartpoint is needed or not.
+ * Set a recovery restart point if appropriate.
+ * This function is called each time a checkpoint record is read from XLOG.
*/
static void
RecoveryRestartPoint(const CheckPoint *checkPoint)
}
SpinLockAcquire(&xlogctl->info_lck);
- XLogCtl->RestartRedoPtr = ReadRecPtr;
- memcpy(&XLogCtl->restartPoint, checkPoint, sizeof(CheckPoint));
+ XLogCtl->lastCheckPointPtr = ReadRecPtr;
+ memcpy(&XLogCtl->lastCheckPoint, checkPoint, sizeof(CheckPoint));
SpinLockRelease(&xlogctl->info_lck);
/*
* XXX: Should we try to perform restartpoints if we're not in consistent
- * recovery?
+ * recovery? The bgwriter isn't doing it for us in that case.
*/
}
/*
+ * This is similar to CreateCheckPoint, but is used during WAL recovery
+ * to establish a point from which recovery can roll forward without
+ * replaying the entire recovery log.
+ *
* As of 8.4, RestartPoints are always created by the bgwriter
- * once we have reachedSafeStartPoint. We use bgwriter's shared memory
- * area wherever we call it from, to keep better code structure.
+ * once we have reachedSafeStartPoint.
*/
void
CreateRestartPoint(int flags)
/* use volatile pointer to prevent code rearrangement */
volatile XLogCtlData *xlogctl = XLogCtl;
- SpinLockAcquire(&xlogctl->info_lck);
- redoRecPtr = xlogctl->RestartRedoPtr;
- memcpy(&restartPoint, &XLogCtl->restartPoint, sizeof(CheckPoint));
- SpinLockRelease(&xlogctl->info_lck);
-
/*
* If the last checkpoint record we've replayed is already our last
* restartpoint, we're done.
if (XLByteLE(redoRecPtr, ControlFile->checkPointCopy.redo))
{
ereport(DEBUG2,
- (errmsg("restartpoint already performed at %X/%X",
+ (errmsg("skipping restartpoint, already performed at %X/%X",
restartPoint.redo.xlogid, restartPoint.redo.xrecoff)));
return;
}
/*
* Acquire CheckpointLock to ensure only one restartpoint happens at a time.
* We rely on this lock to ensure that the startup process doesn't exit
- * Recovery while we are half way through a restartpoint.
+ * Recovery while we are half way through a restartpoint. XXX ?
*/
LWLockAcquire(CheckpointLock, LW_EXCLUSIVE);
+ /* Check that we're still in recovery mode. */
+ if (!IsRecoveryProcessingMode())
+ {
+ ereport(DEBUG2,
+ (errmsg("skipping restartpoint, recovery has already ended")));
+ LWLockRelease(CheckpointLock);
+ return;
+ }
+
+ SpinLockAcquire(&xlogctl->info_lck);
+ redoRecPtr = xlogctl->lastCheckPointPtr;
+ memcpy(&restartPoint, &XLogCtl->lastCheckPoint, sizeof(CheckPoint));
+ SpinLockRelease(&xlogctl->info_lck);
+
CheckPointGuts(restartPoint.redo, flags);
/*