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:
parent
90102bb538
commit
0dc848b031
|
@ -215,14 +215,35 @@ PostgreSQL documentation
|
||||||
<listitem>
|
<listitem>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Write a minimal <filename>recovery.conf</filename> in the output directory (or into
|
Write a minimal <filename>recovery.conf</filename> in the output
|
||||||
the base archive file when using tar format) to ease setting
|
directory (or into the base archive file when using tar format) to
|
||||||
up a standby server.
|
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>
|
</para>
|
||||||
|
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</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>
|
<varlistentry>
|
||||||
<term><option>-T <replaceable class="parameter">olddir</replaceable>=<replaceable class="parameter">newdir</replaceable></option></term>
|
<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>
|
<term><option>--tablespace-mapping=<replaceable class="parameter">olddir</replaceable>=<replaceable class="parameter">newdir</replaceable></option></term>
|
||||||
|
|
|
@ -239,6 +239,7 @@ usage(void)
|
||||||
" (in kB/s, or use suffix \"k\" or \"M\")\n"));
|
" (in kB/s, or use suffix \"k\" or \"M\")\n"));
|
||||||
printf(_(" -R, --write-recovery-conf\n"
|
printf(_(" -R, --write-recovery-conf\n"
|
||||||
" write recovery.conf after backup\n"));
|
" write recovery.conf after backup\n"));
|
||||||
|
printf(_(" -S, --slot=SLOTNAME replication slot to use\n"));
|
||||||
printf(_(" -T, --tablespace-mapping=OLDDIR=NEWDIR\n"
|
printf(_(" -T, --tablespace-mapping=OLDDIR=NEWDIR\n"
|
||||||
" relocate tablespace in OLDDIR to NEWDIR\n"));
|
" relocate tablespace in OLDDIR to NEWDIR\n"));
|
||||||
printf(_(" -x, --xlog include required WAL files in backup (fetch mode)\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);
|
appendPQExpBuffer(recoveryconfcontents, "primary_conninfo = '%s'\n", escaped);
|
||||||
free(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) ||
|
if (PQExpBufferBroken(recoveryconfcontents) ||
|
||||||
PQExpBufferDataBroken(conninfo_buf))
|
PQExpBufferDataBroken(conninfo_buf))
|
||||||
{
|
{
|
||||||
|
@ -1934,6 +1942,7 @@ main(int argc, char **argv)
|
||||||
{"checkpoint", required_argument, NULL, 'c'},
|
{"checkpoint", required_argument, NULL, 'c'},
|
||||||
{"max-rate", required_argument, NULL, 'r'},
|
{"max-rate", required_argument, NULL, 'r'},
|
||||||
{"write-recovery-conf", no_argument, NULL, 'R'},
|
{"write-recovery-conf", no_argument, NULL, 'R'},
|
||||||
|
{"slot", required_argument, NULL, 'S'},
|
||||||
{"tablespace-mapping", required_argument, NULL, 'T'},
|
{"tablespace-mapping", required_argument, NULL, 'T'},
|
||||||
{"xlog", no_argument, NULL, 'x'},
|
{"xlog", no_argument, NULL, 'x'},
|
||||||
{"xlog-method", required_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)
|
long_options, &option_index)) != -1)
|
||||||
{
|
{
|
||||||
switch (c)
|
switch (c)
|
||||||
|
@ -2001,6 +2010,9 @@ main(int argc, char **argv)
|
||||||
case 'R':
|
case 'R':
|
||||||
writerecoveryconf = true;
|
writerecoveryconf = true;
|
||||||
break;
|
break;
|
||||||
|
case 'S':
|
||||||
|
replication_slot = pg_strdup(optarg);
|
||||||
|
break;
|
||||||
case 'T':
|
case 'T':
|
||||||
tablespace_list_append(optarg);
|
tablespace_list_append(optarg);
|
||||||
break;
|
break;
|
||||||
|
@ -2165,6 +2177,16 @@ main(int argc, char **argv)
|
||||||
exit(1);
|
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 (strcmp(xlog_dir, "") != 0)
|
||||||
{
|
{
|
||||||
if (format != 'p')
|
if (format != 'p')
|
||||||
|
|
|
@ -2,7 +2,7 @@ use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
use Cwd;
|
use Cwd;
|
||||||
use TestLib;
|
use TestLib;
|
||||||
use Test::More tests => 44;
|
use Test::More tests => 51;
|
||||||
|
|
||||||
program_help_ok('pg_basebackup');
|
program_help_ok('pg_basebackup');
|
||||||
program_version_ok('pg_basebackup');
|
program_version_ok('pg_basebackup');
|
||||||
|
@ -37,6 +37,7 @@ command_fails(
|
||||||
'pg_basebackup fails because of WAL configuration');
|
'pg_basebackup fails because of WAL configuration');
|
||||||
|
|
||||||
open CONF, ">>$tempdir/pgdata/postgresql.conf";
|
open CONF, ">>$tempdir/pgdata/postgresql.conf";
|
||||||
|
print CONF "max_replication_slots = 10\n";
|
||||||
print CONF "max_wal_senders = 10\n";
|
print CONF "max_wal_senders = 10\n";
|
||||||
print CONF "wal_level = archive\n";
|
print CONF "wal_level = archive\n";
|
||||||
close CONF;
|
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' ],
|
command_ok([ 'pg_basebackup', '-D', "$tempdir/backupxs", '-X', 'stream' ],
|
||||||
'pg_basebackup -X stream runs');
|
'pg_basebackup -X stream runs');
|
||||||
ok(grep(/^[0-9A-F]{24}$/, slurp_dir("$tempdir/backupxf/pg_xlog")), 'WAL files copied');
|
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');
|
||||||
|
|
|
@ -173,8 +173,11 @@ END
|
||||||
sub psql
|
sub psql
|
||||||
{
|
{
|
||||||
my ($dbname, $sql) = @_;
|
my ($dbname, $sql) = @_;
|
||||||
|
my ($stdout, $stderr);
|
||||||
print("# Running SQL command: $sql\n");
|
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
|
sub slurp_dir
|
||||||
|
|
Loading…
Reference in New Issue