aboutsummaryrefslogtreecommitdiff
path: root/src/backend/access/transam/xlog.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/access/transam/xlog.c')
-rw-r--r--src/backend/access/transam/xlog.c84
1 files changed, 70 insertions, 14 deletions
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 18af3d41209..e04250f4e9e 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -722,8 +722,8 @@ typedef struct XLogCtlData
* only relevant for replication or archive recovery
*/
TimestampTz currentChunkStartTime;
- /* Are we requested to pause recovery? */
- bool recoveryPause;
+ /* Recovery pause state */
+ RecoveryPauseState recoveryPauseState;
/*
* lastFpwDisableRecPtr points to the start of the last replayed
@@ -895,6 +895,7 @@ static void validateRecoveryParameters(void);
static void exitArchiveRecovery(TimeLineID endTLI, XLogRecPtr endOfLog);
static bool recoveryStopsBefore(XLogReaderState *record);
static bool recoveryStopsAfter(XLogReaderState *record);
+static void ConfirmRecoveryPaused(void);
static void recoveryPausesHere(bool endOfRecovery);
static bool recoveryApplyDelay(XLogReaderState *record);
static void SetLatestXTime(TimestampTz xtime);
@@ -6034,7 +6035,7 @@ recoveryStopsAfter(XLogReaderState *record)
}
/*
- * Wait until shared recoveryPause flag is cleared.
+ * Wait until shared recoveryPauseState is set to RECOVERY_NOT_PAUSED.
*
* endOfRecovery is true if the recovery target is reached and
* the paused state starts at the end of recovery because of
@@ -6064,34 +6065,72 @@ recoveryPausesHere(bool endOfRecovery)
(errmsg("recovery has paused"),
errhint("Execute pg_wal_replay_resume() to continue.")));
- while (RecoveryIsPaused())
+ /* loop until recoveryPauseState is set to RECOVERY_NOT_PAUSED */
+ while (GetRecoveryPauseState() != RECOVERY_NOT_PAUSED)
{
HandleStartupProcInterrupts();
if (CheckForStandbyTrigger())
return;
pgstat_report_wait_start(WAIT_EVENT_RECOVERY_PAUSE);
+
+ /*
+ * If recovery pause is requested then set it paused. While we are in
+ * the loop, user might resume and pause again so set this every time.
+ */
+ ConfirmRecoveryPaused();
+
pg_usleep(1000000L); /* 1000 ms */
pgstat_report_wait_end();
}
}
-bool
-RecoveryIsPaused(void)
+/*
+ * Get the current state of the recovery pause request.
+ */
+RecoveryPauseState
+GetRecoveryPauseState(void)
{
- bool recoveryPause;
+ RecoveryPauseState state;
SpinLockAcquire(&XLogCtl->info_lck);
- recoveryPause = XLogCtl->recoveryPause;
+ state = XLogCtl->recoveryPauseState;
SpinLockRelease(&XLogCtl->info_lck);
- return recoveryPause;
+ return state;
}
+/*
+ * Set the recovery pause state.
+ *
+ * If recovery pause is requested then sets the recovery pause state to
+ * 'pause requested' if it is not already 'paused'. Otherwise, sets it
+ * to 'not paused' to resume the recovery. The recovery pause will be
+ * confirmed by the ConfirmRecoveryPaused.
+ */
void
SetRecoveryPause(bool recoveryPause)
{
SpinLockAcquire(&XLogCtl->info_lck);
- XLogCtl->recoveryPause = recoveryPause;
+
+ if (!recoveryPause)
+ XLogCtl->recoveryPauseState = RECOVERY_NOT_PAUSED;
+ else if (XLogCtl->recoveryPauseState == RECOVERY_NOT_PAUSED)
+ XLogCtl->recoveryPauseState = RECOVERY_PAUSE_REQUESTED;
+
+ SpinLockRelease(&XLogCtl->info_lck);
+}
+
+/*
+ * Confirm the recovery pause by setting the recovery pause state to
+ * RECOVERY_PAUSED.
+ */
+static void
+ConfirmRecoveryPaused(void)
+{
+ /* If recovery pause is requested then set it paused */
+ SpinLockAcquire(&XLogCtl->info_lck);
+ if (XLogCtl->recoveryPauseState == RECOVERY_PAUSE_REQUESTED)
+ XLogCtl->recoveryPauseState = RECOVERY_PAUSED;
SpinLockRelease(&XLogCtl->info_lck);
}
@@ -6292,7 +6331,7 @@ RecoveryRequiresIntParameter(const char *param_name, int currValue, int minValue
errdetail("If recovery is unpaused, the server will shut down."),
errhint("You can then restart the server after making the necessary configuration changes.")));
- while (RecoveryIsPaused())
+ while (GetRecoveryPauseState() != RECOVERY_NOT_PAUSED)
{
HandleStartupProcInterrupts();
@@ -6311,6 +6350,13 @@ RecoveryRequiresIntParameter(const char *param_name, int currValue, int minValue
warned_for_promote = true;
}
+ /*
+ * If recovery pause is requested then set it paused. While we
+ * are in the loop, user might resume and pause again so set
+ * this every time.
+ */
+ ConfirmRecoveryPaused();
+
pgstat_report_wait_start(WAIT_EVENT_RECOVERY_PAUSE);
pg_usleep(1000000L); /* 1000 ms */
pgstat_report_wait_end();
@@ -7205,7 +7251,7 @@ StartupXLOG(void)
XLogCtl->lastReplayedTLI = XLogCtl->replayEndTLI;
XLogCtl->recoveryLastXTime = 0;
XLogCtl->currentChunkStartTime = 0;
- XLogCtl->recoveryPause = false;
+ XLogCtl->recoveryPauseState = RECOVERY_NOT_PAUSED;
SpinLockRelease(&XLogCtl->info_lck);
/* Also ensure XLogReceiptTime has a sane value */
@@ -7309,7 +7355,8 @@ StartupXLOG(void)
* otherwise would is a minor issue, so it doesn't seem worth
* adding another spinlock cycle to prevent that.
*/
- if (((volatile XLogCtlData *) XLogCtl)->recoveryPause)
+ if (((volatile XLogCtlData *) XLogCtl)->recoveryPauseState !=
+ RECOVERY_NOT_PAUSED)
recoveryPausesHere(false);
/*
@@ -7334,7 +7381,8 @@ StartupXLOG(void)
* here otherwise pausing during the delay-wait wouldn't
* work.
*/
- if (((volatile XLogCtlData *) XLogCtl)->recoveryPause)
+ if (((volatile XLogCtlData *) XLogCtl)->recoveryPauseState !=
+ RECOVERY_NOT_PAUSED)
recoveryPausesHere(false);
}
@@ -12657,6 +12705,14 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
}
/*
+ * Check for recovery pause here so that we can confirm more quickly
+ * that a requested pause has actually taken effect.
+ */
+ if (((volatile XLogCtlData *) XLogCtl)->recoveryPauseState !=
+ RECOVERY_NOT_PAUSED)
+ recoveryPausesHere(false);
+
+ /*
* This possibly-long loop needs to handle interrupts of startup
* process.
*/