aboutsummaryrefslogtreecommitdiff
path: root/src/backend/commands/waitlsn.c
diff options
context:
space:
mode:
authorAlexander Korotkov <akorotkov@postgresql.org>2024-08-10 21:43:02 +0300
committerAlexander Korotkov <akorotkov@postgresql.org>2024-08-10 21:43:02 +0300
commit867d396ccd2a7f0ce55e1fa7ebda00bc8c81147b (patch)
tree2af07b058abba4f384d06781a952203e1c250842 /src/backend/commands/waitlsn.c
parentbbf668d66fbf61d45f1c187b08a5f51537bfb7c7 (diff)
downloadpostgresql-867d396ccd2a7f0ce55e1fa7ebda00bc8c81147b.tar.gz
postgresql-867d396ccd2a7f0ce55e1fa7ebda00bc8c81147b.zip
Adjust pg_wal_replay_wait() procedure behavior on promoted standby
pg_wal_replay_wait() is intended to be called on standby. However, standby can be promoted to primary at any moment, even concurrently with the pg_wal_replay_wait() call. If recovery is not currently in progress that doesn't mean the wait was unsuccessful. Thus, we always need to recheck if the target LSN is replayed. Reported-by: Kevin Hale Boyes Discussion: https://postgr.es/m/CAPpHfdu5QN%2BZGACS%2B7foxmr8_nekgA2PA%2B-G3BuOUrdBLBFb6Q%40mail.gmail.com Author: Alexander Korotkov
Diffstat (limited to 'src/backend/commands/waitlsn.c')
-rw-r--r--src/backend/commands/waitlsn.c42
1 files changed, 33 insertions, 9 deletions
diff --git a/src/backend/commands/waitlsn.c b/src/backend/commands/waitlsn.c
index 3170f0792a5..deefbd458c0 100644
--- a/src/backend/commands/waitlsn.c
+++ b/src/backend/commands/waitlsn.c
@@ -230,14 +230,27 @@ WaitForLSNReplay(XLogRecPtr targetLSN, int64 timeout)
Assert(MyProcNumber >= 0 && MyProcNumber < MaxBackends);
if (!RecoveryInProgress())
+ {
+ /*
+ * Recovery is not in progress. Given that we detected this in the
+ * very first check, this procedure was mistakenly called on primary.
+ * However, it's possible that standby was promoted concurrently to
+ * the procedure call, while target LSN is replayed. So, we still
+ * check the last replay LSN before reporting an error.
+ */
+ if (targetLSN <= GetXLogReplayRecPtr(NULL))
+ return;
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("recovery is not in progress"),
errhint("Waiting for LSN can only be executed during recovery.")));
-
- /* If target LSN is already replayed, exit immediately */
- if (targetLSN <= GetXLogReplayRecPtr(NULL))
- return;
+ }
+ else
+ {
+ /* If target LSN is already replayed, exit immediately */
+ if (targetLSN <= GetXLogReplayRecPtr(NULL))
+ return;
+ }
if (timeout > 0)
{
@@ -257,19 +270,30 @@ WaitForLSNReplay(XLogRecPtr targetLSN, int64 timeout)
int rc;
long delay_ms = 0;
- /* Check if the waited LSN has been replayed */
- currentLSN = GetXLogReplayRecPtr(NULL);
- if (targetLSN <= currentLSN)
- break;
-
/* Recheck that recovery is still in-progress */
if (!RecoveryInProgress())
+ {
+ /*
+ * Recovery was ended, but recheck if target LSN was already
+ * replayed.
+ */
+ currentLSN = GetXLogReplayRecPtr(NULL);
+ if (targetLSN <= currentLSN)
+ return;
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("recovery is not in progress"),
errdetail("Recovery ended before replaying target LSN %X/%X; last replay LSN %X/%X.",
LSN_FORMAT_ARGS(targetLSN),
LSN_FORMAT_ARGS(currentLSN))));
+ }
+ else
+ {
+ /* Check if the waited LSN has been replayed */
+ currentLSN = GetXLogReplayRecPtr(NULL);
+ if (targetLSN <= currentLSN)
+ break;
+ }
/*
* If the timeout value is specified, calculate the number of