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

Commit 6d9fa52

Browse files
committed
pg_receivewal: Add --endpos option
This is primarily useful for making tests of this utility more deterministic, to avoid the complexity of starting pg_receivewal as a deamon in TAP tests. While this is less useful than the equivalent pg_recvlogical option, users can as well use it for example to enforce WAL streaming up to a end-of-backup position, to save only a minimal amount of WAL. Use this new option to stream WAL data in a deterministic way within a new set of TAP tests. Author: Michael Paquier <michael.paquier@gmail.com>
1 parent c1898c3 commit 6d9fa52

File tree

3 files changed

+91
-8
lines changed

3 files changed

+91
-8
lines changed

doc/src/sgml/ref/pg_receivewal.sgml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,22 @@ PostgreSQL documentation
9898
</listitem>
9999
</varlistentry>
100100

101+
<varlistentry>
102+
<term><option>-E <replaceable>lsn</replaceable></option></term>
103+
<term><option>--endpos=<replaceable>lsn</replaceable></option></term>
104+
<listitem>
105+
<para>
106+
Automatically stop replication and exit with normal exit status 0 when
107+
receiving reaches the specified LSN.
108+
</para>
109+
110+
<para>
111+
If there is a record with LSN exactly equal to <replaceable>lsn</>,
112+
the record will be processed.
113+
</para>
114+
</listitem>
115+
</varlistentry>
116+
101117
<varlistentry>
102118
<term><option>--if-not-exists</option></term>
103119
<listitem>

src/bin/pg_basebackup/pg_receivewal.c

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,13 @@ static int verbose = 0;
3636
static int compresslevel = 0;
3737
static int noloop = 0;
3838
static int standby_message_timeout = 10 * 1000; /* 10 sec = default */
39-
static volatile bool time_to_abort = false;
39+
static volatile bool time_to_stop = false;
4040
static bool do_create_slot = false;
4141
static bool slot_exists_ok = false;
4242
static bool do_drop_slot = false;
4343
static bool synchronous = false;
4444
static char *replication_slot = NULL;
45+
static XLogRecPtr endpos = InvalidXLogRecPtr;
4546

4647

4748
static void usage(void);
@@ -77,6 +78,7 @@ usage(void)
7778
printf(_(" %s [OPTION]...\n"), progname);
7879
printf(_("\nOptions:\n"));
7980
printf(_(" -D, --directory=DIR receive write-ahead log files into this directory\n"));
81+
printf(_(" -E, --endpos=LSN exit after receiving the specified LSN\n"));
8082
printf(_(" --if-not-exists do not error if slot already exists when creating a slot\n"));
8183
printf(_(" -n, --no-loop do not loop on connection lost\n"));
8284
printf(_(" -s, --status-interval=SECS\n"
@@ -112,6 +114,16 @@ stop_streaming(XLogRecPtr xlogpos, uint32 timeline, bool segment_finished)
112114
progname, (uint32) (xlogpos >> 32), (uint32) xlogpos,
113115
timeline);
114116

117+
if (!XLogRecPtrIsInvalid(endpos) && endpos < xlogpos)
118+
{
119+
if (verbose)
120+
fprintf(stderr, _("%s: stopped streaming at %X/%X (timeline %u)\n"),
121+
progname, (uint32) (xlogpos >> 32), (uint32) xlogpos,
122+
timeline);
123+
time_to_stop = true;
124+
return true;
125+
}
126+
115127
/*
116128
* Note that we report the previous, not current, position here. After a
117129
* timeline switch, xlogpos points to the beginning of the segment because
@@ -128,7 +140,7 @@ stop_streaming(XLogRecPtr xlogpos, uint32 timeline, bool segment_finished)
128140
prevtimeline = timeline;
129141
prevpos = xlogpos;
130142

131-
if (time_to_abort)
143+
if (time_to_stop)
132144
{
133145
if (verbose)
134146
fprintf(stderr, _("%s: received interrupt signal, exiting\n"),
@@ -448,7 +460,7 @@ StreamLog(void)
448460
static void
449461
sigint_handler(int signum)
450462
{
451-
time_to_abort = true;
463+
time_to_stop = true;
452464
}
453465
#endif
454466

@@ -460,6 +472,7 @@ main(int argc, char **argv)
460472
{"version", no_argument, NULL, 'V'},
461473
{"directory", required_argument, NULL, 'D'},
462474
{"dbname", required_argument, NULL, 'd'},
475+
{"endpos", required_argument, NULL, 'E'},
463476
{"host", required_argument, NULL, 'h'},
464477
{"port", required_argument, NULL, 'p'},
465478
{"username", required_argument, NULL, 'U'},
@@ -481,6 +494,7 @@ main(int argc, char **argv)
481494
int c;
482495
int option_index;
483496
char *db_name;
497+
uint32 hi, lo;
484498

485499
progname = get_progname(argv[0]);
486500
set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_basebackup"));
@@ -500,7 +514,7 @@ main(int argc, char **argv)
500514
}
501515
}
502516

503-
while ((c = getopt_long(argc, argv, "D:d:h:p:U:s:S:nwWvZ:",
517+
while ((c = getopt_long(argc, argv, "D:d:E:h:p:U:s:S:nwWvZ:",
504518
long_options, &option_index)) != -1)
505519
{
506520
switch (c)
@@ -544,6 +558,16 @@ main(int argc, char **argv)
544558
case 'S':
545559
replication_slot = pg_strdup(optarg);
546560
break;
561+
case 'E':
562+
if (sscanf(optarg, "%X/%X", &hi, &lo) != 2)
563+
{
564+
fprintf(stderr,
565+
_("%s: could not parse end position \"%s\"\n"),
566+
progname, optarg);
567+
exit(1);
568+
}
569+
endpos = ((uint64) hi) << 32 | lo;
570+
break;
547571
case 'n':
548572
noloop = 1;
549573
break;
@@ -714,11 +738,11 @@ main(int argc, char **argv)
714738
while (true)
715739
{
716740
StreamLog();
717-
if (time_to_abort)
741+
if (time_to_stop)
718742
{
719743
/*
720-
* We've been Ctrl-C'ed. That's not an error, so exit without an
721-
* errorcode.
744+
* We've been Ctrl-C'ed or end of streaming position has been
745+
* willingly reached, so exit without an error code.
722746
*/
723747
exit(0);
724748
}
Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,51 @@
11
use strict;
22
use warnings;
33
use TestLib;
4-
use Test::More tests => 8;
4+
use PostgresNode;
5+
use Test::More tests => 14;
56

