Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit e546989

Browse files
committed
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
1 parent 73da6b8 commit e546989

File tree

7 files changed

+118
-14
lines changed

7 files changed

+118
-14
lines changed

doc/src/sgml/func.sgml

+50-6
Original file line numberDiff line numberDiff line change
@@ -28989,12 +28989,15 @@ postgres=# SELECT '0/0'::pg_lsn + pd.segment_number * ps.setting::int + :offset
2898928989
</para>
2899028990

2899128991
<table id="recovery-synchronization-procedure-table">
28992-
<title>Recovery Synchronization Procedure</title>
28992+
<title>Recovery Synchronization Procedure and Function</title>
2899328993
<tgroup cols="1">
2899428994
<thead>
2899528995
<row>
2899628996
<entry role="func_table_entry"><para role="func_signature">
28997-
Procedure
28997+
Procedure or Function
28998+
</para>
28999+
<para>
29000+
Type
2899829001
</para>
2899929002
<para>
2900029003
Description
@@ -29010,8 +29013,11 @@ postgres=# SELECT '0/0'::pg_lsn + pd.segment_number * ps.setting::int + :offset
2901029013
</indexterm>
2901129014
<function>pg_wal_replay_wait</function> (
2901229015
<parameter>target_lsn</parameter> <type>pg_lsn</type>,
29013-
<parameter>timeout</parameter> <type>bigint</type> <literal>DEFAULT</literal> <literal>0</literal>)
29014-
<returnvalue>void</returnvalue>
29016+
<parameter>timeout</parameter> <type>bigint</type> <literal>DEFAULT</literal> <literal>0</literal>,
29017+
<parameter>no_error</parameter> <type>bool</type> <literal>DEFAULT</literal> <literal>false</literal>)
29018+
</para>
29019+
<para>
29020+
Procedure
2901529021
</para>
2901629022
<para>
2901729023
Waits until recovery replays <literal>target_lsn</literal>.
@@ -29022,7 +29028,30 @@ postgres=# SELECT '0/0'::pg_lsn + pd.segment_number * ps.setting::int + :offset
2902229028
procedure waits until <literal>target_lsn</literal> is reached or
2902329029
the specified <parameter>timeout</parameter> has elapsed.
2902429030
On timeout, or if the server is promoted before
29025-
<literal>target_lsn</literal> is reached, an error is emitted.
29031+
<literal>target_lsn</literal> is reached, an error is emitted,
29032+
as soon as <parameter>no_error</parameter> is false.
29033+
If <parameter>no_error</parameter> is set to true, then the procedure
29034+
doesn't throw errors. The last result status could be read
29035+
with <function>pg_wal_replay_wait_status</function>.
29036+
</para></entry>
29037+
</row>
29038+
29039+
<row>
29040+
<entry role="func_table_entry"><para role="func_signature">
29041+
<indexterm>
29042+
<primary>pg_wal_replay_wait_status</primary>
29043+
</indexterm>
29044+
<function>pg_wal_replay_wait_status</function> ()
29045+
<returnvalue>text</returnvalue>
29046+
</para>
29047+
<para>
29048+
Function
29049+
</para>
29050+
<para>
29051+
Returns the last result status for
29052+
<function>pg_wal_replay_wait</function> procedure. The possible
29053+
values are <literal>success</literal>, <literal>timeout</literal>,
29054+
and <literal>not in recovery</literal>.
2902629055
</para></entry>
2902729056
</row>
2902829057
</tbody>
@@ -29044,7 +29073,8 @@ postgres=# SELECT '0/0'::pg_lsn + pd.segment_number * ps.setting::int + :offset
2904429073
<para>
2904529074
<function>pg_wal_replay_wait</function> should be called on standby.
2904629075
If a user calls <function>pg_wal_replay_wait</function> on primary, it
29047-
will error out. However, if <function>pg_wal_replay_wait</function> is
29076+
will error out as soon as <parameter>no_error</parameter> is false.
29077+
However, if <function>pg_wal_replay_wait</function> is
2904829078
called on primary promoted from standby and <literal>target_lsn</literal>
2904929079
was already replayed, then <function>pg_wal_replay_wait</function> just
2905029080
exits immediately.
@@ -29090,6 +29120,20 @@ postgres=# CALL pg_wal_replay_wait('0/306EE20', 100);
2909029120
ERROR: timed out while waiting for target LSN 0/306EE20 to be replayed; current replay LSN 0/306EA60
2909129121
</programlisting>
2909229122

