Hi all,
As of now, pg_basebackup creates an empty repository for pg_replslot/
in a base backup, forcing the user to recreate slots on other nodes of
the cluster with pg_create_*_replication_slot, or copy pg_replslot
from another node. This is not really user-friendly especially after a
failover where a given slave may not have the replication slot
information of the master that it is replacing.
The simple patch attached adds a new option in pg_basebackup, called
--replication-slot, allowing to include replication slot information
in a base backup. This is done by extending the command BASE_BACKUP in
the replication protocol.
As it is too late for 9.4, I would like to add it to the first commit
fest of 9.5. Comments are welcome.
Regards,
--
Michael
diff --git a/doc/src/sgml/protocol.sgml b/doc/src/sgml/protocol.sgml
index 36d16a5..4748d08 100644
--- a/doc/src/sgml/protocol.sgml
+++ b/doc/src/sgml/protocol.sgml
@@ -1837,7 +1837,7 @@ The commands accepted in walsender mode are:
</varlistentry>
<varlistentry>
- <term>BASE_BACKUP [<literal>LABEL</literal>
<replaceable>'label'</replaceable>] [<literal>PROGRESS</literal>]
[<literal>FAST</literal>] [<literal>WAL</literal>] [<literal>NOWAIT</literal>]
[<literal>MAX_RATE</literal> <replaceable>rate</replaceable>]</term>
+ <term>BASE_BACKUP [<literal>LABEL</literal>
<replaceable>'label'</replaceable>] [<literal>PROGRESS</literal>]
[<literal>FAST</literal>] [<literal>WAL</literal>] [<literal>NOWAIT</literal>]
[<literal>REPLICATION_SLOT</literal>] [<literal>MAX_RATE</literal>
<replaceable>rate</replaceable>]</term>
<listitem>
<para>
Instructs the server to start streaming a base backup.
@@ -1909,6 +1909,18 @@ The commands accepted in walsender mode are:
</varlistentry>
<varlistentry>
+ <term><literal>REPLICATION_SLOT</literal></term>
+ <listitem>
+ <para>
+ By default, the backup will not include the replication slot
+ information in <filename>pg_replslot</> and is created as an
+ empty repository. Specifying <literal>REPLICATION_SLOT</literal>
+ permits to includes replication slot information in the backup.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><literal>MAX_RATE</literal> <replaceable>rate</></term>
<listitem>
<para>
diff --git a/doc/src/sgml/ref/pg_basebackup.sgml
b/doc/src/sgml/ref/pg_basebackup.sgml
index 6ce0c8c..be77f7b 100644
--- a/doc/src/sgml/ref/pg_basebackup.sgml
+++ b/doc/src/sgml/ref/pg_basebackup.sgml
@@ -210,6 +210,17 @@ PostgreSQL documentation
</varlistentry>
<varlistentry>
+ <term><option>--replication-slot</option></term>
+ <listitem>
+ <para>
+ Include replication slot information in the base backup. This is added
+ in <filename>pg_replslot</filename> by default empty if this option is
+ not specified.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><option>-R</option></term>
<term><option>--write-recovery-conf</option></term>
<listitem>
@@ -254,7 +265,7 @@ PostgreSQL documentation
<term><option>--xlogdir=<replaceable
class="parameter">xlogdir</replaceable></option></term>
<listitem>
<para>
- Specifies the location for the transaction log directory.
+ Specifies the location for the transaction log directory.
<replaceable>xlogdir</replaceable> must be an absolute path.
The transaction log directory can only be specified when
the backup is in plain mode.
diff --git a/src/backend/replication/basebackup.c
b/src/backend/replication/basebackup.c
index f611f59..4a86117 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -45,6 +45,7 @@ typedef struct
bool fastcheckpoint;
bool nowait;
bool includewal;
+ bool replication_slot;
uint32 maxrate;
} basebackup_options;
@@ -71,6 +72,9 @@ static bool backup_started_in_recovery = false;
/* Relative path of temporary statistics directory */
static char *statrelpath = NULL;
+/* Include replication slot data in base backup? */
+static bool include_replication_slots = false;
+
/*
* Size of each block sent into the tar stream for larger files.
*/
@@ -131,6 +135,7 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
datadirpathlen = strlen(DataDir);
backup_started_in_recovery = RecoveryInProgress();
+ include_replication_slots = opt->replication_slot;
startptr = do_pg_start_backup(opt->label, opt->fastcheckpoint,
&starttli,
&labelfile);
@@ -548,6 +553,7 @@ parse_basebackup_options(List *options, basebackup_options
*opt)
bool o_nowait = false;
bool o_wal = false;
bool o_maxrate = false;
+ bool o_replication_slot = false;
MemSet(opt, 0, sizeof(*opt));
foreach(lopt, options)
@@ -618,6 +624,15 @@ parse_basebackup_options(List *options, basebackup_options
*opt)
opt->maxrate = (uint32) maxrate;
o_maxrate = true;
}
+ else if (strcmp(defel->defname, "replication_slot") == 0)
+ {
+ if (o_replication_slot)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("duplicate option
\"%s\"", defel->defname)));
+ opt->replication_slot = true;
+ o_replication_slot = true;
+ }
else
elog(ERROR, "option \"%s\" not recognized",
defel->defname);
@@ -984,10 +999,11 @@ sendDir(char *path, int basepathlen, bool sizeonly, List
*tablespaces)
}
/*
- * Skip pg_replslot, not useful to copy. But include it as an
empty
- * directory anyway, so we get permissions right.
+ * Skip pg_replslot and create it as an empty repository if not
+ * requested in the base backup so we get the permissions right.
*/
- if (strcmp(de->d_name, "pg_replslot") == 0)
+ if (!include_replication_slots &&
+ strcmp(pathbuf, "./pg_replslot") == 0)
{
if (!sizeonly)
_tarWriteHeader(pathbuf + basepathlen + 1,
NULL, &statbuf);
diff --git a/src/backend/replication/repl_gram.y
b/src/backend/replication/repl_gram.y
index 154aaac..6400a0f 100644
--- a/src/backend/replication/repl_gram.y
+++ b/src/backend/replication/repl_gram.y
@@ -70,6 +70,7 @@ Node *replication_parse_result;
%token K_FAST
%token K_NOWAIT
%token K_MAX_RATE
+%token K_REPLICATION_SLOT
%token K_WAL
%token K_TIMELINE
%token K_PHYSICAL
@@ -119,7 +120,8 @@ identify_system:
;
/*
- * BASE_BACKUP [LABEL '<label>'] [PROGRESS] [FAST] [WAL] [NOWAIT] [MAX_RATE %d]
+ * BASE_BACKUP [LABEL '<label>'] [PROGRESS] [FAST]
+ * [WAL] [NOWAIT] [MAX_RATE %d] [REPLICATION_SLOT]
*/
base_backup:
K_BASE_BACKUP base_backup_opt_list
@@ -163,6 +165,11 @@ base_backup_opt:
$$ = makeDefElem("nowait",
(Node
*)makeInteger(TRUE));
}
+ | K_REPLICATION_SLOT
+ {
+ $$ = makeDefElem("replication_slot",
+ (Node
*)makeInteger(TRUE));
+ }
| K_MAX_RATE UCONST
{
$$ = makeDefElem("max_rate",
diff --git a/src/backend/replication/repl_scanner.l
b/src/backend/replication/repl_scanner.l
index a257124..acc5092 100644
--- a/src/backend/replication/repl_scanner.l
+++ b/src/backend/replication/repl_scanner.l
@@ -87,6 +87,7 @@ LABEL { return K_LABEL; }
NOWAIT { return K_NOWAIT; }
PROGRESS { return K_PROGRESS; }
MAX_RATE { return K_MAX_RATE; }
+REPLICATION_SLOT { return K_REPLICATION_SLOT; }
WAL { return K_WAL; }
TIMELINE { return K_TIMELINE; }
START_REPLICATION { return K_START_REPLICATION; }
diff --git a/src/bin/pg_basebackup/pg_basebackup.c
b/src/bin/pg_basebackup/pg_basebackup.c
index 1a468fa..2ad2474 100644
--- a/src/bin/pg_basebackup/pg_basebackup.c
+++ b/src/bin/pg_basebackup/pg_basebackup.c
@@ -62,6 +62,7 @@ static int compresslevel = 0;
static bool includewal = false;
static bool streamwal = false;
static bool fastcheckpoint = false;
+static bool replicationslot = false;
static bool writerecoveryconf = false;
static int standby_message_timeout = 10 * 1000; /* 10 sec =
default */
static pg_time_t last_progress_report = 0;
@@ -229,6 +230,7 @@ usage(void)
printf(_(" -D, --pgdata=DIRECTORY receive base backup into
directory\n"));
printf(_(" -F, --format=p|t output format (plain (default),
tar)\n"));
printf(_(" -r, --max-rate=RATE maximum transfer rate to transfer
data directory\n"));
+ printf(_(" --replication-slot include replication slot data in
base backup\n"));
printf(_(" -R, --write-recovery-conf\n"
" write recovery.conf after
backup\n"));
printf(_(" -T, --tablespace-mapping=OLDDIR=NEWDIR\n"
@@ -1659,13 +1661,14 @@ BaseBackup(void)
maxrate_clause = psprintf("MAX_RATE %u", maxrate);
basebkp =
- psprintf("BASE_BACKUP LABEL '%s' %s %s %s %s %s",
+ psprintf("BASE_BACKUP LABEL '%s' %s %s %s %s %s %s",
escaped_label,
showprogress ? "PROGRESS" : "",
includewal && !streamwal ? "WAL" : "",
fastcheckpoint ? "FAST" : "",
includewal ? "NOWAIT" : "",
- maxrate_clause ? maxrate_clause : "");
+ maxrate_clause ? maxrate_clause : "",
+ replicationslot ? "REPLICATION_SLOT" : "");
if (PQsendQuery(conn, basebkp) == 0)
{
@@ -1965,6 +1968,7 @@ main(int argc, char **argv)
{"verbose", no_argument, NULL, 'v'},
{"progress", no_argument, NULL, 'P'},
{"xlogdir", required_argument, NULL, 1},
+ {"replication-slot", no_argument, NULL, 2},
{NULL, 0, NULL, 0}
};
int c;
@@ -2058,6 +2062,9 @@ main(int argc, char **argv)
case 1:
xlog_dir = pg_strdup(optarg);
break;
+ case 2:
+ replicationslot = true;
+ break;
case 'l':
label = pg_strdup(optarg);
break;
--
Sent via pgsql-hackers mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers