From 01a33198fd8a256191327f314f3c4772666db2c1 Mon Sep 17 00:00:00 2001 From: Ian Barwick Date: Mon, 9 Feb 2015 10:31:03 +0900 Subject: [PATCH] Add configuration file parameter for pg_basebackup "pg_basebackup_options" Enable custom options to be passed to pg_basebackup (e.g. --max-rate, --checkpoint, --xlogdir) "tablespace_mapping" Analogue to pg_basebackup's (9.4 and later) -T/--tablespace-mapping option. Tablespace mapping could also be passed via "pg_basebackup_options", however by providing a separate parameter it makes the configuration file easier to read and allows us to verify the specified tablespaces exist (pg_basebackup won't do this, which can lead to undesired behaviour, i.e. attempting to create the tablespace in the original path). --- config.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ config.h | 15 ++++++++++- 2 files changed, 92 insertions(+), 1 deletion(-) diff --git a/config.c b/config.c index c7053cb9..52c62d81 100644 --- a/config.c +++ b/config.c @@ -22,6 +22,8 @@ #include "strutil.h" #include "repmgr.h" +static void tablespace_list_append(t_configuration_options *options, const char *arg); + void parse_config(const char *config_file, t_configuration_options * options) { @@ -45,6 +47,7 @@ parse_config(const char *config_file, t_configuration_options * options) memset(options->ssh_options, 0, sizeof(options->ssh_options)); memset(options->pg_bindir, 0, sizeof(options->pg_bindir)); memset(options->pgctl_options, 0, sizeof(options->pgctl_options)); + memset(options->pg_basebackup_options, 0, sizeof(options->pg_basebackup_options)); /* if nothing has been provided defaults to 60 */ options->master_response_timeout = 60; @@ -56,6 +59,9 @@ parse_config(const char *config_file, t_configuration_options * options) options->monitor_interval_secs = 2; options->retry_promote_interval_secs = 300; + options->tablespace_dirs.head = NULL; + options->tablespace_dirs.tail = NULL; + /* * Since some commands don't require a config file at all, not having one * isn't necessarily a problem. @@ -132,6 +138,8 @@ parse_config(const char *config_file, t_configuration_options * options) strncpy(options->pg_bindir, value, MAXLEN); else if (strcmp(name, "pg_ctl_options") == 0) strncpy(options->pgctl_options, value, MAXLEN); + else if (strcmp(name, "pg_basebackup_options") == 0) + strncpy(options->pg_basebackup_options, value, MAXLEN); else if (strcmp(name, "logfile") == 0) strncpy(options->logfile, value, MAXLEN); else if (strcmp(name, "monitor_interval_secs") == 0) @@ -140,6 +148,8 @@ parse_config(const char *config_file, t_configuration_options * options) options->retry_promote_interval_secs = atoi(value); else if (strcmp(name, "use_replication_slots") == 0) options->use_replication_slots = atoi(value); + else if (strcmp(name, "tablespace_mapping") == 0) + tablespace_list_append(options, value); else log_warning(_("%s/%s: Unknown name/value pair!\n"), name, value); } @@ -332,3 +342,71 @@ reload_config(char *config_file, t_configuration_options * orig_options) return true; } + + + +/* + * Split argument into old_dir and new_dir and append to tablespace mapping + * list. + * + * Adapted from pg_basebackup.c + */ +static void +tablespace_list_append(t_configuration_options *options, const char *arg) +{ + TablespaceListCell *cell; + char *dst; + char *dst_ptr; + const char *arg_ptr; + + cell = (TablespaceListCell *) malloc(sizeof(TablespaceListCell)); + if(cell == NULL) + { + log_err(_("Unable to allocate memory. Terminating.\n")); + exit(ERR_BAD_CONFIG); + } + + dst_ptr = dst = cell->old_dir; + for (arg_ptr = arg; *arg_ptr; arg_ptr++) + { + if (dst_ptr - dst >= MAXPGPATH) + { + log_err(_("directory name too long\n")); + exit(ERR_BAD_CONFIG); + } + + if (*arg_ptr == '\\' && *(arg_ptr + 1) == '=') + ; /* skip backslash escaping = */ + else if (*arg_ptr == '=' && (arg_ptr == arg || *(arg_ptr - 1) != '\\')) + { + if (*cell->new_dir) + { + log_err(_("multiple \"=\" signs in tablespace mapping\n")); + exit(ERR_BAD_CONFIG); + } + else + { + dst = dst_ptr = cell->new_dir; + } + } + else + *dst_ptr++ = *arg_ptr; + } + + if (!*cell->old_dir || !*cell->new_dir) + { + log_err(_("invalid tablespace mapping format \"%s\", must be \"OLDDIR=NEWDIR\"\n"), + arg); + exit(ERR_BAD_CONFIG); + } + + canonicalize_path(cell->old_dir); + canonicalize_path(cell->new_dir); + + if (options->tablespace_dirs.tail) + options->tablespace_dirs.tail->next = cell; + else + options->tablespace_dirs.head = cell; + + options->tablespace_dirs.tail = cell; +} diff --git a/config.h b/config.h index e608b574..78af51f9 100644 --- a/config.h +++ b/config.h @@ -23,7 +23,18 @@ #include "repmgr.h" #include "strutil.h" +typedef struct TablespaceListCell +{ + struct TablespaceListCell *next; + char old_dir[MAXPGPATH]; + char new_dir[MAXPGPATH]; +} TablespaceListCell; +typedef struct TablespaceList +{ + TablespaceListCell *head; + TablespaceListCell *tail; +} TablespaceList; typedef struct { @@ -45,13 +56,15 @@ typedef struct int reconnect_intvl; char pg_bindir[MAXLEN]; char pgctl_options[MAXLEN]; + char pg_basebackup_options[MAXLEN]; char logfile[MAXLEN]; int monitor_interval_secs; int retry_promote_interval_secs; int use_replication_slots; + TablespaceList tablespace_dirs; } t_configuration_options; -#define T_CONFIGURATION_OPTIONS_INITIALIZER { "", -1, NO_UPSTREAM_NODE, "", MANUAL_FAILOVER, -1, "", "", "", "", "", "", "", -1, -1, -1, "", "", "", 0, 0, 0 } +#define T_CONFIGURATION_OPTIONS_INITIALIZER { "", -1, NO_UPSTREAM_NODE, "", MANUAL_FAILOVER, -1, "", "", "", "", "", "", "", -1, -1, -1, "", "", "", "", 0, 0, 0, {NULL, NULL} } void parse_config(const char *config_file, t_configuration_options * options);