1 /*
2  * dbutils.h
3  *
4  * Copyright (c) 2ndQuadrant, 2010-2020
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #ifndef _REPMGR_DBUTILS_H_
21 #define _REPMGR_DBUTILS_H_
22 
23 #include "access/timeline.h"
24 #include "access/xlogdefs.h"
25 #include "pqexpbuffer.h"
26 #include "portability/instr_time.h"
27 
28 #include "configfile.h"
29 #include "strutil.h"
30 #include "voting.h"
31 
32 #define REPMGR_NODES_COLUMNS \
33 	"n.node_id, " \
34 	"n.type, " \
35 	"n.upstream_node_id, " \
36 	"n.node_name,  " \
37 	"n.conninfo, " \
38 	"n.repluser, " \
39 	"n.slot_name, " \
40 	"n.location, " \
41 	"n.priority, " \
42 	"n.active, " \
43 	"n.config_file, " \
44 	"'' AS upstream_node_name, " \
45 	"NULL AS attached "
46 
47 #define REPMGR_NODES_COLUMNS_WITH_UPSTREAM \
48 	"n.node_id, " \
49 	"n.type, " \
50 	"n.upstream_node_id, " \
51 	"n.node_name, " \
52 	"n.conninfo, " \
53 	"n.repluser, " \
54 	"n.slot_name, " \
55 	"n.location, " \
56 	"n.priority, " \
57 	"n.active, "\
58 	"n.config_file, " \
59 	"un.node_name AS upstream_node_name, " \
60 	"NULL AS attached "
61 
62 
63 #define ERRBUFF_SIZE 512
64 
65 typedef enum
66 {
67 	UNKNOWN = 0,
68 	PRIMARY,
69 	STANDBY,
70 	WITNESS
71 } t_server_type;
72 
73 typedef enum
74 {
75 	REPMGR_INSTALLED = 0,
76 	REPMGR_OLD_VERSION_INSTALLED,
77 	REPMGR_AVAILABLE,
78 	REPMGR_UNAVAILABLE,
79 	REPMGR_UNKNOWN
80 } ExtensionStatus;
81 
82 typedef enum
83 {
84 	RECTYPE_UNKNOWN = -1,
85 	RECTYPE_PRIMARY,
86 	RECTYPE_STANDBY
87 } RecoveryType;
88 
89 typedef enum
90 {
91 	RECORD_ERROR = -1,
92 	RECORD_FOUND,
93 	RECORD_NOT_FOUND
94 } RecordStatus;
95 
96 typedef enum
97 {
98 	MS_NORMAL = 0,
99 	MS_DEGRADED = 1
100 } MonitoringState;
101 
102 typedef enum
103 {
104 	NODE_STATUS_UNKNOWN = -1,
105 	NODE_STATUS_UP,
106 	NODE_STATUS_SHUTTING_DOWN,
107 	NODE_STATUS_DOWN,
108 	NODE_STATUS_UNCLEAN_SHUTDOWN,
109 	NODE_STATUS_REJECTED
110 } NodeStatus;
111 
112 typedef enum
113 {
114 	CONN_UNKNOWN = -1,
115 	CONN_OK,
116 	CONN_BAD,
117 	CONN_ERROR
118 } ConnectionStatus;
119 
120 typedef enum
121 {
122 	/* unable to query "pg_stat_replication" or other error */
123 	NODE_ATTACHED_UNKNOWN = -1,
124 	/* node has record in "pg_stat_replication" and state is not "streaming" */
125 	NODE_ATTACHED,
126 	/* node has record in "pg_stat_replication" but state is not "streaming" */
127 	NODE_NOT_ATTACHED,
128 	/* node has no record in "pg_stat_replication" */
129 	NODE_DETACHED
130 } NodeAttached;
131 
132 typedef enum
133 {
134 	SLOT_UNKNOWN = -1,
135 	SLOT_NOT_FOUND,
136 	SLOT_NOT_PHYSICAL,
137 	SLOT_INACTIVE,
138 	SLOT_ACTIVE
139 } ReplSlotStatus;
140 
141 typedef enum
142 {
143 	BACKUP_STATE_UNKNOWN = -1,
144 	BACKUP_STATE_IN_BACKUP,
145 	BACKUP_STATE_NO_BACKUP
146 } BackupState;
147 
148 
149 
150 /*
151  * Struct to store extension version information
152  */
153 
154 typedef struct s_extension_versions {
155 	char		default_version[8];
156 	int			default_version_num;
157 	char		installed_version[8];
158 	int			installed_version_num;
159 } t_extension_versions;
160 
161 #define T_EXTENSION_VERSIONS_INITIALIZER { \
162 	"", \
163 	UNKNOWN_SERVER_VERSION_NUM, \
164 	"", \
165 	UNKNOWN_SERVER_VERSION_NUM \
166 }
167 
168 
169 typedef struct
170 {
171 	char		current_timestamp[MAXLEN];
172 	bool		in_recovery;
173 	TimeLineID	timeline_id;
174 	char		timeline_id_str[MAXLEN];
175 	XLogRecPtr	last_wal_receive_lsn;
176 	XLogRecPtr	last_wal_replay_lsn;
177 	char		last_xact_replay_timestamp[MAXLEN];
178 	int			replication_lag_time;
179 	bool		receiving_streamed_wal;
180 	bool		wal_replay_paused;
181 	int			upstream_last_seen;
182 	int			upstream_node_id;
183 } ReplInfo;
184 
185 /*
186  * Struct to store node information.
187  *
188  * The first section represents the contents of the "repmgr.nodes"
189  * table; subsequent section contain information collated in
190  * various contexts.
191  */
192 typedef struct s_node_info
193 {
194 	/* contents of "repmgr.nodes" */
195 	int			node_id;
196 	int			upstream_node_id;
197 	t_server_type type;
198 	char		node_name[NAMEDATALEN];
199 	char		upstream_node_name[NAMEDATALEN];
200 	char		conninfo[MAXLEN];
201 	char		repluser[NAMEDATALEN];
202 	char		location[MAXLEN];
203 	int			priority;
204 	bool		active;
205 	char		slot_name[MAXLEN];
206 	char		config_file[MAXPGPATH];
207 	/* used during failover to track node status */
208 	XLogRecPtr	last_wal_receive_lsn;
209 	NodeStatus	node_status;
210 	RecoveryType recovery_type;
211 	MonitoringState monitoring_state;
212 	PGconn	   *conn;
213 	/* for ad-hoc use e.g. when working with a list of nodes */
214 	char		details[MAXLEN];
215 	bool		reachable;
216 	NodeAttached attached;
217 	/* various statistics */
218 	int			max_wal_senders;
219 	int			attached_wal_receivers;
220 	int			max_replication_slots;
221 	int			total_replication_slots;
222 	int			active_replication_slots;
223 	int			inactive_replication_slots;
224 	/* replication info */
225 	ReplInfo   *replication_info;
226 } t_node_info;
227 
228 
229 #define T_NODE_INFO_INITIALIZER { \
230    	/* contents of "repmgr.nodes" */ \
231 	NODE_NOT_FOUND, \
232 	NO_UPSTREAM_NODE, \
233 	UNKNOWN, \
234 	"", \
235 	"", \
236 	"", \
237 	"", \
238 	DEFAULT_LOCATION, \
239 	DEFAULT_PRIORITY, \
240 	true, \
241 	"", \
242 	"", \
243 	/* used during failover to track node status */ \
244 	InvalidXLogRecPtr, \
245 	NODE_STATUS_UNKNOWN, \
246 	RECTYPE_UNKNOWN,  \
247 	MS_NORMAL, \
248 	NULL, \
249 	/* for ad-hoc use e.g. when working with a list of nodes */ \
250 	"", true, true,	\
251 	/* various statistics */ \
252 	-1, -1, -1, -1, -1, -1,	\
253 	NULL \
254 }
255 
256 
257 /* structs to store a list of repmgr node records */
258 typedef struct NodeInfoListCell
259 {
260 	struct NodeInfoListCell *next;
261 	t_node_info *node_info;
262 } NodeInfoListCell;
263 
264 typedef struct NodeInfoList
265 {
266 	NodeInfoListCell *head;
267 	NodeInfoListCell *tail;
268 	int			node_count;
269 } NodeInfoList;
270 
271 #define T_NODE_INFO_LIST_INITIALIZER { \
272 	NULL, \
273 	NULL, \
274 	0 \
275 }
276 
277 typedef struct s_event_info
278 {
279 	char	   *node_name;
280 	char	   *conninfo_str;
281 	int			node_id;
282 } t_event_info;
283 
284 #define T_EVENT_INFO_INITIALIZER { \
285 	NULL, \
286 	NULL, \
287 	UNKNOWN_NODE_ID \
288 }
289 
290 
291 /*
292  * Struct to store list of conninfo keywords and values
293  */
294 typedef struct
295 {
296 	int			size;
297 	char	  **keywords;
298 	char	  **values;
299 } t_conninfo_param_list;
300 
301 #define T_CONNINFO_PARAM_LIST_INITIALIZER { \
302 	0, \
303 	NULL, \
304 	NULL, \
305 }
306 
307 /*
308  * Struct to store replication slot information
309  */
310 typedef struct s_replication_slot
311 {
312 	char		slot_name[MAXLEN];
313 	char		slot_type[MAXLEN];
314 	bool		active;
315 } t_replication_slot;
316 
317 #define T_REPLICATION_SLOT_INITIALIZER { "", "", false }
318 
319 
320 typedef struct s_connection_user
321 {
322 	char		username[MAXLEN];
323 	bool		is_superuser;
324 } t_connection_user;
325 
326 #define T_CONNECTION_USER_INITIALIZER { "", false }
327 
328 
329 typedef struct
330 {
331 	char		filepath[MAXPGPATH];
332 	char		filename[MAXPGPATH];
333 	bool		in_data_directory;
334 } t_configfile_info;
335 
336 #define T_CONFIGFILE_INFO_INITIALIZER { "", "", false }
337 
338 
339 typedef struct
340 {
341 	int			size;
342 	int			entries;
343 	t_configfile_info **files;
344 } t_configfile_list;
345 
346 #define T_CONFIGFILE_LIST_INITIALIZER { 0, 0, NULL }
347 
348 
349 typedef struct
350 {
351 	uint64		system_identifier;
352 	TimeLineID	timeline;
353 	XLogRecPtr	xlogpos;
354 } t_system_identification;
355 
356 #define T_SYSTEM_IDENTIFICATION_INITIALIZER { \
357     UNKNOWN_SYSTEM_IDENTIFIER, \
358     UNKNOWN_TIMELINE_ID, \
359 	InvalidXLogRecPtr \
360 }
361 
362 
363 typedef struct RepmgrdInfo {
364 	int node_id;
365 	int pid;
366 	char pid_text[MAXLEN];
367 	char pid_file[MAXLEN];
368 	bool pg_running;
369 	char pg_running_text[MAXLEN];
370 	RecoveryType recovery_type;
371 	bool running;
372 	char repmgrd_running[MAXLEN];
373 	bool paused;
374 	bool wal_paused_pending_wal;
375 	int  upstream_last_seen;
376 	char upstream_last_seen_text[MAXLEN];
377 } RepmgrdInfo;
378 
379 
380 /* macros */
381 
382 #define is_streaming_replication(x) (x == PRIMARY || x == STANDBY)
383 #define format_lsn(x) (uint32) (x >> 32), (uint32) x
384 
385 /* utility functions */
386 
387 XLogRecPtr	parse_lsn(const char *str);
388 bool		atobool(const char *value);
389 
390 /* connection functions */
391 PGconn	   *establish_db_connection(const char *conninfo,
392 						const bool exit_on_error);
393 PGconn	   *establish_db_connection_quiet(const char *conninfo);
394 PGconn	   *establish_db_connection_by_params(t_conninfo_param_list *param_list,
395 								  const bool exit_on_error);
396 PGconn	   *establish_db_connection_with_replacement_param(const char *conninfo,
397 														   const char *param,
398 														   const char *value,
399 														   const bool exit_on_error);
400 PGconn	   *establish_replication_connection_from_conn(PGconn *conn, const char *repluser);
401 PGconn	   *establish_replication_connection_from_conninfo(const char *conninfo, const char *repluser);
402 
403 PGconn	   *establish_primary_db_connection(PGconn *conn,
404 								const bool exit_on_error);
405 PGconn	   *get_primary_connection(PGconn *standby_conn, int *primary_id, char *primary_conninfo_out);
406 PGconn	   *get_primary_connection_quiet(PGconn *standby_conn, int *primary_id, char *primary_conninfo_out);
407 PGconn	   *duplicate_connection(PGconn *conn, const char *user, bool replication);
408 
409 void		close_connection(PGconn **conn);
410 
411 /* conninfo manipulation functions */
412 bool		get_conninfo_value(const char *conninfo, const char *keyword, char *output);
413 bool		get_conninfo_default_value(const char *param, char *output, int maxlen);
414 void		initialize_conninfo_params(t_conninfo_param_list *param_list, bool set_defaults);
415 void		free_conninfo_params(t_conninfo_param_list *param_list);
416 void		copy_conninfo_params(t_conninfo_param_list *dest_list, t_conninfo_param_list *source_list);
417 void		conn_to_param_list(PGconn *conn, t_conninfo_param_list *param_list);
418 void		param_set(t_conninfo_param_list *param_list, const char *param, const char *value);
419 void		param_set_ine(t_conninfo_param_list *param_list, const char *param, const char *value);
420 char	   *param_get(t_conninfo_param_list *param_list, const char *param);
421 bool		validate_conninfo_string(const char *conninfo_str, char **errmsg);
422 bool		parse_conninfo_string(const char *conninfo_str, t_conninfo_param_list *param_list, char **errmsg, bool ignore_local_params);
423 char	   *param_list_to_string(t_conninfo_param_list *param_list);
424 char	   *normalize_conninfo_string(const char *conninfo_str);
425 bool		has_passfile(void);
426 
427 
428 /* transaction functions */
429 bool		begin_transaction(PGconn *conn);
430 bool		commit_transaction(PGconn *conn);
431 bool		rollback_transaction(PGconn *conn);
432 
433 /* GUC manipulation functions */
434 bool		set_config(PGconn *conn, const char *config_param, const char *config_value);
435 bool		set_config_bool(PGconn *conn, const char *config_param, bool state);
436 int		    guc_set(PGconn *conn, const char *parameter, const char *op, const char *value);
437 bool		get_pg_setting(PGconn *conn, const char *setting, char *output);
438 bool		get_pg_setting_bool(PGconn *conn, const char *setting, bool *output);
439 bool		get_pg_setting_int(PGconn *conn, const char *setting, int *output);
440 bool		alter_system_int(PGconn *conn, const char *name, int value);
441 bool		pg_reload_conf(PGconn *conn);
442 
443 /* server information functions */
444 bool		get_cluster_size(PGconn *conn, char *size);
445 int			get_server_version(PGconn *conn, char *server_version_buf);
446 
447 RecoveryType get_recovery_type(PGconn *conn);
448 int			get_primary_node_id(PGconn *conn);
449 int			get_ready_archive_files(PGconn *conn, const char *data_directory);
450 bool		identify_system(PGconn *repl_conn, t_system_identification *identification);
451 uint64		system_identifier(PGconn *conn);
452 TimeLineHistoryEntry *get_timeline_history(PGconn *repl_conn, TimeLineID tli);
453 
454 /* user/role information functions */
455 bool		can_execute_pg_promote(PGconn *conn);
456 bool		connection_has_pg_monitor_role(PGconn *conn, const char *subrole);
457 bool		is_replication_role(PGconn *conn, char *rolname);
458 bool		is_superuser_connection(PGconn *conn, t_connection_user *userinfo);
459 
460 /* repmgrd shared memory functions */
461 bool		repmgrd_set_local_node_id(PGconn *conn, int local_node_id);
462 int			repmgrd_get_local_node_id(PGconn *conn);
463 bool		repmgrd_check_local_node_id(PGconn *conn);
464 BackupState	server_in_exclusive_backup_mode(PGconn *conn);
465 void		repmgrd_set_pid(PGconn *conn, pid_t repmgrd_pid, const char *pidfile);
466 pid_t		repmgrd_get_pid(PGconn *conn);
467 bool		repmgrd_is_running(PGconn *conn);
468 bool		repmgrd_is_paused(PGconn *conn);
469 bool		repmgrd_pause(PGconn *conn, bool pause);
470 pid_t		get_wal_receiver_pid(PGconn *conn);
471 int			repmgrd_get_upstream_node_id(PGconn *conn);
472 bool		repmgrd_set_upstream_node_id(PGconn *conn, int node_id);
473 
474 /* extension functions */
475 ExtensionStatus get_repmgr_extension_status(PGconn *conn, t_extension_versions *extversions);
476 
477 /* node management functions */
478 void		checkpoint(PGconn *conn);
479 bool		vacuum_table(PGconn *conn, const char *table);
480 bool		promote_standby(PGconn *conn, bool wait, int wait_seconds);
481 bool		resume_wal_replay(PGconn *conn);
482 
483 /* node record functions */
484 t_server_type parse_node_type(const char *type);
485 const char *get_node_type_string(t_server_type type);
486 
487 RecordStatus get_node_record(PGconn *conn, int node_id, t_node_info *node_info);
488 RecordStatus refresh_node_record(PGconn *conn, int node_id, t_node_info *node_info);
489 
490 RecordStatus get_node_record_with_upstream(PGconn *conn, int node_id, t_node_info *node_info);
491 
492 RecordStatus get_node_record_by_name(PGconn *conn, const char *node_name, t_node_info *node_info);
493 t_node_info *get_node_record_pointer(PGconn *conn, int node_id);
494 
495 bool		get_local_node_record(PGconn *conn, int node_id, t_node_info *node_info);
496 bool		get_primary_node_record(PGconn *conn, t_node_info *node_info);
497 
498 bool		get_all_node_records(PGconn *conn, NodeInfoList *node_list);
499 bool		get_all_nodes_count(PGconn *conn, int *count);
500 void		get_downstream_node_records(PGconn *conn, int node_id, NodeInfoList *nodes);
501 void		get_active_sibling_node_records(PGconn *conn, int node_id, int upstream_node_id, NodeInfoList *node_list);
502 bool		get_child_nodes(PGconn *conn, int node_id, NodeInfoList *node_list);
503 void		get_node_records_by_priority(PGconn *conn, NodeInfoList *node_list);
504 bool		get_all_node_records_with_upstream(PGconn *conn, NodeInfoList *node_list);
505 bool		get_downstream_nodes_with_missing_slot(PGconn *conn, int this_node_id, NodeInfoList *noede_list);
506 
507 bool		create_node_record(PGconn *conn, char *repmgr_action, t_node_info *node_info);
508 bool		update_node_record(PGconn *conn, char *repmgr_action, t_node_info *node_info);
509 bool		delete_node_record(PGconn *conn, int node);
510 bool		truncate_node_records(PGconn *conn);
511 
512 bool		update_node_record_set_active(PGconn *conn, int this_node_id, bool active);
513 bool		update_node_record_set_primary(PGconn *conn, int this_node_id);
514 bool		update_node_record_set_active_standby(PGconn *conn, int this_node_id);
515 bool		update_node_record_set_upstream(PGconn *conn, int this_node_id, int new_upstream_node_id);
516 bool		update_node_record_status(PGconn *conn, int this_node_id, char *type, int upstream_node_id, bool active);
517 bool		update_node_record_conn_priority(PGconn *conn, t_configuration_options *options);
518 bool		update_node_record_slot_name(PGconn *primary_conn, int node_id, char *slot_name);
519 
520 bool		witness_copy_node_records(PGconn *primary_conn, PGconn *witness_conn);
521 
522 void		clear_node_info_list(NodeInfoList *nodes);
523 
524 /* PostgreSQL configuration file location functions */
525 bool		get_datadir_configuration_files(PGconn *conn, KeyValueList *list);
526 bool		get_configuration_file_locations(PGconn *conn, t_configfile_list *list);
527 void		config_file_list_init(t_configfile_list *list, int max_size);
528 void		config_file_list_add(t_configfile_list *list, const char *file, const char *filename, bool in_data_dir);
529 
530 /* event functions */
531 bool		create_event_record(PGconn *conn, t_configuration_options *options, int node_id, char *event, bool successful, char *details);
532 bool		create_event_notification(PGconn *conn, t_configuration_options *options, int node_id, char *event, bool successful, char *details);
533 bool		create_event_notification_extended(PGconn *conn, t_configuration_options *options, int node_id, char *event, bool successful, char *details, t_event_info *event_info);
534 PGresult   *get_event_records(PGconn *conn, int node_id, const char *node_name, const char *event, bool all, int limit);
535 
536 /* replication slot functions */
537 void		create_slot_name(char *slot_name, int node_id);
538 
539 bool		create_replication_slot_sql(PGconn *conn, char *slot_name, PQExpBufferData *error_msg);
540 bool		create_replication_slot_replprot(PGconn *conn, PGconn *repl_conn, char *slot_name, PQExpBufferData *error_msg);
541 bool		drop_replication_slot_sql(PGconn *conn, char *slot_name);
542 bool		drop_replication_slot_replprot(PGconn *repl_conn, char *slot_name);
543 
544 RecordStatus get_slot_record(PGconn *conn, char *slot_name, t_replication_slot *record);
545 int			get_free_replication_slot_count(PGconn *conn, int *max_replication_slots);
546 int			get_inactive_replication_slots(PGconn *conn, KeyValueList *list);
547 
548 /* tablespace functions */
549 bool		get_tablespace_name_by_location(PGconn *conn, const char *location, char *name);
550 
551 /* asynchronous query functions */
552 bool		cancel_query(PGconn *conn, int timeout);
553 int			wait_connection_availability(PGconn *conn, int timeout);
554 
555 /* node availability functions */
556 bool		is_server_available(const char *conninfo);
557 bool		is_server_available_quiet(const char *conninfo);
558 bool		is_server_available_params(t_conninfo_param_list *param_list);
559 ExecStatusType	connection_ping(PGconn *conn);
560 ExecStatusType	connection_ping_reconnect(PGconn *conn);
561 
562 /* monitoring functions  */
563 void
564 add_monitoring_record(PGconn *primary_conn,
565 					  PGconn *local_conn,
566 					  int primary_node_id,
567 					  int local_node_id,
568 					  char *monitor_standby_timestamp,
569 					  XLogRecPtr primary_last_wal_location,
570 					  XLogRecPtr last_wal_receive_lsn,
571 					  char *last_xact_replay_timestamp,
572 					  long long unsigned int replication_lag_bytes,
573 					  long long unsigned int apply_lag_bytes
574 );
575 
576 int			get_number_of_monitoring_records_to_delete(PGconn *primary_conn, int keep_history, int node_id);
577 bool		delete_monitoring_records(PGconn *primary_conn, int keep_history, int node_id);
578 
579 
580 
581 /* node voting functions */
582 void		initialize_voting_term(PGconn *conn);
583 int			get_current_term(PGconn *conn);
584 void		increment_current_term(PGconn *conn);
585 bool		announce_candidature(PGconn *conn, t_node_info *this_node, t_node_info *other_node, int electoral_term);
586 void		notify_follow_primary(PGconn *conn, int primary_node_id);
587 bool		get_new_primary(PGconn *conn, int *primary_node_id);
588 void		reset_voting_status(PGconn *conn);
589 
590 /* replication status functions */
591 XLogRecPtr	get_primary_current_lsn(PGconn *conn);
592 XLogRecPtr	get_node_current_lsn(PGconn *conn);
593 XLogRecPtr	get_last_wal_receive_location(PGconn *conn);
594 void		init_replication_info(ReplInfo *replication_info);
595 bool		get_replication_info(PGconn *conn, t_server_type node_type, ReplInfo *replication_info);
596 int			get_replication_lag_seconds(PGconn *conn);
597 TimeLineID	get_node_timeline(PGconn *conn, char *timeline_id_str);
598 void		get_node_replication_stats(PGconn *conn, t_node_info *node_info);
599 NodeAttached is_downstream_node_attached(PGconn *conn, char *node_name, char **node_state);
600 void		set_upstream_last_seen(PGconn *conn, int upstream_node_id);
601 int			get_upstream_last_seen(PGconn *conn, t_server_type node_type);
602 
603 bool		is_wal_replay_paused(PGconn *conn, bool check_pending_wal);
604 
605 /* miscellaneous debugging functions */
606 const char *print_node_status(NodeStatus node_status);
607 const char *print_pqping_status(PGPing ping_status);
608 
609 #endif							/* _REPMGR_DBUTILS_H_ */
610