diff --git a/dbutils.c b/dbutils.c index 790bee28..29a03a08 100644 --- a/dbutils.c +++ b/dbutils.c @@ -53,6 +53,8 @@ static PGconn *_establish_db_connection(const char *conninfo, static PGconn *_get_primary_connection(PGconn *standby_conn, int *primary_id, char *primary_conninfo_out, bool quiet); static bool _set_config(PGconn *conn, const char *config_param, const char *sqlquery); +static bool _get_pg_setting(PGconn *conn, const char *setting, char *str_output, int *int_output); + static RecordStatus _get_node_record(PGconn *conn, char *sqlquery, t_node_info *node_info, bool init_defaults); static void _populate_node_record(PGresult *res, t_node_info *node_info, int row, bool init_defaults); @@ -995,52 +997,37 @@ guc_set(PGconn *conn, const char *parameter, const char *op, return retval; } -/** - * Just like guc_set except with an extra parameter containing the name of - * the pg datatype so that the comparison can be done properly. - */ -int -guc_set_typed(PGconn *conn, const char *parameter, const char *op, - const char *value, const char *datatype) + +bool +get_pg_setting(PGconn *conn, const char *setting, char *output) { - PQExpBufferData query; - PGresult *res = NULL; - int retval = 1; + bool success = _get_pg_setting(conn, setting, output, NULL); - char *escaped_parameter = escape_string(conn, parameter); - char *escaped_value = escape_string(conn, value); - - initPQExpBuffer(&query); - appendPQExpBuffer(&query, - "SELECT true FROM pg_catalog.pg_settings " - " WHERE name = '%s' AND setting::%s %s '%s'::%s", - parameter, datatype, op, value, datatype); - - log_verbose(LOG_DEBUG, "guc_set_typed():\n%s", query.data); - - res = PQexec(conn, query.data); - - if (PQresultStatus(res) != PGRES_TUPLES_OK) + if (success == true) { - log_db_error(conn, query.data, _("guc_set_typed(): unable to execute query")); - retval = -1; - } - else if (PQntuples(res) == 0) - { - retval = 0; + log_verbose(LOG_DEBUG, _("get_pg_setting(): returned value is \"%s\""), output); } - pfree(escaped_parameter); - pfree(escaped_value); - termPQExpBuffer(&query); - PQclear(res); - - return retval; + return success; } bool -get_pg_setting(PGconn *conn, const char *setting, char *output) +get_pg_setting_int(PGconn *conn, const char *setting, int *output) +{ + bool success = _get_pg_setting(conn, setting, NULL, output); + + if (success == true) + { + log_verbose(LOG_DEBUG, _("get_pg_setting_int(): returned value is \"%i\""), *output); + } + + return success; +} + + +bool +_get_pg_setting(PGconn *conn, const char *setting, char *str_output, int *int_output) { PQExpBufferData query; PGresult *res = NULL; @@ -1081,7 +1068,11 @@ get_pg_setting(PGconn *conn, const char *setting, char *output) { if (strcmp(PQgetvalue(res, i, 0), setting) == 0) { - snprintf(output, MAXLEN, "%s", PQgetvalue(res, i, 1)); + if (str_output != NULL) + snprintf(str_output, MAXLEN, "%s", PQgetvalue(res, i, 1)); + else if (int_output != NULL) + *int_output = atoi(PQgetvalue(res, i, 1)); + success = true; break; } @@ -1092,10 +1083,6 @@ get_pg_setting(PGconn *conn, const char *setting, char *output) } } - if (success == true) - { - log_verbose(LOG_DEBUG, _("get_pg_setting(): returned value is \"%s\""), output); - } termPQExpBuffer(&query); PQclear(res); @@ -1104,6 +1091,7 @@ get_pg_setting(PGconn *conn, const char *setting, char *output) } + bool alter_system_int(PGconn *conn, const char *name, int value) { diff --git a/dbutils.h b/dbutils.h index f193e1b5..e518998d 100644 --- a/dbutils.h +++ b/dbutils.h @@ -465,8 +465,8 @@ bool rollback_transaction(PGconn *conn); 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); int guc_set(PGconn *conn, const char *parameter, const char *op, const char *value); -int guc_set_typed(PGconn *conn, const char *parameter, const char *op, const char *value, const char *datatype); bool get_pg_setting(PGconn *conn, const char *setting, char *output); +bool get_pg_setting_int(PGconn *conn, const char *setting, int *output); bool alter_system_int(PGconn *conn, const char *name, int value); bool pg_reload_conf(PGconn *conn); diff --git a/repmgr-action-standby.c b/repmgr-action-standby.c index ed7ce54a..ad21a41e 100644 --- a/repmgr-action-standby.c +++ b/repmgr-action-standby.c @@ -5198,6 +5198,7 @@ check_upstream_config(PGconn *conn, int server_version_num, t_node_info *upstrea ItemList backup_option_errors = {NULL, NULL}; bool xlog_stream = true; standy_clone_mode mode; + bool pg_setting_ok; /* * Detecting the intended cloning mode @@ -5299,13 +5300,14 @@ check_upstream_config(PGconn *conn, int server_version_num, t_node_info *upstrea if (config_file_options.use_replication_slots) { - i = guc_set_typed(conn, "max_replication_slots", ">", - "0", "integer"); - if (i == 0 || i == -1) + pg_setting_ok = get_pg_setting_int(conn, "max_replication_slots", &i); + + if (pg_setting_ok == false || i < 1) { - if (i == 0) + if (pg_setting_ok == true) { log_error(_("parameter \"max_replication_slots\" must be set to at least 1 to enable replication slots")); + log_detail(_("current value is %i"), i); log_hint(_("\"max_replication_slots\" should be set to at least the number of expected standbys")); if (exit_on_error == true) { @@ -5316,6 +5318,11 @@ check_upstream_config(PGconn *conn, int server_version_num, t_node_info *upstrea config_ok = false; } } + + if (pg_setting_ok == true && i > 0 && runtime_options.dry_run == true) + { + log_info(_("parameter \"max_replication_slots\" set to %i"), i); + } } /* @@ -5327,7 +5334,7 @@ check_upstream_config(PGconn *conn, int server_version_num, t_node_info *upstrea bool check_wal_keep_segments = false; /* - * A non-zero `wal_keep_segments` value will almost certainly be + * A non-zero "wal_keep_segments" value will almost certainly be * required if pg_basebackup is being used with --xlog-method=fetch, * *and* no restore command has been specified */ @@ -5339,11 +5346,12 @@ check_upstream_config(PGconn *conn, int server_version_num, t_node_info *upstrea if (check_wal_keep_segments == true) { - i = guc_set_typed(conn, "wal_keep_segments", ">", "0", "integer"); - if (i == 0 || i == -1) + pg_setting_ok = get_pg_setting_int(conn, "wal_keep_segments", &i); + + if (pg_setting_ok == false || i < 1) { - if (i == 0) + if (pg_setting_ok == true) { log_error(_("parameter \"wal_keep_segments\" on the upstream server must be be set to a non-zero value")); log_hint(_("Choose a value sufficiently high enough to retain enough WAL " @@ -5355,8 +5363,7 @@ check_upstream_config(PGconn *conn, int server_version_num, t_node_info *upstrea { log_hint(_("In PostgreSQL 9.4 and later, replication slots can be used, which " "do not require \"wal_keep_segments\" to be set " - "(set parameter \"use_replication_slots\" in repmgr.conf to enable)\n" - )); + "(set parameter \"use_replication_slots\" in repmgr.conf to enable)\n")); } } @@ -5368,6 +5375,11 @@ check_upstream_config(PGconn *conn, int server_version_num, t_node_info *upstrea config_ok = false; } + + if (pg_setting_ok == true && i > 0 && runtime_options.dry_run == true) + { + log_info(_("parameter \"wal_keep_segments\" set to %i"), i); + } } } @@ -5426,12 +5438,13 @@ check_upstream_config(PGconn *conn, int server_version_num, t_node_info *upstrea config_ok = false; } - i = guc_set_typed(conn, "max_wal_senders", ">", "0", "integer"); - if (i == 0 || i == -1) + pg_setting_ok = get_pg_setting_int(conn, "max_wal_senders", &i); + + if (pg_setting_ok == false || i < 1) { - if (i == 0) + if (pg_setting_ok == true) { - log_error(_("parameter \"max_wal_senders\" must be set to be at least 1")); + log_error(_("parameter \"max_wal_senders\" must be set to be at least 1 %i"), i); log_hint(_("\"max_wal_senders\" should be set to at least the number of expected standbys")); } @@ -5443,6 +5456,10 @@ check_upstream_config(PGconn *conn, int server_version_num, t_node_info *upstrea config_ok = false; } + else if (pg_setting_ok == true && i > 0 && runtime_options.dry_run == true) + { + log_info(_("parameter \"max_wal_senders\" set to %i"), i); + } /* * If using pg_basebackup, ensure sufficient replication connections can @@ -5458,7 +5475,7 @@ check_upstream_config(PGconn *conn, int server_version_num, t_node_info *upstrea int i; int available_wal_senders; int min_replication_connections = 1; - + int possible_replication_connections = 0; t_conninfo_param_list repl_conninfo = T_CONNINFO_PARAM_LIST_INITIALIZER; @@ -5472,7 +5489,6 @@ check_upstream_config(PGconn *conn, int server_version_num, t_node_info *upstrea log_notice(_("checking for available walsenders on the source node (%i required)"), min_replication_connections); - /* * check how many free walsenders are available */ @@ -5496,94 +5512,106 @@ check_upstream_config(PGconn *conn, int server_version_num, t_node_info *upstrea exit(ERR_BAD_CONFIG); } } - else + else if (runtime_options.dry_run == true) { - /* - * Sufficient free walsenders appear to be available, check if - * we can connect to them. We check that the required number - * of connections can be made e.g. to rule out a very restrictive - * "CONNECTION LIMIT" setting. - */ + log_info(_("sufficient walsenders available on the source node")); + log_detail(_("%i required, %i available"), + min_replication_connections, + available_wal_senders); + } - int possible_replication_connections = 0; - log_notice(_("checking replication connections can be made to the source server (%i required)"), - min_replication_connections); + /* + * Sufficient free walsenders appear to be available, check if + * we can connect to them. We check that the required number + * of connections can be made e.g. to rule out a very restrictive + * "CONNECTION LIMIT" setting. + */ - /* - * Make a copy of the connection parameter arrays, and append - * "replication". - */ - initialize_conninfo_params(&repl_conninfo, false); + log_notice(_("checking replication connections can be made to the source server (%i required)"), + min_replication_connections); - conn_to_param_list(conn, &repl_conninfo); + /* + * Make a copy of the connection parameter arrays, and append + * "replication". + */ + initialize_conninfo_params(&repl_conninfo, false); - param_set(&repl_conninfo, "replication", "1"); + conn_to_param_list(conn, &repl_conninfo); - if (runtime_options.replication_user[0] != '\0') + param_set(&repl_conninfo, "replication", "1"); + + if (runtime_options.replication_user[0] != '\0') + { + param_set(&repl_conninfo, "user", runtime_options.replication_user); + } + else if (upstream_repluser[0] != '\0') + { + param_set(&repl_conninfo, "user", upstream_repluser); + } + else if (upstream_node_record->repluser[0] != '\0') + { + param_set(&repl_conninfo, "user", upstream_node_record->repluser); + } + + if (strcmp(param_get(&repl_conninfo, "user"), upstream_user) != 0) + { + param_set(&repl_conninfo, "dbname", "replication"); + } + + connections = pg_malloc0(sizeof(PGconn *) * min_replication_connections); + + /* + * Attempt to create the minimum number of required concurrent + * connections + */ + for (i = 0; i < min_replication_connections; i++) + { + PGconn *replication_conn; + + replication_conn = establish_db_connection_by_params(&repl_conninfo, false); + + if (PQstatus(replication_conn) == CONNECTION_OK) { - param_set(&repl_conninfo, "user", runtime_options.replication_user); - } - else if (upstream_repluser[0] != '\0') - { - param_set(&repl_conninfo, "user", upstream_repluser); - } - else if (upstream_node_record->repluser[0] != '\0') - { - param_set(&repl_conninfo, "user", upstream_node_record->repluser); - } - - if (strcmp(param_get(&repl_conninfo, "user"), upstream_user) != 0) - { - param_set(&repl_conninfo, "dbname", "replication"); - } - - connections = pg_malloc0(sizeof(PGconn *) * min_replication_connections); - - /* - * Attempt to create the minimum number of required concurrent - * connections - */ - for (i = 0; i < min_replication_connections; i++) - { - PGconn *replication_conn; - - replication_conn = establish_db_connection_by_params(&repl_conninfo, false); - - if (PQstatus(replication_conn) == CONNECTION_OK) - { - connections[i] = replication_conn; - possible_replication_connections++; - } - } - - /* Close previously created connections */ - for (i = 0; i < possible_replication_connections; i++) - { - PQfinish(connections[i]); - } - - pfree(connections); - free_conninfo_params(&repl_conninfo); - - if (possible_replication_connections < min_replication_connections) - { - config_ok = false; - - log_error(_("unable to establish necessary replication connections")); - - log_hint(_("check replication permissions on the source server")); - - if (exit_on_error == true) - { - PQfinish(conn); - exit(ERR_BAD_CONFIG); - } + connections[i] = replication_conn; + possible_replication_connections++; } } - log_verbose(LOG_INFO, "sufficient walsenders available on source node (%i required)", - min_replication_connections); + /* Close previously created connections */ + for (i = 0; i < possible_replication_connections; i++) + { + PQfinish(connections[i]); + } + + pfree(connections); + free_conninfo_params(&repl_conninfo); + + if (possible_replication_connections < min_replication_connections) + { + config_ok = false; + + log_error(_("unable to establish necessary replication connections")); + log_hint(_("check replication permissions on the source server")); + + if (exit_on_error == true) + { + PQfinish(conn); + exit(ERR_BAD_CONFIG); + } + } + + if (runtime_options.dry_run == true) + { + log_info(_("required number of replication connections could be made to the source server")); + log_detail(_("%i replication connections required"), + min_replication_connections); + } + else + { + log_verbose(LOG_INFO, _("sufficient replication connections could be made to the source server (%i required)"), + min_replication_connections); + } } return config_ok;