From 2339adba6c2ae5d00a67c375d1e6ac6df7aebe21 Mon Sep 17 00:00:00 2001 From: Ian Barwick Date: Fri, 6 Mar 2015 18:39:36 +0900 Subject: [PATCH] Fix event logging when cloning from another standby We can only write to the primary, which we'll need to find seperately when cloning from a standby. --- dbutils.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ dbutils.h | 3 ++ repmgr.c | 34 +++++++++++++++++++--- 3 files changed, 118 insertions(+), 4 deletions(-) diff --git a/dbutils.c b/dbutils.c index 4d207913..87be06f8 100644 --- a/dbutils.c +++ b/dbutils.c @@ -409,6 +409,88 @@ get_pg_setting(PGconn *conn, const char *setting, char *output) } + +/* + * get_primary_connection() + * + * Returns connection to cluster's primary node + * + * This assumes that the primary node information in `repl_nodes` + * is correct. See get_master_connection(), which polls all known + * servers to find out which one is currently primary. + */ +PGconn * +get_primary_connection(PGconn *standby_conn, char *cluster, + int *primary_node_id_ptr, char *primary_conninfo_out) +{ + PGconn *primary_conn = NULL; + PGresult *res; + char sqlquery[QUERY_STR_LEN]; + char primary_conninfo_stack[MAXCONNINFO]; + char *primary_conninfo = &*primary_conninfo_stack; + + /* + * If the caller wanted to get a copy of the connection info string, sub + * out the local stack pointer for the pointer passed by the caller. + */ + if (primary_conninfo_out != NULL) + primary_conninfo = primary_conninfo_out; + + sqlquery_snprintf(sqlquery, + " SELECT n.conninfo, n.name, n.id " + " FROM %s.repl_nodes n " + " WHERE n.cluster = '%s' " + " AND n.type = 'primary' ", + get_repmgr_schema_quoted(standby_conn), + cluster); + + log_debug("get_primary_connection(): %s\n", sqlquery); + + res = PQexec(standby_conn, sqlquery); + + if (PQresultStatus(res) != PGRES_TUPLES_OK) + { + log_err(_("Unable to get conninfo for primary server: %s\n"), + PQerrorMessage(standby_conn)); + PQclear(res); + return NULL; + } + + if(!PQntuples(res)) + { + log_notice(_("No primary server record found")); + PQclear(res); + return NULL; + } + + strncpy(primary_conninfo, PQgetvalue(res, 0, 0), MAXCONNINFO); + + if(primary_node_id_ptr != NULL) + *primary_node_id_ptr = atoi(PQgetvalue(res, 0, 1)); + + PQclear(res); + + log_debug("conninfo is: '%s'\n", primary_conninfo); + primary_conn = establish_db_connection(primary_conninfo, false); + + if (PQstatus(primary_conn) != CONNECTION_OK) + { + log_err(_("Unable to connect to primary node: %s\n"), + PQerrorMessage(primary_conn)); + return NULL; + } + + return primary_conn; +} + + +/* + * get_upstream_connection() + * + * Returns connection to node's upstream node + * + * NOTE: will attempt to connect even if node is marked as inactive + */ PGconn * get_upstream_connection(PGconn *standby_conn, char *cluster, int node_id, int *upstream_node_id_ptr, char *upstream_conninfo_out) @@ -485,6 +567,9 @@ get_upstream_connection(PGconn *standby_conn, char *cluster, int node_id, * NB: If master_conninfo_out may be NULL. If it is non-null, it is assumed to * point to allocated memory of MAXCONNINFO in length, and the master server * connection string is placed there. + * + * To get the primary node from the metadata (i.e. without polling all servers), + * use `get_primary_connection()`. */ PGconn * diff --git a/dbutils.h b/dbutils.h index 8f8da3fe..c7664ea3 100644 --- a/dbutils.h +++ b/dbutils.h @@ -42,6 +42,9 @@ int guc_set_typed(PGconn *conn, const char *parameter, const char *op, const char *value, const char *datatype); +PGconn *get_primary_connection(PGconn *standby_conn, char *cluster, + int *primary_node_id_ptr, + char *primary_conninfo_out); PGconn *get_upstream_connection(PGconn *standby_conn, char *cluster, int node_id, int *upstream_node_id_ptr, diff --git a/repmgr.c b/repmgr.c index d369fb34..0ab2e181 100644 --- a/repmgr.c +++ b/repmgr.c @@ -77,6 +77,7 @@ static bool write_recovery_file_line(FILE *recovery_file, char *recovery_file_pa static int check_server_version(PGconn *conn, char *server_type, bool exit_on_error, char *server_version_string); static bool check_upstream_config(PGconn *conn, int server_version_num, bool exit_on_error); static char *make_pg_path(char *file); +static bool log_event(PGconn *standby_conn, bool success, char *details); static void do_master_register(void); static void do_standby_register(void); @@ -929,6 +930,7 @@ do_standby_clone(void) { PGconn *upstream_conn; PGresult *res; + char sqlquery[QUERY_STR_LEN]; int server_version_num; @@ -1516,16 +1518,19 @@ stop_backup: /* Add details about relevant runtime options used */ appendPQExpBuffer(&event_details, - _("Backup method: %s"), + _("Cloned from host '%s', port %s"), + runtime_options.host, + runtime_options.masterport); + + appendPQExpBuffer(&event_details, + _("; backup method: %s"), runtime_options.rsync_only ? "rsync" : "pg_basebackup"); appendPQExpBuffer(&event_details, _("; --force: %s"), runtime_options.force ? "Y" : "N"); - record_created = create_event_record(upstream_conn, - options.node, - "standby_clone", + record_created = log_event(upstream_conn, true, event_details.data); //destroyPQExpBuffer(&event_details); @@ -1540,6 +1545,27 @@ stop_backup: } +static bool +log_event(PGconn *standby_conn, bool success, char *details) +{ + PGconn *primary_conn; + bool retval; + + primary_conn = get_primary_connection(standby_conn, + options.cluster_name, + NULL, NULL); + + retval = create_event_record(primary_conn, + options.node, + "standby_clone", + success, + details); + PQfinish(primary_conn); + + return retval; +} + + static void do_standby_promote(void) {