Barman support, draft #1

TODO: we need to check what happens with configuration files placed in
non-standard locations.
This commit is contained in:
Gianni Ciolli
2016-07-22 15:08:21 +02:00
parent 9853581d12
commit 2f529e20c1
5 changed files with 609 additions and 39 deletions

View File

@@ -504,6 +504,76 @@ standby's upstream server is the replication cluster master. While of limited
use in a simple master/standby replication cluster, this information is required
to effectively manage cascading replication (see below).
### Using Barman to clone a standby
`repmgr standby clone` also supports Barman, the Backup and
Replication manager (http://www.pgbarman.org/), as a provider of both
base backups and WAL files.
Barman support provides the following advantages:
- the primary node does not need to perform a new backup every time a
new standby is cloned;
- a standby node can be disconnected for longer periods without losing
the ability to catch up, and without causing accumulation of WAL
files on the primary node;
- therefore, `repmgr` does not need to use replication slots, and the
primary node does not need to set `wal_keep_segments`.
> *NOTE*: In view of the above, Barman support is incompatible with
> the `use_replication_slots` setting in `repmgr.conf`.
In order to enable Barman support for `repmgr standby clone`, you must
ensure that:
- the name of the server configured in Barman is equal to the
`cluster_name` setting in `repmgr.conf`;
- the `barman_server` setting in `repmgr.conf` is set to the SSH
hostname of the Barman server;
- the `pg_restore_command` setting in `repmgr.conf` is configured to
use a copy of the `barman-wal-restore` script shipped with Barman
(see below);
- the Barman catalogue includes at least one valid backup for this
server.
> *NOTE*: Barman support is automatically enabled if `barman_server`
> is set. Normally this is a good practice; however, the command line
> option `--without-barman` can be used to disable it.
> *NOTE*: if you have a non-default SSH configuration on the Barman
> server, e.g. using a port other than 22, then you can set those
> parameters in a dedicated Host section in `~/.ssh/config`
> corresponding to the value of `barman_server` in `repmgr.conf`. See
> the "Host" section in `man 5 ssh_config` for more details.
`barman-wal-restore` is a short shell script provided by the Barman
development team, which must be copied in a location accessible to
`repmgr`, and marked as executable; `pg_restore_command` must then be
set as follows:
<script> <Barman hostname> <cluster_name> %f %p
For instance, suppose that we have installed Barman on the `barmansrv`
host, and that we have placed a copy of `barman-wal-restore` into the
`/usr/local/bin` directory. First, we ensure that the script is
executable:
sudo chmod +x /usr/local/bin/barman-wal-restore
Then we check that `repmgr.conf` includes the following lines:
barman_server=barmansrv
pg_restore_command=/usr/local/bin/barman-wal-restore barmansrv test %f %p
Now we can clone a standby using the Barman server:
$ repmgr -h node1 -D 9.5/main -f /etc/repmgr.conf standby clone
[2016-06-12 20:08:35] [NOTICE] destination directory '9.5/main' provided
[2016-06-12 20:08:35] [NOTICE] getting backup from Barman...
[2016-06-12 20:08:36] [NOTICE] standby clone (from Barman) complete
[2016-06-12 20:08:36] [NOTICE] you can now start your PostgreSQL server
[2016-06-12 20:08:36] [HINT] for example : pg_ctl -D 9.5/data start
[2016-06-12 20:08:36] [HINT] After starting the server, you need to register this standby with "repmgr standby register"
Advanced options for cloning a standby
--------------------------------------

View File

@@ -215,6 +215,7 @@ parse_config(t_configuration_options *options)
options->upstream_node = NO_UPSTREAM_NODE;
options->use_replication_slots = 0;
memset(options->conninfo, 0, sizeof(options->conninfo));
memset(options->barman_server, 0, sizeof(options->barman_server));
options->failover = MANUAL_FAILOVER;
options->priority = DEFAULT_PRIORITY;
memset(options->node_name, 0, sizeof(options->node_name));
@@ -310,6 +311,8 @@ parse_config(t_configuration_options *options)
options->upstream_node = repmgr_atoi(value, "upstream_node", &config_errors, false);
else if (strcmp(name, "conninfo") == 0)
strncpy(options->conninfo, value, MAXLEN);
else if (strcmp(name, "barman_server") == 0)
strncpy(options->barman_server, value, MAXLEN);
else if (strcmp(name, "rsync_options") == 0)
strncpy(options->rsync_options, value, QUERY_STR_LEN);
else if (strcmp(name, "ssh_options") == 0)
@@ -635,6 +638,13 @@ reload_config(t_configuration_options *orig_options)
config_changed = true;
}
/* barman_server */
if (strcmp(orig_options->barman_server, new_options.barman_server) != 0)
{
strcpy(orig_options->barman_server, new_options.barman_server);
config_changed = true;
}
/* node */
if (orig_options->node != new_options.node)
{

View File

@@ -58,6 +58,7 @@ typedef struct
int node;
int upstream_node;
char conninfo[MAXLEN];
char barman_server[MAXLEN];
int failover;
int priority;
char node_name[MAXLEN];
@@ -91,7 +92,7 @@ typedef struct
* The following will initialize the structure with a minimal set of options;
* actual defaults are set in parse_config() before parsing the configuration file
*/
#define T_CONFIGURATION_OPTIONS_INITIALIZER { "", -1, NO_UPSTREAM_NODE, "", MANUAL_FAILOVER, -1, "", "", "", "", "", "", "", "", "", "", -1, -1, -1, "", "", "", "", "", 0, 0, 0, 0, "", { NULL, NULL }, {NULL, NULL} }
#define T_CONFIGURATION_OPTIONS_INITIALIZER { "", -1, NO_UPSTREAM_NODE, "", "", MANUAL_FAILOVER, -1, "", "", "", "", "", "", "", "", "", "", -1, -1, -1, "", "", "", "", "", 0, 0, 0, 0, "", { NULL, NULL }, {NULL, NULL} }
typedef struct ItemListCell
{

561
repmgr.c
View File

@@ -105,6 +105,10 @@ static bool check_upstream_config(PGconn *conn, int server_version_num, bool exi
static bool update_node_record_set_master(PGconn *conn, int this_node_id);
static void tablespace_data_append(TablespaceDataList *list, const char *name, const char *oid, const char *location);
static int get_tablespace_data(PGconn *upstream_conn, TablespaceDataList *list);
static int get_tablespace_data_barman(char *, TablespaceDataList *);
static char *string_skip_prefix(const char *prefix, char *string);
static char *string_remove_trailing_newlines(char *string);
static char *make_pg_path(char *file);
@@ -211,6 +215,7 @@ main(int argc, char **argv)
{"pwprompt", optional_argument, NULL, OPT_PWPROMPT},
{"csv", no_argument, NULL, OPT_CSV},
{"node", required_argument, NULL, OPT_NODE},
{"without-barman", no_argument, NULL, OPT_WITHOUT_BARMAN},
{"version", no_argument, NULL, 'V'},
{NULL, 0, NULL, 0}
};
@@ -508,6 +513,9 @@ main(int argc, char **argv)
case OPT_NODE:
runtime_options.node = repmgr_atoi(optarg, "--node", &cli_errors, false);
break;
case OPT_WITHOUT_BARMAN:
runtime_options.without_barman = true;
break;
default:
unknown_option:
@@ -832,6 +840,18 @@ main(int argc, char **argv)
log_warning(_("-w/--wal-keep-segments has no effect when replication slots in use\n"));
}
/*
* STANDBY CLONE in Barman mode is incompatible with
* `use_replication_slots`.
*/
if (action == STANDBY_CLONE &&
! runtime_options.without_barman
&& strcmp(options.barman_server, "") == 0)
{
log_err(_("STANDBY CLONE in Barman mode is incompatible with configuration option \"use_replication_slots\""));
}
/* Initialise the repmgr schema name */
maxlen_snprintf(repmgr_schema, "%s%s", DEFAULT_REPMGR_SCHEMA_PREFIX,
options.cluster_name);
@@ -1562,16 +1582,107 @@ get_tablespace_data(PGconn *upstream_conn, TablespaceDataList *list)
return retval;
}
char *
string_skip_prefix(const char *prefix, char *string)
{
int n;
n = strlen(prefix);
if (strncmp(prefix, string, n))
return NULL;
else
return string + n;
}
char *
string_remove_trailing_newlines(char *string)
{
int n;
n = strlen(string) - 1;
while (n >= 0 && string[n] == '\n')
string[n] = 0;
return string;
}
int
get_tablespace_data_barman
( char *tablespace_data_barman,
TablespaceDataList *tablespace_list)
{
/*
* Example:
* [('main', 24674, '/var/lib/postgresql/tablespaces/9.5/main'), ('alt', 24678, '/var/lib/postgresql/tablespaces/9.5/alt')]
*/
char name[MAXLEN];
char oid[MAXLEN];
char location[MAXPGPATH];
char *p = tablespace_data_barman;
int i;
tablespace_list->head = NULL;
tablespace_list->tail = NULL;
p = string_skip_prefix("[", p);
while (*p == '(')
{
p = string_skip_prefix("('", p);
if (p == NULL) return -1;
i = strcspn(p, "'");
strncpy(name, p, i);
name[i] = 0;
p = string_skip_prefix("', ", p + i);
if (p == NULL) return -1;
i = strcspn(p, ",");
strncpy(oid, p, i);
oid[i] = 0;
p = string_skip_prefix(", '", p + i);
if (p == NULL) return -1;
i = strcspn(p, "'");
strncpy(location, p, i);
location[i] = 0;
p = string_skip_prefix("')", p + i);
if (p == NULL) return -1;
tablespace_data_append (tablespace_list, name, oid, location);
if (*p == ']')
break;
p = string_skip_prefix(", ", p);
if (p == NULL) return -1;
}
return SUCCESS;
}
static void
do_standby_clone(void)
{
PGconn *primary_conn = NULL;
PGconn *upstream_conn;
PGconn *upstream_conn = NULL;
PGresult *res;
enum {
barman,
rsync,
pg_basebackup
} mode;
char sqlquery[QUERY_STR_LEN];
int server_version_num;
int server_version_num = -1;
char cluster_size[MAXLEN];
@@ -1586,6 +1697,8 @@ do_standby_clone(void)
char master_data_directory[MAXPGPATH];
char local_data_directory[MAXPGPATH];
char local_repmgr_directory[MAXPGPATH];
char master_config_file[MAXPGPATH] = "";
char local_config_file[MAXPGPATH] = "";
bool config_file_outside_pgdata = false;
@@ -1606,6 +1719,15 @@ do_standby_clone(void)
PQExpBufferData event_details;
/*
* Detecting the appropriate mode
*/
if (runtime_options.rsync_only)
mode = rsync;
else if (strcmp(options.barman_server, "") != 0 && ! runtime_options.without_barman)
mode = barman;
else
mode = pg_basebackup;
/*
* If dest_dir (-D/--pgdata) was provided, this will become the new data
@@ -1619,6 +1741,9 @@ do_standby_clone(void)
runtime_options.dest_dir);
}
if (mode != barman)
{
param_set("application_name", options.node_name);
/* Connect to check configuration */
@@ -1799,6 +1924,8 @@ do_standby_clone(void)
PQclear(res);
}
/*
* target directory (-D/--pgdata) provided - use that as new data directory
* (useful when executing backup on local machine only or creating the backup
@@ -1811,6 +1938,12 @@ do_standby_clone(void)
strncpy(local_hba_file, runtime_options.dest_dir, MAXPGPATH);
strncpy(local_ident_file, runtime_options.dest_dir, MAXPGPATH);
}
else if (mode == barman)
{
log_err(_("Barman mode requires a destination directory\n"));
log_hint(_("use -D/--data-dir to explicitly specify a data directory\n"));
exit(ERR_BAD_CONFIG);
}
/*
* Otherwise use the same data directory as on the remote host
*/
@@ -1826,9 +1959,9 @@ do_standby_clone(void)
}
/*
* When using rsync only, we need to check the SSH connection early
* In rsync mode, we need to check the SSH connection early
*/
if (runtime_options.rsync_only)
if (mode == rsync)
{
r = test_ssh_connection(runtime_options.host, runtime_options.remote_user);
if (r != 0)
@@ -1856,8 +1989,11 @@ do_standby_clone(void)
* If replication slots requested, create appropriate slot on
* the primary; this must be done before pg_start_backup() is
* issued, either by us or by pg_basebackup.
*
* Replication slots are not supported (and not very useful
* anyway) in Barman mode.
*/
if (options.use_replication_slots)
if (mode != barman && options.use_replication_slots)
{
if (create_replication_slot(upstream_conn, repmgr_slot_name, server_version_num) == false)
{
@@ -1866,24 +2002,324 @@ do_standby_clone(void)
}
}
if (runtime_options.rsync_only)
if (mode == rsync)
{
log_notice(_("starting backup (using rsync)...\n"));
}
else
else if (mode == barman)
{
log_notice(_("getting backup from Barman...\n"));
}
else if (mode == pg_basebackup)
{
log_notice(_("starting backup (using pg_basebackup)...\n"));
if (runtime_options.fast_checkpoint == false)
log_hint(_("this may take some time; consider using the -c/--fast-checkpoint option\n"));
}
if (runtime_options.rsync_only)
if (mode == barman || mode == rsync)
{
PQExpBufferData tablespace_map;
bool tablespace_map_rewrite = false;
char command[MAXLEN];
char filename[MAXLEN];
char buf[MAXLEN];
char backup_directory[MAXLEN];
char backup_id[MAXLEN] = "";
char datadir_list_filename[MAXLEN];
char *p, *q;
PQExpBufferData command_output;
TablespaceDataList tablespace_list = { NULL, NULL };
TablespaceDataListCell *cell_t;
PQExpBufferData tablespace_map;
bool tablespace_map_rewrite = false;
if (mode == barman)
{
bool command_ok;
/*
* Check that there is at least one valid backup
*/
maxlen_snprintf(command, "ssh %s barman show-backup %s latest > /dev/null",
options.barman_server,
options.cluster_name);
command_ok = local_command(command, NULL);
if (command_ok == false)
{
log_err(_("No valid backup for server %s was found in the Barman catalogue\n"),
options.barman_server);
log_hint(_("Refer to the Barman documentation for more information\n"));
exit(ERR_INTERNAL);
}
/*
* Locate Barman's backup directory
*/
maxlen_snprintf(command, "ssh %s barman show-server %s | grep 'backup_directory'",
options.barman_server,
options.cluster_name);
initPQExpBuffer(&command_output);
(void)local_command(
command,
&command_output);
p = string_skip_prefix("\tbackup_directory: ", command_output.data);
if (p == NULL)
{
log_err("Unexpected output from Barman: %s\n",
command_output.data);
exit(ERR_INTERNAL);
}
strncpy(backup_directory, p, MAXLEN);
string_remove_trailing_newlines(backup_directory);
termPQExpBuffer(&command_output);
/*
* Create the local repmgr subdirectory
*/
maxlen_snprintf(local_repmgr_directory, "%s/repmgr", local_data_directory );
maxlen_snprintf(datadir_list_filename, "%s/data.txt", local_repmgr_directory);
if (!create_pg_dir(local_repmgr_directory, runtime_options.force))
{
log_err(_("unable to use directory %s ...\n"),
local_repmgr_directory);
log_hint(_("use -F/--force option to force this directory to be overwritten\n"));
r = ERR_BAD_CONFIG;
retval = ERR_BAD_CONFIG;
goto stop_backup;
}
/*
* Read the list of backup files into a local file. In the
* process:
*
* - determine the backup ID;
* - check, and remove, the prefix;
* - detect tablespaces;
* - filter files in one list per tablespace;
*/
{
FILE *fi; /* input stream */
FILE *fd; /* output for data.txt */
char prefix[MAXLEN];
char output[MAXLEN];
int n;
maxlen_snprintf(command, "ssh %s barman list-files --target=data %s latest",
options.barman_server,
options.cluster_name);
fi = popen(command, "r");
if (fi == NULL)
{
log_err("Cannot launch command: %s\n", command);
exit(ERR_INTERNAL);
}
fd = fopen(datadir_list_filename, "w");
if (fd == NULL)
{
log_err("Cannot open file: %s\n", datadir_list_filename);
exit(ERR_INTERNAL);
}
maxlen_snprintf(prefix, "%s/base/", backup_directory);
while (fgets(output, MAXLEN, fi) != NULL)
{
/*
* Remove prefix
*/
p = string_skip_prefix(prefix, output);
if (p == NULL)
{
log_err("Unexpected output from \"barman list-files\": %s\n",
output);
exit(ERR_INTERNAL);
}
/*
* Remove and note backup ID; copy backup.info
*/
if (! strcmp(backup_id, ""))
{
FILE *fi2;
n = strcspn(p, "/");
strncpy(backup_id, p, n);
strncat(prefix,backup_id,MAXLEN-1);
strncat(prefix,"/",MAXLEN-1);
p = string_skip_prefix(backup_id, p);
p = string_skip_prefix("/", p);
/*
* Copy backup.info
*/
maxlen_snprintf(command,
"rsync -a %s:%s/base/%s/backup.info %s",
options.barman_server,
backup_directory,
backup_id,
local_repmgr_directory);
(void)local_command(
command,
&command_output);
/*
* Get tablespace data
*/
maxlen_snprintf(filename, "%s/backup.info",
local_repmgr_directory);
fi2 = fopen(filename, "r");
if (fi2 == NULL)
{
log_err("Cannot open file: %s\n", filename);
exit(ERR_INTERNAL);
}
while (fgets(buf, MAXLEN, fi2) != NULL)
{
q = string_skip_prefix("tablespaces=", buf);
if (q != NULL)
{
get_tablespace_data_barman
(q, &tablespace_list);
}
q = string_skip_prefix("version=", buf);
if (q != NULL)
{
server_version_num = strtol(q, NULL, 10);
}
}
fclose(fi2);
unlink(filename);
continue;
}
/*
* Skip backup.info
*/
if (string_skip_prefix("backup.info", p))
continue;
/*
* Filter data directory files
*/
if ((q = string_skip_prefix("data/", p)) != NULL)
{
fputs(q, fd);
continue;
}
/*
* Filter other files (i.e. tablespaces)
*/
for (cell_t = tablespace_list.head; cell_t; cell_t = cell_t->next)
{
if ((q = string_skip_prefix(cell_t->oid, p)) != NULL && *q == '/')
{
if (cell_t->f == NULL)
{
maxlen_snprintf(filename, "%s/%s.txt", local_repmgr_directory, cell_t->oid);
cell_t->f = fopen(filename, "w");
if (cell_t->f == NULL)
{
log_err("Cannot open file: %s\n", filename);
exit(ERR_INTERNAL);
}
}
fputs(q + 1, cell_t->f);
break;
}
}
}
fclose(fd);
pclose(fi);
}
/* For 9.5 and greater, create our own tablespace_map file */
if (server_version_num >= 90500)
{
initPQExpBuffer(&tablespace_map);
}
/*
* As of Barman version 1.6.1, the file structure of a backup
* is as follows:
*
* base/ - base backup
* wals/ - WAL files associated to the backup
*
* base/<ID> - backup files
*
* here ID has the standard timestamp form yyyymmddThhmmss
*
* base/<ID>/backup.info - backup metadata, in text format
* base/<ID>/data - data directory
* base/<ID>/<OID> - tablespace with the given oid
*/
/*
* Copy all backup files from the Barman server
*/
maxlen_snprintf(command,
"rsync --progress -a --files-from=%s %s:%s/base/%s/data %s",
datadir_list_filename,
options.barman_server,
backup_directory,
backup_id,
local_data_directory);
(void)local_command(
command,
&command_output);
unlink(datadir_list_filename);
/*
* We must create some PGDATA subdirectories because they are
* not included in the Barman backup.
*/
{
const char* const dirs[] = {
/* Only from 9.5 */
"pg_commit_ts",
/* Only from 9.4 */
"pg_dynshmem", "pg_logical",
/* Already in 9.3 */
"pg_serial", "pg_snapshots", "pg_stat", "pg_stat_tmp", "pg_tblspc",
"pg_twophase", "pg_xlog", 0
};
const int vers[] = {
90500,
90400, 90400,
0, 0, 0, 0, 0,
0, 0, 0
};
for (i = 0; dirs[i]; i++)
{
if (vers[i] > 0 && server_version_num < vers[i])
continue;
maxlen_snprintf(filename, "%s/%s", local_data_directory, dirs[i]);
if(mkdir(filename, S_IRWXU) != 0 && errno != EEXIST)
{
log_err(_("unable to create the %s directory\n"), dirs[i]);
exit(ERR_INTERNAL);
}
}
}
}
else if (mode == rsync)
{
/* For 9.5 and greater, create our own tablespace_map file */
if (server_version_num >= 90500)
{
@@ -1952,6 +2388,7 @@ do_standby_clone(void)
/* Copy tablespaces and, if required, remap to a new location */
retval = get_tablespace_data(upstream_conn, &tablespace_list);
if(retval != SUCCESS) goto stop_backup;
}
for (cell_t = tablespace_list.head; cell_t; cell_t = cell_t->next)
{
@@ -1983,7 +2420,38 @@ do_standby_clone(void)
tblspc_dir_dest = cell_t->location;
}
/*
* Tablespace file copy
*/
if (mode == barman)
{
create_pg_dir(cell_t->location, false);
if (cell_t->f != NULL) /* cell_t->f == NULL iff the tablespace is empty */
{
maxlen_snprintf(command,
"rsync --progress -a --files-from=%s/%s.txt %s:%s/base/%s/%s %s",
local_repmgr_directory,
cell_t->oid,
options.barman_server,
backup_directory,
backup_id,
cell_t->oid,
tblspc_dir_dest);
(void)local_command(
command,
&command_output);
fclose(cell_t->f);
maxlen_snprintf(filename,
"%s/%s.txt",
local_repmgr_directory,
cell_t->oid);
unlink(filename);
}
}
else if (mode == rsync)
{
/* Copy tablespace directory */
r = copy_remote_files(runtime_options.host, runtime_options.remote_user,
cell_t->location, tblspc_dir_dest,
@@ -2001,6 +2469,7 @@ do_standby_clone(void)
cell_t->location);
goto stop_backup;
}
}
/*
* If a valid mapping was provide for this tablespace, arrange for it to
@@ -2008,7 +2477,7 @@ do_standby_clone(void)
* (if no tablespace mappings was provided, the link will be copied as-is
* by pg_basebackup or rsync and no action is required)
*/
if (mapping_found == true)
if (mapping_found == true || mode == barman)
{
/* 9.5 and later - append to the tablespace_map file */
if (server_version_num >= 90500)
@@ -2116,7 +2585,9 @@ do_standby_clone(void)
* standby server as on the primary?
*/
if (external_config_file_copy_required && !runtime_options.ignore_external_config_files)
if (mode != barman &&
external_config_file_copy_required &&
!runtime_options.ignore_external_config_files)
{
log_notice(_("copying configuration files from master\n"));
r = test_ssh_connection(runtime_options.host, runtime_options.remote_user);
@@ -2175,7 +2646,7 @@ do_standby_clone(void)
* When using rsync, copy pg_control file last, emulating the base backup
* protocol.
*/
if (runtime_options.rsync_only)
if (mode == rsync)
{
maxlen_snprintf(local_control_file, "%s/global", local_data_directory);
@@ -2207,7 +2678,7 @@ do_standby_clone(void)
stop_backup:
if (runtime_options.rsync_only && pg_start_backup_executed)
if (mode == rsync && pg_start_backup_executed)
{
log_notice(_("notifying master about backup completion...\n"));
if (stop_backup(upstream_conn, last_wal_segment) == false)
@@ -2239,7 +2710,7 @@ stop_backup:
* files which won't be removed by rsync and which could
* be stale or are otherwise not required
*/
if (runtime_options.rsync_only)
if (mode == rsync)
{
char label_path[MAXPGPATH];
char dirpath[MAXLEN] = "";
@@ -2303,13 +2774,18 @@ stop_backup:
/* Finally, write the recovery.conf file */
create_recovery_file(local_data_directory, upstream_conn);
if (runtime_options.rsync_only)
/* In Barman mode, remove local_repmgr_directory */
if (mode == barman)
rmdir(local_repmgr_directory);
switch(mode)
{
case rsync:
log_notice(_("standby clone (using rsync) complete\n"));
}
else
{
case pg_basebackup:
log_notice(_("standby clone (using pg_basebackup) complete\n"));
case barman:
log_notice(_("standby clone (from Barman) complete\n"));
}
/*
@@ -4544,6 +5020,7 @@ do_help(void)
printf(_("Command-specific configuration options:\n"));
printf(_(" -c, --fast-checkpoint (standby clone) force fast checkpoint\n"));
printf(_(" -r, --rsync-only (standby clone) use only rsync, not pg_basebackup\n"));
printf(_(" --without-barman (standby clone) do not use Barman even if configured\n"));
printf(_(" --recovery-min-apply-delay=VALUE (standby clone, follow) set recovery_min_apply_delay\n" \
" in recovery.conf (PostgreSQL 9.4 and later)\n"));
printf(_(" --ignore-external-config-files (standby clone) don't copy configuration files located\n" \
@@ -5707,10 +6184,10 @@ check_upstream_config(PGconn *conn, int server_version_num, bool exit_on_error)
}
/*
* physical replication slots not available or not requested -
* physical replication slots not available or not requested, and Barman mode not used -
* ensure some reasonably high value set for `wal_keep_segments`
*/
else
else if (! runtime_options.without_barman && strcmp(options.barman_server, "") == 0)
{
i = guc_set_typed(conn, "wal_keep_segments", ">=",
runtime_options.wal_keep_segments, "integer");
@@ -6005,33 +6482,43 @@ remote_command(const char *host, const char *user, const char *command, PQExpBuf
/*
* Execute a command locally.
* Execute a command locally. If outputbuf == NULL, discard the
* output.
*/
static bool
local_command(const char *command, PQExpBufferData *outputbuf)
{
FILE *fp;
char output[MAXLEN];
int retval;
fp = popen(command, "r");
if (fp == NULL)
if (outputbuf == NULL)
{
log_err(_("unable to execute local command:\n%s\n"), command);
return false;
retval = system(command);
return (retval == 0) ? true : false;
}
/* TODO: better error handling */
while (fgets(output, MAXLEN, fp) != NULL)
else
{
appendPQExpBuffer(outputbuf, "%s", output);
fp = popen(command, "r");
if (fp == NULL)
{
log_err(_("unable to execute local command:\n%s\n"), command);
return false;
}
/* TODO: better error handling */
while (fgets(output, MAXLEN, fp) != NULL)
{
appendPQExpBuffer(outputbuf, "%s", output);
}
pclose(fp);
log_verbose(LOG_DEBUG, "local_command(): output returned was:\n%s", outputbuf->data);
return true;
}
pclose(fp);
log_verbose(LOG_DEBUG, "local_command(): output returned was:\n%s", outputbuf->data);
return true;
}

View File

@@ -56,6 +56,7 @@
#define OPT_PWPROMPT 7
#define OPT_CSV 8
#define OPT_NODE 9
#define OPT_WITHOUT_BARMAN 10
/* Run time options type */
@@ -79,6 +80,7 @@ typedef struct
bool fast_checkpoint;
bool ignore_external_config_files;
bool csv_mode;
bool without_barman;
char masterport[MAXLEN];
/*
* configuration file parameters which can be overridden on the
@@ -102,7 +104,7 @@ typedef struct
char recovery_min_apply_delay[MAXLEN];
} t_runtime_options;
#define T_RUNTIME_OPTIONS_INITIALIZER { "", "", "", "", "", "", "", DEFAULT_WAL_KEEP_SEGMENTS, false, false, false, false, false, false, false, false, false, false, "", "", "", "", "fast", "", 0, 0, "", ""}
#define T_RUNTIME_OPTIONS_INITIALIZER { "", "", "", "", "", "", "", DEFAULT_WAL_KEEP_SEGMENTS, false, false, false, false, false, false, false, false, false, false, false, "", "", "", "", "fast", "", 0, 0, "", ""}
struct BackupLabel
{