29123+
The same example uses <function>pg_wal_replay_wait</function> with
29124+
<parameter>no_error</parameter> set to true. In this case, the result
29125+
status must be read with <function>pg_wal_replay_wait_status</function>.
29126+
29127+
<programlisting>
29128+
postgres=# CALL pg_wal_replay_wait('0/306EE20', 100, true);
29129+
CALL
29130+
postgres=# SELECT pg_wal_replay_wait_status();
29131+
pg_wal_replay_wait_status
29132+
---------------------------
29133+
timeout
29134+
(1 row)
29135+
</programlisting>
29136+
2909329137
</para>
2909429138

2909529139
<para>

src/backend/access/transam/xlogfuncs.c

+34-4
Original file line numberDiff line numberDiff line change
@@ -751,15 +751,18 @@ pg_promote(PG_FUNCTION_ARGS)
751751
PG_RETURN_BOOL(false);
752752
}
753753

754+
static WaitLSNResult lastWaitLSNResult = WAIT_LSN_RESULT_SUCCESS;
755+
754756
/*
755-
* Waits until recovery replays the target LSN with optional timeout.
757+
* Waits until recovery replays the target LSN with optional timeout. Unless
758+
* 'no_error' provided throws an error on failure
756759
*/
757760
Datum
758761
pg_wal_replay_wait(PG_FUNCTION_ARGS)
759762
{
760763
XLogRecPtr target_lsn = PG_GETARG_LSN(0);
761764
int64 timeout = PG_GETARG_INT64(1);
762-
WaitLSNResult result;
765+
bool no_error = PG_GETARG_BOOL(2);
763766

764767
if (timeout < 0)
765768
ereport(ERROR,
@@ -800,13 +803,16 @@ pg_wal_replay_wait(PG_FUNCTION_ARGS)
800803
*/
801804
Assert(MyProc->xmin == InvalidTransactionId);
802805

803-
result = WaitForLSNReplay(target_lsn, timeout);
806+
lastWaitLSNResult = WaitForLSNReplay(target_lsn, timeout);
807+
808+
if (no_error)
809+
PG_RETURN_VOID();
804810

805811
/*
806812
* Process the result of WaitForLSNReplay(). Throw appropriate error if
807813
* needed.
808814
*/
809-
switch (result)
815+
switch (lastWaitLSNResult)
810816
{
811817
case WAIT_LSN_RESULT_SUCCESS:
812818
/* Nothing to do on success */
@@ -832,3 +838,27 @@ pg_wal_replay_wait(PG_FUNCTION_ARGS)
832838

833839
PG_RETURN_VOID();
834840
}
841+
842+
Datum
843+
pg_wal_replay_wait_status(PG_FUNCTION_ARGS)
844+
{
845+
const char *result_string = "";
846+
847+
/* Process the result of WaitForLSNReplay(). */
848+
switch (lastWaitLSNResult)
849+
{
850+
case WAIT_LSN_RESULT_SUCCESS:
851+
result_string = "success";
852+
break;
853+
854+
case WAIT_LSN_RESULT_TIMEOUT:
855+
result_string = "timeout";
856+
break;
857+
858+
case WAIT_LSN_RESULT_NOT_IN_RECOVERY:
859+
result_string = "not in recovery";
860+
break;
861+
}
862+
863+
PG_RETURN_TEXT_P(cstring_to_text(result_string));
864+
}

src/backend/access/transam/xlogwait.c

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
*
33
* xlogwait.c
44
* Implements waiting for the given replay LSN, which is used in
5-
* CALL pg_wal_replay_wait(target_lsn pg_lsn, timeout float8).
5+
* CALL pg_wal_replay_wait(target_lsn pg_lsn,
6+
* timeout float8, no_error bool).
67
*
78
* Copyright (c) 2024, PostgreSQL Global Development Group
89
*

src/backend/catalog/system_functions.sql

+3-1
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,9 @@ CREATE OR REPLACE FUNCTION
414414
json_populate_recordset(base anyelement, from_json json, use_json_as_text boolean DEFAULT false)
415415
RETURNS SETOF anyelement LANGUAGE internal STABLE ROWS 100 AS 'json_populate_recordset' PARALLEL SAFE;
416416

417-
CREATE OR REPLACE PROCEDURE pg_wal_replay_wait(target_lsn pg_lsn, timeout int8 DEFAULT 0)
417+
CREATE OR REPLACE PROCEDURE pg_wal_replay_wait(target_lsn pg_lsn,
418+
timeout int8 DEFAULT 0,
419+
no_error bool DEFAULT false)
418420
LANGUAGE internal AS 'pg_wal_replay_wait';
419421

420422
CREATE OR REPLACE FUNCTION pg_logical_slot_get_changes(

src/include/catalog/catversion.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,6 @@
5757
*/
5858

5959
/* yyyymmddN */
60-
#define CATALOG_VERSION_NO 202410222
60+
#define CATALOG_VERSION_NO 202410241
6161

6262
#endif

src/include/catalog/pg_proc.dat

+6-1
Original file line numberDiff line numberDiff line change
@@ -6665,8 +6665,13 @@
66656665
{ oid => '8593',
66666666
descr => 'wait for the target LSN to be replayed on standby with an optional timeout',
66676667
proname => 'pg_wal_replay_wait', prokind => 'p', prorettype => 'void',
6668-
proargtypes => 'pg_lsn int8', proargnames => '{target_lsn,timeout}',
6668+
proargtypes => 'pg_lsn int8 bool', proargnames => '{target_lsn,timeout,no_error}',
66696669
prosrc => 'pg_wal_replay_wait' },
6670+
{ oid => '8594',
6671+
descr => 'the last result for pg_wal_replay_wait()',
6672+
proname => 'pg_wal_replay_wait_status', prorettype => 'text',
6673+
proargtypes => '',
6674+
prosrc => 'pg_wal_replay_wait_status' },
66706675

66716676
{ oid => '6224', descr => 'get resource managers loaded in system',
66726677
proname => 'pg_get_wal_resource_managers', prorows => '50', proretset => 't',

src/test/recovery/t/043_wal_replay_wait.pl

+22
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,20 @@
7777
ok( $stderr =~ /timed out while waiting for target LSN/,
7878
"get timeout on waiting for unreachable LSN");
7979

80+
$output = $node_standby->safe_psql(
81+
'postgres', qq[
82+
CALL pg_wal_replay_wait('${lsn2}', 10, true);
83+
SELECT pg_wal_replay_wait_status();]);
84+
ok( $output eq "success",
85+
"pg_wal_replay_wait_status() returns correct status after successful waiting"
86+
);
87+
$output = $node_standby->safe_psql(
88+
'postgres', qq[
89+
CALL pg_wal_replay_wait('${lsn3}', 10, true);
90+
SELECT pg_wal_replay_wait_status();]);
91+
ok($output eq "timeout",
92+
"pg_wal_replay_wait_status() returns correct status after timeout");
93+
8094
# 4. Check that pg_wal_replay_wait() triggers an error if called on primary,
8195
# within another function, or inside a transaction with an isolation level
8296
# higher than READ COMMITTED.
@@ -193,6 +207,14 @@
193207

194208
ok(1, 'wait for already replayed LSN exits immediately even after promotion');
195209

210+
$output = $node_standby->safe_psql(
211+
'postgres', qq[
212+
CALL pg_wal_replay_wait('${lsn4}', 10, true);
213+
SELECT pg_wal_replay_wait_status();]);
214+
ok( $output eq "not in recovery",
215+
"pg_wal_replay_wait_status() returns correct status after standby promotion"
216+
);
217+
196218
$node_standby->stop;
197219
$node_primary->stop;
198220

0 commit comments

Comments
 (0)