v2-0001-pg_wal_replay_wait-Improve-handling-of-standby-pr.patch

application/octet-stream

Filename: v2-0001-pg_wal_replay_wait-Improve-handling-of-standby-pr.patch
Type: application/octet-stream
Part: 1
Message: Re: pgsql: Implement pg_wal_replay_wait() stored procedure

Patch

Same data as JSON: GET /api/v1/attachments/:id/patch the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes. API reference →
Format: format-patch
Series: patch v2-0001
Subject: pg_wal_replay_wait(): Improve handling of standby promotion
File+
src/backend/access/transam/xlogfuncs.c 12 6
src/backend/access/transam/xlogwait.c 4 2
From 4c8ef6795234c1314a33c03eba4cba790e787cca Mon Sep 17 00:00:00 2001
From: Alexander Korotkov <akorotkov@postgresql.org>
Date: Mon, 4 Nov 2024 06:18:08 +0200
Subject: [PATCH v2 1/2] pg_wal_replay_wait(): Improve handling of standby
 promotion

Currently, when pg_wal_replay_wait() finds the server to be not in recovery,
it assumes concurrent promotion happened.  That leads to certain problems
including:

  1. No distinction between local recovery as streaming WAL replay,
  2. Weird error reporting when there was no recovery.

This commit uses PromoteIsTriggered() checks to improve the situation in
the following ways:

 1. Accept last replay LSN not in recovery mode only when standby was
    promoted,
 2. Show last replay LSN in errdetail() only if standby was promoted.

Reported-by: Heikki Linnakangas
Discussion: https://postgr.es/m/ab0eddce-06d4-4db2-87ce-46fa2427806c%40iki.fi
---
 src/backend/access/transam/xlogfuncs.c | 18 ++++++++++++------
 src/backend/access/transam/xlogwait.c  |  6 ++++--
 2 files changed, 16 insertions(+), 8 deletions(-)

diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index bca1d395683..8abea2dbb57 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -827,12 +827,18 @@ pg_wal_replay_wait(PG_FUNCTION_ARGS)
 			break;
 
 		case WAIT_LSN_RESULT_NOT_IN_RECOVERY:
-			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(target_lsn),
-							   LSN_FORMAT_ARGS(GetXLogReplayRecPtr(NULL)))));
+			if (PromoteIsTriggered())
+				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(target_lsn),
+								   LSN_FORMAT_ARGS(GetXLogReplayRecPtr(NULL)))));
+			else
+				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.")));
 			break;
 	}
 
diff --git a/src/backend/access/transam/xlogwait.c b/src/backend/access/transam/xlogwait.c
index 0ec0898cfbf..fa40762c66a 100644
--- a/src/backend/access/transam/xlogwait.c
+++ b/src/backend/access/transam/xlogwait.c
@@ -238,7 +238,8 @@ WaitForLSNReplay(XLogRecPtr targetLSN, int64 timeout)
 		 * the procedure call, while target LSN is replayed.  So, we still
 		 * check the last replay LSN before reporting an error.
 		 */
-		if (targetLSN <= GetXLogReplayRecPtr(NULL))
+		if (PromoteIsTriggered() &&
+			targetLSN <= GetXLogReplayRecPtr(NULL))
 			return WAIT_LSN_RESULT_SUCCESS;
 		return WAIT_LSN_RESULT_NOT_IN_RECOVERY;
 	}
@@ -276,7 +277,8 @@ WaitForLSNReplay(XLogRecPtr targetLSN, int64 timeout)
 			 */
 			deleteLSNWaiter();
 			currentLSN = GetXLogReplayRecPtr(NULL);
-			if (targetLSN <= currentLSN)
+			if (PromoteIsTriggered() &&
+				targetLSN <= currentLSN)
 				return WAIT_LSN_RESULT_SUCCESS;
 			return WAIT_LSN_RESULT_NOT_IN_RECOVERY;
 		}
-- 
2.39.5 (Apple Git-154)