pg_basebackup: Add --slot option

This option specifies a replication slot for WAL streaming (-X stream),
so that there can be continuous replication slot use between WAL
streaming during the base backup and the start of regular streaming
replication.

Reviewed-by: Michael Paquier <michael.paquier@gmail.com>
This commit is contained in:
Peter Eisentraut 2015-07-21 21:06:45 -04:00
parent 90102bb538
commit 0dc848b031
4 changed files with 72 additions and 6 deletions

View File

@ -215,14 +215,35 @@ PostgreSQL documentation
<listitem>
<para>
Write a minimal <filename>recovery.conf</filename> in the output directory (or into
the base archive file when using tar format) to ease setting
up a standby server.
Write a minimal <filename>recovery.conf</filename> in the output
directory (or into the base archive file when using tar format) to
ease setting up a standby server.
The <filename>recovery.conf</filename> file will record the connection
settings and, if specified, the replication slot
that <application>pg_basebackup</application> is using, so that the
streaming replication will use the same settings later on.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>-S <replaceable>slotname</replaceable></option></term>
<term><option>--slot=<replaceable class="parameter">slotname</replaceable></option></term>
<listitem>
<para>
This option can only be used together with <literal>-X
stream</literal>. It causes the WAL streaming to use the specified
replication slot. If the base backup is intended to be used as a
streaming replication standby using replication slots, it should then
use the same replication slot name
in <filename>recovery.conf</filename>. That way, it is ensured that
the server does not remove any necessary WAL data in the time between
the end of the base backup and the start of streaming replication.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>-T <replaceable class="parameter">olddir</replaceable>=<replaceable class="parameter">newdir</replaceable></option></term>
<term><option>--tablespace-mapping=<replaceable class="parameter">olddir</replaceable>=<replaceable class="parameter">newdir</replaceable></option></term>

View File

@ -239,6 +239,7 @@ usage(void)
" (in kB/s, or use suffix \"k\" or \"M\")\n"));
printf(_(" -R, --write-recovery-conf\n"
" write recovery.conf after backup\n"));
printf(_(" -S, --slot=SLOTNAME replication slot to use\n"));
printf(_(" -T, --tablespace-mapping=OLDDIR=NEWDIR\n"
" relocate tablespace in OLDDIR to NEWDIR\n"));
printf(_(" -x, --xlog include required WAL files in backup (fetch mode)\n"));
@ -1536,6 +1537,13 @@ GenerateRecoveryConf(PGconn *conn)
appendPQExpBuffer(recoveryconfcontents, "primary_conninfo = '%s'\n", escaped);
free(escaped);
if (replication_slot)
{
escaped = escape_quotes(replication_slot);
appendPQExpBuffer(recoveryconfcontents, "primary_slot_name = '%s'\n", replication_slot);
free(escaped);
}
if (PQExpBufferBroken(recoveryconfcontents) ||
PQExpBufferDataBroken(conninfo_buf))
{
@ -1934,6 +1942,7 @@ main(int argc, char **argv)
{"checkpoint", required_argument, NULL, 'c'},
{"max-rate", required_argument, NULL, 'r'},
{"write-recovery-conf", no_argument, NULL, 'R'},
{"slot", required_argument, NULL, 'S'},
{"tablespace-mapping", required_argument, NULL, 'T'},
{"xlog", no_argument, NULL, 'x'},
{"xlog-method", required_argument, NULL, 'X'},
@ -1974,7 +1983,7 @@ main(int argc, char **argv)
}
}
while ((c = getopt_long(argc, argv, "D:F:r:RT:xX:l:zZ:d:c:h:p:U:s:wWvP",
while ((c = getopt_long(argc, argv, "D:F:r:RT:xX:l:zZ:d:c:h:p:U:s:S:wWvP",
long_options, &option_index)) != -1)
{
switch (c)
@ -2001,6 +2010,9 @@ main(int argc, char **argv)
case 'R':
writerecoveryconf = true;
break;
case 'S':
replication_slot = pg_strdup(optarg);
break;
case 'T':
tablespace_list_append(optarg);
break;
@ -2165,6 +2177,16 @@ main(int argc, char **argv)
exit(1);
}
if (replication_slot && !streamwal)
{
fprintf(stderr,
_("%s: replication slots can only be used with WAL streaming\n"),
progname);
fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
progname);
exit(1);
}
if (strcmp(xlog_dir, "") != 0)
{
if (format != 'p')

View File

@ -2,7 +2,7 @@ use strict;
use warnings;
use Cwd;
use TestLib;
use Test::More tests => 44;
use Test::More tests => 51;
program_help_ok('pg_basebackup');
program_version_ok('pg_basebackup');
@ -37,6 +37,7 @@ command_fails(
'pg_basebackup fails because of WAL configuration');
open CONF, ">>$tempdir/pgdata/postgresql.conf";
print CONF "max_replication_slots = 10\n";
print CONF "max_wal_senders = 10\n";
print CONF "wal_level = archive\n";
close CONF;
@ -156,3 +157,22 @@ ok(grep(/^[0-9A-F]{24}$/, slurp_dir("$tempdir/backupxf/pg_xlog")), 'WAL files co
command_ok([ 'pg_basebackup', '-D', "$tempdir/backupxs", '-X', 'stream' ],
'pg_basebackup -X stream runs');
ok(grep(/^[0-9A-F]{24}$/, slurp_dir("$tempdir/backupxf/pg_xlog")), 'WAL files copied');
command_fails([ 'pg_basebackup', '-D', "$tempdir/fail", '-S', 'slot1' ],
'pg_basebackup with replication slot fails without -X stream');
command_fails([ 'pg_basebackup', '-D', "$tempdir/backupxs_sl_fail", '-X', 'stream', '-S', 'slot1' ],
'pg_basebackup fails with nonexistent replication slot');
psql 'postgres', q{SELECT * FROM pg_create_physical_replication_slot('slot1')};
my $lsn = psql 'postgres', q{SELECT restart_lsn FROM pg_replication_slots WHERE slot_name = 'slot1'};
is($lsn, '', 'restart LSN of new slot is null');
command_ok([ 'pg_basebackup', '-D', "$tempdir/backupxs_sl", '-X', 'stream', '-S', 'slot1' ],
'pg_basebackup -X stream with replication slot runs');
$lsn = psql 'postgres', q{SELECT restart_lsn FROM pg_replication_slots WHERE slot_name = 'slot1'};
like($lsn, qr!^0/[0-9A-Z]{8}$!, 'restart LSN of slot has advanced');
command_ok([ 'pg_basebackup', '-D', "$tempdir/backupxs_sl_R", '-X', 'stream', '-S', 'slot1', '-R' ],
'pg_basebackup with replication slot and -R runs');
like(slurp_file("$tempdir/backupxs_sl_R/recovery.conf"),
qr/^primary_slot_name = 'slot1'$/m,
'recovery.conf sets primary_slot_name');

View File

@ -173,8 +173,11 @@ END
sub psql
{
my ($dbname, $sql) = @_;
my ($stdout, $stderr);
print("# Running SQL command: $sql\n");
run [ 'psql', '-X', '-q', '-d', $dbname, '-f', '-' ], '<', \$sql or die;
run [ 'psql', '-X', '-A', '-t', '-q', '-d', $dbname, '-f', '-' ], '<', \$sql, '>', \$stdout, '2>', \$stderr or die;
chomp $stdout;
return $stdout;
}
sub slurp_dir