diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c index 943d80470bf1ff5a7adf609126a66e13ed0475d6..73edcf2dc3e57017b850931bd21b7a64e643ae73 100644 --- a/src/backend/replication/basebackup.c +++ b/src/backend/replication/basebackup.c @@ -32,6 +32,14 @@ #include "utils/memutils.h" #include "utils/ps_status.h" +typedef struct +{ + const char *label; + bool progress; + bool fastcheckpoint; +} basebackup_options; + + static int64 sendDir(char *path, int basepathlen, bool sizeonly); static void sendFile(char *path, int basepathlen, struct stat * statbuf); static void _tarWriteHeader(char *filename, char *linktarget, @@ -40,7 +48,8 @@ static void send_int8_string(StringInfoData *buf, int64 intval); static void SendBackupHeader(List *tablespaces); static void SendBackupDirectory(char *location, char *spcoid); static void base_backup_cleanup(int code, Datum arg); -static void perform_base_backup(const char *backup_label, bool progress, DIR *tblspcdir, bool fastcheckpoint); +static void perform_base_backup(basebackup_options *opt, DIR *tblspcdir); +static void parse_basebackup_options(List *options, basebackup_options *opt); typedef struct { @@ -67,9 +76,9 @@ base_backup_cleanup(int code, Datum arg) * clobbered by longjmp" from stupider versions of gcc. */ static void -perform_base_backup(const char *backup_label, bool progress, DIR *tblspcdir, bool fastcheckpoint) +perform_base_backup(basebackup_options *opt, DIR *tblspcdir) { - do_pg_start_backup(backup_label, fastcheckpoint); + do_pg_start_backup(opt->label, opt->fastcheckpoint); PG_ENSURE_ERROR_CLEANUP(base_backup_cleanup, (Datum) 0); { @@ -81,7 +90,7 @@ perform_base_backup(const char *backup_label, bool progress, DIR *tblspcdir, boo /* Add a node for the base directory */ ti = palloc0(sizeof(tablespaceinfo)); - ti->size = progress ? sendDir(".", 1, true) : -1; + ti->size = opt->progress ? sendDir(".", 1, true) : -1; tablespaces = lappend(tablespaces, ti); /* Collect information about all tablespaces */ @@ -107,7 +116,7 @@ perform_base_backup(const char *backup_label, bool progress, DIR *tblspcdir, boo ti = palloc(sizeof(tablespaceinfo)); ti->oid = pstrdup(de->d_name); ti->path = pstrdup(linkpath); - ti->size = progress ? sendDir(linkpath, strlen(linkpath), true) : -1; + ti->size = opt->progress ? sendDir(linkpath, strlen(linkpath), true) : -1; tablespaces = lappend(tablespaces, ti); } @@ -128,6 +137,58 @@ perform_base_backup(const char *backup_label, bool progress, DIR *tblspcdir, boo do_pg_stop_backup(); } +/* + * Parse the base backup options passed down by the parser + */ +static void +parse_basebackup_options(List *options, basebackup_options *opt) +{ + ListCell *lopt; + bool o_label = false; + bool o_progress = false; + bool o_fast = false; + + MemSet(opt, 0, sizeof(opt)); + foreach(lopt, options) + { + DefElem *defel = (DefElem *) lfirst(lopt); + + if (strcmp(defel->defname, "label") == 0) + { + if (o_label) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("duplicate option \"%s\"", defel->defname))); + opt->label = strVal(defel->arg); + o_label = true; + } + else if (strcmp(defel->defname, "progress") == 0) + { + if (o_progress) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("duplicate option \"%s\"", defel->defname))); + opt->progress = true; + o_progress = true; + } + else if (strcmp(defel->defname, "fast") == 0) + { + if (o_fast) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("duplicate option \"%s\"", defel->defname))); + opt->fastcheckpoint = true; + o_fast = true; + } + else + elog(ERROR, "option \"%s\" not recognized", + defel->defname); + } + if (opt->label == NULL) + opt->label = "base backup"; +} + + /* * SendBaseBackup() - send a complete base backup. * @@ -135,11 +196,14 @@ perform_base_backup(const char *backup_label, bool progress, DIR *tblspcdir, boo * pg_stop_backup() for the user. */ void -SendBaseBackup(const char *backup_label, bool progress, bool fastcheckpoint) +SendBaseBackup(BaseBackupCmd *cmd) { DIR *dir; MemoryContext backup_context; MemoryContext old_context; + basebackup_options opt; + + parse_basebackup_options(cmd->options, &opt); backup_context = AllocSetContextCreate(CurrentMemoryContext, "Streaming base backup context", @@ -150,15 +214,12 @@ SendBaseBackup(const char *backup_label, bool progress, bool fastcheckpoint) WalSndSetState(WALSNDSTATE_BACKUP); - if (backup_label == NULL) - backup_label = "base backup"; - if (update_process_title) { char activitymsg[50]; snprintf(activitymsg, sizeof(activitymsg), "sending backup \"%s\"", - backup_label); + opt.label); set_ps_display(activitymsg, false); } @@ -168,7 +229,7 @@ SendBaseBackup(const char *backup_label, bool progress, bool fastcheckpoint) ereport(ERROR, (errmsg("unable to open directory pg_tblspc: %m"))); - perform_base_backup(backup_label, progress, dir, fastcheckpoint); + perform_base_backup(&opt, dir); FreeDir(dir); diff --git a/src/backend/replication/repl_gram.y b/src/backend/replication/repl_gram.y index e4f4c4742f68783c964c0da8f8450819935ca9ac..879a0bd7db0d9248027cd5869ccc34567185301f 100644 --- a/src/backend/replication/repl_gram.y +++ b/src/backend/replication/repl_gram.y @@ -15,6 +15,8 @@ #include "postgres.h" +#include "nodes/makefuncs.h" +#include "nodes/parsenodes.h" #include "replication/replnodes.h" #include "replication/walsender.h" @@ -55,6 +57,8 @@ Node *replication_parse_result; XLogRecPtr recptr; Node *node; + List *list; + DefElem *defelt; } /* Non-keyword tokens */ @@ -71,9 +75,8 @@ Node *replication_parse_result; %type <node> command %type <node> base_backup start_replication identify_system -%type <boolval> opt_progress opt_fast -%type <str> opt_label - +%type <list> base_backup_opt_list +%type <defelt> base_backup_opt %% firstcmd: command opt_semicolon @@ -106,28 +109,34 @@ identify_system: * BASE_BACKUP [LABEL <label>] [PROGRESS] [FAST] */ base_backup: - K_BASE_BACKUP opt_label opt_progress opt_fast + K_BASE_BACKUP base_backup_opt_list { BaseBackupCmd *cmd = (BaseBackupCmd *) makeNode(BaseBackupCmd); - - cmd->label = $2; - cmd->progress = $3; - cmd->fastcheckpoint = $4; - + cmd->options = $2; $$ = (Node *) cmd; } ; -opt_label: K_LABEL SCONST { $$ = $2; } - | /* EMPTY */ { $$ = NULL; } - ; +base_backup_opt_list: base_backup_opt_list base_backup_opt { $$ = lappend($1, $2); } + | /* EMPTY */ { $$ = NIL; } + +base_backup_opt: + K_LABEL SCONST + { + $$ = makeDefElem("label", + (Node *)makeString($2)); + } + | K_PROGRESS + { + $$ = makeDefElem("progress", + (Node *)makeInteger(TRUE)); + } + | K_FAST + { + $$ = makeDefElem("fast", + (Node *)makeInteger(TRUE)); + } -opt_progress: K_PROGRESS { $$ = true; } - | /* EMPTY */ { $$ = false; } - ; -opt_fast: K_FAST { $$ = true; } - | /* EMPTY */ { $$ = false; } - ; /* * START_REPLICATION %X/%X diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c index 8a6392345697035028ba2c08165e050ae3d5330b..44efa9fc25e8d37a94e2d7e72264c0794a96a211 100644 --- a/src/backend/replication/walsender.c +++ b/src/backend/replication/walsender.c @@ -399,17 +399,13 @@ HandleReplicationCommand(const char *cmd_string) break; case T_BaseBackupCmd: - { - BaseBackupCmd *cmd = (BaseBackupCmd *) cmd_node; - - SendBaseBackup(cmd->label, cmd->progress, cmd->fastcheckpoint); + SendBaseBackup((BaseBackupCmd *) cmd_node); - /* Send CommandComplete and ReadyForQuery messages */ - EndCommand("SELECT", DestRemote); - ReadyForQuery(DestRemote); - /* ReadyForQuery did pq_flush for us */ - break; - } + /* Send CommandComplete and ReadyForQuery messages */ + EndCommand("SELECT", DestRemote); + ReadyForQuery(DestRemote); + /* ReadyForQuery did pq_flush for us */ + break; default: ereport(FATAL, diff --git a/src/include/replication/basebackup.h b/src/include/replication/basebackup.h index 80f814b2e7c6e6b11d4c5a1ddf815cb831fc3ed5..af6a36621f247942d3915b7f0de358ce493137f8 100644 --- a/src/include/replication/basebackup.h +++ b/src/include/replication/basebackup.h @@ -12,6 +12,8 @@ #ifndef _BASEBACKUP_H #define _BASEBACKUP_H -extern void SendBaseBackup(const char *backup_label, bool progress, bool fastcheckpoint); +#include "replication/replnodes.h" + +extern void SendBaseBackup(BaseBackupCmd *cmd); #endif /* _BASEBACKUP_H */ diff --git a/src/include/replication/replnodes.h b/src/include/replication/replnodes.h index fc814146baf895e7674cb51996143b4fc4b46085..6fc037580fa92a7ea455be2433378fda49b5cef4 100644 --- a/src/include/replication/replnodes.h +++ b/src/include/replication/replnodes.h @@ -45,9 +45,7 @@ typedef struct IdentifySystemCmd typedef struct BaseBackupCmd { NodeTag type; - char *label; - bool progress; - bool fastcheckpoint; + List *options; } BaseBackupCmd;