Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitf61e1dd

Browse files
committed
Allow pg_receivewal to stream from a slot's restart LSN
Prior to this patch, when running pg_receivewal, the streaming startpoint would be the current location of the archives if anything isfound in the local directory where WAL segments are written, andpg_receivewal would fall back to the current WAL flush location if thereare no archives, as of the result of an IDENTIFY_SYSTEM command.If for some reason the WAL files from pg_receivewal were moved, it isbetter to try a restart where we left at, which is the replicationslot's restart_lsn instead of skipping right to the current flushlocation, to avoid holes in the WAL backed up. This commit changespg_receivewal to use the following sequence of methods to determine thestarting streaming LSN:- Scan the local archives.- Use the slot's restart_lsn, if supported by the backend and if a slotis defined.- Fallback to the current flush LSN as reported by IDENTIFY_SYSTEM.To keep compatibility with older server versions, we only attempt to useREAD_REPLICATION_SLOT if the backend version is at least 15, andfallback to the older behavior of streaming from the current flushLSN if the command is not supported.Some TAP tests are added to cover this feature.Author: Ronan DunklauReviewed-by: Kyotaro Horiguchi, Michael Paquier, Bharath RupireddyDiscussion:https://postgr.es/m/18708360.4lzOvYHigE@aivenronan
1 parent8781b0c commitf61e1dd

File tree

5 files changed

+191
-4
lines changed

5 files changed

+191
-4
lines changed

‎doc/src/sgml/ref/pg_receivewal.sgml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,17 @@ PostgreSQL documentation
8888
</para>
8989
</listitem>
9090

91+
<listitem>
92+
<para>
93+
If a starting point cannot not be calculated with the previous method,
94+
and if a replication slot is used, an extra
95+
<command>READ_REPLICATION_SLOT</command> command is issued to retrieve
96+
the slot's <literal>restart_lsn</literal> to use as starting point.
97+
This option is only available when streaming write-ahead logs from
98+
<productname>PostgreSQL</productname> 15 and up.
99+
</para>
100+
</listitem>
101+
91102
<listitem>
92103
<para>
93104
If a starting point cannot be calculated with the previous method,

‎src/bin/pg_basebackup/pg_receivewal.c

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -404,15 +404,40 @@ StreamLog(void)
404404
exit(1);
405405

406406
/*
407-
* Figure out where to start streaming.
407+
* Figure out where to start streaming. First scan the local directory.
408408
*/
409409
stream.startpos=FindStreamingStart(&stream.timeline);
410410
if (stream.startpos==InvalidXLogRecPtr)
411411
{
412-
stream.startpos=serverpos;
413-
stream.timeline=servertli;
412+
/*
413+
* Try to get the starting point from the slot if any. This is
414+
* supported in PostgreSQL 15 and newer.
415+
*/
416+
if (replication_slot!=NULL&&
417+
PQserverVersion(conn) >=150000)
418+
{
419+
if (!GetSlotInformation(conn,replication_slot,&stream.startpos,
420+
&stream.timeline))
421+
{
422+
/* Error is logged by GetSlotInformation() */
423+
return;
424+
}
425+
}
426+
427+
/*
428+
* If it the starting point is still not known, use the current WAL
429+
* flush value as last resort.
430+
*/
431+
if (stream.startpos==InvalidXLogRecPtr)
432+
{
433+
stream.startpos=serverpos;
434+
stream.timeline=servertli;
435+
}
414436
}
415437

438+
Assert(stream.startpos!=InvalidXLogRecPtr&&
439+
stream.timeline!=0);
440+
416441
/*
417442
* Always start streaming at the beginning of a segment
418443
*/

‎src/bin/pg_basebackup/streamutil.c

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,103 @@ RunIdentifySystem(PGconn *conn, char **sysid, TimeLineID *starttli,
479479
return true;
480480
}
481481

