diff --git a/config.h.in b/config.h.in
index 69adebae..b977437d 100644
--- a/config.h.in
+++ b/config.h.in
@@ -2,4 +2,3 @@
/* Only build repmgr for BDR */
#undef BDR_ONLY
-
diff --git a/configfile.c b/configfile.c
index c590309c..f6a17321 100644
--- a/configfile.c
+++ b/configfile.c
@@ -260,6 +260,7 @@ _parse_config(t_configuration_options *options, ItemList *error_list, ItemList *
options->tablespace_mapping.head = NULL;
options->tablespace_mapping.tail = NULL;
memset(options->recovery_min_apply_delay, 0, sizeof(options->recovery_min_apply_delay));
+ options->recovery_min_apply_delay_provided = false;
options->use_primary_conninfo_password = false;
/*-----------------
@@ -435,7 +436,10 @@ _parse_config(t_configuration_options *options, ItemList *error_list, ItemList *
else if (strcmp(name, "restore_command") == 0)
strncpy(options->restore_command, value, MAXLEN);
else if (strcmp(name, "recovery_min_apply_delay") == 0)
+ {
parse_time_unit_parameter(name, value, options->recovery_min_apply_delay, error_list);
+ options->recovery_min_apply_delay_provided = true;
+ }
else if (strcmp(name, "use_primary_conninfo_password") == 0)
options->use_primary_conninfo_password = parse_bool(value, name, error_list);
diff --git a/configfile.h b/configfile.h
index 7beb4961..13504e77 100644
--- a/configfile.h
+++ b/configfile.h
@@ -88,6 +88,7 @@ typedef struct
char restore_command[MAXLEN];
TablespaceList tablespace_mapping;
char recovery_min_apply_delay[MAXLEN];
+ bool recovery_min_apply_delay_provided;
bool use_primary_conninfo_password;
/* node check settings */
@@ -152,7 +153,7 @@ typedef struct
/* log settings */ \
"", "", "", DEFAULT_LOG_STATUS_INTERVAL, \
/* standby action settings */ \
- false, "", "", { NULL, NULL }, "", false, \
+ false, "", "", { NULL, NULL }, "", false, false, \
/* node check settings */ \
DEFAULT_ARCHIVE_READY_WARNING, DEFAULT_ARCHIVE_READY_CRITICAL, \
DEFAULT_REPLICATION_LAG_WARNING, DEFAULT_REPLICATION_LAG_CRITICAL, \
diff --git a/configure b/configure
index 71c256d4..08d3eca4 100755
--- a/configure
+++ b/configure
@@ -1841,7 +1841,7 @@ if test "$major_version_num" -lt '10'; then
version_num_int=$(echo "$version_num"|
$SED -e 's/^\([0-9]*\)\.\([0-9]*\)$/\1\2/')
- if test "$version_num_int" -lt '94'; then
+ if test "$version_num_int" -lt '93'; then
as_fn_error $? "repmgr is not compatible with detected PostgreSQL version: $version_num" "$LINENO" 5
fi
else
diff --git a/configure.in b/configure.in
index 7f036c11..3fd4f30a 100644
--- a/configure.in
+++ b/configure.in
@@ -38,7 +38,7 @@ if test "$major_version_num" -lt '10'; then
version_num_int=$(echo "$version_num"|
$SED -e 's/^\([[0-9]]*\)\.\([[0-9]]*\)$/\1\2/')
- if test "$version_num_int" -lt '94'; then
+ if test "$version_num_int" -lt '93'; then
AC_MSG_ERROR([repmgr is not compatible with detected PostgreSQL version: $version_num])
fi
else
diff --git a/dbutils.c b/dbutils.c
index 00e02ecb..1cc83377 100644
--- a/dbutils.c
+++ b/dbutils.c
@@ -3619,10 +3619,6 @@ request_vote(PGconn *conn, t_node_info *this_node, t_node_info *other_node, int
"SELECT repmgr.request_vote(%i, %i)",
this_node->node_id,
electoral_term);
-/* "SELECT repmgr.request_vote(%i, '%X/%X'::pg_lsn)",
- this_node->node_id,
- (uint32) (last_wal_receive_lsn >> 32),
- (uint32) last_wal_receive_lsn);*/
res = PQexec(conn, query.data);
termPQExpBuffer(&query);
diff --git a/repmgr--4.0.sql b/repmgr--4.0.sql
index 8621d921..b84c87f3 100644
--- a/repmgr--4.0.sql
+++ b/repmgr--4.0.sql
@@ -23,6 +23,16 @@ CREATE TABLE repmgr.events (
details TEXT NULL
);
+DO $repmgr$
+DECLARE
+ DECLARE server_version_num INT;
+BEGIN
+ SELECT setting
+ FROM pg_catalog.pg_settings
+ WHERE name = 'server_version_num'
+ INTO server_version_num;
+ IF server_version_num >= 90400 THEN
+ EXECUTE $repmgr_func$
CREATE TABLE repmgr.monitoring_history (
primary_node_id INTEGER NOT NULL,
standby_node_id INTEGER NOT NULL,
@@ -32,7 +42,26 @@ CREATE TABLE repmgr.monitoring_history (
last_wal_standby_location PG_LSN,
replication_lag BIGINT NOT NULL,
apply_lag BIGINT NOT NULL
-);
+)
+ $repmgr_func$;
+ ELSE
+ EXECUTE $repmgr_func$
+CREATE TABLE repmgr.monitoring_history (
+ primary_node_id INTEGER NOT NULL,
+ standby_node_id INTEGER NOT NULL,
+ last_monitor_time TIMESTAMP WITH TIME ZONE NOT NULL,
+ last_apply_time TIMESTAMP WITH TIME ZONE,
+ last_wal_primary_location TEXT NOT NULL,
+ last_wal_standby_location TEXT,
+ replication_lag BIGINT NOT NULL,
+ apply_lag BIGINT NOT NULL
+)
+ $repmgr_func$;
+ END IF;
+END$repmgr$;
+
+
+
CREATE INDEX idx_monitoring_history_time
ON repmgr.monitoring_history (last_monitor_time, standby_node_id);
@@ -73,10 +102,33 @@ CREATE FUNCTION standby_get_last_updated()
/* failover functions */
+
+DO $repmgr$
+DECLARE
+ DECLARE server_version_num INT;
+BEGIN
+ SELECT setting
+ FROM pg_catalog.pg_settings
+ WHERE name = 'server_version_num'
+ INTO server_version_num;
+
+ IF server_version_num >= 90400 THEN
+ EXECUTE $repmgr_func$
CREATE FUNCTION request_vote(INT,INT)
RETURNS pg_lsn
AS 'MODULE_PATHNAME', 'request_vote'
LANGUAGE C STRICT;
+ $repmgr_func$;
+ ELSE
+ EXECUTE $repmgr_func$
+CREATE FUNCTION request_vote(INT,INT)
+ RETURNS TEXT
+ AS 'MODULE_PATHNAME', 'request_vote'
+ LANGUAGE C STRICT;
+ $repmgr_func$;
+ END IF;
+END$repmgr$;
+
CREATE FUNCTION get_voting_status()
RETURNS INT
diff --git a/repmgr-action-node.c b/repmgr-action-node.c
index dc604dfb..84d41b7d 100644
--- a/repmgr-action-node.c
+++ b/repmgr-action-node.c
@@ -1598,6 +1598,7 @@ do_node_rejoin(void)
t_node_info primary_node_record = T_NODE_INFO_INITIALIZER;
bool success = true;
+ int server_version_num = UNKNOWN_SERVER_VERSION_NUM;
/* check node is not actually running */
@@ -1646,6 +1647,12 @@ do_node_rejoin(void)
/* check provided upstream connection */
upstream_conn = establish_db_connection_by_params(&source_conninfo, true);
+ /* sanity-checks for 9.3 */
+ server_version_num = get_server_version(upstream_conn, NULL);
+
+ if (server_version_num < 90400)
+ check_93_config();
+
if (get_primary_node_record(upstream_conn, &primary_node_record) == false)
{
log_error(_("unable to retrieve primary node record"));
diff --git a/repmgr-action-standby.c b/repmgr-action-standby.c
index 8290b316..ecf6c76d 100644
--- a/repmgr-action-standby.c
+++ b/repmgr-action-standby.c
@@ -81,7 +81,6 @@ static bool check_upstream_config(PGconn *conn, int server_version_num, t_node_i
static void check_primary_standby_version_match(PGconn *conn, PGconn *primary_conn);
static void check_recovery_type(PGconn *conn);
-
static void initialise_direct_clone(t_node_info *node_record);
static int run_basebackup(t_node_info *node_record);
static int run_file_backup(t_node_info *node_record);
@@ -96,6 +95,11 @@ static void get_barman_property(char *dst, char *name, char *local_repmgr_direct
static int get_tablespace_data_barman(char *, TablespaceDataList *);
static char *make_barman_ssh_command(char *buf);
+static bool create_recovery_file(t_node_info *node_record, t_conninfo_param_list *recovery_conninfo, const char *data_dir);
+static void write_primary_conninfo(char *line, t_conninfo_param_list *param_list);
+static bool write_recovery_file_line(FILE *recovery_file, char *recovery_file_path, char *line);
+
+
static NodeStatus parse_node_status_is_shutdown_cleanly(const char *node_status_output, XLogRecPtr *checkPoint);
static CheckStatus parse_node_check_archiver(const char *node_check_output, int *files, int *threshold);
static CheckStatus parse_node_check_replication_lag(const char *node_check_output, int *seconds, int *threshold);
@@ -1539,6 +1543,7 @@ do_standby_follow(void)
RecordStatus record_status = RECORD_NOT_FOUND;
int timer = 0;
+ int server_version_num = UNKNOWN_SERVER_VERSION_NUM;
PQExpBufferData follow_output;
bool success = false;
@@ -1557,6 +1562,12 @@ do_standby_follow(void)
/* check this is a standby */
check_recovery_type(local_conn);
+ /* sanity-checks for 9.3 */
+ server_version_num = get_server_version(local_conn, NULL);
+
+ if (server_version_num < 90400)
+ check_93_config();
+
if (runtime_options.upstream_node_id != NO_UPSTREAM_NODE)
{
/* check not self! */
@@ -1677,13 +1688,11 @@ do_standby_follow(void)
initPQExpBuffer(&follow_output);
- success = do_standby_follow_internal(
- primary_conn,
+ success = do_standby_follow_internal(primary_conn,
&primary_node_record,
&follow_output);
- create_event_notification(
- primary_conn,
+ create_event_notification(primary_conn,
&config_file_options,
config_file_options.node_id,
"standby_follow",
@@ -1713,6 +1722,9 @@ do_standby_follow(void)
/*
* Perform the actuall "follow" operation; this is executed by
* "node rejoin" too.
+ *
+ * For PostgreSQL 9.3, ensure check_93_config() was called before calling
+ * this function.
*/
bool
do_standby_follow_internal(PGconn *primary_conn, t_node_info *primary_node_record, PQExpBufferData *output)
@@ -3098,6 +3110,10 @@ check_source_server()
}
}
+ /* disable configuration file options incompatible with 9.3 */
+ if (source_server_version_num < 90400)
+ check_93_config();
+
check_upstream_config(source_conn, source_server_version_num, &node_record, true);
}
@@ -3198,6 +3214,8 @@ check_source_server_via_barman()
* Perform sanity check on upstream server configuration before starting cloning
* process
*
+ * For PostreSQL 9.3, ensure check_93_config() is called before calling this.
+ *
* TODO:
* - check user is qualified to perform base backup
*/
@@ -3248,6 +3266,12 @@ check_upstream_config(PGconn *conn, int server_version_num, t_node_info *node_in
xlog_stream = false;
/* Check that WAL level is set correctly */
+ if (server_version_num < 90400)
+ {
+ i = guc_set(conn, "wal_level", "=", "hot_standby");
+ wal_error_message = _("parameter \"wal_level\" must be set to \"hot_standby\"");
+ }
+ else
{
char *levels_pre96[] = {
"hot_standby",
@@ -3272,12 +3296,12 @@ check_upstream_config(PGconn *conn, int server_version_num, t_node_info *node_in
if (server_version_num < 90600)
{
levels = (char **) levels_pre96;
- wal_error_message = _("parameter 'wal_level' must be set to 'hot_standby' or 'logical'");
+ wal_error_message = _("parameter \"wal_level\" must be set to \"hot_standby\" or \"logical\"");
}
else
{
levels = (char **) levels_96plus;
- wal_error_message = _("parameter 'wal_level' must be set to 'replica' or 'logical'");
+ wal_error_message = _("parameter \"wal_level\" must be set to \"replica\" or \"logical\"");
}
do
@@ -3596,57 +3620,64 @@ initialise_direct_clone(t_node_info *node_record)
if (config_file_options.tablespace_mapping.head != NULL)
{
- TablespaceListCell *cell = false;
- KeyValueList not_found = {NULL, NULL};
- int total = 0,
- matched = 0;
- bool success = false;
-
- for (cell = config_file_options.tablespace_mapping.head; cell; cell = cell->next)
+ if (server_version_num < 90400)
{
- char *old_dir_escaped = escape_string(source_conn, cell->old_dir);
- char name[MAXLEN] = "";
-
- success = get_tablespace_name_by_location(source_conn, old_dir_escaped, name);
- pfree(old_dir_escaped);
-
- if (success == true)
- {
- matched++;
- }
- else
- {
- key_value_list_set(
- ¬_found,
- cell->old_dir,
- "");
- }
-
- total++;
+ log_error(_("tablespace mapping not supported in PostgreSQL 9.3, ignoring"));
}
-
- if (not_found.head != NULL)
+ else
{
- PQExpBufferData detail;
- KeyValueListCell *kv_cell;
+ TablespaceListCell *cell = false;
+ KeyValueList not_found = {NULL, NULL};
+ int total = 0,
+ matched = 0;
+ bool success = false;
- log_error(_("%i of %i mapped tablespaces not found"),
- total - matched, total);
- initPQExpBuffer(&detail);
-
- for (kv_cell = not_found.head; kv_cell; kv_cell = kv_cell->next)
+ for (cell = config_file_options.tablespace_mapping.head; cell; cell = cell->next)
{
- appendPQExpBuffer(
- &detail,
- " %s\n", kv_cell->key);
+ char *old_dir_escaped = escape_string(source_conn, cell->old_dir);
+ char name[MAXLEN] = "";
+
+ success = get_tablespace_name_by_location(source_conn, old_dir_escaped, name);
+ pfree(old_dir_escaped);
+
+ if (success == true)
+ {
+ matched++;
+ }
+ else
+ {
+ key_value_list_set(¬_found,
+ cell->old_dir,
+ "");
+ }
+
+ total++;
}
- log_detail(_("following tablespaces not found:\n%s"),
- detail.data);
- termPQExpBuffer(&detail);
+ if (not_found.head != NULL)
+ {
+ PQExpBufferData detail;
+ KeyValueListCell *kv_cell;
- exit(ERR_BAD_CONFIG);
+ log_error(_("%i of %i mapped tablespaces not found"),
+ total - matched, total);
+
+ initPQExpBuffer(&detail);
+
+ for (kv_cell = not_found.head; kv_cell; kv_cell = kv_cell->next)
+ {
+ appendPQExpBuffer(
+ &detail,
+ " %s\n", kv_cell->key);
+ }
+
+ log_detail(_("following tablespaces not found:\n%s"),
+ detail.data);
+ termPQExpBuffer(&detail);
+
+ exit(ERR_BAD_CONFIG);
+ }
}
}
@@ -4751,6 +4782,225 @@ drop_replication_slot_if_exists(PGconn *conn, int node_id, char *slot_name)
}
+/*
+ * Creates a recovery.conf file for a standby
+ *
+ * A database connection pointer is required for escaping primary_conninfo
+ * parameters. When cloning from Barman and --no-upstream-connection ) this
+ * might not be available.
+ */
+bool
+create_recovery_file(t_node_info *node_record, t_conninfo_param_list *recovery_conninfo, const char *data_dir)
+{
+ FILE *recovery_file;
+ char recovery_file_path[MAXPGPATH] = "";
+ char line[MAXLEN] = "";
+ mode_t um;
+
+ maxpath_snprintf(recovery_file_path, "%s/%s", data_dir, RECOVERY_COMMAND_FILE);
+
+ /* Set umask to 0600 */
+ um = umask((~(S_IRUSR | S_IWUSR)) & (S_IRWXG | S_IRWXO));
+ recovery_file = fopen(recovery_file_path, "w");
+ umask(um);
+
+ if (recovery_file == NULL)
+ {
+ log_error(_("unable to create recovery.conf file at \"%s\""),
+ recovery_file_path);
+ log_detail("%s", strerror(errno));
+
+ return false;
+ }
+
+ log_debug("create_recovery_file(): creating \"%s\"...",
+ recovery_file_path);
+
+ /* standby_mode = 'on' */
+ maxlen_snprintf(line, "standby_mode = 'on'\n");
+
+ if (write_recovery_file_line(recovery_file, recovery_file_path, line) == false)
+ return false;
+
+ trim(line);
+ log_debug("recovery.conf: %s", line);
+
+ /* primary_conninfo = '...' */
+
+ /*
+ * the user specified --upstream-conninfo string - copy that
+ */
+ if (strlen(runtime_options.upstream_conninfo))
+ {
+ char *escaped = escape_recovery_conf_value(runtime_options.upstream_conninfo);
+
+ maxlen_snprintf(line, "primary_conninfo = '%s'\n",
+ escaped);
+ free(escaped);
+ }
+
+ /*
+ * otherwise use the conninfo inferred from the upstream connection and/or
+ * node record
+ */
+ else
+ {
+ write_primary_conninfo(line, recovery_conninfo);
+ }
+
+ if (write_recovery_file_line(recovery_file, recovery_file_path, line) == false)
+ return false;
+
+ trim(line);
+ log_debug("recovery.conf: %s", line);
+
+ /* recovery_target_timeline = 'latest' */
+ maxlen_snprintf(line, "recovery_target_timeline = 'latest'\n");
+
+ if (write_recovery_file_line(recovery_file, recovery_file_path, line) == false)
+ return false;
+
+ trim(line);
+ log_debug("recovery.conf: %s", line);
+
+ /* recovery_min_apply_delay = ... (optional) */
+ if (config_file_options.recovery_min_apply_delay_provided == true)
+ {
+ maxlen_snprintf(line, "recovery_min_apply_delay = %s\n",
+ config_file_options.recovery_min_apply_delay);
+ if (write_recovery_file_line(recovery_file, recovery_file_path, line) == false)
+ return false;
+
+ trim(line);
+ log_debug("recovery.conf: %s", line);
+ }
+
+ /* primary_slot_name = '...' (optional, for 9.4 and later) */
+ if (config_file_options.use_replication_slots)
+ {
+ maxlen_snprintf(line, "primary_slot_name = %s\n",
+ node_record->slot_name);
+ if (write_recovery_file_line(recovery_file, recovery_file_path, line) == false)
+ return false;
+
+ trim(line);
+ log_debug("recovery.conf: %s", line);
+ }
+
+ /*
+ * If restore_command is set, we use it as restore_command in
+ * recovery.conf
+ */
+ if (strcmp(config_file_options.restore_command, "") != 0)
+ {
+ maxlen_snprintf(line, "restore_command = '%s'\n",
+ config_file_options.restore_command);
+ if (write_recovery_file_line(recovery_file, recovery_file_path, line) == false)
+ return false;
+
+ trim(line);
+ log_debug("recovery.conf: %s", line);
+ }
+ fclose(recovery_file);
+
+ return true;
+}
+
+
+static bool
+write_recovery_file_line(FILE *recovery_file, char *recovery_file_path, char *line)
+{
+ if (fputs(line, recovery_file) == EOF)
+ {
+ log_error(_("unable to write to recovery file at \"%s\""), recovery_file_path);
+ fclose(recovery_file);
+ return false;
+ }
+
+ return true;
+}
+
+
+static void
+write_primary_conninfo(char *line, t_conninfo_param_list *param_list)
+{
+ PQExpBufferData conninfo_buf;
+ bool application_name_provided = false;
+ bool password_provided = false;
+ int c;
+ char *escaped = NULL;
+ t_conninfo_param_list env_conninfo;
+
+ initialize_conninfo_params(&env_conninfo, true);
+
+ initPQExpBuffer(&conninfo_buf);
+
+ for (c = 0; c < param_list->size && param_list->keywords[c] != NULL; c++)
+ {
+ /*
+ * Skip empty settings and ones which don't make any sense in
+ * recovery.conf
+ */
+ if (strcmp(param_list->keywords[c], "dbname") == 0 ||
+ strcmp(param_list->keywords[c], "replication") == 0 ||
+ (param_list->values[c] == NULL) ||
+ (param_list->values[c] != NULL && param_list->values[c][0] == '\0'))
+ continue;
+
+ /* only include "password" if explicitly requested */
+ if (strcmp(param_list->keywords[c], "password") == 0)
+ {
+ password_provided = true;
+ }
+
+ if (conninfo_buf.len != 0)
+ appendPQExpBufferChar(&conninfo_buf, ' ');
+
+ if (strcmp(param_list->keywords[c], "application_name") == 0)
+ application_name_provided = true;
+
+ appendPQExpBuffer(&conninfo_buf, "%s=", param_list->keywords[c]);
+ appendConnStrVal(&conninfo_buf, param_list->values[c]);
+ }
+
+ /* "application_name" not provided - default to repmgr node name */
+ if (application_name_provided == false)
+ {
+ if (strlen(config_file_options.node_name))
+ {
+ appendPQExpBuffer(&conninfo_buf, " application_name=");
+ appendConnStrVal(&conninfo_buf, config_file_options.node_name);
+ }
+ else
+ {
+ appendPQExpBuffer(&conninfo_buf, " application_name=repmgr");
+ }
+ }
+
+ /* no password provided explicitly */
+ if (password_provided == false)
+ {
+ if (config_file_options.use_primary_conninfo_password == true)
+ {
+ const char *password = param_get(&env_conninfo, "password");
+
+ if (password != NULL)
+ {
+ appendPQExpBuffer(&conninfo_buf, " password=");
+ appendConnStrVal(&conninfo_buf, password);
+ }
+ }
+ }
+
+ escaped = escape_recovery_conf_value(conninfo_buf.data);
+ maxlen_snprintf(line, "primary_conninfo = '%s'\n", escaped);
+
+ free(escaped);
+ free_conninfo_params(&env_conninfo);
+ termPQExpBuffer(&conninfo_buf);
+}
+
+
/* TODO: consolidate code in below functions */
static NodeStatus
parse_node_status_is_shutdown_cleanly(const char *node_status_output, XLogRecPtr *checkPoint)
diff --git a/repmgr-client-global.h b/repmgr-client-global.h
index 066dbec4..30018650 100644
--- a/repmgr-client-global.h
+++ b/repmgr-client-global.h
@@ -198,6 +198,7 @@ extern t_node_info target_node_info;
extern int check_server_version(PGconn *conn, char *server_type, bool exit_on_error, char *server_version_string);
+extern void check_93_config(void);
extern bool create_repmgr_extension(PGconn *conn);
extern int test_ssh_connection(char *host, char *remote_user);
extern bool local_command(const char *command, PQExpBufferData *outputbuf);
@@ -211,8 +212,6 @@ extern void print_error_list(ItemList *error_list, int log_level);
extern char *make_pg_path(const char *file);
-extern bool create_recovery_file(t_node_info *node_record, t_conninfo_param_list *recovery_conninfo, const char *data_dir);
-
extern void get_superuser_connection(PGconn **conn, PGconn **superuser_conn, PGconn **privileged_conn);
extern bool remote_command(const char *host, const char *user, const char *command, PQExpBufferData *outputbuf);
diff --git a/repmgr-client.c b/repmgr-client.c
index 0494ec51..4105758c 100644
--- a/repmgr-client.c
+++ b/repmgr-client.c
@@ -1998,6 +1998,30 @@ check_server_version(PGconn *conn, char *server_type, bool exit_on_error, char *
}
+
+/*
+ * check_93_config()
+ *
+ * Disable options not compatible with PostgreSQL 9.3
+ */
+void
+check_93_config(void)
+{
+ if (config_file_options.recovery_min_apply_delay_provided == true)
+ {
+ config_file_options.recovery_min_apply_delay_provided = false;
+ log_warning(_("configuration file option \"recovery_min_apply_delay\" not compatible with PostgreSQL 9.3, ignoring"));
+ }
+
+ if (config_file_options.use_replication_slots == true)
+ {
+ config_file_options.use_replication_slots = false;
+ log_warning(_("configuration file option \"use_replication_slots\" not compatible with PostgreSQL 9.3, ignoring"));
+ log_hint(_("replication slots are available from PostgreSQL 9.4"));
+ }
+}
+
+
int
test_ssh_connection(char *host, char *remote_user)
{
@@ -2272,223 +2296,6 @@ copy_remote_files(char *host, char *remote_user, char *remote_path,
-/*
- * Creates a recovery.conf file for a standby
- *
- * A database connection pointer is required for escaping primary_conninfo
- * parameters. When cloning from Barman and --no-upstream-connection ) this
- * might not be available.
- */
-bool
-create_recovery_file(t_node_info *node_record, t_conninfo_param_list *recovery_conninfo, const char *data_dir)
-{
- FILE *recovery_file;
- char recovery_file_path[MAXPGPATH] = "";
- char line[MAXLEN] = "";
- mode_t um;
-
- maxpath_snprintf(recovery_file_path, "%s/%s", data_dir, RECOVERY_COMMAND_FILE);
-
- /* Set umask to 0600 */
- um = umask((~(S_IRUSR | S_IWUSR)) & (S_IRWXG | S_IRWXO));
- recovery_file = fopen(recovery_file_path, "w");
- umask(um);
-
- if (recovery_file == NULL)
- {
- log_error(_("unable to create recovery.conf file at \"%s\""),
- recovery_file_path);
- log_detail("%s", strerror(errno));
-
- return false;
- }
-
- log_debug("create_recovery_file(): creating \"%s\"...",
- recovery_file_path);
-
- /* standby_mode = 'on' */
- maxlen_snprintf(line, "standby_mode = 'on'\n");
-
- if (write_recovery_file_line(recovery_file, recovery_file_path, line) == false)
- return false;
-
- trim(line);
- log_debug("recovery.conf: %s", line);
-
- /* primary_conninfo = '...' */
-
- /*
- * the user specified --upstream-conninfo string - copy that
- */
- if (strlen(runtime_options.upstream_conninfo))
- {
- char *escaped = escape_recovery_conf_value(runtime_options.upstream_conninfo);
-
- maxlen_snprintf(line, "primary_conninfo = '%s'\n",
- escaped);
- free(escaped);
- }
-
- /*
- * otherwise use the conninfo inferred from the upstream connection and/or
- * node record
- */
- else
- {
- write_primary_conninfo(line, recovery_conninfo);
- }
-
- if (write_recovery_file_line(recovery_file, recovery_file_path, line) == false)
- return false;
-
- trim(line);
- log_debug("recovery.conf: %s", line);
-
- /* recovery_target_timeline = 'latest' */
- maxlen_snprintf(line, "recovery_target_timeline = 'latest'\n");
-
- if (write_recovery_file_line(recovery_file, recovery_file_path, line) == false)
- return false;
-
- trim(line);
- log_debug("recovery.conf: %s", line);
-
- /* recovery_min_apply_delay = ... (optional) */
- if (*config_file_options.recovery_min_apply_delay)
- {
- maxlen_snprintf(line, "recovery_min_apply_delay = %s\n",
- config_file_options.recovery_min_apply_delay);
- if (write_recovery_file_line(recovery_file, recovery_file_path, line) == false)
- return false;
-
- trim(line);
- log_debug("recovery.conf: %s", line);
- }
-
- /* primary_slot_name = '...' (optional, for 9.4 and later) */
- if (config_file_options.use_replication_slots)
- {
- maxlen_snprintf(line, "primary_slot_name = %s\n",
- node_record->slot_name);
- if (write_recovery_file_line(recovery_file, recovery_file_path, line) == false)
- return false;
-
- trim(line);
- log_debug("recovery.conf: %s", line);
- }
-
- /*
- * If restore_command is set, we use it as restore_command in
- * recovery.conf
- */
- if (strcmp(config_file_options.restore_command, "") != 0)
- {
- maxlen_snprintf(line, "restore_command = '%s'\n",
- config_file_options.restore_command);
- if (write_recovery_file_line(recovery_file, recovery_file_path, line) == false)
- return false;
-
- trim(line);
- log_debug("recovery.conf: %s", line);
- }
- fclose(recovery_file);
-
- return true;
-}
-
-
-static bool
-write_recovery_file_line(FILE *recovery_file, char *recovery_file_path, char *line)
-{
- if (fputs(line, recovery_file) == EOF)
- {
- log_error(_("unable to write to recovery file at \"%s\""), recovery_file_path);
- fclose(recovery_file);
- return false;
- }
-
- return true;
-}
-
-
-static void
-write_primary_conninfo(char *line, t_conninfo_param_list *param_list)
-{
- PQExpBufferData conninfo_buf;
- bool application_name_provided = false;
- bool password_provided = false;
- int c;
- char *escaped = NULL;
- t_conninfo_param_list env_conninfo;
-
- initialize_conninfo_params(&env_conninfo, true);
-
- initPQExpBuffer(&conninfo_buf);
-
- for (c = 0; c < param_list->size && param_list->keywords[c] != NULL; c++)
- {
- /*
- * Skip empty settings and ones which don't make any sense in
- * recovery.conf
- */
- if (strcmp(param_list->keywords[c], "dbname") == 0 ||
- strcmp(param_list->keywords[c], "replication") == 0 ||
- (param_list->values[c] == NULL) ||
- (param_list->values[c] != NULL && param_list->values[c][0] == '\0'))
- continue;
-
- /* only include "password" if explicitly requested */
- if (strcmp(param_list->keywords[c], "password") == 0)
- {
- password_provided = true;
- }
-
- if (conninfo_buf.len != 0)
- appendPQExpBufferChar(&conninfo_buf, ' ');
-
- if (strcmp(param_list->keywords[c], "application_name") == 0)
- application_name_provided = true;
-
- appendPQExpBuffer(&conninfo_buf, "%s=", param_list->keywords[c]);
- appendConnStrVal(&conninfo_buf, param_list->values[c]);
- }
-
- /* "application_name" not provided - default to repmgr node name */
- if (application_name_provided == false)
- {
- if (strlen(config_file_options.node_name))
- {
- appendPQExpBuffer(&conninfo_buf, " application_name=");
- appendConnStrVal(&conninfo_buf, config_file_options.node_name);
- }
- else
- {
- appendPQExpBuffer(&conninfo_buf, " application_name=repmgr");
- }
- }
-
- /* no password provided explicitly */
- if (password_provided == false)
- {
- if (config_file_options.use_primary_conninfo_password == true)
- {
- const char *password = param_get(&env_conninfo, "password");
-
- if (password != NULL)
- {
- appendPQExpBuffer(&conninfo_buf, " password=");
- appendConnStrVal(&conninfo_buf, password);
- }
- }
- }
-
- escaped = escape_recovery_conf_value(conninfo_buf.data);
- maxlen_snprintf(line, "primary_conninfo = '%s'\n", escaped);
-
- free(escaped);
- free_conninfo_params(&env_conninfo);
- termPQExpBuffer(&conninfo_buf);
-}
/*
diff --git a/repmgr-client.h b/repmgr-client.h
index f53b1efc..aeeef397 100644
--- a/repmgr-client.h
+++ b/repmgr-client.h
@@ -204,7 +204,4 @@ static const char *action_name(const int action);
static void check_cli_parameters(const int action);
-static void write_primary_conninfo(char *line, t_conninfo_param_list *param_list);
-static bool write_recovery_file_line(FILE *recovery_file, char *recovery_file_path, char *line);
-
#endif /* _REPMGR_CLIENT_H_ */
diff --git a/repmgr.c b/repmgr.c
index af54ecaf..eabfcc81 100644
--- a/repmgr.c
+++ b/repmgr.c
@@ -20,6 +20,7 @@
* along with this program. If not, see .
*/
+
#include "postgres.h"
#include "fmgr.h"
#include "access/xlog.h"
@@ -31,7 +32,11 @@
#include "storage/shmem.h"
#include "storage/spin.h"
#include "utils/builtins.h"
+
+#if (PG_VERSION_NUM >= 90400)
#include "utils/pg_lsn.h"
+#endif
+
#include "utils/timestamp.h"
#include "executor/spi.h"
@@ -280,14 +285,24 @@ request_vote(PG_FUNCTION_ARGS)
{
#ifndef BDR_ONLY
StringInfoData query;
+
+#if (PG_VERSION_NUM >= 90400)
XLogRecPtr our_lsn = InvalidXLogRecPtr;
+ bool isnull;
+#else
+ char *value = NULL;
+ char lsn_text[64] = "";
+#endif
/* node_id used for logging purposes */
int requesting_node_id = PG_GETARG_INT32(0);
int current_electoral_term = PG_GETARG_INT32(1);
int ret;
- bool isnull;
+
+
+
+
if (!shared_state)
PG_RETURN_NULL();
@@ -326,17 +341,30 @@ request_vote(PG_FUNCTION_ARGS)
{
SPI_finish();
elog(WARNING, "unable to retrieve last received LSN");
+
+#if (PG_VERSION_NUM >= 90400)
PG_RETURN_LSN(InvalidOid);
+#else
+ PG_RETURN_TEXT_P(cstring_to_text("0/0"));
+#endif
}
+#if (PG_VERSION_NUM >= 90400)
our_lsn = DatumGetLSN(SPI_getbinval(SPI_tuptable->vals[0],
SPI_tuptable->tupdesc,
1, &isnull));
-
elog(DEBUG1, "our LSN is %X/%X",
(uint32) (our_lsn >> 32),
(uint32) our_lsn);
+#else
+ value = SPI_getvalue(SPI_tuptable->vals[0],
+ SPI_tuptable->tupdesc,
+ 1);
+ strncpy(lsn_text, value, 64);
+ pfree(value);
+ elog(DEBUG1, "our LSN is %s", lsn_text);
+#endif
/* indicate this node has responded to a vote request */
shared_state->voting_status = VS_VOTE_REQUEST_RECEIVED;
@@ -347,7 +375,11 @@ request_vote(PG_FUNCTION_ARGS)
/* should we free "query" here? */
SPI_finish();
+#if (PG_VERSION_NUM >= 90400)
PG_RETURN_LSN(our_lsn);
+#else
+ PG_RETURN_TEXT_P(cstring_to_text(lsn_text));
+#endif
#else
PG_RETURN(InvalidOid);
#endif
diff --git a/repmgr.h b/repmgr.h
index 5b5ec855..ff8f4022 100644
--- a/repmgr.h
+++ b/repmgr.h
@@ -26,6 +26,8 @@
#include
#include
+#include
+#include
#include
#include
@@ -39,8 +41,8 @@
#include "dbutils.h"
#include "log.h"
-#define MIN_SUPPORTED_VERSION "9.4"
-#define MIN_SUPPORTED_VERSION_NUM 90400
+#define MIN_SUPPORTED_VERSION "9.3"
+#define MIN_SUPPORTED_VERSION_NUM 90300
#define REPLICATION_TYPE_PHYSICAL 1
#define REPLICATION_TYPE_BDR 2