Make pg_basebackup use temporary replication slots
Temporary replication slots will be used by default when wal streaming is used and no slot name is specified with -S. If a slot name is specified, then a permanent slot with that name is used. If --no-slot is specified, then no permanent or temporary slot will be used. Temporary slots are only used on 10.0 and newer, of course.
This commit is contained in:
parent
8fa6019b40
commit
e7b020f786
@ -240,6 +240,31 @@ PostgreSQL documentation
|
|||||||
the server does not remove any necessary WAL data in the time between
|
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.
|
the end of the base backup and the start of streaming replication.
|
||||||
</para>
|
</para>
|
||||||
|
<para>
|
||||||
|
If this option is not specified and the server supports temporary
|
||||||
|
replication slots (version 10 and later), then a temporary replication
|
||||||
|
slot is automatically used for WAL streaming.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>--no-slot</option></term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
This option prevents the creation of a temporary replication slot
|
||||||
|
during the backup even if it's supported by the server.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
Temporary replication slots are created by default if no slot name
|
||||||
|
is given with the option <option>-S</option> when using log streaming.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
The main purpose of this option is to allow taking a base backup when
|
||||||
|
the server is out of free replication slots. Using replication slots
|
||||||
|
is almost always preferred, because it prevents needed WAL from being
|
||||||
|
removed by the server during the backup.
|
||||||
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
@ -61,6 +61,11 @@ typedef struct TablespaceList
|
|||||||
*/
|
*/
|
||||||
#define MINIMUM_VERSION_FOR_PG_WAL 100000
|
#define MINIMUM_VERSION_FOR_PG_WAL 100000
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Temporary replication slots are supported from version 10.
|
||||||
|
*/
|
||||||
|
#define MINIMUM_VERSION_FOR_TEMP_SLOTS 100000
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Different ways to include WAL
|
* Different ways to include WAL
|
||||||
*/
|
*/
|
||||||
@ -88,6 +93,8 @@ static bool do_sync = true;
|
|||||||
static int standby_message_timeout = 10 * 1000; /* 10 sec = default */
|
static int standby_message_timeout = 10 * 1000; /* 10 sec = default */
|
||||||
static pg_time_t last_progress_report = 0;
|
static pg_time_t last_progress_report = 0;
|
||||||
static int32 maxrate = 0; /* no limit by default */
|
static int32 maxrate = 0; /* no limit by default */
|
||||||
|
static char *replication_slot = NULL;
|
||||||
|
static bool temp_replication_slot = true;
|
||||||
|
|
||||||
static bool success = false;
|
static bool success = false;
|
||||||
static bool made_new_pgdata = false;
|
static bool made_new_pgdata = false;
|
||||||
@ -332,6 +339,7 @@ usage(void)
|
|||||||
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(_(" -S, --slot=SLOTNAME replication slot to use\n"));
|
||||||
|
printf(_(" --no-slot prevent creation of temporary replication slot\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-method=none|fetch|stream\n"
|
printf(_(" -X, --xlog-method=none|fetch|stream\n"
|
||||||
@ -460,6 +468,7 @@ typedef struct
|
|||||||
char xlog[MAXPGPATH]; /* directory or tarfile depending on mode */
|
char xlog[MAXPGPATH]; /* directory or tarfile depending on mode */
|
||||||
char *sysidentifier;
|
char *sysidentifier;
|
||||||
int timeline;
|
int timeline;
|
||||||
|
bool temp_slot;
|
||||||
} logstreamer_param;
|
} logstreamer_param;
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@ -479,6 +488,10 @@ LogStreamerMain(logstreamer_param *param)
|
|||||||
stream.do_sync = do_sync;
|
stream.do_sync = do_sync;
|
||||||
stream.mark_done = true;
|
stream.mark_done = true;
|
||||||
stream.partial_suffix = NULL;
|
stream.partial_suffix = NULL;
|
||||||
|
stream.replication_slot = replication_slot;
|
||||||
|
stream.temp_slot = param->temp_slot;
|
||||||
|
if (stream.temp_slot && !stream.replication_slot)
|
||||||
|
stream.replication_slot = psprintf("pg_basebackup_%d", (int) getpid());
|
||||||
|
|
||||||
if (format == 'p')
|
if (format == 'p')
|
||||||
stream.walmethod = CreateWalDirectoryMethod(param->xlog, do_sync);
|
stream.walmethod = CreateWalDirectoryMethod(param->xlog, do_sync);
|
||||||
@ -565,6 +578,11 @@ StartLogStreamer(char *startpos, uint32 timeline, char *sysidentifier)
|
|||||||
PQserverVersion(conn) < MINIMUM_VERSION_FOR_PG_WAL ?
|
PQserverVersion(conn) < MINIMUM_VERSION_FOR_PG_WAL ?
|
||||||
"pg_xlog" : "pg_wal");
|
"pg_xlog" : "pg_wal");
|
||||||
|
|
||||||
|
/* Temporary replication slots are only supported in 10 and newer */
|
||||||
|
if (PQserverVersion(conn) < MINIMUM_VERSION_FOR_TEMP_SLOTS)
|
||||||
|
param->temp_slot = false;
|
||||||
|
else
|
||||||
|
param->temp_slot = temp_replication_slot;
|
||||||
|
|
||||||
if (format == 'p')
|
if (format == 'p')
|
||||||
{
|
{
|
||||||
@ -2063,11 +2081,13 @@ main(int argc, char **argv)
|
|||||||
{"verbose", no_argument, NULL, 'v'},
|
{"verbose", no_argument, NULL, 'v'},
|
||||||
{"progress", no_argument, NULL, 'P'},
|
{"progress", no_argument, NULL, 'P'},
|
||||||
{"xlogdir", required_argument, NULL, 1},
|
{"xlogdir", required_argument, NULL, 1},
|
||||||
|
{"no-slot", no_argument, NULL, 2},
|
||||||
{NULL, 0, NULL, 0}
|
{NULL, 0, NULL, 0}
|
||||||
};
|
};
|
||||||
int c;
|
int c;
|
||||||
|
|
||||||
int option_index;
|
int option_index;
|
||||||
|
bool no_slot = false;
|
||||||
|
|
||||||
progname = get_progname(argv[0]);
|
progname = get_progname(argv[0]);
|
||||||
set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_basebackup"));
|
set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_basebackup"));
|
||||||
@ -2117,7 +2137,16 @@ main(int argc, char **argv)
|
|||||||
writerecoveryconf = true;
|
writerecoveryconf = true;
|
||||||
break;
|
break;
|
||||||
case 'S':
|
case 'S':
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When specifying replication slot name, use a permanent
|
||||||
|
* slot.
|
||||||
|
*/
|
||||||
replication_slot = pg_strdup(optarg);
|
replication_slot = pg_strdup(optarg);
|
||||||
|
temp_replication_slot = false;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
no_slot = true;
|
||||||
break;
|
break;
|
||||||
case 'T':
|
case 'T':
|
||||||
tablespace_list_append(optarg);
|
tablespace_list_append(optarg);
|
||||||
@ -2277,7 +2306,7 @@ main(int argc, char **argv)
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (replication_slot && includewal != STREAM_WAL)
|
if ((replication_slot || no_slot) && includewal != STREAM_WAL)
|
||||||
{
|
{
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
_("%s: replication slots can only be used with WAL streaming\n"),
|
_("%s: replication slots can only be used with WAL streaming\n"),
|
||||||
@ -2287,6 +2316,20 @@ main(int argc, char **argv)
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (no_slot)
|
||||||
|
{
|
||||||
|
if (replication_slot)
|
||||||
|
{
|
||||||
|
fprintf(stderr,
|
||||||
|
_("%s: --no-slot cannot be used with slot name\n"),
|
||||||
|
progname);
|
||||||
|
fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
|
||||||
|
progname);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
temp_replication_slot = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (strcmp(xlog_dir, "") != 0)
|
if (strcmp(xlog_dir, "") != 0)
|
||||||
{
|
{
|
||||||
if (format != 'p')
|
if (format != 'p')
|
||||||
|
@ -41,6 +41,7 @@ static bool do_create_slot = false;
|
|||||||
static bool slot_exists_ok = false;
|
static bool slot_exists_ok = false;
|
||||||
static bool do_drop_slot = false;
|
static bool do_drop_slot = false;
|
||||||
static bool synchronous = false;
|
static bool synchronous = false;
|
||||||
|
static char *replication_slot = NULL;
|
||||||
|
|
||||||
|
|
||||||
static void usage(void);
|
static void usage(void);
|
||||||
@ -340,6 +341,8 @@ StreamLog(void)
|
|||||||
stream.mark_done = false;
|
stream.mark_done = false;
|
||||||
stream.walmethod = CreateWalDirectoryMethod(basedir, stream.do_sync);
|
stream.walmethod = CreateWalDirectoryMethod(basedir, stream.do_sync);
|
||||||
stream.partial_suffix = ".partial";
|
stream.partial_suffix = ".partial";
|
||||||
|
stream.replication_slot = replication_slot;
|
||||||
|
stream.temp_slot = false;
|
||||||
|
|
||||||
ReceiveXlogStream(conn, &stream);
|
ReceiveXlogStream(conn, &stream);
|
||||||
|
|
||||||
|
@ -45,6 +45,7 @@ static bool do_create_slot = false;
|
|||||||
static bool slot_exists_ok = false;
|
static bool slot_exists_ok = false;
|
||||||
static bool do_start_slot = false;
|
static bool do_start_slot = false;
|
||||||
static bool do_drop_slot = false;
|
static bool do_drop_slot = false;
|
||||||
|
static char *replication_slot = NULL;
|
||||||
|
|
||||||
/* filled pairwise with option, value. value may be NULL */
|
/* filled pairwise with option, value. value may be NULL */
|
||||||
static char **options;
|
static char **options;
|
||||||
|
@ -455,10 +455,10 @@ ReceiveXlogStream(PGconn *conn, StreamCtl *stream)
|
|||||||
* synchronous_standby_names, but we've protected them against it so
|
* synchronous_standby_names, but we've protected them against it so
|
||||||
* far, so let's continue to do so unless specifically requested.
|
* far, so let's continue to do so unless specifically requested.
|
||||||
*/
|
*/
|
||||||
if (replication_slot != NULL)
|
if (stream->replication_slot != NULL)
|
||||||
{
|
{
|
||||||
reportFlushPosition = true;
|
reportFlushPosition = true;
|
||||||
sprintf(slotcmd, "SLOT \"%s\" ", replication_slot);
|
sprintf(slotcmd, "SLOT \"%s\" ", stream->replication_slot);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -508,6 +508,24 @@ ReceiveXlogStream(PGconn *conn, StreamCtl *stream)
|
|||||||
PQclear(res);
|
PQclear(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create temporary replication slot if one is needed
|
||||||
|
*/
|
||||||
|
if (stream->temp_slot)
|
||||||
|
{
|
||||||
|
snprintf(query, sizeof(query),
|
||||||
|
"CREATE_REPLICATION_SLOT \"%s\" TEMPORARY PHYSICAL RESERVE_WAL",
|
||||||
|
stream->replication_slot);
|
||||||
|
res = PQexec(conn, query);
|
||||||
|
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
||||||
|
{
|
||||||
|
fprintf(stderr, _("%s: could not create temporary replication slot \"%s\": %s"),
|
||||||
|
progname, stream->replication_slot, PQerrorMessage(conn));
|
||||||
|
PQclear(res);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* initialize flush position to starting point, it's the caller's
|
* initialize flush position to starting point, it's the caller's
|
||||||
* responsibility that that's sane.
|
* responsibility that that's sane.
|
||||||
|
@ -37,13 +37,15 @@ typedef struct StreamCtl
|
|||||||
* often */
|
* often */
|
||||||
bool synchronous; /* Flush immediately WAL data on write */
|
bool synchronous; /* Flush immediately WAL data on write */
|
||||||
bool mark_done; /* Mark segment as done in generated archive */
|
bool mark_done; /* Mark segment as done in generated archive */
|
||||||
bool do_sync; /* Flush to disk to ensure consistent state
|
bool do_sync; /* Flush to disk to ensure consistent state of
|
||||||
* of data */
|
* data */
|
||||||
|
|
||||||
stream_stop_callback stream_stop; /* Stop streaming when returns true */
|
stream_stop_callback stream_stop; /* Stop streaming when returns true */
|
||||||
|
|
||||||
WalWriteMethod *walmethod; /* How to write the WAL */
|
WalWriteMethod *walmethod; /* How to write the WAL */
|
||||||
char *partial_suffix; /* Suffix appended to partially received files */
|
char *partial_suffix; /* Suffix appended to partially received files */
|
||||||
|
char *replication_slot; /* Replication slot to use, or NULL */
|
||||||
|
bool temp_slot; /* Create temporary replication slot */
|
||||||
} StreamCtl;
|
} StreamCtl;
|
||||||
|
|
||||||
|
|
||||||
|
@ -38,7 +38,6 @@ char *connection_string = NULL;
|
|||||||
char *dbhost = NULL;
|
char *dbhost = NULL;
|
||||||
char *dbuser = NULL;
|
char *dbuser = NULL;
|
||||||
char *dbport = NULL;
|
char *dbport = NULL;
|
||||||
char *replication_slot = NULL;
|
|
||||||
char *dbname = NULL;
|
char *dbname = NULL;
|
||||||
int dbgetpassword = 0; /* 0=auto, -1=never, 1=always */
|
int dbgetpassword = 0; /* 0=auto, -1=never, 1=always */
|
||||||
static bool have_password = false;
|
static bool have_password = false;
|
||||||
|
@ -23,7 +23,6 @@ extern char *dbuser;
|
|||||||
extern char *dbport;
|
extern char *dbport;
|
||||||
extern char *dbname;
|
extern char *dbname;
|
||||||
extern int dbgetpassword;
|
extern int dbgetpassword;
|
||||||
extern char *replication_slot;
|
|
||||||
|
|
||||||
/* Connection kept global so we can disconnect easily */
|
/* Connection kept global so we can disconnect easily */
|
||||||
extern PGconn *conn;
|
extern PGconn *conn;
|
||||||
|
@ -4,7 +4,7 @@ use Cwd;
|
|||||||
use Config;
|
use Config;
|
||||||
use PostgresNode;
|
use PostgresNode;
|
||||||
use TestLib;
|
use TestLib;
|
||||||
use Test::More tests => 71;
|
use Test::More tests => 72;
|
||||||
|
|
||||||
program_help_ok('pg_basebackup');
|
program_help_ok('pg_basebackup');
|
||||||
program_version_ok('pg_basebackup');
|
program_version_ok('pg_basebackup');
|
||||||
@ -244,6 +244,9 @@ $node->command_ok(
|
|||||||
[ 'pg_basebackup', '-D', "$tempdir/backupxst", '-X', 'stream', '-Ft' ],
|
[ 'pg_basebackup', '-D', "$tempdir/backupxst", '-X', 'stream', '-Ft' ],
|
||||||
'pg_basebackup -X stream runs in tar mode');
|
'pg_basebackup -X stream runs in tar mode');
|
||||||
ok(-f "$tempdir/backupxst/pg_wal.tar", "tar file was created");
|
ok(-f "$tempdir/backupxst/pg_wal.tar", "tar file was created");
|
||||||
|
$node->command_ok(
|
||||||
|
[ 'pg_basebackup', '-D', "$tempdir/backupnoslot", '-X', 'stream', '--no-slot' ],
|
||||||
|
'pg_basebackup -X stream runs with --no-slot');
|
||||||
|
|
||||||
$node->command_fails(
|
$node->command_fails(
|
||||||
[ 'pg_basebackup', '-D', "$tempdir/fail", '-S', 'slot1' ],
|
[ 'pg_basebackup', '-D', "$tempdir/fail", '-S', 'slot1' ],
|
||||||
|
Loading…
x
Reference in New Issue
Block a user