67
program_help_ok('pg_receivewal');
78
program_version_ok('pg_receivewal');
89
program_options_handling_ok('pg_receivewal');
10+
11+
my $primary = get_new_node('primary');
12+
$primary->init(allows_streaming => 1);
13+
$primary->start;
14+
15+
my $stream_dir = $primary->basedir . '/archive_wal';
16+
mkdir($stream_dir);
17+
18+
# Sanity checks for command line options.
19+
$primary->command_fails(['pg_receivewal'],
20+
'pg_receivewal needs target directory specified');
21+
$primary->command_fails(
22+
[ 'pg_receivewal', '-D', $stream_dir, '--create-slot', '--drop-slot' ],
23+
'failure if both --create-slot and --drop-slot specified');
24+
$primary->command_fails(
25+
[ 'pg_receivewal', '-D', $stream_dir, '--create-slot' ],
26+
'failure if --create-slot specified without --slot');
27+
28+
# Slot creation and drop
29+
my $slot_name = 'test';
30+
$primary->command_ok(
31+
[ 'pg_receivewal', '--slot', $slot_name, '--create-slot' ],
32+
'creating a replication slot');
33+
$primary->command_ok([ 'pg_receivewal', '--slot', $slot_name, '--drop-slot' ],
34+
'dropping a replication slot');
35+
36+
# Generate some WAL. Use --synchronous at the same time to add more
37+
# code coverage. Switch to the next segment first so that subsequent
38+
# restarts of pg_receivewal will see this segment as full..
39+
$primary->psql('postgres', 'CREATE TABLE test_table(x integer);');
40+
$primary->psql('postgres', 'SELECT pg_switch_wal();');
41+
my $nextlsn =
42+
$primary->safe_psql('postgres', 'SELECT pg_current_wal_insert_lsn();');
43+
chomp($nextlsn);
44+
$primary->psql('postgres',
45+
'INSERT INTO test_table VALUES (generate_series(1,100));');
46+
47+
# Stream up to the given position.
48+
$primary->command_ok(
49+
[ 'pg_receivewal', '-D', $stream_dir, '--verbose',
50+
'--endpos', $nextlsn, '--synchronous', '--no-loop' ],
51+
'streaming some WAL with --synchronous');

0 commit comments

Comments
 (0)