diff --git a/dbutils.c b/dbutils.c index edb0b367..12f7b2d0 100644 --- a/dbutils.c +++ b/dbutils.c @@ -1255,7 +1255,7 @@ get_primary_node_id(PGconn *conn) initPQExpBuffer(&query); appendPQExpBuffer(&query, "SELECT node_id " - " FROM repmgr.nodes " + " FROM repmgr.nodes " " WHERE type = 'primary' " " AND active IS TRUE "); @@ -1866,8 +1866,8 @@ get_node_record(PGconn *conn, int node_id, t_node_info *node_info) initPQExpBuffer(&query); appendPQExpBuffer(&query, "SELECT " REPMGR_NODES_COLUMNS - " FROM repmgr.nodes " - " WHERE node_id = %i", + " FROM repmgr.nodes n " + " WHERE n.node_id = %i", node_id); log_verbose(LOG_DEBUG, "get_node_record():\n %s", query.data); @@ -1894,8 +1894,8 @@ get_node_record_by_name(PGconn *conn, const char *node_name, t_node_info *node_i appendPQExpBuffer(&query, "SELECT " REPMGR_NODES_COLUMNS - " FROM repmgr.nodes " - " WHERE node_name = '%s' ", + " FROM repmgr.nodes n " + " WHERE n.node_name = '%s' ", node_name); log_verbose(LOG_DEBUG, "get_node_record_by_name():\n %s", query.data); @@ -2020,8 +2020,8 @@ get_all_node_records(PGconn *conn, NodeInfoList *node_list) appendPQExpBuffer(&query, " SELECT " REPMGR_NODES_COLUMNS - " FROM repmgr.nodes " - "ORDER BY node_id "); + " FROM repmgr.nodes n " + "ORDER BY n.node_id "); log_verbose(LOG_DEBUG, "get_all_node_records():\n%s", query.data); @@ -2046,9 +2046,9 @@ get_downstream_node_records(PGconn *conn, int node_id, NodeInfoList *node_list) appendPQExpBuffer(&query, " SELECT " REPMGR_NODES_COLUMNS - " FROM repmgr.nodes " - " WHERE upstream_node_id = %i " - "ORDER BY node_id ", + " FROM repmgr.nodes n " + " WHERE n.upstream_node_id = %i " + "ORDER BY n.node_id ", node_id); log_verbose(LOG_DEBUG, "get_downstream_node_records():\n%s", query.data); @@ -2075,11 +2075,11 @@ get_active_sibling_node_records(PGconn *conn, int node_id, int upstream_node_id, appendPQExpBuffer(&query, " SELECT " REPMGR_NODES_COLUMNS - " FROM repmgr.nodes " - " WHERE upstream_node_id = %i " - " AND node_id != %i " - " AND active IS TRUE " - "ORDER BY node_id ", + " FROM repmgr.nodes n " + " WHERE n.upstream_node_id = %i " + " AND n.node_id != %i " + " AND n.active IS TRUE " + "ORDER BY n.node_id ", upstream_node_id, node_id); @@ -2107,8 +2107,8 @@ get_node_records_by_priority(PGconn *conn, NodeInfoList *node_list) appendPQExpBuffer(&query, " SELECT " REPMGR_NODES_COLUMNS - " FROM repmgr.nodes " - "ORDER BY priority DESC, node_name "); + " FROM repmgr.nodes n " + "ORDER BY n.priority DESC, n.node_name "); log_verbose(LOG_DEBUG, "get_node_records_by_priority():\n%s", query.data); @@ -2166,6 +2166,44 @@ get_all_node_records_with_upstream(PGconn *conn, NodeInfoList *node_list) +bool +get_downsteam_nodes_with_missing_slot(PGconn *conn, int this_node_id, NodeInfoList *node_list) +{ + PQExpBufferData query; + PGresult *res = NULL; + + initPQExpBuffer(&query); + + appendPQExpBuffer(&query, + " SELECT " REPMGR_NODES_COLUMNS + " FROM repmgr.nodes n " + "LEFT JOIN pg_catalog.pg_replication_slots rs " + " ON rs.slot_name = n.node_name " + " WHERE rs.slot_name IS NULL " + " AND n.node_id != %i ", + this_node_id); + + log_verbose(LOG_DEBUG, "get_all_node_records_with_missing_slot():\n%s", query.data); + + res = PQexec(conn, query.data); + + termPQExpBuffer(&query); + + if (PQresultStatus(res) != PGRES_TUPLES_OK) + { + log_error(_("unable to retrieve node records")); + log_detail("%s", PQerrorMessage(conn)); + PQclear(res); + return false; + } + + _populate_node_records(res, node_list); + + PQclear(res); + + return true; +} + bool create_node_record(PGconn *conn, char *repmgr_action, t_node_info *node_info) { @@ -4308,8 +4346,8 @@ is_bdr_repmgr(PGconn *conn) appendPQExpBuffer(&query, "SELECT COUNT(*)" - " FROM repmgr.nodes" - " WHERE type != 'bdr' "); + " FROM repmgr.nodes n" + " WHERE n.type != 'bdr' "); res = PQexec(conn, query.data); termPQExpBuffer(&query); @@ -4478,9 +4516,9 @@ get_bdr_other_node_name(PGconn *conn, int node_id, char *node_name) initPQExpBuffer(&query); appendPQExpBuffer(&query, - " SELECT node_name " - " FROM repmgr.nodes " - " WHERE node_id != %i", + " SELECT n.node_name " + " FROM repmgr.nodes n " + " WHERE n.node_id != %i", node_id); log_verbose(LOG_DEBUG, "get_bdr_other_node_name():\n %s", query.data); diff --git a/dbutils.h b/dbutils.h index 95e8abd0..6a9b5a47 100644 --- a/dbutils.h +++ b/dbutils.h @@ -28,7 +28,7 @@ #include "strutil.h" #include "voting.h" -#define REPMGR_NODES_COLUMNS "node_id, type, upstream_node_id, node_name, conninfo, repluser, slot_name, location, priority, active, config_file, '' AS upstream_node_name " +#define REPMGR_NODES_COLUMNS "n.node_id, n.type, n.upstream_node_id, n.node_name, n.conninfo, n.repluser, n.slot_name, n.location, n.priority, n.active, n.config_file, '' AS upstream_node_name " #define BDR_NODES_COLUMNS "node_sysid, node_timeline, node_dboid, node_status, node_name, node_local_dsn, node_init_from_dsn, node_read_only, node_seq_id" #define ERRBUFF_SIZE 512 @@ -419,6 +419,7 @@ void get_downstream_node_records(PGconn *conn, int node_id, NodeInfoList *nodes void get_active_sibling_node_records(PGconn *conn, int node_id, int upstream_node_id, NodeInfoList *node_list); void get_node_records_by_priority(PGconn *conn, NodeInfoList *node_list); bool get_all_node_records_with_upstream(PGconn *conn, NodeInfoList *node_list); +bool get_downsteam_nodes_with_missing_slot(PGconn *conn, int this_node_id, NodeInfoList *noede_list); bool create_node_record(PGconn *conn, char *repmgr_action, t_node_info *node_info); bool update_node_record(PGconn *conn, char *repmgr_action, t_node_info *node_info); diff --git a/repmgr-action-node.c b/repmgr-action-node.c index 329872fa..a1485e90 100644 --- a/repmgr-action-node.c +++ b/repmgr-action-node.c @@ -250,8 +250,7 @@ do_node_status(void) if (node_info.max_wal_senders >= 0) { /* In CSV mode, raw values supplied as well */ - key_value_list_set_format( - &node_status, + key_value_list_set_format(&node_status, "Replication connections", "%i (of maximal %i)", node_info.attached_wal_receivers, @@ -259,8 +258,7 @@ do_node_status(void) } else if (node_info.max_wal_senders == 0) { - key_value_list_set_format( - &node_status, + key_value_list_set_format(&node_status, "Replication connections", "disabled"); } @@ -277,8 +275,7 @@ do_node_status(void) initPQExpBuffer(&slotinfo); - appendPQExpBuffer( - &slotinfo, + appendPQExpBuffer(&slotinfo, "%i (of maximal %i)", node_info.active_replication_slots + node_info.inactive_replication_slots, node_info.max_replication_slots); @@ -290,8 +287,7 @@ do_node_status(void) "; %i inactive", node_info.inactive_replication_slots); - item_list_append_format( - &warnings, + item_list_append_format(&warnings, _("- node has %i inactive replication slots"), node_info.inactive_replication_slots); } @@ -310,6 +306,37 @@ do_node_status(void) } + /* + * check for missing replication slots - we do this regardless of + * what "max_replication_slots" is set to + */ + + { + NodeInfoList missing_slots = T_NODE_INFO_LIST_INITIALIZER; + get_downsteam_nodes_with_missing_slot(conn, + config_file_options.node_id, + &missing_slots); + + if (missing_slots.node_count > 0) + { + NodeInfoListCell *missing_slot_cell = NULL; + + item_list_append_format(&warnings, + _("- replication slots missing for following %i node(s):"), + missing_slots.node_count); + + for (missing_slot_cell = missing_slots.head; missing_slot_cell; missing_slot_cell = missing_slot_cell->next) + { + item_list_append_format(&warnings, + _(" - %s (ID: %i, slot name: \"%s\")"), + missing_slot_cell->node_info->node_name, + missing_slot_cell->node_info->node_id, + missing_slot_cell->node_info->slot_name); + } + } + } + + if (node_info.type == STANDBY) { key_value_list_set_format(&node_status,