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 (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers