aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlexander Korotkov <akorotkov@postgresql.org>2024-10-24 14:40:23 +0300
committerAlexander Korotkov <akorotkov@postgresql.org>2024-10-24 15:02:21 +0300
commite546989a269d5d73d283901aadcfda8c6d98e87b (patch)
tree64e1c28c70bd3647bd51baa95ca20a41787a986a /src
parent73da6b8d1b3e8b7541961c3534e584243cb0470e (diff)
downloadpostgresql-e546989a269d5d73d283901aadcfda8c6d98e87b.tar.gz
postgresql-e546989a269d5d73d283901aadcfda8c6d98e87b.zip
Add 'no_error' argument to pg_wal_replay_wait()
This argument allow skipping throwing an error. Instead, the result status can be obtained using pg_wal_replay_wait_status() function. Catversion is bumped. Reported-by: Michael Paquier Discussion: https://postgr.es/m/ZtUF17gF0pNpwZDI%40paquier.xyz Reviewed-by: Pavel Borisov
Diffstat (limited to 'src')
-rw-r--r--src/backend/access/transam/xlogfuncs.c38
-rw-r--r--src/backend/access/transam/xlogwait.c3
-rw-r--r--src/backend/catalog/system_functions.sql4
-rw-r--r--src/include/catalog/catversion.h2
-rw-r--r--src/include/catalog/pg_proc.dat7
-rw-r--r--src/test/recovery/t/043_wal_replay_wait.pl22
6 files changed, 68 insertions, 8 deletions
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index ddca78d3717..bca1d395683 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -751,15 +751,18 @@ pg_promote(PG_FUNCTION_ARGS)
PG_RETURN_BOOL(false);
}
+static WaitLSNResult lastWaitLSNResult = WAIT_LSN_RESULT_SUCCESS;
+
/*
- * Waits until recovery replays the target LSN with optional timeout.
+ * Waits until recovery replays the target LSN with optional timeout. Unless
+ * 'no_error' provided throws an error on failure
*/
Datum
pg_wal_replay_wait(PG_FUNCTION_ARGS)
{
XLogRecPtr target_lsn = PG_GETARG_LSN(0);
int64 timeout = PG_GETARG_INT64(1);
- WaitLSNResult result;
+ bool no_error = PG_GETARG_BOOL(2);
if (timeout < 0)
ereport(ERROR,
@@ -800,13 +803,16 @@ pg_wal_replay_wait(PG_FUNCTION_ARGS)
*/
Assert(MyProc->xmin == InvalidTransactionId);
- result = WaitForLSNReplay(target_lsn, timeout);
+ lastWaitLSNResult = WaitForLSNReplay(target_lsn, timeout);
+
+ if (no_error)
+ PG_RETURN_VOID();
/*
* Process the result of WaitForLSNReplay(). Throw appropriate error if
* needed.
*/
- switch (result)
+ switch (lastWaitLSNResult)
{
case WAIT_LSN_RESULT_SUCCESS:
/* Nothing to do on success */
@@ -832,3 +838,27 @@ pg_wal_replay_wait(PG_FUNCTION_ARGS)
PG_RETURN_VOID();
}
+
+Datum
+pg_wal_replay_wait_status(PG_FUNCTION_ARGS)
+{
+ const char *result_string = "";
+
+ /* Process the result of WaitForLSNReplay(). */
+ switch (lastWaitLSNResult)
+ {
+ case WAIT_LSN_RESULT_SUCCESS:
+ result_string = "success";
+ break;
+
+ case WAIT_LSN_RESULT_TIMEOUT:
+ result_string = "timeout";
+ break;
+
+ case WAIT_LSN_RESULT_NOT_IN_RECOVERY:
+ result_string = "not in recovery";
+ break;
+ }
+
+ PG_RETURN_TEXT_P(cstring_to_text(result_string));
+}
diff --git a/src/backend/access/transam/xlogwait.c b/src/backend/access/transam/xlogwait.c
index 58fb10aa5a8..8860a9c73da 100644
--- a/src/backend/access/transam/xlogwait.c
+++ b/src/backend/access/transam/xlogwait.c
@@ -2,7 +2,8 @@
*
* xlogwait.c
* Implements waiting for the given replay LSN, which is used in
- * CALL pg_wal_replay_wait(target_lsn pg_lsn, timeout float8).
+ * CALL pg_wal_replay_wait(target_lsn pg_lsn,
+ * timeout float8, no_error bool).
*
* Copyright (c) 2024, PostgreSQL Global Development Group
*
diff --git a/src/backend/catalog/system_functions.sql b/src/backend/catalog/system_functions.sql
index 9c223edfac9..20d3b9b73fd 100644
--- a/src/backend/catalog/system_functions.sql
+++ b/src/backend/catalog/system_functions.sql
@@ -414,7 +414,9 @@ CREATE OR REPLACE FUNCTION
json_populate_recordset(base anyelement, from_json json, use_json_as_text boolean DEFAULT false)
RETURNS SETOF anyelement LANGUAGE internal STABLE ROWS 100 AS 'json_populate_recordset' PARALLEL SAFE;
-CREATE OR REPLACE PROCEDURE pg_wal_replay_wait(target_lsn pg_lsn, timeout int8 DEFAULT 0)
+CREATE OR REPLACE PROCEDURE pg_wal_replay_wait(target_lsn pg_lsn,
+ timeout int8 DEFAULT 0,
+ no_error bool DEFAULT false)
LANGUAGE internal AS 'pg_wal_replay_wait';
CREATE OR REPLACE FUNCTION pg_logical_slot_get_changes(
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index 391bf04bf5d..8e0d93239fe 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -57,6 +57,6 @@
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 202410222
+#define CATALOG_VERSION_NO 202410241
#endif
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 6297b7c679d..90010d32a85 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -6665,8 +6665,13 @@
{ oid => '8593',
descr => 'wait for the target LSN to be replayed on standby with an optional timeout',
proname => 'pg_wal_replay_wait', prokind => 'p', prorettype => 'void',
- proargtypes => 'pg_lsn int8', proargnames => '{target_lsn,timeout}',
+ proargtypes => 'pg_lsn int8 bool', proargnames => '{target_lsn,timeout,no_error}',
prosrc => 'pg_wal_replay_wait' },
+{ oid => '8594',
+ descr => 'the last result for pg_wal_replay_wait()',
+ proname => 'pg_wal_replay_wait_status', prorettype => 'text',
+ proargtypes => '',
+ prosrc => 'pg_wal_replay_wait_status' },
{ oid => '6224', descr => 'get resource managers loaded in system',
proname => 'pg_get_wal_resource_managers', prorows => '50', proretset => 't',
diff --git a/src/test/recovery/t/043_wal_replay_wait.pl b/src/test/recovery/t/043_wal_replay_wait.pl
index cf77a9eec70..5857b943711 100644
--- a/src/test/recovery/t/043_wal_replay_wait.pl
+++ b/src/test/recovery/t/043_wal_replay_wait.pl
@@ -77,6 +77,20 @@ $node_standby->psql(
ok( $stderr =~ /timed out while waiting for target LSN/,
"get timeout on waiting for unreachable LSN");
+$output = $node_standby->safe_psql(
+ 'postgres', qq[
+ CALL pg_wal_replay_wait('${lsn2}', 10, true);
+ SELECT pg_wal_replay_wait_status();]);
+ok( $output eq "success",
+ "pg_wal_replay_wait_status() returns correct status after successful waiting"
+);
+$output = $node_standby->safe_psql(
+ 'postgres', qq[
+ CALL pg_wal_replay_wait('${lsn3}', 10, true);
+ SELECT pg_wal_replay_wait_status();]);
+ok($output eq "timeout",
+ "pg_wal_replay_wait_status() returns correct status after timeout");
+
# 4. Check that pg_wal_replay_wait() triggers an error if called on primary,
# within another function, or inside a transaction with an isolation level
# higher than READ COMMITTED.
@@ -193,6 +207,14 @@ $node_standby->safe_psql('postgres', "CALL pg_wal_replay_wait('${lsn5}');");
ok(1, 'wait for already replayed LSN exits immediately even after promotion');
+$output = $node_standby->safe_psql(
+ 'postgres', qq[
+ CALL pg_wal_replay_wait('${lsn4}', 10, true);
+ SELECT pg_wal_replay_wait_status();]);
+ok( $output eq "not in recovery",
+ "pg_wal_replay_wait_status() returns correct status after standby promotion"
+);
+
$node_standby->stop;
$node_primary->stop;