From d26989bd12d4d5c1375cb5b9af6fe5198fede130 Mon Sep 17 00:00:00 2001 From: Ian Barwick Date: Fri, 22 Jun 2018 11:44:56 +0900 Subject: [PATCH] node status: improve output and documentation In the default text output mode, list inactive slots. In CSV output mode, list inactive slots as additional information; add output line with number of missing slots and a list thereof. Also document --csv output mode. --- dbutils.c | 46 +++++++++++++++++++++++++++-- dbutils.h | 3 +- doc/repmgr-node-status.sgml | 16 +++++++++- repmgr-action-node.c | 58 +++++++++++++++++++++++++++++++++---- repmgr-action-standby.c | 2 +- 5 files changed, 113 insertions(+), 12 deletions(-) diff --git a/dbutils.c b/dbutils.c index fb038426..767fc13c 100644 --- a/dbutils.c +++ b/dbutils.c @@ -2917,8 +2917,7 @@ get_datadir_configuration_files(PGconn *conn, KeyValueList *list) for (i = 0; i < PQntuples(res); i++) { - key_value_list_set( - list, + key_value_list_set(list, PQgetvalue(res, i, 1), PQgetvalue(res, i, 0)); } @@ -3655,7 +3654,7 @@ get_slot_record(PGconn *conn, char *slot_name, t_replication_slot *record) int -get_free_replication_slots(PGconn *conn) +get_free_replication_slot_count(PGconn *conn) { PQExpBufferData query; PGresult *res = NULL; @@ -3692,6 +3691,47 @@ get_free_replication_slots(PGconn *conn) } +int +get_inactive_replication_slots(PGconn *conn, KeyValueList *list) +{ + PQExpBufferData query; + PGresult *res = NULL; + int i, inactive_slots = 0; + + initPQExpBuffer(&query); + + appendPQExpBuffer(&query, + " SELECT slot_name, slot_type " + " FROM pg_catalog.pg_replication_slots " + " WHERE active IS FALSE " + " ORDER BY slot_name "); + + res = PQexec(conn, query.data); + termPQExpBuffer(&query); + + if (PQresultStatus(res) != PGRES_TUPLES_OK) + { + log_error(_("unable to execute replication slot query")); + log_detail("%s", PQerrorMessage(conn)); + PQclear(res); + return -1; + } + + inactive_slots = PQntuples(res); + + for (i = 0; i < inactive_slots; i++) + { + key_value_list_set(list, + PQgetvalue(res, i, 0), + PQgetvalue(res, i, 1)); + } + + PQclear(res); + return inactive_slots; +} + + + /* ==================== */ /* tablespace functions */ /* ==================== */ diff --git a/dbutils.h b/dbutils.h index 461d4f55..c56024d4 100644 --- a/dbutils.h +++ b/dbutils.h @@ -455,7 +455,8 @@ void create_slot_name(char *slot_name, int node_id); bool create_replication_slot(PGconn *conn, char *slot_name, int server_version_num, PQExpBufferData *error_msg); bool drop_replication_slot(PGconn *conn, char *slot_name); RecordStatus get_slot_record(PGconn *conn, char *slot_name, t_replication_slot *record); -int get_free_replication_slots(PGconn *conn); +int get_free_replication_slot_count(PGconn *conn); +int get_inactive_replication_slots(PGconn *conn, KeyValueList *list); /* tablespace functions */ bool get_tablespace_name_by_location(PGconn *conn, const char *location, char *name); diff --git a/doc/repmgr-node-status.sgml b/doc/repmgr-node-status.sgml index e44d29b3..c7474e67 100644 --- a/doc/repmgr-node-status.sgml +++ b/doc/repmgr-node-status.sgml @@ -24,7 +24,7 @@ Example - $ repmgr -f /etc/repmgr.comf node status + $ repmgr -f /etc/repmgr.conf node status Node "node1": PostgreSQL version: 10beta1 Total data size: 30 MB @@ -38,6 +38,20 @@ + + Output format + + + + + + --csv: generate output in CSV format + + + + + + See also diff --git a/repmgr-action-node.c b/repmgr-action-node.c index 2792536b..e7356f8a 100644 --- a/repmgr-action-node.c +++ b/repmgr-action-node.c @@ -71,6 +71,7 @@ do_node_status(void) KeyValueList node_status = {NULL, NULL}; KeyValueListCell *cell = NULL; + NodeInfoList missing_slots = T_NODE_INFO_LIST_INITIALIZER; ItemList warnings = {NULL, NULL}; RecoveryType recovery_type = RECTYPE_UNKNOWN; @@ -265,7 +266,6 @@ do_node_status(void) else { PQExpBufferData slotinfo; - NodeInfoList missing_slots = T_NODE_INFO_LIST_INITIALIZER; /* * check for missing replication slots - we do this regardless of @@ -305,6 +305,11 @@ do_node_status(void) if (node_info.inactive_replication_slots > 0) { + KeyValueList inactive_replication_slots = {NULL, NULL}; + KeyValueListCell *cell = NULL; + + (void) get_inactive_replication_slots(conn, &inactive_replication_slots); + appendPQExpBuffer(&slotinfo, "; %i inactive", node_info.inactive_replication_slots); @@ -312,6 +317,14 @@ do_node_status(void) item_list_append_format(&warnings, _("- node has %i inactive replication slots"), node_info.inactive_replication_slots); + + for (cell = inactive_replication_slots.head; cell; cell = cell->next) + { + item_list_append_format(&warnings, + " - %s (%s)", cell->key, cell->value); + } + + key_value_list_free(&inactive_replication_slots); } key_value_list_set(&node_status, @@ -415,10 +428,44 @@ do_node_status(void) "\"active_replication_slots\",%i\n", node_info.active_replication_slots); + /* output inactive slot information */ appendPQExpBuffer(&output, - "\"inactive_replaction_slots\",%i\n", + "\"inactive_replication_slots\",%i", node_info.inactive_replication_slots); + if (node_info.inactive_replication_slots) + { + KeyValueList inactive_replication_slots = {NULL, NULL}; + KeyValueListCell *cell = NULL; + + (void) get_inactive_replication_slots(conn, &inactive_replication_slots); + for (cell = inactive_replication_slots.head; cell; cell = cell->next) + { + appendPQExpBuffer(&output, + ",\"%s\"", cell->key); + } + + key_value_list_free(&inactive_replication_slots); + } + + /* output missing slot information */ + + appendPQExpBuffer(&output, "\n"); + appendPQExpBuffer(&output, + "\"missing_replication_slots\",%i", + missing_slots.node_count); + + if (missing_slots.node_count > 0) + { + NodeInfoListCell *missing_slot_cell = NULL; + + for (missing_slot_cell = missing_slots.head; missing_slot_cell; missing_slot_cell = missing_slot_cell->next) + { + appendPQExpBuffer(&output, + ",\"%s\"", missing_slot_cell->node_info->slot_name); + } + } + } else { @@ -439,12 +486,11 @@ do_node_status(void) termPQExpBuffer(&output); - if (warnings.head != NULL && runtime_options.terse == false) + if (runtime_options.output_mode == OM_TEXT && warnings.head != NULL && runtime_options.terse == false) { log_warning(_("following issue(s) were detected:")); print_item_list(&warnings); - /* add this when functionality implemented */ - /* log_hint(_("execute \"repmgr node check\" for more details")); */ + log_hint(_("execute \"repmgr node check\" for more details")); } key_value_list_free(&node_status); @@ -1337,7 +1383,7 @@ do_node_check_replication_lag(PGconn *conn, OutputMode mode, t_node_info *node_i return status; } -/* TODO: ensure only runs on streaming replication nodes */ + static CheckStatus do_node_check_downstream(PGconn *conn, OutputMode mode, CheckStatusList *list_output) { diff --git a/repmgr-action-standby.c b/repmgr-action-standby.c index 4c94be7a..1931115f 100644 --- a/repmgr-action-standby.c +++ b/repmgr-action-standby.c @@ -2257,7 +2257,7 @@ do_standby_follow(void) if (config_file_options.use_replication_slots) { - int free_slots = get_free_replication_slots(primary_conn); + int free_slots = get_free_replication_slot_count(primary_conn); if (free_slots < 0) { log_error(_("unable to determine number of free replication slots on the primary"));