482+
/*
483+
* Run READ_REPLICATION_SLOT through a given connection and give back to
484+
* caller some result information if requested for this slot:
485+
* - Start LSN position, InvalidXLogRecPtr if unknown.
486+
* - Current timeline ID, 0 if unknown.
487+
* Returns false on failure, and true otherwise.
488+
*/
489+
bool
490+
GetSlotInformation(PGconn*conn,constchar*slot_name,
491+
XLogRecPtr*restart_lsn,TimeLineID*restart_tli)
492+
{
493+
PGresult*res;
494+
PQExpBufferquery;
495+
XLogRecPtrlsn_loc=InvalidXLogRecPtr;
496+
TimeLineIDtli_loc=0;
497+
498+
if (restart_lsn)
499+
*restart_lsn=lsn_loc;
500+
if (restart_tli)
501+
*restart_tli=tli_loc;
502+
503+
query=createPQExpBuffer();
504+
appendPQExpBuffer(query,"READ_REPLICATION_SLOT %s",slot_name);
505+
res=PQexec(conn,query->data);
506+
destroyPQExpBuffer(query);
507+
508+
if (PQresultStatus(res)!=PGRES_TUPLES_OK)
509+
{
510+
pg_log_error("could not send replication command \"%s\": %s",
511+
"READ_REPLICATION_SLOT",PQerrorMessage(conn));
512+
PQclear(res);
513+
return false;
514+
}
515+
516+
/* The command should always return precisely one tuple and three fields */
517+
if (PQntuples(res)!=1||PQnfields(res)!=3)
518+
{
519+
pg_log_error("could not read replication slot \"%s\": got %d rows and %d fields, expected %d rows and %d fields",
520+
slot_name,PQntuples(res),PQnfields(res),1,3);
521+
PQclear(res);
522+
return false;
523+
}
524+
525+
/*
526+
* When the slot doesn't exist, the command returns a tuple with NULL
527+
* values. This checks only the slot type field.
528+
*/
529+
if (PQgetisnull(res,0,0))
530+
{
531+
pg_log_error("could not find replication slot \"%s\"",slot_name);
532+
PQclear(res);
533+
return false;
534+
}
535+
536+
/*
537+
* Note that this cannot happen as READ_REPLICATION_SLOT supports only
538+
* physical slots, but play it safe.
539+
*/
540+
if (strcmp(PQgetvalue(res,0,0),"physical")!=0)
541+
{
542+
pg_log_error("expected a physical replication slot, got type \"%s\" instead",
543+
PQgetvalue(res,0,0));
544+
PQclear(res);
545+
return false;
546+
}
547+
548+
/* restart LSN */
549+
if (!PQgetisnull(res,0,1))
550+
{
551+
uint32hi,
552+
lo;
553+
554+
if (sscanf(PQgetvalue(res,0,1),"%X/%X",&hi,&lo)!=2)
555+
{
556+
pg_log_error("could not parse restart_lsn \"%s\" for replication slot \"%s\"",
557+
PQgetvalue(res,0,1),slot_name);
558+
PQclear(res);
559+
return false;
560+
}
561+
lsn_loc= ((uint64)hi) <<32 |lo;
562+
}
563+
564+
/* current TLI */
565+
if (!PQgetisnull(res,0,2))
566+
tli_loc= (TimeLineID)atol(PQgetvalue(res,0,2));
567+
568+
PQclear(res);
569+
570+
/* Assign results if requested */
571+
if (restart_lsn)
572+
*restart_lsn=lsn_loc;
573+
if (restart_tli)
574+
*restart_tli=tli_loc;
575+
576+
return true;
577+
}
578+
482579
/*
483580
* Create a replication slot for the given connection. This function
484581
* returns true in case of success.

‎src/bin/pg_basebackup/streamutil.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ extern void AppendIntegerCommandOption(PQExpBuffer buf,
5252
booluse_new_option_syntax,
5353
char*option_name,int32option_value);
5454

55+
externboolGetSlotInformation(PGconn*conn,constchar*slot_name,
56+
XLogRecPtr*restart_lsn,
57+
TimeLineID*restart_tli);
5558
externboolRetrieveWalSegSize(PGconn*conn);
5659
externTimestampTzfeGetCurrentTimestamp(void);
5760
externvoidfeTimestampDifference(TimestampTzstart_time,TimestampTzstop_time,

‎src/bin/pg_basebackup/t/020_pg_receivewal.pl

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
use warnings;
66
use PostgreSQL::Test::Utils;
77
use PostgreSQL::Test::Cluster;
8-
use Test::Moretests=>27;
8+
use Test::Moretests=>31;
99

1010
program_help_ok('pg_receivewal');
1111
program_version_ok('pg_receivewal');
@@ -72,6 +72,8 @@
7272
my@partial_wals =glob"$stream_dir/*\.partial";
7373
is(scalar(@partial_wals), 1,"one partial WAL segment was created");
7474

75+
note"Testing pg_receivewal with compression methods";
76+
7577
# Check ZLIB compression if available.
7678
SKIP:
7779
{
@@ -155,3 +157,52 @@
155157
ok(check_mode_recursive($stream_dir, 0700, 0600),
156158
"check stream dir permissions");
157159
}
160+
161+
note"Testing pg_receivewal with slot as starting streaming point";
162+
163+
# When using a replication slot, archiving should be resumed from the slot's
164+
# restart LSN. Use a new archive location and new slot for this test.
165+
my$slot_dir =$primary->basedir .'/slot_wal';
166+
mkdir($slot_dir);
167+
$slot_name ='archive_slot';
168+
169+
# Setup the slot, reserving WAL at creation (corresponding to the
170+
# last redo LSN here, actually).
171+
$primary->psql('postgres',
172+
"SELECT pg_create_physical_replication_slot('$slot_name', true);");
173+
174+
# Get the segment name associated with the slot's restart LSN, that should
175+
# be archived.
176+
my$walfile_streamed =$primary->safe_psql(
177+
'postgres',
178+
"SELECT pg_walfile_name(restart_lsn)
179+
FROM pg_replication_slots
180+
WHERE slot_name = '$slot_name';");
181+
182+
# Switch to a new segment, to make sure that the segment retained by the
183+
# slot is still streamed. This may not be necessary, but play it safe.
184+
$primary->psql('postgres',
185+
'INSERT INTO test_table VALUES (generate_series(1,100));');
186+
$primary->psql('postgres','SELECT pg_switch_wal();');
187+
$nextlsn =
188+
$primary->safe_psql('postgres','SELECT pg_current_wal_insert_lsn();');
189+
chomp($nextlsn);
190+
191+
# Check case where the slot does not exist.
192+
$primary->command_fails_like(
193+
[
194+
'pg_receivewal','-D',$slot_dir,'--slot',
195+
'nonexistentslot','-n','--no-sync','--verbose',
196+
'--endpos',$nextlsn
197+
],
198+
qr/pg_receivewal: error: could not find replication slot "nonexistentslot"/,
199+
'pg_receivewal fails with non-existing slot');
200+
$primary->command_ok(
201+
[
202+
'pg_receivewal','-D',$slot_dir,'--slot',
203+
$slot_name,'-n','--no-sync','--verbose',
204+
'--endpos',$nextlsn
205+
],
206+
"WAL streamed from the slot's restart_lsn");
207+
ok(-e"$slot_dir/$walfile_streamed",
208+
"WAL from the slot's restart_lsn has been archived");

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp