diff --git a/HISTORY b/HISTORY index afbb5760..f7207ca0 100644 --- a/HISTORY +++ b/HISTORY @@ -6,6 +6,7 @@ repmgr: if replication slots in use, where possible delete slot on old upstream node after following new upstream (Ian) repmgr: improve logging of rsync actions (Ian) + repmgr: improve `standby clone` when synchronous replication in use (Ian) 3.3 2016-12-27 repmgr: always log to STDERR even if log facility defined (Ian) diff --git a/dbutils.c b/dbutils.c index 97e293cf..1124900f 100644 --- a/dbutils.c +++ b/dbutils.c @@ -33,6 +33,7 @@ char repmgr_schema[MAXLEN] = ""; char repmgr_schema_quoted[MAXLEN] = ""; static int _get_node_record(PGconn *conn, char *cluster, char *sqlquery, t_node_info *node_info); +static bool _set_config(PGconn *conn, const char *config_param, const char *sqlquery); PGconn * _establish_db_connection(const char *conninfo, const bool exit_on_error, const bool log_notice, const bool verbose_only) @@ -1150,19 +1151,12 @@ stop_backup(PGconn *conn, char *last_wal_segment) } + bool -set_config_bool(PGconn *conn, const char *config_param, bool state) +_set_config(PGconn *conn, const char *config_param, const char *sqlquery) { - char sqlquery[QUERY_STR_LEN]; PGresult *res; - sqlquery_snprintf(sqlquery, - "SET %s TO %s", - config_param, - state ? "TRUE" : "FALSE"); - - log_verbose(LOG_DEBUG, "set_config_bool():\n%s\n", sqlquery); - res = PQexec(conn, sqlquery); if (PQresultStatus(res) != PGRES_COMMAND_OK) @@ -1177,6 +1171,36 @@ set_config_bool(PGconn *conn, const char *config_param, bool state) return true; } +bool +set_config(PGconn *conn, const char *config_param, const char *config_value) +{ + char sqlquery[QUERY_STR_LEN]; + + sqlquery_snprintf(sqlquery, + "SET %s TO '%s'", + config_param, + config_value); + + log_verbose(LOG_DEBUG, "set_config():\n%s\n", sqlquery); + + return _set_config(conn, config_param, sqlquery); +} + +bool +set_config_bool(PGconn *conn, const char *config_param, bool state) +{ + char sqlquery[QUERY_STR_LEN]; + + sqlquery_snprintf(sqlquery, + "SET %s TO %s", + config_param, + state ? "TRUE" : "FALSE"); + + log_verbose(LOG_DEBUG, "set_config_bool():\n%s\n", sqlquery); + + return _set_config(conn, config_param, sqlquery); +} + /* * witness_copy_node_records() diff --git a/dbutils.h b/dbutils.h index f73b9e70..29c7baf0 100644 --- a/dbutils.h +++ b/dbutils.h @@ -124,6 +124,7 @@ int get_slot_record(PGconn *conn, char *slot_name, t_replication_slot *record) bool drop_replication_slot(PGconn *conn, char *slot_name); bool start_backup(PGconn *conn, char *first_wal_segment, bool fast_checkpoint); bool stop_backup(PGconn *conn, char *last_wal_segment); +bool set_config(PGconn *conn, const char *config_param, const char *config_value); bool set_config_bool(PGconn *conn, const char *config_param, bool state); bool witness_copy_node_records(PGconn *masterconn, PGconn *witnessconn, char *cluster_name); bool create_node_record(PGconn *conn, char *action, int node, char *type, int upstream_node, char *cluster_name, char *node_name, char *conninfo, int priority, char *slot_name, bool active); diff --git a/repmgr.c b/repmgr.c index 932a9406..145757e9 100644 --- a/repmgr.c +++ b/repmgr.c @@ -758,7 +758,7 @@ main(int argc, char **argv) { if (optind < argc) { - if (runtime_options.host_param_provided == true) + if (runtime_options.host[0]) { PQExpBufferData additional_host_arg; initPQExpBuffer(&additional_host_arg); @@ -2954,6 +2954,8 @@ do_standby_clone(void) primary_conn = source_conn; } + + /* * Sanity-check that the master node has a repmgr schema - if not * present, fail with an error (unless -F/--force is used) @@ -2973,6 +2975,7 @@ do_standby_clone(void) log_warning(_("expected repmgr schema '%s' not found on master server\n"), get_repmgr_schema()); } + /* Fetch the source's data directory */ if (get_pg_setting(source_conn, "data_directory", master_data_directory) == false) { @@ -2994,6 +2997,8 @@ do_standby_clone(void) log_hint(_("use -D/--data-dir to explicitly specify a data directory\n")); } + + /* * Copy the source connection so that we have some default values, * particularly stuff like passwords extracted from PGPASSFILE; @@ -3017,6 +3022,18 @@ do_standby_clone(void) strncpy(recovery_conninfo_str, upstream_node_record.conninfo_str, MAXLEN); } } + + /* Finally, set `synchronous_commit` to `local` to avoid problems + * if synchronous commit is in use. + */ + + if (primary_conn != NULL && PQstatus(primary_conn) == CONNECTION_OK) + { + if (set_config(primary_conn, "synchronous_commit", "local") == false) + { + exit(ERR_DB_QUERY); + } + } } if (mode == barman && PQstatus(source_conn) != CONNECTION_OK) @@ -3578,9 +3595,6 @@ do_standby_clone(void) /* * We must create some PGDATA subdirectories because they are * not included in the Barman backup. - * - * See class RsyncBackupExecutor in the Barman source (barman/backup_executor.py) - * for a definitive list of excluded directories. */ { const char* const dirs[] = { @@ -3591,14 +3605,14 @@ do_standby_clone(void) /* Only from 9.4 */ "pg_dynshmem", "pg_logical", "pg_logical/snapshots", "pg_logical/mappings", "pg_replslot", /* Already in 9.3 */ - "pg_notify", "pg_serial", "pg_snapshots", "pg_stat", "pg_stat_tmp", "pg_tblspc", + "pg_serial", "pg_snapshots", "pg_stat", "pg_stat_tmp", "pg_tblspc", "pg_twophase", "pg_xlog", 0 }; const int vers[] = { 100000, 90500, 90400, 90400, 90400, 90400, 90400, - 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, -100000, 0 }; for (i = 0; dirs[i]; i++) @@ -3628,17 +3642,6 @@ do_standby_clone(void) initPQExpBuffer(&tablespace_map); } - /* - * From 9.1 default is to wait for a sync standby to ack, avoid that by - * turning off sync rep for this session - */ - if (set_config_bool(source_conn, "synchronous_commit", false) == false) - { - r = ERR_BAD_CONFIG; - retval = ERR_BAD_CONFIG; - goto stop_backup; - } - if (start_backup(source_conn, first_wal_segment, runtime_options.fast_checkpoint) == false) { r = ERR_BAD_BASEBACKUP;