mirror of
https://github.com/EnterpriseDB/repmgr.git
synced 2026-03-27 17:06:29 +00:00
pgindent run
This commit is contained in:
1
compat.c
1
compat.c
@@ -104,4 +104,3 @@ appendShellString(PQExpBuffer buf, const char *str)
|
|||||||
|
|
||||||
appendPQExpBufferChar(buf, '\'');
|
appendPQExpBufferChar(buf, '\'');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
6
compat.h
6
compat.h
@@ -23,10 +23,8 @@
|
|||||||
#ifndef _COMPAT_H_
|
#ifndef _COMPAT_H_
|
||||||
#define _COMPAT_H_
|
#define _COMPAT_H_
|
||||||
|
|
||||||
extern void
|
extern void appendConnStrVal(PQExpBuffer buf, const char *str);
|
||||||
appendConnStrVal(PQExpBuffer buf, const char *str);
|
|
||||||
|
|
||||||
extern void
|
extern void appendShellString(PQExpBuffer buf, const char *str);
|
||||||
appendShellString(PQExpBuffer buf, const char *str);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
100
configfile.c
100
configfile.c
@@ -63,10 +63,10 @@ load_config(const char *config_file, bool verbose, bool terse, t_configuration_o
|
|||||||
struct stat stat_config;
|
struct stat stat_config;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If a configuration file was provided, check it exists, otherwise
|
* If a configuration file was provided, check it exists, otherwise emit
|
||||||
* emit an error and terminate. We assume that if a user explicitly
|
* an error and terminate. We assume that if a user explicitly provides a
|
||||||
* provides a configuration file, they'll want to make sure it's
|
* configuration file, they'll want to make sure it's used and not fall
|
||||||
* used and not fall back to any of the defaults.
|
* back to any of the defaults.
|
||||||
*/
|
*/
|
||||||
if (config_file != NULL && config_file[0] != '\0')
|
if (config_file != NULL && config_file[0] != '\0')
|
||||||
{
|
{
|
||||||
@@ -92,18 +92,19 @@ load_config(const char *config_file, bool verbose, bool terse, t_configuration_o
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*-----------
|
||||||
* If no configuration file was provided, attempt to find a default file
|
* If no configuration file was provided, attempt to find a default file
|
||||||
* in this order:
|
* in this order:
|
||||||
* - current directory
|
* - current directory
|
||||||
* - /etc/repmgr.conf
|
* - /etc/repmgr.conf
|
||||||
* - default sysconfdir
|
* - default sysconfdir
|
||||||
*
|
*
|
||||||
* here we just check for the existence of the file; parse_config()
|
* here we just check for the existence of the file; parse_config() will
|
||||||
* will handle read errors etc.
|
* handle read errors etc.
|
||||||
*
|
*
|
||||||
* XXX modify this section so package maintainers can provide a patch
|
* XXX modify this section so package maintainers can provide a patch
|
||||||
* specifying location of a distribution-specific configuration file
|
* specifying location of a distribution-specific configuration file
|
||||||
|
*-----------
|
||||||
*/
|
*/
|
||||||
if (config_file_provided == false)
|
if (config_file_provided == false)
|
||||||
{
|
{
|
||||||
@@ -159,7 +160,7 @@ load_config(const char *config_file, bool verbose, bool terse, t_configuration_o
|
|||||||
goto end_search;
|
goto end_search;
|
||||||
}
|
}
|
||||||
|
|
||||||
end_search:
|
end_search:
|
||||||
if (config_file_found == true)
|
if (config_file_found == true)
|
||||||
{
|
{
|
||||||
if (verbose == true)
|
if (verbose == true)
|
||||||
@@ -186,8 +187,8 @@ void
|
|||||||
parse_config(t_configuration_options *options, bool terse)
|
parse_config(t_configuration_options *options, bool terse)
|
||||||
{
|
{
|
||||||
/* Collate configuration file errors here for friendlier reporting */
|
/* Collate configuration file errors here for friendlier reporting */
|
||||||
static ItemList config_errors = { NULL, NULL };
|
static ItemList config_errors = {NULL, NULL};
|
||||||
static ItemList config_warnings = { NULL, NULL };
|
static ItemList config_warnings = {NULL, NULL};
|
||||||
|
|
||||||
_parse_config(options, &config_errors, &config_warnings);
|
_parse_config(options, &config_errors, &config_warnings);
|
||||||
|
|
||||||
@@ -273,7 +274,8 @@ _parse_config(t_configuration_options *options, ItemList *error_list, ItemList *
|
|||||||
/* default to 6 reconnection attempts at intervals of 10 seconds */
|
/* default to 6 reconnection attempts at intervals of 10 seconds */
|
||||||
options->reconnect_attempts = DEFAULT_RECONNECTION_ATTEMPTS;
|
options->reconnect_attempts = DEFAULT_RECONNECTION_ATTEMPTS;
|
||||||
options->reconnect_interval = DEFAULT_RECONNECTION_INTERVAL;
|
options->reconnect_interval = DEFAULT_RECONNECTION_INTERVAL;
|
||||||
options->monitoring_history = false; /* new in 4.0, replaces --monitoring-history */
|
options->monitoring_history = false; /* new in 4.0, replaces
|
||||||
|
* --monitoring-history */
|
||||||
options->degraded_monitoring_timeout = -1;
|
options->degraded_monitoring_timeout = -1;
|
||||||
options->async_query_timeout = DEFAULT_ASYNC_QUERY_TIMEOUT;
|
options->async_query_timeout = DEFAULT_ASYNC_QUERY_TIMEOUT;
|
||||||
options->primary_notification_timeout = DEFAULT_PRIMARY_NOTIFICATION_TIMEOUT;
|
options->primary_notification_timeout = DEFAULT_PRIMARY_NOTIFICATION_TIMEOUT;
|
||||||
@@ -333,9 +335,9 @@ _parse_config(t_configuration_options *options, ItemList *error_list, ItemList *
|
|||||||
fp = fopen(config_file_path, "r");
|
fp = fopen(config_file_path, "r");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A configuration file has been found, either provided by the user
|
* A configuration file has been found, either provided by the user or
|
||||||
* or found in one of the default locations. If we can't open it,
|
* found in one of the default locations. If we can't open it, fail with
|
||||||
* fail with an error.
|
* an error.
|
||||||
*/
|
*/
|
||||||
if (fp == NULL)
|
if (fp == NULL)
|
||||||
{
|
{
|
||||||
@@ -387,7 +389,7 @@ _parse_config(t_configuration_options *options, ItemList *error_list, ItemList *
|
|||||||
strncpy(options->replication_user, value, NAMEDATALEN);
|
strncpy(options->replication_user, value, NAMEDATALEN);
|
||||||
else
|
else
|
||||||
item_list_append(error_list,
|
item_list_append(error_list,
|
||||||
_( "value for \"replication_user\" must contain fewer than " STR(NAMEDATALEN) " characters"));
|
_("value for \"replication_user\" must contain fewer than " STR(NAMEDATALEN) " characters"));
|
||||||
}
|
}
|
||||||
else if (strcmp(name, "pg_bindir") == 0)
|
else if (strcmp(name, "pg_bindir") == 0)
|
||||||
strncpy(options->pg_bindir, value, MAXPGPATH);
|
strncpy(options->pg_bindir, value, MAXPGPATH);
|
||||||
@@ -524,7 +526,10 @@ _parse_config(t_configuration_options *options, ItemList *error_list, ItemList *
|
|||||||
else if (strcmp(name, "promote_delay") == 0)
|
else if (strcmp(name, "promote_delay") == 0)
|
||||||
options->promote_delay = repmgr_atoi(value, name, error_list, 1);
|
options->promote_delay = repmgr_atoi(value, name, error_list, 1);
|
||||||
|
|
||||||
/* Following parameters have been deprecated or renamed from 3.x - issue a warning */
|
/*
|
||||||
|
* Following parameters have been deprecated or renamed from 3.x -
|
||||||
|
* issue a warning
|
||||||
|
*/
|
||||||
else if (strcmp(name, "cluster") == 0)
|
else if (strcmp(name, "cluster") == 0)
|
||||||
{
|
{
|
||||||
item_list_append(warning_list,
|
item_list_append(warning_list,
|
||||||
@@ -578,14 +583,18 @@ _parse_config(t_configuration_options *options, ItemList *error_list, ItemList *
|
|||||||
known_parameter = false;
|
known_parameter = false;
|
||||||
log_warning(_("%s/%s: unknown name/value pair provided; ignoring"), name, value);
|
log_warning(_("%s/%s: unknown name/value pair provided; ignoring"), name, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Raise an error if a known parameter is provided with an empty value.
|
* Raise an error if a known parameter is provided with an empty
|
||||||
* Currently there's no reason why empty parameters are needed; if
|
* value. Currently there's no reason why empty parameters are needed;
|
||||||
* we want to accept those, we'd need to add stricter default checking,
|
* if we want to accept those, we'd need to add stricter default
|
||||||
* as currently e.g. an empty `node` value will be converted to '0'.
|
* checking, as currently e.g. an empty `node` value will be converted
|
||||||
|
* to '0'.
|
||||||
*/
|
*/
|
||||||
if (known_parameter == true && !strlen(value)) {
|
if (known_parameter == true && !strlen(value))
|
||||||
|
{
|
||||||
char error_message_buf[MAXLEN] = "";
|
char error_message_buf[MAXLEN] = "";
|
||||||
|
|
||||||
maxlen_snprintf(error_message_buf,
|
maxlen_snprintf(error_message_buf,
|
||||||
_("\"%s\": no value provided"),
|
_("\"%s\": no value provided"),
|
||||||
name);
|
name);
|
||||||
@@ -618,10 +627,11 @@ _parse_config(t_configuration_options *options, ItemList *error_list, ItemList *
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Sanity check the provided conninfo string
|
/*
|
||||||
|
* Sanity check the provided conninfo string
|
||||||
*
|
*
|
||||||
* NOTE: PQconninfoParse() verifies the string format and checks for valid options
|
* NOTE: PQconninfoParse() verifies the string format and checks for
|
||||||
* but does not sanity check values
|
* valid options but does not sanity check values
|
||||||
*/
|
*/
|
||||||
|
|
||||||
PQconninfoOption *conninfo_options = NULL;
|
PQconninfoOption *conninfo_options = NULL;
|
||||||
@@ -631,6 +641,7 @@ _parse_config(t_configuration_options *options, ItemList *error_list, ItemList *
|
|||||||
if (conninfo_options == NULL)
|
if (conninfo_options == NULL)
|
||||||
{
|
{
|
||||||
char error_message_buf[MAXLEN] = "";
|
char error_message_buf[MAXLEN] = "";
|
||||||
|
|
||||||
snprintf(error_message_buf,
|
snprintf(error_message_buf,
|
||||||
MAXLEN,
|
MAXLEN,
|
||||||
_("\"conninfo\": %s (provided: \"%s\")"),
|
_("\"conninfo\": %s (provided: \"%s\")"),
|
||||||
@@ -662,7 +673,7 @@ _parse_config(t_configuration_options *options, ItemList *error_list, ItemList *
|
|||||||
_("\archive_ready_critical\" must be greater than \"archive_ready_warning\""));
|
_("\archive_ready_critical\" must be greater than \"archive_ready_warning\""));
|
||||||
}
|
}
|
||||||
|
|
||||||
if( options->replication_lag_warning >= options->replication_lag_critical)
|
if (options->replication_lag_warning >= options->replication_lag_critical)
|
||||||
{
|
{
|
||||||
item_list_append(error_list,
|
item_list_append(error_list,
|
||||||
_("\replication_lag_critical\" must be greater than \"replication_lag_warning\""));
|
_("\replication_lag_critical\" must be greater than \"replication_lag_warning\""));
|
||||||
@@ -780,7 +791,7 @@ _parse_line(char *buf, char *name, char *value)
|
|||||||
if (buf[i] == '=')
|
if (buf[i] == '=')
|
||||||
break;
|
break;
|
||||||
|
|
||||||
switch(buf[i])
|
switch (buf[i])
|
||||||
{
|
{
|
||||||
/* Ignore whitespace */
|
/* Ignore whitespace */
|
||||||
case ' ':
|
case ' ':
|
||||||
@@ -799,9 +810,9 @@ _parse_line(char *buf, char *name, char *value)
|
|||||||
*/
|
*/
|
||||||
for (; i < MAXLEN; ++i)
|
for (; i < MAXLEN; ++i)
|
||||||
{
|
{
|
||||||
if (buf[i+1] == ' ')
|
if (buf[i + 1] == ' ')
|
||||||
continue;
|
continue;
|
||||||
if (buf[i+1] == '\t')
|
if (buf[i + 1] == '\t')
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -912,8 +923,8 @@ reload_config(t_configuration_options *orig_options)
|
|||||||
bool config_changed = false;
|
bool config_changed = false;
|
||||||
bool log_config_changed = false;
|
bool log_config_changed = false;
|
||||||
|
|
||||||
static ItemList config_errors = { NULL, NULL };
|
static ItemList config_errors = {NULL, NULL};
|
||||||
static ItemList config_warnings = { NULL, NULL };
|
static ItemList config_warnings = {NULL, NULL};
|
||||||
|
|
||||||
log_info(_("reloading configuration file"));
|
log_info(_("reloading configuration file"));
|
||||||
|
|
||||||
@@ -980,7 +991,7 @@ reload_config(t_configuration_options *orig_options)
|
|||||||
/* conninfo */
|
/* conninfo */
|
||||||
if (strcmp(orig_options->conninfo, new_options.conninfo) != 0)
|
if (strcmp(orig_options->conninfo, new_options.conninfo) != 0)
|
||||||
{
|
{
|
||||||
/* Test conninfo string works*/
|
/* Test conninfo string works */
|
||||||
conn = establish_db_connection(new_options.conninfo, false);
|
conn = establish_db_connection(new_options.conninfo, false);
|
||||||
if (!conn || (PQstatus(conn) != CONNECTION_OK))
|
if (!conn || (PQstatus(conn) != CONNECTION_OK))
|
||||||
{
|
{
|
||||||
@@ -1234,7 +1245,8 @@ repmgr_atoi(const char *value, const char *config_item, ItemList *error_list, in
|
|||||||
|
|
||||||
initPQExpBuffer(&errors);
|
initPQExpBuffer(&errors);
|
||||||
|
|
||||||
/* It's possible that some versions of strtol() don't treat an empty
|
/*
|
||||||
|
* It's possible that some versions of strtol() don't treat an empty
|
||||||
* string as an error.
|
* string as an error.
|
||||||
*/
|
*/
|
||||||
if (*value == '\0')
|
if (*value == '\0')
|
||||||
@@ -1253,14 +1265,14 @@ repmgr_atoi(const char *value, const char *config_item, ItemList *error_list, in
|
|||||||
_("\"%s\": invalid value (provided: \"%s\")"),
|
_("\"%s\": invalid value (provided: \"%s\")"),
|
||||||
config_item, value);
|
config_item, value);
|
||||||
}
|
}
|
||||||
else if ((int32)longval < longval)
|
else if ((int32) longval < longval)
|
||||||
{
|
{
|
||||||
appendPQExpBuffer(&errors,
|
appendPQExpBuffer(&errors,
|
||||||
_("\"%s\": must be a positive signed 32 bit integer, i.e. 2147483647 or less (provided: \"%s\")"),
|
_("\"%s\": must be a positive signed 32 bit integer, i.e. 2147483647 or less (provided: \"%s\")"),
|
||||||
config_item,
|
config_item,
|
||||||
value);
|
value);
|
||||||
}
|
}
|
||||||
else if ((int32)longval < minval)
|
else if ((int32) longval < minval)
|
||||||
/* Disallow negative values for most parameters */
|
/* Disallow negative values for most parameters */
|
||||||
{
|
{
|
||||||
appendPQExpBuffer(&errors,
|
appendPQExpBuffer(&errors,
|
||||||
@@ -1510,13 +1522,14 @@ parse_pg_basebackup_options(const char *pg_basebackup_options, t_basebackup_opti
|
|||||||
char *options_string_ptr = NULL;
|
char *options_string_ptr = NULL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Add parsed options to this list, then copy to an array
|
* Add parsed options to this list, then copy to an array to pass to
|
||||||
* to pass to getopt
|
* getopt
|
||||||
*/
|
*/
|
||||||
static ItemList option_argv = { NULL, NULL };
|
static ItemList option_argv = {NULL, NULL};
|
||||||
|
|
||||||
char *argv_item = NULL;
|
char *argv_item = NULL;
|
||||||
int c, argc_item = 1;
|
int c,
|
||||||
|
argc_item = 1;
|
||||||
|
|
||||||
char **argv_array = NULL;
|
char **argv_array = NULL;
|
||||||
ItemListCell *cell = NULL;
|
ItemListCell *cell = NULL;
|
||||||
@@ -1536,8 +1549,8 @@ parse_pg_basebackup_options(const char *pg_basebackup_options, t_basebackup_opti
|
|||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* From PostgreSQL 10, --xlog-method is renamed --wal-method
|
* From PostgreSQL 10, --xlog-method is renamed --wal-method and there's
|
||||||
* and there's also --no-slot, which we'll want to consider.
|
* also --no-slot, which we'll want to consider.
|
||||||
*/
|
*/
|
||||||
static struct option long_options_10[] =
|
static struct option long_options_10[] =
|
||||||
{
|
{
|
||||||
@@ -1576,8 +1589,8 @@ parse_pg_basebackup_options(const char *pg_basebackup_options, t_basebackup_opti
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Array of argument values to pass to getopt_long - this will need to
|
* Array of argument values to pass to getopt_long - this will need to
|
||||||
* include an empty string as the first value (normally this would be
|
* include an empty string as the first value (normally this would be the
|
||||||
* the program name)
|
* program name)
|
||||||
*/
|
*/
|
||||||
argv_array = pg_malloc0(sizeof(char *) * (argc_item + 2));
|
argv_array = pg_malloc0(sizeof(char *) * (argc_item + 2));
|
||||||
|
|
||||||
@@ -1648,7 +1661,8 @@ parse_pg_basebackup_options(const char *pg_basebackup_options, t_basebackup_opti
|
|||||||
|
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < argc_item + 2; i ++)
|
|
||||||
|
for (i = 0; i < argc_item + 2; i++)
|
||||||
pfree(argv_array[i]);
|
pfree(argv_array[i]);
|
||||||
}
|
}
|
||||||
pfree(argv_array);
|
pfree(argv_array);
|
||||||
|
|||||||
@@ -31,7 +31,8 @@
|
|||||||
extern bool config_file_found;
|
extern bool config_file_found;
|
||||||
extern char config_file_path[MAXPGPATH];
|
extern char config_file_path[MAXPGPATH];
|
||||||
|
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
FAILOVER_MANUAL,
|
FAILOVER_MANUAL,
|
||||||
FAILOVER_AUTOMATIC
|
FAILOVER_AUTOMATIC
|
||||||
} failover_mode_opt;
|
} failover_mode_opt;
|
||||||
@@ -186,7 +187,8 @@ typedef struct
|
|||||||
#define T_BASEBACKUP_OPTIONS_INITIALIZER { "", "", false }
|
#define T_BASEBACKUP_OPTIONS_INITIALIZER { "", "", false }
|
||||||
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
RTA_PAUSE,
|
RTA_PAUSE,
|
||||||
RTA_PROMOTE,
|
RTA_PROMOTE,
|
||||||
RTA_SHUTDOWN
|
RTA_SHUTDOWN
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ get_data_checksum_version(const char *data_directory)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
data_checksum_version = (int)control_file_info->control_file->data_checksum_version;
|
data_checksum_version = (int) control_file_info->control_file->data_checksum_version;
|
||||||
}
|
}
|
||||||
|
|
||||||
pfree(control_file_info->control_file);
|
pfree(control_file_info->control_file);
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ typedef struct
|
|||||||
} ControlFileInfo;
|
} ControlFileInfo;
|
||||||
|
|
||||||
extern DBState get_db_state(const char *data_directory);
|
extern DBState get_db_state(const char *data_directory);
|
||||||
extern const char * describe_db_state(DBState state);
|
extern const char *describe_db_state(DBState state);
|
||||||
extern int get_data_checksum_version(const char *data_directory);
|
extern int get_data_checksum_version(const char *data_directory);
|
||||||
extern uint64 get_system_identifier(const char *data_directory);
|
extern uint64 get_system_identifier(const char *data_directory);
|
||||||
extern XLogRecPtr get_latest_checkpoint_location(const char *data_directory);
|
extern XLogRecPtr get_latest_checkpoint_location(const char *data_directory);
|
||||||
|
|||||||
236
dbutils.c
236
dbutils.c
@@ -62,10 +62,11 @@ XLogRecPtr
|
|||||||
parse_lsn(const char *str)
|
parse_lsn(const char *str)
|
||||||
{
|
{
|
||||||
XLogRecPtr ptr = InvalidXLogRecPtr;
|
XLogRecPtr ptr = InvalidXLogRecPtr;
|
||||||
uint32 high, low;
|
uint32 high,
|
||||||
|
low;
|
||||||
|
|
||||||
if (sscanf(str, "%x/%x", &high, &low) == 2)
|
if (sscanf(str, "%x/%x", &high, &low) == 2)
|
||||||
ptr = (((XLogRecPtr)high) << 32) + (XLogRecPtr)low;
|
ptr = (((XLogRecPtr) high) << 32) + (XLogRecPtr) low;
|
||||||
|
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
@@ -75,7 +76,7 @@ parse_lsn(const char *str)
|
|||||||
* Wrap query with appropriate DDL function, if required.
|
* Wrap query with appropriate DDL function, if required.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
wrap_ddl_query(PQExpBufferData *query_buf, int replication_type, const char *fmt, ...)
|
wrap_ddl_query(PQExpBufferData *query_buf, int replication_type, const char *fmt,...)
|
||||||
{
|
{
|
||||||
va_list arglist;
|
va_list arglist;
|
||||||
char buf[MAXLEN];
|
char buf[MAXLEN];
|
||||||
@@ -175,7 +176,8 @@ _establish_db_connection(const char *conninfo, const bool exit_on_error, const b
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* set "synchronous_commit" to "local" in case synchronous replication is in use
|
* set "synchronous_commit" to "local" in case synchronous replication is
|
||||||
|
* in use
|
||||||
*
|
*
|
||||||
* XXX set this explicitly before any write operations
|
* XXX set this explicitly before any write operations
|
||||||
*/
|
*/
|
||||||
@@ -218,7 +220,8 @@ establish_db_connection_quiet(const char *conninfo)
|
|||||||
|
|
||||||
|
|
||||||
PGconn
|
PGconn
|
||||||
*establish_primary_db_connection(PGconn *conn,
|
*
|
||||||
|
establish_primary_db_connection(PGconn *conn,
|
||||||
const bool exit_on_error)
|
const bool exit_on_error)
|
||||||
{
|
{
|
||||||
t_node_info primary_node_info = T_NODE_INFO_INITIALIZER;
|
t_node_info primary_node_info = T_NODE_INFO_INITIALIZER;
|
||||||
@@ -275,7 +278,7 @@ establish_db_connection_by_params(t_conninfo_param_list *param_list,
|
|||||||
param_set_ine(param_list, "fallback_application_name", "repmgr");
|
param_set_ine(param_list, "fallback_application_name", "repmgr");
|
||||||
|
|
||||||
/* Connect to the database using the provided parameters */
|
/* Connect to the database using the provided parameters */
|
||||||
conn = PQconnectdbParams((const char**)param_list->keywords, (const char**)param_list->values, true);
|
conn = PQconnectdbParams((const char **) param_list->keywords, (const char **) param_list->values, true);
|
||||||
|
|
||||||
/* Check to see that the backend connection was successfully made */
|
/* Check to see that the backend connection was successfully made */
|
||||||
if ((PQstatus(conn) != CONNECTION_OK))
|
if ((PQstatus(conn) != CONNECTION_OK))
|
||||||
@@ -294,8 +297,8 @@ establish_db_connection_by_params(t_conninfo_param_list *param_list,
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* set "synchronous_commit" to "local" in case synchronous replication is in
|
* set "synchronous_commit" to "local" in case synchronous replication
|
||||||
* use (provided this is not a replication connection)
|
* is in use (provided this is not a replication connection)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
for (i = 0; param_list->keywords[i]; i++)
|
for (i = 0; param_list->keywords[i]; i++)
|
||||||
@@ -398,7 +401,7 @@ initialize_conninfo_params(t_conninfo_param_list *param_list, bool set_defaults)
|
|||||||
|
|
||||||
/* Count maximum number of parameters */
|
/* Count maximum number of parameters */
|
||||||
for (def = defs; def->keyword; def++)
|
for (def = defs; def->keyword; def++)
|
||||||
param_list->size ++;
|
param_list->size++;
|
||||||
|
|
||||||
/* Initialize our internal parameter list */
|
/* Initialize our internal parameter list */
|
||||||
param_list->keywords = pg_malloc0(sizeof(char *) * (param_list->size + 1));
|
param_list->keywords = pg_malloc0(sizeof(char *) * (param_list->size + 1));
|
||||||
@@ -451,6 +454,7 @@ void
|
|||||||
copy_conninfo_params(t_conninfo_param_list *dest_list, t_conninfo_param_list *source_list)
|
copy_conninfo_params(t_conninfo_param_list *dest_list, t_conninfo_param_list *source_list)
|
||||||
{
|
{
|
||||||
int c;
|
int c;
|
||||||
|
|
||||||
for (c = 0; c < source_list->size && source_list->keywords[c] != NULL; c++)
|
for (c = 0; c < source_list->size && source_list->keywords[c] != NULL; c++)
|
||||||
{
|
{
|
||||||
if (source_list->values[c] != NULL && source_list->values[c][0] != '\0')
|
if (source_list->values[c] != NULL && source_list->values[c][0] != '\0')
|
||||||
@@ -489,6 +493,7 @@ param_set(t_conninfo_param_list *param_list, const char *param, const char *valu
|
|||||||
if (c < param_list->size)
|
if (c < param_list->size)
|
||||||
{
|
{
|
||||||
int param_len = strlen(param) + 1;
|
int param_len = strlen(param) + 1;
|
||||||
|
|
||||||
param_list->keywords[c] = pg_malloc0(param_len);
|
param_list->keywords[c] = pg_malloc0(param_len);
|
||||||
param_list->values[c] = pg_malloc0(value_len);
|
param_list->values[c] = pg_malloc0(value_len);
|
||||||
|
|
||||||
@@ -497,9 +502,9 @@ param_set(t_conninfo_param_list *param_list, const char *param, const char *valu
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* It's theoretically possible a parameter couldn't be added as
|
* It's theoretically possible a parameter couldn't be added as the array
|
||||||
* the array is full, but it's highly improbable so we won't
|
* is full, but it's highly improbable so we won't handle it at the
|
||||||
* handle it at the moment.
|
* moment.
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -531,6 +536,7 @@ param_set_ine(t_conninfo_param_list *param_list, const char *param, const char *
|
|||||||
if (c < param_list->size)
|
if (c < param_list->size)
|
||||||
{
|
{
|
||||||
int param_len = strlen(param) + 1;
|
int param_len = strlen(param) + 1;
|
||||||
|
|
||||||
param_list->keywords[c] = pg_malloc0(param_len);
|
param_list->keywords[c] = pg_malloc0(param_len);
|
||||||
param_list->values[c] = pg_malloc0(value_len);
|
param_list->values[c] = pg_malloc0(value_len);
|
||||||
|
|
||||||
@@ -1261,8 +1267,7 @@ get_replication_info(PGconn *conn, ReplInfo *replication_info)
|
|||||||
server_version_num = get_server_version(conn, NULL);
|
server_version_num = get_server_version(conn, NULL);
|
||||||
|
|
||||||
initPQExpBuffer(&query);
|
initPQExpBuffer(&query);
|
||||||
appendPQExpBuffer(
|
appendPQExpBuffer(&query,
|
||||||
&query,
|
|
||||||
" SELECT ts, "
|
" SELECT ts, "
|
||||||
" last_wal_receive_lsn, "
|
" last_wal_receive_lsn, "
|
||||||
" last_wal_replay_lsn, "
|
" last_wal_replay_lsn, "
|
||||||
@@ -1277,8 +1282,7 @@ get_replication_info(PGconn *conn, ReplInfo *replication_info)
|
|||||||
|
|
||||||
if (server_version_num >= 100000)
|
if (server_version_num >= 100000)
|
||||||
{
|
{
|
||||||
appendPQExpBuffer(
|
appendPQExpBuffer(&query,
|
||||||
&query,
|
|
||||||
" SELECT CURRENT_TIMESTAMP AS ts, "
|
" SELECT CURRENT_TIMESTAMP AS ts, "
|
||||||
" pg_catalog.pg_last_wal_receive_lsn() AS last_wal_receive_lsn, "
|
" pg_catalog.pg_last_wal_receive_lsn() AS last_wal_receive_lsn, "
|
||||||
" pg_catalog.pg_last_wal_replay_lsn() AS last_wal_replay_lsn, "
|
" pg_catalog.pg_last_wal_replay_lsn() AS last_wal_replay_lsn, "
|
||||||
@@ -1286,16 +1290,14 @@ get_replication_info(PGconn *conn, ReplInfo *replication_info)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
appendPQExpBuffer(
|
appendPQExpBuffer(&query,
|
||||||
&query,
|
|
||||||
" SELECT CURRENT_TIMESTAMP AS ts, "
|
" SELECT CURRENT_TIMESTAMP AS ts, "
|
||||||
" pg_catalog.pg_last_xlog_receive_location() AS last_wal_receive_lsn, "
|
" pg_catalog.pg_last_xlog_receive_location() AS last_wal_receive_lsn, "
|
||||||
" pg_catalog.pg_last_xlog_replay_location() AS last_wal_replay_lsn, "
|
" pg_catalog.pg_last_xlog_replay_location() AS last_wal_replay_lsn, "
|
||||||
" pg_catalog.pg_last_xact_replay_timestamp() AS last_xact_replay_timestamp ");
|
" pg_catalog.pg_last_xact_replay_timestamp() AS last_xact_replay_timestamp ");
|
||||||
}
|
}
|
||||||
|
|
||||||
appendPQExpBuffer(
|
appendPQExpBuffer(&query,
|
||||||
&query,
|
|
||||||
" ) q ");
|
" ) q ");
|
||||||
|
|
||||||
log_verbose(LOG_DEBUG, "get_replication_info():\n%s", query.data);
|
log_verbose(LOG_DEBUG, "get_replication_info():\n%s", query.data);
|
||||||
@@ -1318,6 +1320,7 @@ get_replication_info(PGconn *conn, ReplInfo *replication_info)
|
|||||||
strncpy(replication_info->last_xact_replay_timestamp, PQgetvalue(res, 0, 3), MAXLEN);
|
strncpy(replication_info->last_xact_replay_timestamp, PQgetvalue(res, 0, 3), MAXLEN);
|
||||||
replication_info->replication_lag_time = atoi(PQgetvalue(res, 0, 4));
|
replication_info->replication_lag_time = atoi(PQgetvalue(res, 0, 4));
|
||||||
replication_info->receiving_streamed_wal = atobool(PQgetvalue(res, 0, 5));
|
replication_info->receiving_streamed_wal = atobool(PQgetvalue(res, 0, 5));
|
||||||
|
|
||||||
PQclear(res);
|
PQclear(res);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -1334,8 +1337,7 @@ can_use_pg_rewind(PGconn *conn, const char *data_directory, PQExpBufferData *rea
|
|||||||
|
|
||||||
if (server_version_num < 90500)
|
if (server_version_num < 90500)
|
||||||
{
|
{
|
||||||
appendPQExpBuffer(
|
appendPQExpBuffer(reason,
|
||||||
reason,
|
|
||||||
_("pg_rewind available from PostgreSQL 9.5"));
|
_("pg_rewind available from PostgreSQL 9.5"));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -1345,18 +1347,17 @@ can_use_pg_rewind(PGconn *conn, const char *data_directory, PQExpBufferData *rea
|
|||||||
if (can_use == false)
|
if (can_use == false)
|
||||||
appendPQExpBuffer(reason, "; ");
|
appendPQExpBuffer(reason, "; ");
|
||||||
|
|
||||||
appendPQExpBuffer(
|
appendPQExpBuffer(reason,
|
||||||
reason,
|
|
||||||
_("\"full_page_writes\" must be set to \"on\""));
|
_("\"full_page_writes\" must be set to \"on\""));
|
||||||
|
|
||||||
can_use = false;
|
can_use = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* "wal_log_hints" off - are data checksums available?
|
* "wal_log_hints" off - are data checksums available? Note: we're
|
||||||
* Note: we're checking the local pg_control file here as the value will
|
* checking the local pg_control file here as the value will be the same
|
||||||
* be the same throughout the cluster and saves a round-trip to the
|
* throughout the cluster and saves a round-trip to the demotion
|
||||||
* demotion candidate.
|
* candidate.
|
||||||
*/
|
*/
|
||||||
if (guc_set(conn, "wal_log_hints", "=", "on") == false)
|
if (guc_set(conn, "wal_log_hints", "=", "on") == false)
|
||||||
{
|
{
|
||||||
@@ -1367,8 +1368,7 @@ can_use_pg_rewind(PGconn *conn, const char *data_directory, PQExpBufferData *rea
|
|||||||
if (can_use == false)
|
if (can_use == false)
|
||||||
appendPQExpBuffer(reason, "; ");
|
appendPQExpBuffer(reason, "; ");
|
||||||
|
|
||||||
appendPQExpBuffer(
|
appendPQExpBuffer(reason,
|
||||||
reason,
|
|
||||||
_("\"wal_log_hints\" is set to \"off\" but unable to determine checksum version"));
|
_("\"wal_log_hints\" is set to \"off\" but unable to determine checksum version"));
|
||||||
can_use = false;
|
can_use = false;
|
||||||
}
|
}
|
||||||
@@ -1377,8 +1377,7 @@ can_use_pg_rewind(PGconn *conn, const char *data_directory, PQExpBufferData *rea
|
|||||||
if (can_use == false)
|
if (can_use == false)
|
||||||
appendPQExpBuffer(reason, "; ");
|
appendPQExpBuffer(reason, "; ");
|
||||||
|
|
||||||
appendPQExpBuffer(
|
appendPQExpBuffer(reason,
|
||||||
reason,
|
|
||||||
_("\"wal_log_hints\" is set to \"off\" and checksums are disabled"));
|
_("\"wal_log_hints\" is set to \"off\" and checksums are disabled"));
|
||||||
|
|
||||||
can_use = false;
|
can_use = false;
|
||||||
@@ -1421,7 +1420,7 @@ get_ready_archive_files(PGconn *conn, const char *data_directory)
|
|||||||
log_error(_("unable to access archive_status directory \"%s\""),
|
log_error(_("unable to access archive_status directory \"%s\""),
|
||||||
archive_status_dir);
|
archive_status_dir);
|
||||||
log_detail("%s", strerror(errno));
|
log_detail("%s", strerror(errno));
|
||||||
/* XXX magic number*/
|
/* XXX magic number */
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1432,7 +1431,7 @@ get_ready_archive_files(PGconn *conn, const char *data_directory)
|
|||||||
log_error(_("unable to open archive directory \"%s\""),
|
log_error(_("unable to open archive directory \"%s\""),
|
||||||
archive_status_dir);
|
archive_status_dir);
|
||||||
log_detail("%s", strerror(errno));
|
log_detail("%s", strerror(errno));
|
||||||
/* XXX magic number*/
|
/* XXX magic number */
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1456,11 +1455,11 @@ get_ready_archive_files(PGconn *conn, const char *data_directory)
|
|||||||
basenamelen = (int) strlen(arcdir_ent->d_name) - 6;
|
basenamelen = (int) strlen(arcdir_ent->d_name) - 6;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* count anything ending in ".ready"; for a more precise implementation
|
* count anything ending in ".ready"; for a more precise
|
||||||
* see: src/backend/postmaster/pgarch.c
|
* implementation see: src/backend/postmaster/pgarch.c
|
||||||
*/
|
*/
|
||||||
if (strcmp(arcdir_ent->d_name + basenamelen, ".ready") == 0)
|
if (strcmp(arcdir_ent->d_name + basenamelen, ".ready") == 0)
|
||||||
ready_count ++;
|
ready_count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
closedir(arcdir);
|
closedir(arcdir);
|
||||||
@@ -1483,20 +1482,17 @@ get_replication_lag_seconds(PGconn *conn)
|
|||||||
|
|
||||||
if (server_version_num >= 100000)
|
if (server_version_num >= 100000)
|
||||||
{
|
{
|
||||||
appendPQExpBuffer(
|
appendPQExpBuffer(&query,
|
||||||
&query,
|
|
||||||
" SELECT CASE WHEN (pg_catalog.pg_last_wal_receive_lsn() = pg_catalog.pg_last_wal_replay_lsn()) ");
|
" SELECT CASE WHEN (pg_catalog.pg_last_wal_receive_lsn() = pg_catalog.pg_last_wal_replay_lsn()) ");
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
appendPQExpBuffer(
|
appendPQExpBuffer(&query,
|
||||||
&query,
|
|
||||||
" SELECT CASE WHEN (pg_catalog.pg_last_xlog_receive_location() = pg_catalog.pg_last_xlog_replay_location()) ");
|
" SELECT CASE WHEN (pg_catalog.pg_last_xlog_receive_location() = pg_catalog.pg_last_xlog_replay_location()) ");
|
||||||
}
|
}
|
||||||
|
|
||||||
appendPQExpBuffer(
|
appendPQExpBuffer(&query,
|
||||||
&query,
|
|
||||||
" THEN 0 "
|
" THEN 0 "
|
||||||
" ELSE EXTRACT(epoch FROM (pg_catalog.clock_timestamp() - pg_catalog.pg_last_xact_replay_timestamp()))::INT "
|
" ELSE EXTRACT(epoch FROM (pg_catalog.clock_timestamp() - pg_catalog.pg_last_xact_replay_timestamp()))::INT "
|
||||||
" END "
|
" END "
|
||||||
@@ -1557,8 +1553,7 @@ repmgrd_set_local_node_id(PGconn *conn, int local_node_id)
|
|||||||
|
|
||||||
initPQExpBuffer(&query);
|
initPQExpBuffer(&query);
|
||||||
|
|
||||||
appendPQExpBuffer(
|
appendPQExpBuffer(&query,
|
||||||
&query,
|
|
||||||
" SELECT repmgr.set_local_node_id(%i)",
|
" SELECT repmgr.set_local_node_id(%i)",
|
||||||
local_node_id);
|
local_node_id);
|
||||||
|
|
||||||
@@ -1581,7 +1576,8 @@ repmgrd_set_local_node_id(PGconn *conn, int local_node_id)
|
|||||||
/* result functions */
|
/* result functions */
|
||||||
/* ================ */
|
/* ================ */
|
||||||
|
|
||||||
bool atobool(const char *value)
|
bool
|
||||||
|
atobool(const char *value)
|
||||||
{
|
{
|
||||||
return (strcmp(value, "t") == 0)
|
return (strcmp(value, "t") == 0)
|
||||||
? true
|
? true
|
||||||
@@ -1760,7 +1756,7 @@ parse_node_type(const char *type)
|
|||||||
const char *
|
const char *
|
||||||
get_node_type_string(t_server_type type)
|
get_node_type_string(t_server_type type)
|
||||||
{
|
{
|
||||||
switch(type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case PRIMARY:
|
case PRIMARY:
|
||||||
return "primary";
|
return "primary";
|
||||||
@@ -1895,7 +1891,8 @@ get_local_node_record(PGconn *conn, int node_id, t_node_info *node_info)
|
|||||||
|
|
||||||
|
|
||||||
static
|
static
|
||||||
void _populate_node_records(PGresult *res, NodeInfoList *node_list)
|
void
|
||||||
|
_populate_node_records(PGresult *res, NodeInfoList *node_list)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@@ -1909,6 +1906,7 @@ void _populate_node_records(PGresult *res, NodeInfoList *node_list)
|
|||||||
for (i = 0; i < PQntuples(res); i++)
|
for (i = 0; i < PQntuples(res); i++)
|
||||||
{
|
{
|
||||||
NodeInfoListCell *cell;
|
NodeInfoListCell *cell;
|
||||||
|
|
||||||
cell = (NodeInfoListCell *) pg_malloc0(sizeof(NodeInfoListCell));
|
cell = (NodeInfoListCell *) pg_malloc0(sizeof(NodeInfoListCell));
|
||||||
|
|
||||||
cell->node_info = pg_malloc0(sizeof(t_node_info));
|
cell->node_info = pg_malloc0(sizeof(t_node_info));
|
||||||
@@ -1936,8 +1934,7 @@ get_all_node_records(PGconn *conn, NodeInfoList *node_list)
|
|||||||
|
|
||||||
initPQExpBuffer(&query);
|
initPQExpBuffer(&query);
|
||||||
|
|
||||||
appendPQExpBuffer(
|
appendPQExpBuffer(&query,
|
||||||
&query,
|
|
||||||
" SELECT " REPMGR_NODES_COLUMNS
|
" SELECT " REPMGR_NODES_COLUMNS
|
||||||
" FROM repmgr.nodes "
|
" FROM repmgr.nodes "
|
||||||
"ORDER BY node_id ");
|
"ORDER BY node_id ");
|
||||||
@@ -1963,8 +1960,7 @@ get_downstream_node_records(PGconn *conn, int node_id, NodeInfoList *node_list)
|
|||||||
|
|
||||||
initPQExpBuffer(&query);
|
initPQExpBuffer(&query);
|
||||||
|
|
||||||
appendPQExpBuffer(
|
appendPQExpBuffer(&query,
|
||||||
&query,
|
|
||||||
" SELECT " REPMGR_NODES_COLUMNS
|
" SELECT " REPMGR_NODES_COLUMNS
|
||||||
" FROM repmgr.nodes "
|
" FROM repmgr.nodes "
|
||||||
" WHERE upstream_node_id = %i "
|
" WHERE upstream_node_id = %i "
|
||||||
@@ -1993,8 +1989,7 @@ get_active_sibling_node_records(PGconn *conn, int node_id, int upstream_node_id,
|
|||||||
|
|
||||||
initPQExpBuffer(&query);
|
initPQExpBuffer(&query);
|
||||||
|
|
||||||
appendPQExpBuffer(
|
appendPQExpBuffer(&query,
|
||||||
&query,
|
|
||||||
" SELECT " REPMGR_NODES_COLUMNS
|
" SELECT " REPMGR_NODES_COLUMNS
|
||||||
" FROM repmgr.nodes "
|
" FROM repmgr.nodes "
|
||||||
" WHERE upstream_node_id = %i "
|
" WHERE upstream_node_id = %i "
|
||||||
@@ -2026,8 +2021,7 @@ get_node_records_by_priority(PGconn *conn, NodeInfoList *node_list)
|
|||||||
|
|
||||||
initPQExpBuffer(&query);
|
initPQExpBuffer(&query);
|
||||||
|
|
||||||
appendPQExpBuffer(
|
appendPQExpBuffer(&query,
|
||||||
&query,
|
|
||||||
" SELECT " REPMGR_NODES_COLUMNS
|
" SELECT " REPMGR_NODES_COLUMNS
|
||||||
" FROM repmgr.nodes "
|
" FROM repmgr.nodes "
|
||||||
"ORDER BY priority DESC, node_name ");
|
"ORDER BY priority DESC, node_name ");
|
||||||
@@ -2053,8 +2047,7 @@ get_all_node_records_with_upstream(PGconn *conn, NodeInfoList *node_list)
|
|||||||
|
|
||||||
initPQExpBuffer(&query);
|
initPQExpBuffer(&query);
|
||||||
|
|
||||||
appendPQExpBuffer(
|
appendPQExpBuffer(&query,
|
||||||
&query,
|
|
||||||
" SELECT n.node_id, n.type, n.upstream_node_id, n.node_name, n.conninfo, n.repluser, "
|
" SELECT 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, un.node_name AS upstream_node_name "
|
" n.slot_name, n.location, n.priority, n.active, un.node_name AS upstream_node_name "
|
||||||
" FROM repmgr.nodes n "
|
" FROM repmgr.nodes n "
|
||||||
@@ -2120,10 +2113,11 @@ _create_update_node_record(PGconn *conn, char *action, t_node_info *node_info)
|
|||||||
if (node_info->upstream_node_id == NO_UPSTREAM_NODE && node_info->type == STANDBY)
|
if (node_info->upstream_node_id == NO_UPSTREAM_NODE && node_info->type == STANDBY)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* No explicit upstream node id provided for standby - attempt to
|
* No explicit upstream node id provided for standby - attempt to get
|
||||||
* get primary node id
|
* primary node id
|
||||||
*/
|
*/
|
||||||
int primary_node_id = get_primary_node_id(conn);
|
int primary_node_id = get_primary_node_id(conn);
|
||||||
|
|
||||||
maxlen_snprintf(upstream_node_id, "%i", primary_node_id);
|
maxlen_snprintf(upstream_node_id, "%i", primary_node_id);
|
||||||
upstream_node_id_ptr = upstream_node_id;
|
upstream_node_id_ptr = upstream_node_id;
|
||||||
}
|
}
|
||||||
@@ -2394,8 +2388,7 @@ update_node_record_conn_priority(PGconn *conn, t_configuration_options *options)
|
|||||||
|
|
||||||
initPQExpBuffer(&query);
|
initPQExpBuffer(&query);
|
||||||
|
|
||||||
appendPQExpBuffer(
|
appendPQExpBuffer(&query,
|
||||||
&query,
|
|
||||||
"UPDATE repmgr.nodes "
|
"UPDATE repmgr.nodes "
|
||||||
" SET conninfo = '%s', "
|
" SET conninfo = '%s', "
|
||||||
" priority = %d "
|
" priority = %d "
|
||||||
@@ -2459,8 +2452,7 @@ get_node_replication_stats(PGconn *conn, t_node_info *node_info)
|
|||||||
|
|
||||||
initPQExpBuffer(&query);
|
initPQExpBuffer(&query);
|
||||||
|
|
||||||
appendPQExpBuffer(
|
appendPQExpBuffer(&query,
|
||||||
&query,
|
|
||||||
" SELECT current_setting('max_wal_senders')::INT AS max_wal_senders, "
|
" SELECT current_setting('max_wal_senders')::INT AS max_wal_senders, "
|
||||||
" (SELECT COUNT(*) FROM pg_catalog.pg_stat_replication) AS attached_wal_receivers, "
|
" (SELECT COUNT(*) FROM pg_catalog.pg_stat_replication) AS attached_wal_receivers, "
|
||||||
" current_setting('max_replication_slots')::INT AS max_replication_slots, "
|
" current_setting('max_replication_slots')::INT AS max_replication_slots, "
|
||||||
@@ -2503,8 +2495,7 @@ is_downstream_node_attached(PGconn *conn, char *node_name)
|
|||||||
|
|
||||||
initPQExpBuffer(&query);
|
initPQExpBuffer(&query);
|
||||||
|
|
||||||
appendPQExpBuffer(
|
appendPQExpBuffer(&query,
|
||||||
&query,
|
|
||||||
" SELECT COUNT(*) FROM pg_catalog.pg_stat_replication "
|
" SELECT COUNT(*) FROM pg_catalog.pg_stat_replication "
|
||||||
" WHERE application_name = '%s'",
|
" WHERE application_name = '%s'",
|
||||||
node_name);
|
node_name);
|
||||||
@@ -2592,8 +2583,7 @@ get_datadir_configuration_files(PGconn *conn, KeyValueList *list)
|
|||||||
|
|
||||||
initPQExpBuffer(&query);
|
initPQExpBuffer(&query);
|
||||||
|
|
||||||
appendPQExpBuffer(
|
appendPQExpBuffer(&query,
|
||||||
&query,
|
|
||||||
"WITH files AS ( "
|
"WITH files AS ( "
|
||||||
" WITH dd AS ( "
|
" WITH dd AS ( "
|
||||||
" SELECT setting "
|
" SELECT setting "
|
||||||
@@ -2647,8 +2637,7 @@ get_configuration_file_locations(PGconn *conn, t_configfile_list *list)
|
|||||||
|
|
||||||
initPQExpBuffer(&query);
|
initPQExpBuffer(&query);
|
||||||
|
|
||||||
appendPQExpBuffer(
|
appendPQExpBuffer(&query,
|
||||||
&query,
|
|
||||||
" WITH dd AS ( "
|
" WITH dd AS ( "
|
||||||
" SELECT setting AS data_directory"
|
" SELECT setting AS data_directory"
|
||||||
" FROM pg_catalog.pg_settings "
|
" FROM pg_catalog.pg_settings "
|
||||||
@@ -2697,8 +2686,7 @@ get_configuration_file_locations(PGconn *conn, t_configfile_list *list)
|
|||||||
/* Fetch locations of pg_hba.conf and pg_ident.conf */
|
/* Fetch locations of pg_hba.conf and pg_ident.conf */
|
||||||
initPQExpBuffer(&query);
|
initPQExpBuffer(&query);
|
||||||
|
|
||||||
appendPQExpBuffer(
|
appendPQExpBuffer(&query,
|
||||||
&query,
|
|
||||||
" WITH dd AS ( "
|
" WITH dd AS ( "
|
||||||
" SELECT setting AS data_directory"
|
" SELECT setting AS data_directory"
|
||||||
" FROM pg_catalog.pg_settings "
|
" FROM pg_catalog.pg_settings "
|
||||||
@@ -2781,7 +2769,7 @@ config_file_list_add(t_configfile_list *list, const char *file, const char *file
|
|||||||
strncpy(list->files[list->entries]->filename, filename, MAXPGPATH);
|
strncpy(list->files[list->entries]->filename, filename, MAXPGPATH);
|
||||||
list->files[list->entries]->in_data_directory = in_data_dir;
|
list->files[list->entries]->in_data_directory = in_data_dir;
|
||||||
|
|
||||||
list->entries ++;
|
list->entries++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -2860,20 +2848,21 @@ _create_event(PGconn *conn, t_configuration_options *options, int node_id, char
|
|||||||
* Only attempt to write a record if a connection handle was provided.
|
* Only attempt to write a record if a connection handle was provided.
|
||||||
* Also check that the repmgr schema has been properly initialised - if
|
* Also check that the repmgr schema has been properly initialised - if
|
||||||
* not it means no configuration file was provided, which can happen with
|
* not it means no configuration file was provided, which can happen with
|
||||||
* e.g. `repmgr standby clone`, and we won't know which schema to write to.
|
* e.g. `repmgr standby clone`, and we won't know which schema to write
|
||||||
|
* to.
|
||||||
*/
|
*/
|
||||||
if (conn != NULL && PQstatus(conn) == CONNECTION_OK)
|
if (conn != NULL && PQstatus(conn) == CONNECTION_OK)
|
||||||
{
|
{
|
||||||
int n_node_id = htonl(node_id);
|
int n_node_id = htonl(node_id);
|
||||||
char *t_successful = successful ? "TRUE" : "FALSE";
|
char *t_successful = successful ? "TRUE" : "FALSE";
|
||||||
|
|
||||||
const char *values[4] = { (char *)&n_node_id,
|
const char *values[4] = {(char *) &n_node_id,
|
||||||
event,
|
event,
|
||||||
t_successful,
|
t_successful,
|
||||||
details
|
details
|
||||||
};
|
};
|
||||||
|
|
||||||
int lengths[4] = { sizeof(n_node_id),
|
int lengths[4] = {sizeof(n_node_id),
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
0
|
0
|
||||||
@@ -2924,8 +2913,8 @@ _create_event(PGconn *conn, t_configuration_options *options, int node_id, char
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* If no database connection provided, or the query failed, generate a
|
* If no database connection provided, or the query failed, generate a
|
||||||
* current timestamp ourselves. This isn't quite the same
|
* current timestamp ourselves. This isn't quite the same format as
|
||||||
* format as PostgreSQL, but is close enough for diagnostic use.
|
* PostgreSQL, but is close enough for diagnostic use.
|
||||||
*/
|
*/
|
||||||
if (!strlen(event_timestamp))
|
if (!strlen(event_timestamp))
|
||||||
{
|
{
|
||||||
@@ -2949,9 +2938,9 @@ _create_event(PGconn *conn, t_configuration_options *options, int node_id, char
|
|||||||
int r = 0;
|
int r = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If configuration option 'event_notifications' was provided,
|
* If configuration option 'event_notifications' was provided, check
|
||||||
* check if this event is one of the ones listed; if not listed,
|
* if this event is one of the ones listed; if not listed, don't
|
||||||
* don't execute the notification script.
|
* execute the notification script.
|
||||||
*
|
*
|
||||||
* (If 'event_notifications' was not provided, we assume the script
|
* (If 'event_notifications' was not provided, we assume the script
|
||||||
* should be executed for all events).
|
* should be executed for all events).
|
||||||
@@ -2971,7 +2960,8 @@ _create_event(PGconn *conn, t_configuration_options *options, int node_id, char
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Event type not found in the 'event_notifications' list - return early
|
* Event type not found in the 'event_notifications' list - return
|
||||||
|
* early
|
||||||
*/
|
*/
|
||||||
if (notify_ok == false)
|
if (notify_ok == false)
|
||||||
{
|
{
|
||||||
@@ -2984,7 +2974,7 @@ _create_event(PGconn *conn, t_configuration_options *options, int node_id, char
|
|||||||
end_ptr = parsed_command + MAXPGPATH - 1;
|
end_ptr = parsed_command + MAXPGPATH - 1;
|
||||||
*end_ptr = '\0';
|
*end_ptr = '\0';
|
||||||
|
|
||||||
for(src_ptr = options->event_notification_command; *src_ptr; src_ptr++)
|
for (src_ptr = options->event_notification_command; *src_ptr; src_ptr++)
|
||||||
{
|
{
|
||||||
if (*src_ptr == '%')
|
if (*src_ptr == '%')
|
||||||
{
|
{
|
||||||
@@ -3099,8 +3089,8 @@ create_replication_slot(PGconn *conn, char *slot_name, int server_version_num, P
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Check whether slot exists already; if it exists and is active, that
|
* Check whether slot exists already; if it exists and is active, that
|
||||||
* means another active standby is using it, which creates an error situation;
|
* means another active standby is using it, which creates an error
|
||||||
* if not we can reuse it as-is
|
* situation; if not we can reuse it as-is
|
||||||
*/
|
*/
|
||||||
|
|
||||||
record_status = get_slot_record(conn, slot_name, &slot_info);
|
record_status = get_slot_record(conn, slot_name, &slot_info);
|
||||||
@@ -3117,7 +3107,7 @@ create_replication_slot(PGconn *conn, char *slot_name, int server_version_num, P
|
|||||||
|
|
||||||
if (slot_info.active == false)
|
if (slot_info.active == false)
|
||||||
{
|
{
|
||||||
// XXX is this a good idea?
|
/* XXX is this a good idea? */
|
||||||
log_debug("replication slot \"%s\" exists but is inactive; reusing",
|
log_debug("replication slot \"%s\" exists but is inactive; reusing",
|
||||||
slot_name);
|
slot_name);
|
||||||
|
|
||||||
@@ -3429,14 +3419,13 @@ add_monitoring_record(
|
|||||||
char *last_xact_replay_timestamp,
|
char *last_xact_replay_timestamp,
|
||||||
long long unsigned int replication_lag_bytes,
|
long long unsigned int replication_lag_bytes,
|
||||||
long long unsigned int apply_lag_bytes
|
long long unsigned int apply_lag_bytes
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
PQExpBufferData query;
|
PQExpBufferData query;
|
||||||
|
|
||||||
initPQExpBuffer(&query);
|
initPQExpBuffer(&query);
|
||||||
|
|
||||||
appendPQExpBuffer(
|
appendPQExpBuffer(&query,
|
||||||
&query,
|
|
||||||
"INSERT INTO repmgr.monitoring_history "
|
"INSERT INTO repmgr.monitoring_history "
|
||||||
" (primary_node_id, "
|
" (primary_node_id, "
|
||||||
" standby_node_id, "
|
" standby_node_id, "
|
||||||
@@ -3476,7 +3465,7 @@ add_monitoring_record(
|
|||||||
|
|
||||||
res = PQexec(local_conn, "SELECT repmgr.standby_set_last_updated()");
|
res = PQexec(local_conn, "SELECT repmgr.standby_set_last_updated()");
|
||||||
|
|
||||||
/* not critical if the above query fails*/
|
/* not critical if the above query fails */
|
||||||
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
||||||
log_warning(_("unable to set last_updated:\n %s"), PQerrorMessage(local_conn));
|
log_warning(_("unable to set last_updated:\n %s"), PQerrorMessage(local_conn));
|
||||||
|
|
||||||
@@ -3549,22 +3538,20 @@ request_vote(PGconn *conn, t_node_info *this_node, t_node_info *other_node, int
|
|||||||
log_debug("NULL returned by repmgr.request_vote()");
|
log_debug("NULL returned by repmgr.request_vote()");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* get the node's last receive location anyway
|
* get the node's last receive location anyway TODO: have
|
||||||
* TODO: have repmgr.request_vote() return two values
|
* repmgr.request_vote() return two values
|
||||||
*/
|
*/
|
||||||
|
|
||||||
initPQExpBuffer(&query);
|
initPQExpBuffer(&query);
|
||||||
|
|
||||||
if (server_version_num >= 100000)
|
if (server_version_num >= 100000)
|
||||||
{
|
{
|
||||||
appendPQExpBuffer(
|
appendPQExpBuffer(&query,
|
||||||
&query,
|
|
||||||
"SELECT pg_catalog.pg_last_wal_receive_lsn()");
|
"SELECT pg_catalog.pg_last_wal_receive_lsn()");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
appendPQExpBuffer(
|
appendPQExpBuffer(&query,
|
||||||
&query,
|
|
||||||
"SELECT pg_catalog.pg_last_xlog_receive_location()");
|
"SELECT pg_catalog.pg_last_xlog_receive_location()");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3676,7 +3663,7 @@ notify_follow_primary(PGconn *conn, int primary_node_id)
|
|||||||
primary_node_id);
|
primary_node_id);
|
||||||
log_verbose(LOG_DEBUG, "notify_follow_primary():\n %s", query.data);
|
log_verbose(LOG_DEBUG, "notify_follow_primary():\n %s", query.data);
|
||||||
|
|
||||||
// XXX handle failure
|
/* XXX handle failure */
|
||||||
res = PQexec(conn, query.data);
|
res = PQexec(conn, query.data);
|
||||||
termPQExpBuffer(&query);
|
termPQExpBuffer(&query);
|
||||||
|
|
||||||
@@ -3706,7 +3693,7 @@ get_new_primary(PGconn *conn, int *primary_node_id)
|
|||||||
|
|
||||||
res = PQexec(conn, query.data);
|
res = PQexec(conn, query.data);
|
||||||
termPQExpBuffer(&query);
|
termPQExpBuffer(&query);
|
||||||
// XXX handle error
|
/* XXX handle error */
|
||||||
|
|
||||||
new_primary_node_id = atoi(PQgetvalue(res, 0, 0));
|
new_primary_node_id = atoi(PQgetvalue(res, 0, 0));
|
||||||
|
|
||||||
@@ -3738,7 +3725,7 @@ reset_voting_status(PGconn *conn)
|
|||||||
res = PQexec(conn, query.data);
|
res = PQexec(conn, query.data);
|
||||||
termPQExpBuffer(&query);
|
termPQExpBuffer(&query);
|
||||||
|
|
||||||
// COMMAND_OK?
|
/* COMMAND_OK? */
|
||||||
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
||||||
{
|
{
|
||||||
log_error(_("unable to execute repmgr.reset_voting_status():\n %s"),
|
log_error(_("unable to execute repmgr.reset_voting_status():\n %s"),
|
||||||
@@ -3820,8 +3807,7 @@ is_bdr_db(PGconn *conn, PQExpBufferData *output)
|
|||||||
|
|
||||||
initPQExpBuffer(&query);
|
initPQExpBuffer(&query);
|
||||||
|
|
||||||
appendPQExpBuffer(
|
appendPQExpBuffer(&query,
|
||||||
&query,
|
|
||||||
"SELECT COUNT(*) FROM pg_catalog.pg_extension WHERE extname='bdr'");
|
"SELECT COUNT(*) FROM pg_catalog.pg_extension WHERE extname='bdr'");
|
||||||
|
|
||||||
res = PQexec(conn, query.data);
|
res = PQexec(conn, query.data);
|
||||||
@@ -3852,8 +3838,7 @@ is_bdr_db(PGconn *conn, PQExpBufferData *output)
|
|||||||
|
|
||||||
initPQExpBuffer(&query);
|
initPQExpBuffer(&query);
|
||||||
|
|
||||||
appendPQExpBuffer(
|
appendPQExpBuffer(&query,
|
||||||
&query,
|
|
||||||
"SELECT bdr.bdr_is_active_in_db()");
|
"SELECT bdr.bdr_is_active_in_db()");
|
||||||
res = PQexec(conn, query.data);
|
res = PQexec(conn, query.data);
|
||||||
termPQExpBuffer(&query);
|
termPQExpBuffer(&query);
|
||||||
@@ -3884,8 +3869,7 @@ is_active_bdr_node(PGconn *conn, const char *node_name)
|
|||||||
bool is_active_bdr_node = false;
|
bool is_active_bdr_node = false;
|
||||||
|
|
||||||
initPQExpBuffer(&query);
|
initPQExpBuffer(&query);
|
||||||
appendPQExpBuffer(
|
appendPQExpBuffer(&query,
|
||||||
&query,
|
|
||||||
" SELECT COALESCE(s.active, TRUE) AS active"
|
" SELECT COALESCE(s.active, TRUE) AS active"
|
||||||
" FROM bdr.bdr_nodes n "
|
" FROM bdr.bdr_nodes n "
|
||||||
" LEFT JOIN pg_replication_slots s "
|
" LEFT JOIN pg_replication_slots s "
|
||||||
@@ -3920,8 +3904,7 @@ is_bdr_repmgr(PGconn *conn)
|
|||||||
|
|
||||||
initPQExpBuffer(&query);
|
initPQExpBuffer(&query);
|
||||||
|
|
||||||
appendPQExpBuffer(
|
appendPQExpBuffer(&query,
|
||||||
&query,
|
|
||||||
"SELECT COUNT(*)"
|
"SELECT COUNT(*)"
|
||||||
" FROM repmgr.nodes"
|
" FROM repmgr.nodes"
|
||||||
" WHERE type != 'bdr' ");
|
" WHERE type != 'bdr' ");
|
||||||
@@ -3952,8 +3935,7 @@ is_table_in_bdr_replication_set(PGconn *conn, const char *tablename, const char
|
|||||||
|
|
||||||
initPQExpBuffer(&query);
|
initPQExpBuffer(&query);
|
||||||
|
|
||||||
appendPQExpBuffer(
|
appendPQExpBuffer(&query,
|
||||||
&query,
|
|
||||||
"SELECT COUNT(*) "
|
"SELECT COUNT(*) "
|
||||||
" FROM UNNEST(bdr.table_get_replication_sets('repmgr.%s')) AS repset "
|
" FROM UNNEST(bdr.table_get_replication_sets('repmgr.%s')) AS repset "
|
||||||
" WHERE repset='%s' ",
|
" WHERE repset='%s' ",
|
||||||
@@ -3987,8 +3969,7 @@ add_table_to_bdr_replication_set(PGconn *conn, const char *tablename, const char
|
|||||||
|
|
||||||
initPQExpBuffer(&query);
|
initPQExpBuffer(&query);
|
||||||
|
|
||||||
appendPQExpBuffer(
|
appendPQExpBuffer(&query,
|
||||||
&query,
|
|
||||||
"SELECT bdr.table_set_replication_sets('repmgr.%s', '{%s}')",
|
"SELECT bdr.table_set_replication_sets('repmgr.%s', '{%s}')",
|
||||||
tablename,
|
tablename,
|
||||||
set);
|
set);
|
||||||
@@ -4023,8 +4004,7 @@ bdr_node_exists(PGconn *conn, const char *node_name)
|
|||||||
|
|
||||||
initPQExpBuffer(&query);
|
initPQExpBuffer(&query);
|
||||||
|
|
||||||
appendPQExpBuffer(
|
appendPQExpBuffer(&query,
|
||||||
&query,
|
|
||||||
"SELECT COUNT(*)"
|
"SELECT COUNT(*)"
|
||||||
" FROM bdr.bdr_nodes"
|
" FROM bdr.bdr_nodes"
|
||||||
" WHERE node_name = '%s'",
|
" WHERE node_name = '%s'",
|
||||||
@@ -4057,8 +4037,7 @@ get_bdr_node_replication_slot_status(PGconn *conn, const char *node_name)
|
|||||||
|
|
||||||
initPQExpBuffer(&query);
|
initPQExpBuffer(&query);
|
||||||
|
|
||||||
appendPQExpBuffer(
|
appendPQExpBuffer(&query,
|
||||||
&query,
|
|
||||||
" SELECT s.active "
|
" SELECT s.active "
|
||||||
" FROM pg_catalog.pg_replication_slots s "
|
" FROM pg_catalog.pg_replication_slots s "
|
||||||
" WHERE slot_name = "
|
" WHERE slot_name = "
|
||||||
@@ -4097,8 +4076,7 @@ get_bdr_other_node_name(PGconn *conn, int node_id, char *node_name)
|
|||||||
|
|
||||||
initPQExpBuffer(&query);
|
initPQExpBuffer(&query);
|
||||||
|
|
||||||
appendPQExpBuffer(
|
appendPQExpBuffer(&query,
|
||||||
&query,
|
|
||||||
" SELECT node_name "
|
" SELECT node_name "
|
||||||
" FROM repmgr.nodes "
|
" FROM repmgr.nodes "
|
||||||
" WHERE node_id != %i",
|
" WHERE node_id != %i",
|
||||||
@@ -4109,7 +4087,7 @@ get_bdr_other_node_name(PGconn *conn, int node_id, char *node_name)
|
|||||||
res = PQexec(conn, query.data);
|
res = PQexec(conn, query.data);
|
||||||
termPQExpBuffer(&query);
|
termPQExpBuffer(&query);
|
||||||
|
|
||||||
if(PQresultStatus(res) == PGRES_TUPLES_OK)
|
if (PQresultStatus(res) == PGRES_TUPLES_OK)
|
||||||
{
|
{
|
||||||
strncpy(node_name, PQgetvalue(res, 0, 0), MAXLEN);
|
strncpy(node_name, PQgetvalue(res, 0, 0), MAXLEN);
|
||||||
}
|
}
|
||||||
@@ -4132,8 +4110,7 @@ add_extension_tables_to_bdr_replication_set(PGconn *conn)
|
|||||||
|
|
||||||
initPQExpBuffer(&query);
|
initPQExpBuffer(&query);
|
||||||
|
|
||||||
appendPQExpBuffer(
|
appendPQExpBuffer(&query,
|
||||||
&query,
|
|
||||||
" SELECT c.relname "
|
" SELECT c.relname "
|
||||||
" FROM pg_class c "
|
" FROM pg_class c "
|
||||||
"INNER JOIN pg_namespace n "
|
"INNER JOIN pg_namespace n "
|
||||||
@@ -4146,7 +4123,7 @@ add_extension_tables_to_bdr_replication_set(PGconn *conn)
|
|||||||
|
|
||||||
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
||||||
{
|
{
|
||||||
//
|
/* */
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -4174,8 +4151,7 @@ get_all_bdr_node_records(PGconn *conn, BdrNodeInfoList *node_list)
|
|||||||
|
|
||||||
initPQExpBuffer(&query);
|
initPQExpBuffer(&query);
|
||||||
|
|
||||||
appendPQExpBuffer(
|
appendPQExpBuffer(&query,
|
||||||
&query,
|
|
||||||
" SELECT " BDR_NODES_COLUMNS
|
" SELECT " BDR_NODES_COLUMNS
|
||||||
" FROM bdr.bdr_nodes "
|
" FROM bdr.bdr_nodes "
|
||||||
"ORDER BY node_seq_id ");
|
"ORDER BY node_seq_id ");
|
||||||
@@ -4199,8 +4175,7 @@ get_bdr_node_record_by_name(PGconn *conn, const char *node_name, t_bdr_node_info
|
|||||||
|
|
||||||
initPQExpBuffer(&query);
|
initPQExpBuffer(&query);
|
||||||
|
|
||||||
appendPQExpBuffer(
|
appendPQExpBuffer(&query,
|
||||||
&query,
|
|
||||||
" SELECT " BDR_NODES_COLUMNS
|
" SELECT " BDR_NODES_COLUMNS
|
||||||
" FROM bdr.bdr_nodes "
|
" FROM bdr.bdr_nodes "
|
||||||
" WHERE node_name = '%s'",
|
" WHERE node_name = '%s'",
|
||||||
@@ -4236,11 +4211,12 @@ get_bdr_node_record_by_name(PGconn *conn, const char *node_name, t_bdr_node_info
|
|||||||
|
|
||||||
|
|
||||||
static
|
static
|
||||||
void _populate_bdr_node_records(PGresult *res, BdrNodeInfoList *node_list)
|
void
|
||||||
|
_populate_bdr_node_records(PGresult *res, BdrNodeInfoList *node_list)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
clear_node_info_list((NodeInfoList *)node_list);
|
clear_node_info_list((NodeInfoList *) node_list);
|
||||||
|
|
||||||
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
||||||
{
|
{
|
||||||
@@ -4250,6 +4226,7 @@ void _populate_bdr_node_records(PGresult *res, BdrNodeInfoList *node_list)
|
|||||||
for (i = 0; i < PQntuples(res); i++)
|
for (i = 0; i < PQntuples(res); i++)
|
||||||
{
|
{
|
||||||
BdrNodeInfoListCell *cell;
|
BdrNodeInfoListCell *cell;
|
||||||
|
|
||||||
cell = (BdrNodeInfoListCell *) pg_malloc0(sizeof(BdrNodeInfoListCell));
|
cell = (BdrNodeInfoListCell *) pg_malloc0(sizeof(BdrNodeInfoListCell));
|
||||||
|
|
||||||
cell->node_info = pg_malloc0(sizeof(t_bdr_node_info));
|
cell->node_info = pg_malloc0(sizeof(t_bdr_node_info));
|
||||||
@@ -4294,8 +4271,7 @@ am_bdr_failover_handler(PGconn *conn, int node_id)
|
|||||||
|
|
||||||
initPQExpBuffer(&query);
|
initPQExpBuffer(&query);
|
||||||
|
|
||||||
appendPQExpBuffer(
|
appendPQExpBuffer(&query,
|
||||||
&query,
|
|
||||||
"SELECT repmgr.am_bdr_failover_handler(%i)",
|
"SELECT repmgr.am_bdr_failover_handler(%i)",
|
||||||
node_id);
|
node_id);
|
||||||
|
|
||||||
@@ -4322,9 +4298,9 @@ void
|
|||||||
unset_bdr_failover_handler(PGconn *conn)
|
unset_bdr_failover_handler(PGconn *conn)
|
||||||
{
|
{
|
||||||
PGresult *res = NULL;
|
PGresult *res = NULL;
|
||||||
|
|
||||||
res = PQexec(conn, "SELECT repmgr.unset_bdr_failover_handler()");
|
res = PQexec(conn, "SELECT repmgr.unset_bdr_failover_handler()");
|
||||||
|
|
||||||
PQclear(res);
|
PQclear(res);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
36
dbutils.h
36
dbutils.h
@@ -33,52 +33,60 @@
|
|||||||
|
|
||||||
#define ERRBUFF_SIZE 512
|
#define ERRBUFF_SIZE 512
|
||||||
|
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
UNKNOWN = 0,
|
UNKNOWN = 0,
|
||||||
PRIMARY,
|
PRIMARY,
|
||||||
STANDBY,
|
STANDBY,
|
||||||
BDR
|
BDR
|
||||||
} t_server_type;
|
} t_server_type;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
REPMGR_INSTALLED = 0,
|
REPMGR_INSTALLED = 0,
|
||||||
REPMGR_AVAILABLE,
|
REPMGR_AVAILABLE,
|
||||||
REPMGR_UNAVAILABLE,
|
REPMGR_UNAVAILABLE,
|
||||||
REPMGR_UNKNOWN
|
REPMGR_UNKNOWN
|
||||||
} ExtensionStatus;
|
} ExtensionStatus;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
RECTYPE_UNKNOWN = -1,
|
RECTYPE_UNKNOWN = -1,
|
||||||
RECTYPE_PRIMARY,
|
RECTYPE_PRIMARY,
|
||||||
RECTYPE_STANDBY
|
RECTYPE_STANDBY
|
||||||
} RecoveryType;
|
} RecoveryType;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
RECORD_ERROR = -1,
|
RECORD_ERROR = -1,
|
||||||
RECORD_FOUND,
|
RECORD_FOUND,
|
||||||
RECORD_NOT_FOUND
|
RECORD_NOT_FOUND
|
||||||
} RecordStatus;
|
} RecordStatus;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
MS_NORMAL = 0,
|
MS_NORMAL = 0,
|
||||||
MS_DEGRADED = 1
|
MS_DEGRADED = 1
|
||||||
} MonitoringState;
|
} MonitoringState;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
NODE_STATUS_UNKNOWN = -1,
|
NODE_STATUS_UNKNOWN = -1,
|
||||||
NODE_STATUS_UP,
|
NODE_STATUS_UP,
|
||||||
NODE_STATUS_DOWN,
|
NODE_STATUS_DOWN,
|
||||||
NODE_STATUS_UNCLEAN_SHUTDOWN
|
NODE_STATUS_UNCLEAN_SHUTDOWN
|
||||||
} NodeStatus;
|
} NodeStatus;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
VR_VOTE_REFUSED = -1,
|
VR_VOTE_REFUSED = -1,
|
||||||
VR_POSITIVE_VOTE,
|
VR_POSITIVE_VOTE,
|
||||||
VR_NEGATIVE_VOTE
|
VR_NEGATIVE_VOTE
|
||||||
} VoteRequestResult;
|
} VoteRequestResult;
|
||||||
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
SLOT_UNKNOWN = -1,
|
SLOT_UNKNOWN = -1,
|
||||||
SLOT_INACTIVE,
|
SLOT_INACTIVE,
|
||||||
SLOT_ACTIVE
|
SLOT_ACTIVE
|
||||||
@@ -260,7 +268,8 @@ typedef struct BdrNodeInfoList
|
|||||||
0 \
|
0 \
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
char current_timestamp[MAXLEN];
|
char current_timestamp[MAXLEN];
|
||||||
uint64 last_wal_receive_lsn;
|
uint64 last_wal_receive_lsn;
|
||||||
uint64 last_wal_replay_lsn;
|
uint64 last_wal_replay_lsn;
|
||||||
@@ -321,7 +330,8 @@ extern int server_version_num;
|
|||||||
|
|
||||||
XLogRecPtr parse_lsn(const char *str);
|
XLogRecPtr parse_lsn(const char *str);
|
||||||
|
|
||||||
extern void wrap_ddl_query(PQExpBufferData *query_buf, int replication_type, const char *fmt, ...)
|
extern void
|
||||||
|
wrap_ddl_query(PQExpBufferData *query_buf, int replication_type, const char *fmt,...)
|
||||||
__attribute__((format(PG_PRINTF_ATTRIBUTE, 3, 4)));
|
__attribute__((format(PG_PRINTF_ATTRIBUTE, 3, 4)));
|
||||||
bool atobool(const char *value);
|
bool atobool(const char *value);
|
||||||
|
|
||||||
@@ -445,7 +455,8 @@ int wait_connection_availability(PGconn *conn, long long timeout);
|
|||||||
bool is_server_available(const char *conninfo);
|
bool is_server_available(const char *conninfo);
|
||||||
|
|
||||||
/* monitoring functions */
|
/* monitoring functions */
|
||||||
void add_monitoring_record(
|
void
|
||||||
|
add_monitoring_record(
|
||||||
PGconn *primary_conn,
|
PGconn *primary_conn,
|
||||||
PGconn *local_conn,
|
PGconn *local_conn,
|
||||||
int primary_node_id,
|
int primary_node_id,
|
||||||
@@ -456,7 +467,7 @@ void add_monitoring_record(
|
|||||||
char *last_xact_replay_timestamp,
|
char *last_xact_replay_timestamp,
|
||||||
long long unsigned int replication_lag_bytes,
|
long long unsigned int replication_lag_bytes,
|
||||||
long long unsigned int apply_lag_bytes
|
long long unsigned int apply_lag_bytes
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
/* node voting functions */
|
/* node voting functions */
|
||||||
@@ -494,4 +505,3 @@ bool am_bdr_failover_handler(PGconn *conn, int node_id);
|
|||||||
void unset_bdr_failover_handler(PGconn *conn);
|
void unset_bdr_failover_handler(PGconn *conn);
|
||||||
|
|
||||||
#endif /* _REPMGR_DBUTILS_H_ */
|
#endif /* _REPMGR_DBUTILS_H_ */
|
||||||
|
|
||||||
|
|||||||
@@ -321,4 +321,3 @@ unlink_dir_callback(const char *fpath, const struct stat *sb, int typeflag, stru
|
|||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -45,4 +45,3 @@
|
|||||||
#define ERR_OUT_OF_MEMORY 21
|
#define ERR_OUT_OF_MEMORY 21
|
||||||
|
|
||||||
#endif /* _ERRCODE_H_ */
|
#endif /* _ERRCODE_H_ */
|
||||||
|
|
||||||
|
|||||||
39
log.c
39
log.c
@@ -37,7 +37,8 @@
|
|||||||
/* #define REPMGR_DEBUG */
|
/* #define REPMGR_DEBUG */
|
||||||
|
|
||||||
static int detect_log_facility(const char *facility);
|
static int detect_log_facility(const char *facility);
|
||||||
static void _stderr_log_with_level(const char *level_name, int level, const char *fmt, va_list ap)
|
static void
|
||||||
|
_stderr_log_with_level(const char *level_name, int level, const char *fmt, va_list ap)
|
||||||
__attribute__((format(PG_PRINTF_ATTRIBUTE, 3, 0)));
|
__attribute__((format(PG_PRINTF_ATTRIBUTE, 3, 0)));
|
||||||
|
|
||||||
int log_type = REPMGR_STDERR;
|
int log_type = REPMGR_STDERR;
|
||||||
@@ -45,6 +46,7 @@ int log_level = LOG_NOTICE;
|
|||||||
int last_log_level = LOG_INFO;
|
int last_log_level = LOG_INFO;
|
||||||
int verbose_logging = false;
|
int verbose_logging = false;
|
||||||
int terse_logging = false;
|
int terse_logging = false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Global variable to be set by the main application to ensure any log output
|
* Global variable to be set by the main application to ensure any log output
|
||||||
* emitted before logger_init is called, is output in the correct format
|
* emitted before logger_init is called, is output in the correct format
|
||||||
@@ -52,7 +54,7 @@ int terse_logging = false;
|
|||||||
int logger_output_mode = OM_DAEMON;
|
int logger_output_mode = OM_DAEMON;
|
||||||
|
|
||||||
extern void
|
extern void
|
||||||
stderr_log_with_level(const char *level_name, int level, const char *fmt, ...)
|
stderr_log_with_level(const char *level_name, int level, const char *fmt,...)
|
||||||
{
|
{
|
||||||
va_list arglist;
|
va_list arglist;
|
||||||
|
|
||||||
@@ -67,8 +69,8 @@ _stderr_log_with_level(const char *level_name, int level, const char *fmt, va_li
|
|||||||
char buf[100];
|
char buf[100];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Store the requested level so that if there's a subsequent
|
* Store the requested level so that if there's a subsequent log_hint() or
|
||||||
* log_hint() or log_detail(), we can suppress that if appropriate.
|
* log_detail(), we can suppress that if appropriate.
|
||||||
*/
|
*/
|
||||||
last_log_level = level;
|
last_log_level = level;
|
||||||
|
|
||||||
@@ -80,6 +82,7 @@ _stderr_log_with_level(const char *level_name, int level, const char *fmt, va_li
|
|||||||
{
|
{
|
||||||
time_t t;
|
time_t t;
|
||||||
struct tm *tm;
|
struct tm *tm;
|
||||||
|
|
||||||
time(&t);
|
time(&t);
|
||||||
tm = localtime(&t);
|
tm = localtime(&t);
|
||||||
strftime(buf, 100, "[%Y-%m-%d %H:%M:%S]", tm);
|
strftime(buf, 100, "[%Y-%m-%d %H:%M:%S]", tm);
|
||||||
@@ -97,7 +100,7 @@ _stderr_log_with_level(const char *level_name, int level, const char *fmt, va_li
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
log_hint(const char *fmt, ...)
|
log_hint(const char *fmt,...)
|
||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
|
|
||||||
@@ -111,7 +114,7 @@ log_hint(const char *fmt, ...)
|
|||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
log_detail(const char *fmt, ...)
|
log_detail(const char *fmt,...)
|
||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
|
|
||||||
@@ -125,7 +128,7 @@ log_detail(const char *fmt, ...)
|
|||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
log_verbose(int level, const char *fmt, ...)
|
log_verbose(int level, const char *fmt,...)
|
||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
|
|
||||||
@@ -133,7 +136,7 @@ log_verbose(int level, const char *fmt, ...)
|
|||||||
|
|
||||||
if (verbose_logging == true)
|
if (verbose_logging == true)
|
||||||
{
|
{
|
||||||
switch(level)
|
switch (level)
|
||||||
{
|
{
|
||||||
case LOG_EMERG:
|
case LOG_EMERG:
|
||||||
_stderr_log_with_level("EMERG", level, fmt, ap);
|
_stderr_log_with_level("EMERG", level, fmt, ap);
|
||||||
@@ -202,8 +205,8 @@ logger_init(t_configuration_options *opts, const char *ident)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* STDERR only logging requested - finish here without setting up any further
|
* STDERR only logging requested - finish here without setting up any
|
||||||
* logging facility.
|
* further logging facility.
|
||||||
*/
|
*/
|
||||||
if (logger_output_mode == OM_COMMAND_LINE)
|
if (logger_output_mode == OM_COMMAND_LINE)
|
||||||
return true;
|
return true;
|
||||||
@@ -251,9 +254,10 @@ logger_init(t_configuration_options *opts, const char *ident)
|
|||||||
{
|
{
|
||||||
FILE *fd;
|
FILE *fd;
|
||||||
|
|
||||||
/* Check if we can write to the specified file before redirecting
|
/*
|
||||||
* stderr - if freopen() fails, stderr output will vanish into
|
* Check if we can write to the specified file before redirecting
|
||||||
* the ether and the user won't know what's going on.
|
* stderr - if freopen() fails, stderr output will vanish into the
|
||||||
|
* ether and the user won't know what's going on.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
fd = fopen(opts->log_file, "a");
|
fd = fopen(opts->log_file, "a");
|
||||||
@@ -270,9 +274,9 @@ logger_init(t_configuration_options *opts, const char *ident)
|
|||||||
fd = freopen(opts->log_file, "a", stderr);
|
fd = freopen(opts->log_file, "a", stderr);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* It's possible freopen() may still fail due to e.g. a race condition;
|
* It's possible freopen() may still fail due to e.g. a race
|
||||||
* as it's not feasible to restore stderr after a failed freopen(),
|
* condition; as it's not feasible to restore stderr after a failed
|
||||||
* we'll write to stdout as a last resort.
|
* freopen(), we'll write to stdout as a last resort.
|
||||||
*/
|
*/
|
||||||
if (fd == NULL)
|
if (fd == NULL)
|
||||||
{
|
{
|
||||||
@@ -318,7 +322,8 @@ logger_set_verbose(void)
|
|||||||
* options and hints.
|
* options and hints.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void logger_set_terse(void)
|
void
|
||||||
|
logger_set_terse(void)
|
||||||
{
|
{
|
||||||
terse_logging = true;
|
terse_logging = true;
|
||||||
}
|
}
|
||||||
|
|||||||
11
log.h
11
log.h
@@ -122,18 +122,21 @@ int detect_log_level(const char *level);
|
|||||||
|
|
||||||
/* Logger initialisation and shutdown */
|
/* Logger initialisation and shutdown */
|
||||||
|
|
||||||
bool logger_init(t_configuration_options * opts, const char *ident);
|
bool logger_init(t_configuration_options *opts, const char *ident);
|
||||||
|
|
||||||
bool logger_shutdown(void);
|
bool logger_shutdown(void);
|
||||||
|
|
||||||
void logger_set_verbose(void);
|
void logger_set_verbose(void);
|
||||||
void logger_set_terse(void);
|
void logger_set_terse(void);
|
||||||
|
|
||||||
void log_detail(const char *fmt, ...)
|
void
|
||||||
|
log_detail(const char *fmt,...)
|
||||||
__attribute__((format(PG_PRINTF_ATTRIBUTE, 1, 2)));
|
__attribute__((format(PG_PRINTF_ATTRIBUTE, 1, 2)));
|
||||||
void log_hint(const char *fmt, ...)
|
void
|
||||||
|
log_hint(const char *fmt,...)
|
||||||
__attribute__((format(PG_PRINTF_ATTRIBUTE, 1, 2)));
|
__attribute__((format(PG_PRINTF_ATTRIBUTE, 1, 2)));
|
||||||
void log_verbose(int level, const char *fmt, ...)
|
void
|
||||||
|
log_verbose(int level, const char *fmt,...)
|
||||||
__attribute__((format(PG_PRINTF_ATTRIBUTE, 2, 3)));
|
__attribute__((format(PG_PRINTF_ATTRIBUTE, 2, 3)));
|
||||||
|
|
||||||
extern int log_type;
|
extern int log_type;
|
||||||
|
|||||||
@@ -136,15 +136,15 @@ do_bdr_register(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* before adding the extension tables to the replication set,
|
* before adding the extension tables to the replication set, if any other
|
||||||
* if any other BDR nodes exist, populate repmgr.nodes with a copy
|
* BDR nodes exist, populate repmgr.nodes with a copy of existing entries
|
||||||
* of existing entries
|
|
||||||
*
|
*
|
||||||
* currently we won't copy the contents of any other tables
|
* currently we won't copy the contents of any other tables
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
NodeInfoList local_node_records = T_NODE_INFO_LIST_INITIALIZER;
|
NodeInfoList local_node_records = T_NODE_INFO_LIST_INITIALIZER;
|
||||||
|
|
||||||
get_all_node_records(conn, &local_node_records);
|
get_all_node_records(conn, &local_node_records);
|
||||||
|
|
||||||
if (local_node_records.node_count == 0)
|
if (local_node_records.node_count == 0)
|
||||||
@@ -236,9 +236,10 @@ do_bdr_register(void)
|
|||||||
if (record_status == RECORD_FOUND)
|
if (record_status == RECORD_FOUND)
|
||||||
{
|
{
|
||||||
bool node_updated = false;
|
bool node_updated = false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* At this point we will have established there are no non-BDR records,
|
* At this point we will have established there are no non-BDR
|
||||||
* so no need to verify the node type
|
* records, so no need to verify the node type
|
||||||
*/
|
*/
|
||||||
if (!runtime_options.force)
|
if (!runtime_options.force)
|
||||||
{
|
{
|
||||||
@@ -250,8 +251,8 @@ do_bdr_register(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* don't permit changing the node name - this must match the
|
* don't permit changing the node name - this must match the BDR node
|
||||||
* BDR node name set when the node was registered.
|
* name set when the node was registered.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (strncmp(node_info.node_name, config_file_options.node_name, MAXLEN) != 0)
|
if (strncmp(node_info.node_name, config_file_options.node_name, MAXLEN) != 0)
|
||||||
|
|||||||
@@ -27,7 +27,8 @@
|
|||||||
#define SHOW_HEADER_COUNT 7
|
#define SHOW_HEADER_COUNT 7
|
||||||
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
SHOW_ID = 0,
|
SHOW_ID = 0,
|
||||||
SHOW_NAME,
|
SHOW_NAME,
|
||||||
SHOW_ROLE,
|
SHOW_ROLE,
|
||||||
@@ -39,7 +40,8 @@ typedef enum {
|
|||||||
|
|
||||||
#define EVENT_HEADER_COUNT 6
|
#define EVENT_HEADER_COUNT 6
|
||||||
|
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
EV_NODE_ID = 0,
|
EV_NODE_ID = 0,
|
||||||
EV_NODE_NAME,
|
EV_NODE_NAME,
|
||||||
EV_EVENT,
|
EV_EVENT,
|
||||||
@@ -50,7 +52,8 @@ typedef enum {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
struct ColHeader {
|
struct ColHeader
|
||||||
|
{
|
||||||
char title[MAXLEN];
|
char title[MAXLEN];
|
||||||
int max_length;
|
int max_length;
|
||||||
int cur_length;
|
int cur_length;
|
||||||
@@ -78,7 +81,7 @@ do_cluster_show(void)
|
|||||||
NodeInfoList nodes = T_NODE_INFO_LIST_INITIALIZER;
|
NodeInfoList nodes = T_NODE_INFO_LIST_INITIALIZER;
|
||||||
NodeInfoListCell *cell = NULL;
|
NodeInfoListCell *cell = NULL;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
ItemList warnings = { NULL, NULL };
|
ItemList warnings = {NULL, NULL};
|
||||||
|
|
||||||
/* Connect to local database to obtain cluster connection data */
|
/* Connect to local database to obtain cluster connection data */
|
||||||
log_verbose(LOG_INFO, _("connecting to database\n"));
|
log_verbose(LOG_INFO, _("connecting to database\n"));
|
||||||
@@ -106,8 +109,8 @@ do_cluster_show(void)
|
|||||||
strncpy(headers_show[SHOW_CONNINFO].title, _("Connection string"), MAXLEN);
|
strncpy(headers_show[SHOW_CONNINFO].title, _("Connection string"), MAXLEN);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* NOTE: if repmgr is ever localized into non-ASCII locales,
|
* NOTE: if repmgr is ever localized into non-ASCII locales, use
|
||||||
* use pg_wcssize() or similar to establish printed column length
|
* pg_wcssize() or similar to establish printed column length
|
||||||
*/
|
*/
|
||||||
|
|
||||||
for (i = 0; i < SHOW_HEADER_COUNT; i++)
|
for (i = 0; i < SHOW_HEADER_COUNT; i++)
|
||||||
@@ -136,7 +139,8 @@ do_cluster_show(void)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* TODO: count nodes marked as "? unreachable" and add a hint about
|
* TODO: count nodes marked as "? unreachable" and add a hint about
|
||||||
* the other cluster commands for better determining whether unreachable.
|
* the other cluster commands for better determining whether
|
||||||
|
* unreachable.
|
||||||
*/
|
*/
|
||||||
switch (cell->node_info->type)
|
switch (cell->node_info->type)
|
||||||
{
|
{
|
||||||
@@ -191,7 +195,7 @@ do_cluster_show(void)
|
|||||||
/* node is unreachable */
|
/* node is unreachable */
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* node is unreachable but marked active*/
|
/* node is unreachable but marked active */
|
||||||
if (cell->node_info->active == true)
|
if (cell->node_info->active == true)
|
||||||
{
|
{
|
||||||
appendPQExpBuffer(&details, "? unreachable");
|
appendPQExpBuffer(&details, "? unreachable");
|
||||||
@@ -259,7 +263,7 @@ do_cluster_show(void)
|
|||||||
/* node is unreachable */
|
/* node is unreachable */
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* node is unreachable but marked active*/
|
/* node is unreachable but marked active */
|
||||||
if (cell->node_info->active == true)
|
if (cell->node_info->active == true)
|
||||||
{
|
{
|
||||||
appendPQExpBuffer(&details, "? unreachable");
|
appendPQExpBuffer(&details, "? unreachable");
|
||||||
@@ -345,6 +349,7 @@ do_cluster_show(void)
|
|||||||
for (i = 0; i < SHOW_HEADER_COUNT; i++)
|
for (i = 0; i < SHOW_HEADER_COUNT; i++)
|
||||||
{
|
{
|
||||||
int j;
|
int j;
|
||||||
|
|
||||||
for (j = 0; j < headers_show[i].max_length; j++)
|
for (j = 0; j < headers_show[i].max_length; j++)
|
||||||
printf("-");
|
printf("-");
|
||||||
|
|
||||||
@@ -365,8 +370,8 @@ do_cluster_show(void)
|
|||||||
int recovery_type = RECTYPE_UNKNOWN;
|
int recovery_type = RECTYPE_UNKNOWN;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* here we explicitly convert the RecoveryType to integer values to
|
* here we explicitly convert the RecoveryType to integer values
|
||||||
* avoid implicit dependency on the values in the enum
|
* to avoid implicit dependency on the values in the enum
|
||||||
*/
|
*/
|
||||||
switch (cell->node_info->recovery_type)
|
switch (cell->node_info->recovery_type)
|
||||||
{
|
{
|
||||||
@@ -388,12 +393,12 @@ do_cluster_show(void)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
printf( " %-*i ", headers_show[SHOW_ID].max_length, cell->node_info->node_id);
|
printf(" %-*i ", headers_show[SHOW_ID].max_length, cell->node_info->node_id);
|
||||||
printf("| %-*s ", headers_show[SHOW_NAME].max_length, cell->node_info->node_name);
|
printf("| %-*s ", headers_show[SHOW_NAME].max_length, cell->node_info->node_name);
|
||||||
printf("| %-*s ", headers_show[SHOW_ROLE].max_length, get_node_type_string(cell->node_info->type));
|
printf("| %-*s ", headers_show[SHOW_ROLE].max_length, get_node_type_string(cell->node_info->type));
|
||||||
printf("| %-*s ", headers_show[SHOW_STATUS].max_length, cell->node_info->details);
|
printf("| %-*s ", headers_show[SHOW_STATUS].max_length, cell->node_info->details);
|
||||||
printf("| %-*s ", headers_show[SHOW_UPSTREAM_NAME].max_length , cell->node_info->upstream_node_name);
|
printf("| %-*s ", headers_show[SHOW_UPSTREAM_NAME].max_length, cell->node_info->upstream_node_name);
|
||||||
printf("| %-*s ", headers_show[SHOW_LOCATION].max_length , cell->node_info->location);
|
printf("| %-*s ", headers_show[SHOW_LOCATION].max_length, cell->node_info->location);
|
||||||
printf("| %-*s\n", headers_show[SHOW_CONNINFO].max_length, cell->node_info->conninfo);
|
printf("| %-*s\n", headers_show[SHOW_CONNINFO].max_length, cell->node_info->conninfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -516,7 +521,8 @@ do_cluster_event(void)
|
|||||||
exit(ERR_DB_QUERY);
|
exit(ERR_DB_QUERY);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PQntuples(res) == 0) {
|
if (PQntuples(res) == 0)
|
||||||
|
{
|
||||||
/* print this message directly, rather than as a log line */
|
/* print this message directly, rather than as a log line */
|
||||||
printf(_("no matching events found\n"));
|
printf(_("no matching events found\n"));
|
||||||
PQclear(res);
|
PQclear(res);
|
||||||
@@ -536,14 +542,14 @@ do_cluster_event(void)
|
|||||||
headers_event[i].max_length = strlen(headers_event[i].title);
|
headers_event[i].max_length = strlen(headers_event[i].title);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(i = 0; i < PQntuples(res); i++)
|
for (i = 0; i < PQntuples(res); i++)
|
||||||
{
|
{
|
||||||
int j;
|
int j;
|
||||||
|
|
||||||
for (j = 0; j < EVENT_HEADER_COUNT; j++)
|
for (j = 0; j < EVENT_HEADER_COUNT; j++)
|
||||||
{
|
{
|
||||||
headers_event[j].cur_length = strlen(PQgetvalue(res, i, j));
|
headers_event[j].cur_length = strlen(PQgetvalue(res, i, j));
|
||||||
if(headers_event[j].cur_length > headers_event[j].max_length)
|
if (headers_event[j].cur_length > headers_event[j].max_length)
|
||||||
{
|
{
|
||||||
headers_event[j].max_length = headers_event[j].cur_length;
|
headers_event[j].max_length = headers_event[j].cur_length;
|
||||||
}
|
}
|
||||||
@@ -567,6 +573,7 @@ do_cluster_event(void)
|
|||||||
for (i = 0; i < EVENT_HEADER_COUNT; i++)
|
for (i = 0; i < EVENT_HEADER_COUNT; i++)
|
||||||
{
|
{
|
||||||
int j;
|
int j;
|
||||||
|
|
||||||
for (j = 0; j < headers_event[i].max_length; j++)
|
for (j = 0; j < headers_event[i].max_length; j++)
|
||||||
printf("-");
|
printf("-");
|
||||||
|
|
||||||
@@ -578,7 +585,7 @@ do_cluster_event(void)
|
|||||||
|
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
||||||
for(i = 0; i < PQntuples(res); i++)
|
for (i = 0; i < PQntuples(res); i++)
|
||||||
{
|
{
|
||||||
int j;
|
int j;
|
||||||
|
|
||||||
@@ -607,7 +614,8 @@ do_cluster_event(void)
|
|||||||
void
|
void
|
||||||
do_cluster_crosscheck(void)
|
do_cluster_crosscheck(void)
|
||||||
{
|
{
|
||||||
int i = 0, n = 0;
|
int i = 0,
|
||||||
|
n = 0;
|
||||||
char c;
|
char c;
|
||||||
const char *node_header = "Name";
|
const char *node_header = "Name";
|
||||||
int name_length = strlen(node_header);
|
int name_length = strlen(node_header);
|
||||||
@@ -642,22 +650,23 @@ do_cluster_crosscheck(void)
|
|||||||
int node_ix = 0;
|
int node_ix = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The value of entry (i,j) is equal to the
|
* The value of entry (i,j) is equal to the maximum value of all
|
||||||
* maximum value of all the (i,j,k). Indeed:
|
* the (i,j,k). Indeed:
|
||||||
*
|
*
|
||||||
* - if one of the (i,j,k) is 0 (node up), then 0
|
* - if one of the (i,j,k) is 0 (node up), then 0 (the node is
|
||||||
* (the node is up);
|
* up);
|
||||||
*
|
*
|
||||||
* - if the (i,j,k) are either -1 (down) or -2
|
* - if the (i,j,k) are either -1 (down) or -2 (unknown), then -1
|
||||||
* (unknown), then -1 (the node is down);
|
* (the node is down);
|
||||||
*
|
*
|
||||||
* - if all the (i,j,k) are -2 (unknown), then -2
|
* - if all the (i,j,k) are -2 (unknown), then -2 (the node is in
|
||||||
* (the node is in an unknown state).
|
* an unknown state).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
for(node_ix = 0; node_ix < n; node_ix ++)
|
for (node_ix = 0; node_ix < n; node_ix++)
|
||||||
{
|
{
|
||||||
int node_status = cube[node_ix]->matrix_list_rec[i]->node_status_list[column_node_ix]->node_status;
|
int node_status = cube[node_ix]->matrix_list_rec[i]->node_status_list[column_node_ix]->node_status;
|
||||||
|
|
||||||
if (node_status > max_node_status)
|
if (node_status > max_node_status)
|
||||||
max_node_status = node_status;
|
max_node_status = node_status;
|
||||||
}
|
}
|
||||||
@@ -685,7 +694,9 @@ do_cluster_crosscheck(void)
|
|||||||
|
|
||||||
/* clean up allocated cube array */
|
/* clean up allocated cube array */
|
||||||
{
|
{
|
||||||
int h, j;
|
int h,
|
||||||
|
j;
|
||||||
|
|
||||||
for (h = 0; h < n; h++)
|
for (h = 0; h < n; h++)
|
||||||
{
|
{
|
||||||
for (i = 0; i < n; i++)
|
for (i = 0; i < n; i++)
|
||||||
@@ -710,7 +721,9 @@ do_cluster_crosscheck(void)
|
|||||||
void
|
void
|
||||||
do_cluster_matrix()
|
do_cluster_matrix()
|
||||||
{
|
{
|
||||||
int i = 0, j = 0, n = 0;
|
int i = 0,
|
||||||
|
j = 0,
|
||||||
|
n = 0;
|
||||||
|
|
||||||
const char *node_header = "Name";
|
const char *node_header = "Name";
|
||||||
int name_length = strlen(node_header);
|
int name_length = strlen(node_header);
|
||||||
@@ -789,7 +802,8 @@ do_cluster_matrix()
|
|||||||
static void
|
static void
|
||||||
matrix_set_node_status(t_node_matrix_rec **matrix_rec_list, int n, int node_id, int connection_node_id, int connection_status)
|
matrix_set_node_status(t_node_matrix_rec **matrix_rec_list, int n, int node_id, int connection_node_id, int connection_status)
|
||||||
{
|
{
|
||||||
int i, j;
|
int i,
|
||||||
|
j;
|
||||||
|
|
||||||
for (i = 0; i < n; i++)
|
for (i = 0; i < n; i++)
|
||||||
{
|
{
|
||||||
@@ -813,7 +827,8 @@ static int
|
|||||||
build_cluster_matrix(t_node_matrix_rec ***matrix_rec_dest, int *name_length)
|
build_cluster_matrix(t_node_matrix_rec ***matrix_rec_dest, int *name_length)
|
||||||
{
|
{
|
||||||
PGconn *conn = NULL;
|
PGconn *conn = NULL;
|
||||||
int i = 0, j = 0;
|
int i = 0,
|
||||||
|
j = 0;
|
||||||
int local_node_id = UNKNOWN_NODE_ID;
|
int local_node_id = UNKNOWN_NODE_ID;
|
||||||
int node_count = 0;
|
int node_count = 0;
|
||||||
NodeInfoList nodes = T_NODE_INFO_LIST_INITIALIZER;
|
NodeInfoList nodes = T_NODE_INFO_LIST_INITIALIZER;
|
||||||
@@ -852,9 +867,7 @@ build_cluster_matrix(t_node_matrix_rec ***matrix_rec_dest, int *name_length)
|
|||||||
/*
|
/*
|
||||||
* Allocate an empty matrix record list
|
* Allocate an empty matrix record list
|
||||||
*
|
*
|
||||||
* -2 == NULL ?
|
* -2 == NULL ? -1 == Error x 0 == OK *
|
||||||
* -1 == Error x
|
|
||||||
* 0 == OK *
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
matrix_rec_list = (t_node_matrix_rec **) pg_malloc0(sizeof(t_node_matrix_rec) * nodes.node_count);
|
matrix_rec_list = (t_node_matrix_rec **) pg_malloc0(sizeof(t_node_matrix_rec) * nodes.node_count);
|
||||||
@@ -902,9 +915,11 @@ build_cluster_matrix(t_node_matrix_rec ***matrix_rec_dest, int *name_length)
|
|||||||
{
|
{
|
||||||
int connection_status = 0;
|
int connection_status = 0;
|
||||||
t_conninfo_param_list remote_conninfo = T_CONNINFO_PARAM_LIST_INITIALIZER;
|
t_conninfo_param_list remote_conninfo = T_CONNINFO_PARAM_LIST_INITIALIZER;
|
||||||
char *host = NULL, *p = NULL;
|
char *host = NULL,
|
||||||
|
*p = NULL;
|
||||||
int connection_node_id = cell->node_info->node_id;
|
int connection_node_id = cell->node_info->node_id;
|
||||||
int x, y;
|
int x,
|
||||||
|
y;
|
||||||
PGconn *node_conn = NULL;
|
PGconn *node_conn = NULL;
|
||||||
|
|
||||||
initialize_conninfo_params(&remote_conninfo, false);
|
initialize_conninfo_params(&remote_conninfo, false);
|
||||||
@@ -948,9 +963,9 @@ build_cluster_matrix(t_node_matrix_rec ***matrix_rec_dest, int *name_length)
|
|||||||
initPQExpBuffer(&command);
|
initPQExpBuffer(&command);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We'll pass cluster name and database connection string to the remote
|
* We'll pass cluster name and database connection string to the
|
||||||
* repmgr - those are the only values it needs to work, and saves us
|
* remote repmgr - those are the only values it needs to work, and
|
||||||
* making assumptions about the location of repmgr.conf
|
* saves us making assumptions about the location of repmgr.conf
|
||||||
*/
|
*/
|
||||||
appendPQExpBuffer(&command,
|
appendPQExpBuffer(&command,
|
||||||
"\"%s -d '%s' ",
|
"\"%s -d '%s' ",
|
||||||
@@ -975,7 +990,7 @@ build_cluster_matrix(t_node_matrix_rec ***matrix_rec_dest, int *name_length)
|
|||||||
|
|
||||||
initPQExpBuffer(&command_output);
|
initPQExpBuffer(&command_output);
|
||||||
|
|
||||||
(void)remote_command(
|
(void) remote_command(
|
||||||
host,
|
host,
|
||||||
runtime_options.remote_user,
|
runtime_options.remote_user,
|
||||||
command.data,
|
command.data,
|
||||||
@@ -998,7 +1013,7 @@ build_cluster_matrix(t_node_matrix_rec ***matrix_rec_dest, int *name_length)
|
|||||||
nodes.node_count,
|
nodes.node_count,
|
||||||
connection_node_id,
|
connection_node_id,
|
||||||
x,
|
x,
|
||||||
(y == -1) ? -1 : 0 );
|
(y == -1) ? -1 : 0);
|
||||||
|
|
||||||
while (*p && (*p != '\n'))
|
while (*p && (*p != '\n'))
|
||||||
p++;
|
p++;
|
||||||
@@ -1026,7 +1041,9 @@ static int
|
|||||||
build_cluster_crosscheck(t_node_status_cube ***dest_cube, int *name_length)
|
build_cluster_crosscheck(t_node_status_cube ***dest_cube, int *name_length)
|
||||||
{
|
{
|
||||||
PGconn *conn = NULL;
|
PGconn *conn = NULL;
|
||||||
int h, i, j;
|
int h,
|
||||||
|
i,
|
||||||
|
j;
|
||||||
NodeInfoList nodes = T_NODE_INFO_LIST_INITIALIZER;
|
NodeInfoList nodes = T_NODE_INFO_LIST_INITIALIZER;
|
||||||
NodeInfoListCell *cell = NULL;
|
NodeInfoListCell *cell = NULL;
|
||||||
|
|
||||||
@@ -1056,9 +1073,7 @@ build_cluster_crosscheck(t_node_status_cube ***dest_cube, int *name_length)
|
|||||||
/*
|
/*
|
||||||
* Allocate an empty cube matrix structure
|
* Allocate an empty cube matrix structure
|
||||||
*
|
*
|
||||||
* -2 == NULL
|
* -2 == NULL -1 == Error 0 == OK
|
||||||
* -1 == Error
|
|
||||||
* 0 == OK
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
cube = (t_node_status_cube **) pg_malloc(sizeof(t_node_status_cube *) * nodes.node_count);
|
cube = (t_node_status_cube **) pg_malloc(sizeof(t_node_status_cube *) * nodes.node_count);
|
||||||
@@ -1155,7 +1170,7 @@ build_cluster_crosscheck(t_node_status_cube ***dest_cube, int *name_length)
|
|||||||
/* fix to work with --node-id */
|
/* fix to work with --node-id */
|
||||||
if (cube[i]->node_id == config_file_options.node_id)
|
if (cube[i]->node_id == config_file_options.node_id)
|
||||||
{
|
{
|
||||||
(void)local_command(
|
(void) local_command(
|
||||||
command.data,
|
command.data,
|
||||||
&command_output);
|
&command_output);
|
||||||
}
|
}
|
||||||
@@ -1181,7 +1196,7 @@ build_cluster_crosscheck(t_node_status_cube ***dest_cube, int *name_length)
|
|||||||
|
|
||||||
log_verbose(LOG_DEBUG, "build_cluster_crosscheck(): executing\n %s", quoted_command.data);
|
log_verbose(LOG_DEBUG, "build_cluster_crosscheck(): executing\n %s", quoted_command.data);
|
||||||
|
|
||||||
(void)remote_command(
|
(void) remote_command(
|
||||||
host,
|
host,
|
||||||
runtime_options.remote_user,
|
runtime_options.remote_user,
|
||||||
quoted_command.data,
|
quoted_command.data,
|
||||||
@@ -1195,7 +1210,7 @@ build_cluster_crosscheck(t_node_status_cube ***dest_cube, int *name_length)
|
|||||||
|
|
||||||
p = command_output.data;
|
p = command_output.data;
|
||||||
|
|
||||||
if(!strlen(command_output.data))
|
if (!strlen(command_output.data))
|
||||||
{
|
{
|
||||||
termPQExpBuffer(&command_output);
|
termPQExpBuffer(&command_output);
|
||||||
continue;
|
continue;
|
||||||
@@ -1243,7 +1258,9 @@ build_cluster_crosscheck(t_node_status_cube ***dest_cube, int *name_length)
|
|||||||
static void
|
static void
|
||||||
cube_set_node_status(t_node_status_cube **cube, int n, int execute_node_id, int matrix_node_id, int connection_node_id, int connection_status)
|
cube_set_node_status(t_node_status_cube **cube, int n, int execute_node_id, int matrix_node_id, int connection_node_id, int connection_status)
|
||||||
{
|
{
|
||||||
int h, i, j;
|
int h,
|
||||||
|
i,
|
||||||
|
j;
|
||||||
|
|
||||||
|
|
||||||
for (h = 0; h < n; h++)
|
for (h = 0; h < n; h++)
|
||||||
|
|||||||
@@ -69,10 +69,10 @@ do_node_status(void)
|
|||||||
char cluster_size[MAXLEN];
|
char cluster_size[MAXLEN];
|
||||||
PQExpBufferData output;
|
PQExpBufferData output;
|
||||||
|
|
||||||
KeyValueList node_status = { NULL, NULL };
|
KeyValueList node_status = {NULL, NULL};
|
||||||
KeyValueListCell *cell = NULL;
|
KeyValueListCell *cell = NULL;
|
||||||
|
|
||||||
ItemList warnings = { NULL, NULL };
|
ItemList warnings = {NULL, NULL};
|
||||||
RecoveryType recovery_type = RECTYPE_UNKNOWN;
|
RecoveryType recovery_type = RECTYPE_UNKNOWN;
|
||||||
ReplInfo replication_info = T_REPLINFO_INTIALIZER;
|
ReplInfo replication_info = T_REPLINFO_INTIALIZER;
|
||||||
t_recovery_conf recovery_conf = T_RECOVERY_CONF_INITIALIZER;
|
t_recovery_conf recovery_conf = T_RECOVERY_CONF_INITIALIZER;
|
||||||
@@ -268,6 +268,7 @@ do_node_status(void)
|
|||||||
if (node_info.max_replication_slots > 0)
|
if (node_info.max_replication_slots > 0)
|
||||||
{
|
{
|
||||||
PQExpBufferData slotinfo;
|
PQExpBufferData slotinfo;
|
||||||
|
|
||||||
initPQExpBuffer(&slotinfo);
|
initPQExpBuffer(&slotinfo);
|
||||||
|
|
||||||
appendPQExpBuffer(
|
appendPQExpBuffer(
|
||||||
@@ -456,7 +457,8 @@ do_node_status(void)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
static
|
static
|
||||||
void _do_node_status_is_shutdown_cleanly(void)
|
void
|
||||||
|
_do_node_status_is_shutdown_cleanly(void)
|
||||||
{
|
{
|
||||||
PGPing ping_status;
|
PGPing ping_status;
|
||||||
PQExpBufferData output;
|
PQExpBufferData output;
|
||||||
@@ -503,7 +505,10 @@ void _do_node_status_is_shutdown_cleanly(void)
|
|||||||
|
|
||||||
if (db_state != DB_SHUTDOWNED && db_state != DB_SHUTDOWNED_IN_RECOVERY)
|
if (db_state != DB_SHUTDOWNED && db_state != DB_SHUTDOWNED_IN_RECOVERY)
|
||||||
{
|
{
|
||||||
/* node is not running, but pg_controldata says it is - unclean shutdown */
|
/*
|
||||||
|
* node is not running, but pg_controldata says it is - unclean
|
||||||
|
* shutdown
|
||||||
|
*/
|
||||||
if (node_status != NODE_STATUS_UP)
|
if (node_status != NODE_STATUS_UP)
|
||||||
{
|
{
|
||||||
node_status = NODE_STATUS_UNCLEAN_SHUTDOWN;
|
node_status = NODE_STATUS_UNCLEAN_SHUTDOWN;
|
||||||
@@ -517,7 +522,11 @@ void _do_node_status_is_shutdown_cleanly(void)
|
|||||||
{
|
{
|
||||||
node_status = NODE_STATUS_UNKNOWN;
|
node_status = NODE_STATUS_UNKNOWN;
|
||||||
}
|
}
|
||||||
/* if still "UNKNOWN" at this point, then the node must be cleanly shut down */
|
|
||||||
|
/*
|
||||||
|
* if still "UNKNOWN" at this point, then the node must be cleanly shut
|
||||||
|
* down
|
||||||
|
*/
|
||||||
else if (node_status == NODE_STATUS_UNKNOWN)
|
else if (node_status == NODE_STATUS_UNKNOWN)
|
||||||
{
|
{
|
||||||
node_status = NODE_STATUS_DOWN;
|
node_status = NODE_STATUS_DOWN;
|
||||||
@@ -557,7 +566,7 @@ do_node_check(void)
|
|||||||
|
|
||||||
t_node_info node_info = T_NODE_INFO_INITIALIZER;
|
t_node_info node_info = T_NODE_INFO_INITIALIZER;
|
||||||
|
|
||||||
CheckStatusList status_list = { NULL, NULL };
|
CheckStatusList status_list = {NULL, NULL};
|
||||||
CheckStatusListCell *cell = NULL;
|
CheckStatusListCell *cell = NULL;
|
||||||
|
|
||||||
|
|
||||||
@@ -576,8 +585,9 @@ do_node_check(void)
|
|||||||
/* add replication statistics to node record */
|
/* add replication statistics to node record */
|
||||||
get_node_replication_stats(conn, &node_info);
|
get_node_replication_stats(conn, &node_info);
|
||||||
|
|
||||||
/* handle specific checks
|
/*
|
||||||
* ====================== */
|
* handle specific checks ======================
|
||||||
|
*/
|
||||||
if (runtime_options.archive_ready == true)
|
if (runtime_options.archive_ready == true)
|
||||||
{
|
{
|
||||||
(void) do_node_check_archive_ready(conn, runtime_options.output_mode, NULL);
|
(void) do_node_check_archive_ready(conn, runtime_options.output_mode, NULL);
|
||||||
@@ -1225,8 +1235,8 @@ do_node_check_downstream(PGconn *conn, OutputMode mode, CheckStatusList *list_ou
|
|||||||
NodeInfoListCell *cell = NULL;
|
NodeInfoListCell *cell = NULL;
|
||||||
int missing_nodes_count = 0;
|
int missing_nodes_count = 0;
|
||||||
CheckStatus status = CHECK_STATUS_OK;
|
CheckStatus status = CHECK_STATUS_OK;
|
||||||
ItemList missing_nodes = { NULL, NULL };
|
ItemList missing_nodes = {NULL, NULL};
|
||||||
ItemList attached_nodes = { NULL, NULL };
|
ItemList attached_nodes = {NULL, NULL};
|
||||||
PQExpBufferData details;
|
PQExpBufferData details;
|
||||||
|
|
||||||
initPQExpBuffer(&details);
|
initPQExpBuffer(&details);
|
||||||
@@ -1237,7 +1247,7 @@ do_node_check_downstream(PGconn *conn, OutputMode mode, CheckStatusList *list_ou
|
|||||||
{
|
{
|
||||||
if (is_downstream_node_attached(conn, cell->node_info->node_name) == false)
|
if (is_downstream_node_attached(conn, cell->node_info->node_name) == false)
|
||||||
{
|
{
|
||||||
missing_nodes_count ++;
|
missing_nodes_count++;
|
||||||
item_list_append_format(&missing_nodes,
|
item_list_append_format(&missing_nodes,
|
||||||
"%s (ID: %i)",
|
"%s (ID: %i)",
|
||||||
cell->node_info->node_name,
|
cell->node_info->node_name,
|
||||||
@@ -1269,6 +1279,7 @@ do_node_check_downstream(PGconn *conn, OutputMode mode, CheckStatusList *list_ou
|
|||||||
{
|
{
|
||||||
ItemListCell *missing_cell = NULL;
|
ItemListCell *missing_cell = NULL;
|
||||||
bool first = true;
|
bool first = true;
|
||||||
|
|
||||||
status = CHECK_STATUS_CRITICAL;
|
status = CHECK_STATUS_CRITICAL;
|
||||||
|
|
||||||
appendPQExpBuffer(
|
appendPQExpBuffer(
|
||||||
@@ -1330,6 +1341,7 @@ do_node_check_downstream(PGconn *conn, OutputMode mode, CheckStatusList *list_ou
|
|||||||
{
|
{
|
||||||
ItemListCell *attached_cell = NULL;
|
ItemListCell *attached_cell = NULL;
|
||||||
bool first = true;
|
bool first = true;
|
||||||
|
|
||||||
if (missing_nodes_count)
|
if (missing_nodes_count)
|
||||||
printf("; ");
|
printf("; ");
|
||||||
printf("attached: ");
|
printf("attached: ");
|
||||||
@@ -1433,7 +1445,7 @@ do_node_service(void)
|
|||||||
|
|
||||||
log_notice(_("issuing CHECKPOINT"));
|
log_notice(_("issuing CHECKPOINT"));
|
||||||
|
|
||||||
// check superuser conn!
|
/* check superuser conn! */
|
||||||
checkpoint(conn);
|
checkpoint(conn);
|
||||||
|
|
||||||
PQfinish(conn);
|
PQfinish(conn);
|
||||||
@@ -1661,8 +1673,8 @@ do_node_rejoin(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Forcibly rewind node if requested (this is mainly for use when
|
* Forcibly rewind node if requested (this is mainly for use when this
|
||||||
* this action is being executed by "repmgr standby switchover")
|
* action is being executed by "repmgr standby switchover")
|
||||||
*/
|
*/
|
||||||
if (runtime_options.force_rewind == true)
|
if (runtime_options.force_rewind == true)
|
||||||
{
|
{
|
||||||
@@ -1783,7 +1795,7 @@ _do_node_archive_config(void)
|
|||||||
DIR *arcdir;
|
DIR *arcdir;
|
||||||
|
|
||||||
|
|
||||||
KeyValueList config_files = { NULL, NULL };
|
KeyValueList config_files = {NULL, NULL};
|
||||||
KeyValueListCell *cell = NULL;
|
KeyValueListCell *cell = NULL;
|
||||||
int copied_count = 0;
|
int copied_count = 0;
|
||||||
|
|
||||||
@@ -1811,7 +1823,7 @@ _do_node_archive_config(void)
|
|||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
else if(!S_ISDIR(statbuf.st_mode))
|
else if (!S_ISDIR(statbuf.st_mode))
|
||||||
{
|
{
|
||||||
log_error(_("\"%s\" exists but is not a directory"),
|
log_error(_("\"%s\" exists but is not a directory"),
|
||||||
archive_dir);
|
archive_dir);
|
||||||
@@ -1830,8 +1842,8 @@ _do_node_archive_config(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* attempt to remove any existing files in the directory
|
* attempt to remove any existing files in the directory TODO: collate
|
||||||
* TODO: collate problem files into list
|
* problem files into list
|
||||||
*/
|
*/
|
||||||
while ((arcdir_ent = readdir(arcdir)) != NULL)
|
while ((arcdir_ent = readdir(arcdir)) != NULL)
|
||||||
{
|
{
|
||||||
@@ -2027,8 +2039,9 @@ _do_node_restore_config(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Finally, delete directory - it should be empty unless it's been interfered
|
* Finally, delete directory - it should be empty unless it's been
|
||||||
* with for some reason, in which case manual intervention is required
|
* interfered with for some reason, in which case manual intervention is
|
||||||
|
* required
|
||||||
*/
|
*/
|
||||||
if (rmdir(archive_dir) != 0 && errno != EEXIST)
|
if (rmdir(archive_dir) != 0 && errno != EEXIST)
|
||||||
{
|
{
|
||||||
@@ -2063,7 +2076,8 @@ format_archive_dir(char *archive_dir)
|
|||||||
static bool
|
static bool
|
||||||
copy_file(const char *src_file, const char *dest_file)
|
copy_file(const char *src_file, const char *dest_file)
|
||||||
{
|
{
|
||||||
FILE *ptr_old, *ptr_new;
|
FILE *ptr_old,
|
||||||
|
*ptr_new;
|
||||||
int a = 0;
|
int a = 0;
|
||||||
|
|
||||||
ptr_old = fopen(src_file, "r");
|
ptr_old = fopen(src_file, "r");
|
||||||
@@ -2080,7 +2094,7 @@ copy_file(const char *src_file, const char *dest_file)
|
|||||||
|
|
||||||
chmod(dest_file, S_IRUSR | S_IWUSR);
|
chmod(dest_file, S_IRUSR | S_IWUSR);
|
||||||
|
|
||||||
while(1)
|
while (1)
|
||||||
{
|
{
|
||||||
a = fgetc(ptr_old);
|
a = fgetc(ptr_old);
|
||||||
|
|
||||||
|
|||||||
@@ -83,8 +83,8 @@ do_primary_register(void)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* In --dry-run mode we can't proceed any further as the following code
|
* In --dry-run mode we can't proceed any further as the following code
|
||||||
* attempts to query the repmgr metadata, which won't exist until
|
* attempts to query the repmgr metadata, which won't exist until the
|
||||||
* the extension is installed
|
* extension is installed
|
||||||
*/
|
*/
|
||||||
if (runtime_options.dry_run == true)
|
if (runtime_options.dry_run == true)
|
||||||
{
|
{
|
||||||
@@ -100,7 +100,10 @@ do_primary_register(void)
|
|||||||
{
|
{
|
||||||
if (current_primary_id != config_file_options.node_id)
|
if (current_primary_id != config_file_options.node_id)
|
||||||
{
|
{
|
||||||
/* it's impossible to add a second primary to a streaming replication cluster */
|
/*
|
||||||
|
* it's impossible to add a second primary to a streaming
|
||||||
|
* replication cluster
|
||||||
|
*/
|
||||||
log_error(_("there is already an active registered primary (node ID: %i) in this cluster"), current_primary_id);
|
log_error(_("there is already an active registered primary (node ID: %i) in this cluster"), current_primary_id);
|
||||||
PQfinish(primary_conn);
|
PQfinish(primary_conn);
|
||||||
PQfinish(conn);
|
PQfinish(conn);
|
||||||
@@ -115,8 +118,9 @@ do_primary_register(void)
|
|||||||
begin_transaction(conn);
|
begin_transaction(conn);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check for an active primary node record with a different ID. This shouldn't
|
* Check for an active primary node record with a different ID. This
|
||||||
* happen, but could do if an existing primary was shut down without being unregistered.
|
* shouldn't happen, but could do if an existing primary was shut down
|
||||||
|
* without being unregistered.
|
||||||
*/
|
*/
|
||||||
current_primary_id = get_primary_node_id(conn);
|
current_primary_id = get_primary_node_id(conn);
|
||||||
if (current_primary_id != NODE_NOT_FOUND && current_primary_id != config_file_options.node_id)
|
if (current_primary_id != NODE_NOT_FOUND && current_primary_id != config_file_options.node_id)
|
||||||
@@ -130,8 +134,8 @@ do_primary_register(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check whether there's an existing record for this node, and
|
* Check whether there's an existing record for this node, and update it
|
||||||
* update it if --force set
|
* if --force set
|
||||||
*/
|
*/
|
||||||
|
|
||||||
record_status = get_node_record(conn, config_file_options.node_id, &node_info);
|
record_status = get_node_record(conn, config_file_options.node_id, &node_info);
|
||||||
@@ -257,8 +261,8 @@ do_primary_unregister(void)
|
|||||||
get_local_node_record(local_conn, config_file_options.node_id, &local_node_info);
|
get_local_node_record(local_conn, config_file_options.node_id, &local_node_info);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Obtain a connection to the current primary node - if this isn't possible,
|
* Obtain a connection to the current primary node - if this isn't
|
||||||
* abort as we won't be able to update the "nodes" table anyway.
|
* possible, abort as we won't be able to update the "nodes" table anyway.
|
||||||
*/
|
*/
|
||||||
primary_conn = establish_primary_db_connection(local_conn, false);
|
primary_conn = establish_primary_db_connection(local_conn, false);
|
||||||
|
|
||||||
@@ -367,7 +371,10 @@ do_primary_unregister(void)
|
|||||||
/* Node appears to be a standby */
|
/* Node appears to be a standby */
|
||||||
if (recovery_type == RECTYPE_STANDBY)
|
if (recovery_type == RECTYPE_STANDBY)
|
||||||
{
|
{
|
||||||
/* We'll refuse to do anything unless the node record shows it as a primary */
|
/*
|
||||||
|
* We'll refuse to do anything unless the node record shows it as
|
||||||
|
* a primary
|
||||||
|
*/
|
||||||
if (target_node_info_ptr->type != PRIMARY)
|
if (target_node_info_ptr->type != PRIMARY)
|
||||||
{
|
{
|
||||||
log_error(_("node %s (ID: %i) is a %s, unable to unregister"),
|
log_error(_("node %s (ID: %i) is a %s, unable to unregister"),
|
||||||
@@ -376,9 +383,11 @@ do_primary_unregister(void)
|
|||||||
get_node_type_string(target_node_info_ptr->type));
|
get_node_type_string(target_node_info_ptr->type));
|
||||||
can_unregister = false;
|
can_unregister = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If --F/--force not set, hint that it might be appropriate to
|
* If --F/--force not set, hint that it might be appropriate to
|
||||||
* register the node as a standby rather than unregister as primary
|
* register the node as a standby rather than unregister as
|
||||||
|
* primary
|
||||||
*/
|
*/
|
||||||
else if (!runtime_options.force)
|
else if (!runtime_options.force)
|
||||||
{
|
{
|
||||||
@@ -415,8 +424,10 @@ do_primary_unregister(void)
|
|||||||
PQfinish(primary_conn);
|
PQfinish(primary_conn);
|
||||||
exit(ERR_BAD_CONFIG);
|
exit(ERR_BAD_CONFIG);
|
||||||
}
|
}
|
||||||
/* This appears to be the cluster primary - cowardly refuse
|
|
||||||
* to delete the record
|
/*
|
||||||
|
* This appears to be the cluster primary - cowardly refuse to
|
||||||
|
* delete the record
|
||||||
*/
|
*/
|
||||||
if (primary_node_info.node_id == target_node_info_ptr->node_id)
|
if (primary_node_info.node_id == target_node_info_ptr->node_id)
|
||||||
{
|
{
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -160,12 +160,14 @@ typedef struct
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
barman,
|
barman,
|
||||||
pg_basebackup
|
pg_basebackup
|
||||||
} standy_clone_mode;
|
} standy_clone_mode;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
ACTION_UNKNOWN = -1,
|
ACTION_UNKNOWN = -1,
|
||||||
ACTION_NONE,
|
ACTION_NONE,
|
||||||
ACTION_START,
|
ACTION_START,
|
||||||
|
|||||||
225
repmgr-client.c
225
repmgr-client.c
@@ -86,8 +86,8 @@ t_node_info target_node_info = T_NODE_INFO_INITIALIZER;
|
|||||||
|
|
||||||
|
|
||||||
/* Collate command line errors and warnings here for friendlier reporting */
|
/* Collate command line errors and warnings here for friendlier reporting */
|
||||||
static ItemList cli_errors = { NULL, NULL };
|
static ItemList cli_errors = {NULL, NULL};
|
||||||
static ItemList cli_warnings = { NULL, NULL };
|
static ItemList cli_warnings = {NULL, NULL};
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
@@ -109,9 +109,9 @@ main(int argc, char **argv)
|
|||||||
set_progname(argv[0]);
|
set_progname(argv[0]);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Tell the logger we're a command-line program - this will
|
* Tell the logger we're a command-line program - this will ensure any
|
||||||
* ensure any output logged before the logger is initialized
|
* output logged before the logger is initialized will be formatted
|
||||||
* will be formatted correctly. Can be overriden with "--log-to-file".
|
* correctly. Can be overriden with "--log-to-file".
|
||||||
*/
|
*/
|
||||||
logger_output_mode = OM_COMMAND_LINE;
|
logger_output_mode = OM_COMMAND_LINE;
|
||||||
|
|
||||||
@@ -119,14 +119,13 @@ main(int argc, char **argv)
|
|||||||
* Initialize and pre-populate conninfo parameters; these will be
|
* Initialize and pre-populate conninfo parameters; these will be
|
||||||
* overwritten if matching command line parameters are provided.
|
* overwritten if matching command line parameters are provided.
|
||||||
*
|
*
|
||||||
* Only some actions will need these, but we need to do this before
|
* Only some actions will need these, but we need to do this before the
|
||||||
* the command line is parsed.
|
* command line is parsed.
|
||||||
*
|
*
|
||||||
* Note: PQconndefaults() does not provide a default value for
|
* Note: PQconndefaults() does not provide a default value for "dbname",
|
||||||
* "dbname", but if none is provided will default to "username"
|
* but if none is provided will default to "username" when the connection
|
||||||
* when the connection is made. We won't set "dbname" here if no
|
* is made. We won't set "dbname" here if no default available, as that
|
||||||
* default available, as that would break the libpq behaviour if
|
* would break the libpq behaviour if non-default username is provided.
|
||||||
* non-default username is provided.
|
|
||||||
*/
|
*/
|
||||||
initialize_conninfo_params(&default_conninfo, true);
|
initialize_conninfo_params(&default_conninfo, true);
|
||||||
|
|
||||||
@@ -180,16 +179,16 @@ main(int argc, char **argv)
|
|||||||
&optindex)) != -1)
|
&optindex)) != -1)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* NOTE: some integer parameters (e.g. -p/--port) are stored internally
|
* NOTE: some integer parameters (e.g. -p/--port) are stored
|
||||||
* as strings. We use repmgr_atoi() to check these but discard the
|
* internally as strings. We use repmgr_atoi() to check these but
|
||||||
* returned integer; repmgr_atoi() will append the error message to the
|
* discard the returned integer; repmgr_atoi() will append the error
|
||||||
* provided list.
|
* message to the provided list.
|
||||||
*/
|
*/
|
||||||
switch (c)
|
switch (c)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Options which cause repmgr to exit in this block;
|
* Options which cause repmgr to exit in this block; these are
|
||||||
* these are the only ones which can be executed as root user
|
* the only ones which can be executed as root user
|
||||||
*/
|
*/
|
||||||
case OPT_HELP: /* --help */
|
case OPT_HELP: /* --help */
|
||||||
help_option = true;
|
help_option = true;
|
||||||
@@ -202,9 +201,11 @@ main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'V':
|
case 'V':
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* in contrast to repmgr3 and earlier, we only display the repmgr version
|
* in contrast to repmgr3 and earlier, we only display the
|
||||||
* as it's not specific to a particular PostgreSQL version
|
* repmgr version as it's not specific to a particular
|
||||||
|
* PostgreSQL version
|
||||||
*/
|
*/
|
||||||
printf("%s %s\n", progname(), REPMGR_VERSION);
|
printf("%s %s\n", progname(), REPMGR_VERSION);
|
||||||
exit(SUCCESS);
|
exit(SUCCESS);
|
||||||
@@ -250,16 +251,20 @@ main(int argc, char **argv)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* These are the standard database connection options; with the
|
* These are the standard database connection options; with
|
||||||
* exception of -d/--dbname (which could be a conninfo string)
|
* the exception of -d/--dbname (which could be a conninfo
|
||||||
* we'll also set these values in "source_conninfo" (overwriting
|
* string) we'll also set these values in "source_conninfo"
|
||||||
* preset values from environment variables).
|
* (overwriting preset values from environment variables). XXX
|
||||||
* XXX check this is same as psql
|
* check this is same as psql
|
||||||
*/
|
*/
|
||||||
/* -d/--dbname */
|
/* -d/--dbname */
|
||||||
case 'd':
|
case 'd':
|
||||||
strncpy(runtime_options.dbname, optarg, MAXLEN);
|
strncpy(runtime_options.dbname, optarg, MAXLEN);
|
||||||
/* dbname will be set in source_conninfo later after checking if it's a conninfo string */
|
|
||||||
|
/*
|
||||||
|
* dbname will be set in source_conninfo later after checking
|
||||||
|
* if it's a conninfo string
|
||||||
|
*/
|
||||||
runtime_options.connection_param_provided = true;
|
runtime_options.connection_param_provided = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -322,8 +327,9 @@ main(int argc, char **argv)
|
|||||||
strncpy(runtime_options.node_name, optarg, MAXLEN);
|
strncpy(runtime_options.node_name, optarg, MAXLEN);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* standby options *
|
/*
|
||||||
* --------------- */
|
* standby options * ---------------
|
||||||
|
*/
|
||||||
|
|
||||||
/* --upstream-node-id */
|
/* --upstream-node-id */
|
||||||
case OPT_UPSTREAM_NODE_ID:
|
case OPT_UPSTREAM_NODE_ID:
|
||||||
@@ -502,6 +508,7 @@ main(int argc, char **argv)
|
|||||||
case 'L':
|
case 'L':
|
||||||
{
|
{
|
||||||
int detected_log_level = detect_log_level(optarg);
|
int detected_log_level = detect_log_level(optarg);
|
||||||
|
|
||||||
if (detected_log_level != -1)
|
if (detected_log_level != -1)
|
||||||
{
|
{
|
||||||
strncpy(runtime_options.log_level, optarg, MAXLEN);
|
strncpy(runtime_options.log_level, optarg, MAXLEN);
|
||||||
@@ -509,6 +516,7 @@ main(int argc, char **argv)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
PQExpBufferData invalid_log_level;
|
PQExpBufferData invalid_log_level;
|
||||||
|
|
||||||
initPQExpBuffer(&invalid_log_level);
|
initPQExpBuffer(&invalid_log_level);
|
||||||
appendPQExpBuffer(&invalid_log_level, _("invalid log level \"%s\" provided"), optarg);
|
appendPQExpBuffer(&invalid_log_level, _("invalid log level \"%s\" provided"), optarg);
|
||||||
item_list_append(&cli_errors, invalid_log_level.data);
|
item_list_append(&cli_errors, invalid_log_level.data);
|
||||||
@@ -597,6 +605,7 @@ main(int argc, char **argv)
|
|||||||
if (opts == NULL)
|
if (opts == NULL)
|
||||||
{
|
{
|
||||||
PQExpBufferData conninfo_error;
|
PQExpBufferData conninfo_error;
|
||||||
|
|
||||||
initPQExpBuffer(&conninfo_error);
|
initPQExpBuffer(&conninfo_error);
|
||||||
appendPQExpBuffer(&conninfo_error, _("error parsing conninfo:\n%s"), errmsg);
|
appendPQExpBuffer(&conninfo_error, _("error parsing conninfo:\n%s"), errmsg);
|
||||||
item_list_append(&cli_errors, conninfo_error.data);
|
item_list_append(&cli_errors, conninfo_error.data);
|
||||||
@@ -613,6 +622,7 @@ main(int argc, char **argv)
|
|||||||
* settings take priority
|
* settings take priority
|
||||||
*/
|
*/
|
||||||
PQconninfoOption *opt;
|
PQconninfoOption *opt;
|
||||||
|
|
||||||
for (opt = opts; opt->keyword != NULL; opt++)
|
for (opt = opts; opt->keyword != NULL; opt++)
|
||||||
{
|
{
|
||||||
if (opt->val != NULL && opt->val[0] != '\0')
|
if (opt->val != NULL && opt->val[0] != '\0')
|
||||||
@@ -654,9 +664,9 @@ main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Disallow further running as root to prevent directory ownership problems.
|
* Disallow further running as root to prevent directory ownership
|
||||||
* We check this here to give the root user a chance to execute --help/--version
|
* problems. We check this here to give the root user a chance to execute
|
||||||
* options.
|
* --help/--version options.
|
||||||
*/
|
*/
|
||||||
if (geteuid() == 0 && help_option == false)
|
if (geteuid() == 0 && help_option == false)
|
||||||
{
|
{
|
||||||
@@ -681,13 +691,14 @@ main(int argc, char **argv)
|
|||||||
/*
|
/*
|
||||||
* Determine the node type and action; following are valid:
|
* Determine the node type and action; following are valid:
|
||||||
*
|
*
|
||||||
* { PRIMARY | MASTER } REGISTER |
|
* { PRIMARY | MASTER } REGISTER | STANDBY {REGISTER | UNREGISTER | CLONE
|
||||||
* STANDBY {REGISTER | UNREGISTER | CLONE [node] | PROMOTE | FOLLOW [node] | SWITCHOVER | REWIND} |
|
* [node] | PROMOTE | FOLLOW [node] | SWITCHOVER | REWIND} | BDR {
|
||||||
* BDR { REGISTER | UNREGISTER } |
|
* REGISTER | UNREGISTER } | NODE { STATUS | CHECK | REJOIN |
|
||||||
* NODE { STATUS | CHECK | REJOIN | ARCHIVE-CONFIG | RESTORE-CONFIG | SERVICE } |
|
* ARCHIVE-CONFIG | RESTORE-CONFIG | SERVICE } | CLUSTER { CROSSCHECK |
|
||||||
* CLUSTER { CROSSCHECK | MATRIX | SHOW | CLEANUP | EVENT }
|
* MATRIX | SHOW | CLEANUP | EVENT }
|
||||||
*
|
*
|
||||||
* [node] is an optional hostname, provided instead of the -h/--host option
|
* [node] is an optional hostname, provided instead of the -h/--host
|
||||||
|
* option
|
||||||
*/
|
*/
|
||||||
if (optind < argc)
|
if (optind < argc)
|
||||||
{
|
{
|
||||||
@@ -706,7 +717,7 @@ main(int argc, char **argv)
|
|||||||
if (repmgr_command != NULL)
|
if (repmgr_command != NULL)
|
||||||
{
|
{
|
||||||
#ifndef BDR_ONLY
|
#ifndef BDR_ONLY
|
||||||
if (strcasecmp(repmgr_command, "PRIMARY") == 0 || strcasecmp(repmgr_command, "MASTER") == 0 )
|
if (strcasecmp(repmgr_command, "PRIMARY") == 0 || strcasecmp(repmgr_command, "MASTER") == 0)
|
||||||
{
|
{
|
||||||
if (help_option == true)
|
if (help_option == true)
|
||||||
{
|
{
|
||||||
@@ -823,6 +834,7 @@ main(int argc, char **argv)
|
|||||||
if (action == NO_ACTION)
|
if (action == NO_ACTION)
|
||||||
{
|
{
|
||||||
PQExpBufferData command_error;
|
PQExpBufferData command_error;
|
||||||
|
|
||||||
initPQExpBuffer(&command_error);
|
initPQExpBuffer(&command_error);
|
||||||
|
|
||||||
if (repmgr_command == NULL)
|
if (repmgr_command == NULL)
|
||||||
@@ -853,7 +865,10 @@ main(int argc, char **argv)
|
|||||||
item_list_append(&cli_errors, command_error.data);
|
item_list_append(&cli_errors, command_error.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* STANDBY CLONE historically accepts the upstream hostname as an additional argument */
|
/*
|
||||||
|
* STANDBY CLONE historically accepts the upstream hostname as an
|
||||||
|
* additional argument
|
||||||
|
*/
|
||||||
if (action == STANDBY_CLONE)
|
if (action == STANDBY_CLONE)
|
||||||
{
|
{
|
||||||
if (optind < argc)
|
if (optind < argc)
|
||||||
@@ -861,6 +876,7 @@ main(int argc, char **argv)
|
|||||||
if (runtime_options.host_param_provided == true)
|
if (runtime_options.host_param_provided == true)
|
||||||
{
|
{
|
||||||
PQExpBufferData additional_host_arg;
|
PQExpBufferData additional_host_arg;
|
||||||
|
|
||||||
initPQExpBuffer(&additional_host_arg);
|
initPQExpBuffer(&additional_host_arg);
|
||||||
appendPQExpBuffer(&additional_host_arg,
|
appendPQExpBuffer(&additional_host_arg,
|
||||||
_("host name provided both with %s and as an extra parameter"),
|
_("host name provided both with %s and as an extra parameter"),
|
||||||
@@ -879,6 +895,7 @@ main(int argc, char **argv)
|
|||||||
if (optind < argc)
|
if (optind < argc)
|
||||||
{
|
{
|
||||||
PQExpBufferData too_many_args;
|
PQExpBufferData too_many_args;
|
||||||
|
|
||||||
initPQExpBuffer(&too_many_args);
|
initPQExpBuffer(&too_many_args);
|
||||||
appendPQExpBuffer(&too_many_args, _("too many command-line arguments (first extra is \"%s\")"), argv[optind]);
|
appendPQExpBuffer(&too_many_args, _("too many command-line arguments (first extra is \"%s\")"), argv[optind]);
|
||||||
item_list_append(&cli_errors, too_many_args.data);
|
item_list_append(&cli_errors, too_many_args.data);
|
||||||
@@ -886,9 +903,9 @@ main(int argc, char **argv)
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The configuration file is not required for some actions (e.g. 'standby clone'),
|
* The configuration file is not required for some actions (e.g. 'standby
|
||||||
* however if available we'll parse it anyway for options like 'log_level',
|
* clone'), however if available we'll parse it anyway for options like
|
||||||
* 'use_replication_slots' etc.
|
* 'log_level', 'use_replication_slots' etc.
|
||||||
*/
|
*/
|
||||||
load_config(runtime_options.config_file,
|
load_config(runtime_options.config_file,
|
||||||
runtime_options.verbose,
|
runtime_options.verbose,
|
||||||
@@ -899,8 +916,8 @@ main(int argc, char **argv)
|
|||||||
check_cli_parameters(action);
|
check_cli_parameters(action);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Sanity checks for command line parameters completed by now;
|
* Sanity checks for command line parameters completed by now; any further
|
||||||
* any further errors will be runtime ones
|
* errors will be runtime ones
|
||||||
*/
|
*/
|
||||||
if (cli_errors.head != NULL)
|
if (cli_errors.head != NULL)
|
||||||
{
|
{
|
||||||
@@ -909,8 +926,8 @@ main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Print any warnings about inappropriate command line options,
|
* Print any warnings about inappropriate command line options, unless
|
||||||
* unless -t/--terse set
|
* -t/--terse set
|
||||||
*/
|
*/
|
||||||
if (cli_warnings.head != NULL && runtime_options.terse == false)
|
if (cli_warnings.head != NULL && runtime_options.terse == false)
|
||||||
{
|
{
|
||||||
@@ -918,8 +935,10 @@ main(int argc, char **argv)
|
|||||||
print_item_list(&cli_warnings);
|
print_item_list(&cli_warnings);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* post-processing following command line parameter checks
|
/*
|
||||||
* ======================================================= */
|
* post-processing following command line parameter checks
|
||||||
|
* =======================================================
|
||||||
|
*/
|
||||||
|
|
||||||
if (runtime_options.csv == true)
|
if (runtime_options.csv == true)
|
||||||
{
|
{
|
||||||
@@ -953,18 +972,27 @@ main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Check for configuration file items which can be overriden by runtime options */
|
/*
|
||||||
/* ============================================================================ */
|
* Check for configuration file items which can be overriden by runtime
|
||||||
|
* options
|
||||||
|
*/
|
||||||
|
|
||||||
/* Command-line parameter -L/--log-level overrides any setting in config file*/
|
/*
|
||||||
|
* ============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Command-line parameter -L/--log-level overrides any setting in config
|
||||||
|
* file
|
||||||
|
*/
|
||||||
if (*runtime_options.log_level != '\0')
|
if (*runtime_options.log_level != '\0')
|
||||||
{
|
{
|
||||||
strncpy(config_file_options.log_level, runtime_options.log_level, MAXLEN);
|
strncpy(config_file_options.log_level, runtime_options.log_level, MAXLEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialise pg_bindir - command line parameter will override
|
* Initialise pg_bindir - command line parameter will override any setting
|
||||||
* any setting in the configuration file
|
* in the configuration file
|
||||||
*/
|
*/
|
||||||
if (!strlen(runtime_options.pg_bindir))
|
if (!strlen(runtime_options.pg_bindir))
|
||||||
{
|
{
|
||||||
@@ -975,6 +1003,7 @@ main(int argc, char **argv)
|
|||||||
if (strlen(runtime_options.pg_bindir))
|
if (strlen(runtime_options.pg_bindir))
|
||||||
{
|
{
|
||||||
int len = strlen(runtime_options.pg_bindir);
|
int len = strlen(runtime_options.pg_bindir);
|
||||||
|
|
||||||
if (runtime_options.pg_bindir[len - 1] != '/')
|
if (runtime_options.pg_bindir[len - 1] != '/')
|
||||||
{
|
{
|
||||||
maxlen_snprintf(pg_bindir, "%s/", runtime_options.pg_bindir);
|
maxlen_snprintf(pg_bindir, "%s/", runtime_options.pg_bindir);
|
||||||
@@ -987,11 +1016,12 @@ main(int argc, char **argv)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize the logger. We've previously requested STDERR logging only
|
* Initialize the logger. We've previously requested STDERR logging only
|
||||||
* to ensure the repmgr command doesn't have its output diverted to a logging
|
* to ensure the repmgr command doesn't have its output diverted to a
|
||||||
* facility (which usually doesn't make sense for a command line program).
|
* logging facility (which usually doesn't make sense for a command line
|
||||||
|
* program).
|
||||||
*
|
*
|
||||||
* If required (e.g. when calling repmgr from repmgrd), this behaviour can be
|
* If required (e.g. when calling repmgr from repmgrd), this behaviour can
|
||||||
* overridden with "--log-to-file".
|
* be overridden with "--log-to-file".
|
||||||
*/
|
*/
|
||||||
|
|
||||||
logger_init(&config_file_options, progname());
|
logger_init(&config_file_options, progname());
|
||||||
@@ -1025,11 +1055,11 @@ main(int argc, char **argv)
|
|||||||
* If a node was specified (by --node-id or --node-name), check it exists
|
* If a node was specified (by --node-id or --node-name), check it exists
|
||||||
* (and pre-populate a record for later use).
|
* (and pre-populate a record for later use).
|
||||||
*
|
*
|
||||||
* At this point check_cli_parameters() will already have determined
|
* At this point check_cli_parameters() will already have determined if
|
||||||
* if provision of these is valid for the action, otherwise it unsets them.
|
* provision of these is valid for the action, otherwise it unsets them.
|
||||||
*
|
*
|
||||||
* We need to check this much later than other command line parameters
|
* We need to check this much later than other command line parameters as
|
||||||
* as we need to wait until the configuration file is parsed and we can
|
* we need to wait until the configuration file is parsed and we can
|
||||||
* obtain the conninfo string.
|
* obtain the conninfo string.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -1062,6 +1092,7 @@ main(int argc, char **argv)
|
|||||||
else if (runtime_options.node_name[0] != '\0')
|
else if (runtime_options.node_name[0] != '\0')
|
||||||
{
|
{
|
||||||
char *escaped = escape_string(conn, runtime_options.node_name);
|
char *escaped = escape_string(conn, runtime_options.node_name);
|
||||||
|
|
||||||
if (escaped == NULL)
|
if (escaped == NULL)
|
||||||
{
|
{
|
||||||
log_error(_("unable to escape value provided for --node-name"));
|
log_error(_("unable to escape value provided for --node-name"));
|
||||||
@@ -1196,7 +1227,8 @@ main(int argc, char **argv)
|
|||||||
static void
|
static void
|
||||||
check_cli_parameters(const int action)
|
check_cli_parameters(const int action)
|
||||||
{
|
{
|
||||||
/* ========================================================================
|
/*
|
||||||
|
* ========================================================================
|
||||||
* check all parameters required for an action are provided, and warn
|
* check all parameters required for an action are provided, and warn
|
||||||
* about ineffective actions
|
* about ineffective actions
|
||||||
* ========================================================================
|
* ========================================================================
|
||||||
@@ -1244,7 +1276,11 @@ check_cli_parameters(const int action)
|
|||||||
action_name(action));
|
action_name(action));
|
||||||
}
|
}
|
||||||
|
|
||||||
// XXX if -D/--pgdata provided, and also config_file_options.pgdaga, warn -D/--pgdata will be ignored
|
/*
|
||||||
|
* XXX if -D/--pgdata provided, and also
|
||||||
|
* config_file_options.pgdaga, warn -D/--pgdata will be
|
||||||
|
* ignored
|
||||||
|
*/
|
||||||
|
|
||||||
if (*runtime_options.upstream_conninfo)
|
if (*runtime_options.upstream_conninfo)
|
||||||
{
|
{
|
||||||
@@ -1267,8 +1303,8 @@ check_cli_parameters(const int action)
|
|||||||
case STANDBY_FOLLOW:
|
case STANDBY_FOLLOW:
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* if `repmgr standby follow` executed with host params, ensure data
|
* if `repmgr standby follow` executed with host params,
|
||||||
* directory was provided
|
* ensure data directory was provided
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -1306,12 +1342,13 @@ check_cli_parameters(const int action)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ========================================================================
|
/*
|
||||||
|
* ========================================================================
|
||||||
* warn if parameters provided for an action where they're not relevant
|
* warn if parameters provided for an action where they're not relevant
|
||||||
* ========================================================================
|
* ========================================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* --host etc.*/
|
/* --host etc. */
|
||||||
if (runtime_options.connection_param_provided)
|
if (runtime_options.connection_param_provided)
|
||||||
{
|
{
|
||||||
switch (action)
|
switch (action)
|
||||||
@@ -1573,13 +1610,13 @@ check_cli_parameters(const int action)
|
|||||||
int used_options = 0;
|
int used_options = 0;
|
||||||
|
|
||||||
if (runtime_options.csv == true)
|
if (runtime_options.csv == true)
|
||||||
used_options ++;
|
used_options++;
|
||||||
|
|
||||||
if (runtime_options.nagios == true)
|
if (runtime_options.nagios == true)
|
||||||
used_options ++;
|
used_options++;
|
||||||
|
|
||||||
if (runtime_options.optformat == true)
|
if (runtime_options.optformat == true)
|
||||||
used_options ++;
|
used_options++;
|
||||||
|
|
||||||
if (used_options > 1)
|
if (used_options > 1)
|
||||||
{
|
{
|
||||||
@@ -1592,10 +1629,10 @@ check_cli_parameters(const int action)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static const char*
|
static const char *
|
||||||
action_name(const int action)
|
action_name(const int action)
|
||||||
{
|
{
|
||||||
switch(action)
|
switch (action)
|
||||||
{
|
{
|
||||||
case PRIMARY_REGISTER:
|
case PRIMARY_REGISTER:
|
||||||
return "PRIMARY REGISTER";
|
return "PRIMARY REGISTER";
|
||||||
@@ -1648,7 +1685,7 @@ print_error_list(ItemList *error_list, int log_level)
|
|||||||
|
|
||||||
for (cell = error_list->head; cell; cell = cell->next)
|
for (cell = error_list->head; cell; cell = cell->next)
|
||||||
{
|
{
|
||||||
switch(log_level)
|
switch (log_level)
|
||||||
{
|
{
|
||||||
/* Currently we only need errors and warnings */
|
/* Currently we only need errors and warnings */
|
||||||
case LOG_ERROR:
|
case LOG_ERROR:
|
||||||
@@ -1772,7 +1809,7 @@ create_repmgr_extension(PGconn *conn)
|
|||||||
|
|
||||||
extension_status = get_repmgr_extension_status(conn);
|
extension_status = get_repmgr_extension_status(conn);
|
||||||
|
|
||||||
switch(extension_status)
|
switch (extension_status)
|
||||||
{
|
{
|
||||||
case REPMGR_UNKNOWN:
|
case REPMGR_UNKNOWN:
|
||||||
log_error(_("unable to determine status of \"repmgr\" extension"));
|
log_error(_("unable to determine status of \"repmgr\" extension"));
|
||||||
@@ -1948,12 +1985,13 @@ int
|
|||||||
test_ssh_connection(char *host, char *remote_user)
|
test_ssh_connection(char *host, char *remote_user)
|
||||||
{
|
{
|
||||||
char script[MAXLEN] = "";
|
char script[MAXLEN] = "";
|
||||||
int r = 1, i;
|
int r = 1,
|
||||||
|
i;
|
||||||
|
|
||||||
/* On some OS, true is located in a different place than in Linux
|
/*
|
||||||
* we have to try them all until all alternatives are gone or we
|
* On some OS, true is located in a different place than in Linux we have
|
||||||
* found `true' because the target OS may differ from the source
|
* to try them all until all alternatives are gone or we found `true'
|
||||||
* OS
|
* because the target OS may differ from the source OS
|
||||||
*/
|
*/
|
||||||
const char *bin_true_paths[] = {
|
const char *bin_true_paths[] = {
|
||||||
"/bin/true",
|
"/bin/true",
|
||||||
@@ -2142,12 +2180,12 @@ copy_remote_files(char *host, char *remote_user, char *remote_path,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* When copying the main PGDATA directory, certain files and contents
|
* When copying the main PGDATA directory, certain files and contents of
|
||||||
* of certain directories need to be excluded.
|
* certain directories need to be excluded.
|
||||||
*
|
*
|
||||||
* See function 'sendDir()' in 'src/backend/replication/basebackup.c' -
|
* See function 'sendDir()' in 'src/backend/replication/basebackup.c' -
|
||||||
* we're basically simulating what pg_basebackup does, but with rsync rather
|
* we're basically simulating what pg_basebackup does, but with rsync
|
||||||
* than the BASEBACKUP replication protocol command.
|
* rather than the BASEBACKUP replication protocol command.
|
||||||
*
|
*
|
||||||
* *However* currently we'll always copy the contents of the 'pg_replslot'
|
* *However* currently we'll always copy the contents of the 'pg_replslot'
|
||||||
* directory and delete later if appropriate.
|
* directory and delete later if appropriate.
|
||||||
@@ -2268,13 +2306,15 @@ create_recovery_file(t_node_info *node_record, t_conninfo_param_list *recovery_c
|
|||||||
if (strlen(runtime_options.upstream_conninfo))
|
if (strlen(runtime_options.upstream_conninfo))
|
||||||
{
|
{
|
||||||
char *escaped = escape_recovery_conf_value(runtime_options.upstream_conninfo);
|
char *escaped = escape_recovery_conf_value(runtime_options.upstream_conninfo);
|
||||||
|
|
||||||
maxlen_snprintf(line, "primary_conninfo = '%s'\n",
|
maxlen_snprintf(line, "primary_conninfo = '%s'\n",
|
||||||
escaped);
|
escaped);
|
||||||
free(escaped);
|
free(escaped);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* otherwise use the conninfo inferred from the upstream connection
|
* otherwise use the conninfo inferred from the upstream connection and/or
|
||||||
* and/or node record
|
* node record
|
||||||
*/
|
*/
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -2320,7 +2360,10 @@ create_recovery_file(t_node_info *node_record, t_conninfo_param_list *recovery_c
|
|||||||
log_debug("recovery.conf: %s", line);
|
log_debug("recovery.conf: %s", line);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If restore_command is set, we use it as restore_command in recovery.conf */
|
/*
|
||||||
|
* If restore_command is set, we use it as restore_command in
|
||||||
|
* recovery.conf
|
||||||
|
*/
|
||||||
if (strcmp(config_file_options.restore_command, "") != 0)
|
if (strcmp(config_file_options.restore_command, "") != 0)
|
||||||
{
|
{
|
||||||
maxlen_snprintf(line, "restore_command = '%s'\n",
|
maxlen_snprintf(line, "restore_command = '%s'\n",
|
||||||
@@ -2523,7 +2566,7 @@ get_server_action(t_server_action action, char *script, char *data_dir)
|
|||||||
if (data_dir == NULL || data_dir[0] == '\0')
|
if (data_dir == NULL || data_dir[0] == '\0')
|
||||||
data_dir = "(none provided)";
|
data_dir = "(none provided)";
|
||||||
|
|
||||||
switch(action)
|
switch (action)
|
||||||
{
|
{
|
||||||
case ACTION_NONE:
|
case ACTION_NONE:
|
||||||
script[0] = '\0';
|
script[0] = '\0';
|
||||||
@@ -2698,7 +2741,7 @@ get_server_action(t_server_action action, char *script, char *data_dir)
|
|||||||
bool
|
bool
|
||||||
data_dir_required_for_action(t_server_action action)
|
data_dir_required_for_action(t_server_action action)
|
||||||
{
|
{
|
||||||
switch(action)
|
switch (action)
|
||||||
{
|
{
|
||||||
case ACTION_NONE:
|
case ACTION_NONE:
|
||||||
return false;
|
return false;
|
||||||
@@ -2750,8 +2793,8 @@ void
|
|||||||
get_node_data_directory(char *data_dir_buf)
|
get_node_data_directory(char *data_dir_buf)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* the configuration file setting has priority, and will always be
|
* the configuration file setting has priority, and will always be set
|
||||||
* set when a configuration file was provided
|
* when a configuration file was provided
|
||||||
*/
|
*/
|
||||||
if (config_file_options.data_directory[0] != '\0')
|
if (config_file_options.data_directory[0] != '\0')
|
||||||
{
|
{
|
||||||
@@ -2802,7 +2845,7 @@ init_node_record(t_node_info *node_record)
|
|||||||
/* use the "user" value from "conninfo" */
|
/* use the "user" value from "conninfo" */
|
||||||
char repluser[MAXLEN] = "";
|
char repluser[MAXLEN] = "";
|
||||||
|
|
||||||
(void)get_conninfo_value(config_file_options.conninfo, "user", repluser);
|
(void) get_conninfo_value(config_file_options.conninfo, "user", repluser);
|
||||||
strncpy(node_record->repluser, repluser, NAMEDATALEN);
|
strncpy(node_record->repluser, repluser, NAMEDATALEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -141,22 +141,22 @@ static struct option long_options[] =
|
|||||||
|
|
||||||
/* "standby switchover" options */
|
/* "standby switchover" options */
|
||||||
{"remote-config-file", required_argument, NULL, 'C'},
|
{"remote-config-file", required_argument, NULL, 'C'},
|
||||||
{"always-promote", no_argument, NULL, OPT_ALWAYS_PROMOTE },
|
{"always-promote", no_argument, NULL, OPT_ALWAYS_PROMOTE},
|
||||||
{"force-rewind", no_argument, NULL, OPT_FORCE_REWIND },
|
{"force-rewind", no_argument, NULL, OPT_FORCE_REWIND},
|
||||||
{"siblings-follow", no_argument, NULL, OPT_SIBLINGS_FOLLOW },
|
{"siblings-follow", no_argument, NULL, OPT_SIBLINGS_FOLLOW},
|
||||||
|
|
||||||
/* "node status" options */
|
/* "node status" options */
|
||||||
{"is-shutdown-cleanly", no_argument, NULL, OPT_IS_SHUTDOWN_CLEANLY },
|
{"is-shutdown-cleanly", no_argument, NULL, OPT_IS_SHUTDOWN_CLEANLY},
|
||||||
|
|
||||||
/* "node check" options */
|
/* "node check" options */
|
||||||
{"archive-ready", no_argument, NULL, OPT_ARCHIVE_READY },
|
{"archive-ready", no_argument, NULL, OPT_ARCHIVE_READY},
|
||||||
{"downstream", no_argument, NULL, OPT_DOWNSTREAM },
|
{"downstream", no_argument, NULL, OPT_DOWNSTREAM},
|
||||||
{"replication-lag", no_argument, NULL, OPT_REPLICATION_LAG },
|
{"replication-lag", no_argument, NULL, OPT_REPLICATION_LAG},
|
||||||
{"role", no_argument, NULL, OPT_ROLE },
|
{"role", no_argument, NULL, OPT_ROLE},
|
||||||
{"slots", no_argument, NULL, OPT_SLOTS },
|
{"slots", no_argument, NULL, OPT_SLOTS},
|
||||||
|
|
||||||
/* "node join" options */
|
/* "node join" options */
|
||||||
{"config-files", required_argument, NULL, OPT_CONFIG_FILES },
|
{"config-files", required_argument, NULL, OPT_CONFIG_FILES},
|
||||||
|
|
||||||
/* "node service" options */
|
/* "node service" options */
|
||||||
{"action", required_argument, NULL, OPT_ACTION},
|
{"action", required_argument, NULL, OPT_ACTION},
|
||||||
@@ -165,16 +165,16 @@ static struct option long_options[] =
|
|||||||
{"checkpoint", no_argument, NULL, OPT_CHECKPOINT},
|
{"checkpoint", no_argument, NULL, OPT_CHECKPOINT},
|
||||||
|
|
||||||
/* "cluster event" options */
|
/* "cluster event" options */
|
||||||
{"all", no_argument, NULL, OPT_ALL },
|
{"all", no_argument, NULL, OPT_ALL},
|
||||||
{"event", required_argument, NULL, OPT_EVENT },
|
{"event", required_argument, NULL, OPT_EVENT},
|
||||||
{"limit", required_argument, NULL, OPT_LIMIT },
|
{"limit", required_argument, NULL, OPT_LIMIT},
|
||||||
|
|
||||||
/* Following options for internal use */
|
/* Following options for internal use */
|
||||||
{"config-archive-dir", required_argument, NULL, OPT_CONFIG_ARCHIVE_DIR},
|
{"config-archive-dir", required_argument, NULL, OPT_CONFIG_ARCHIVE_DIR},
|
||||||
|
|
||||||
/* deprecated */
|
/* deprecated */
|
||||||
{"no-conninfo-password", no_argument, NULL, OPT_NO_CONNINFO_PASSWORD},
|
{"no-conninfo-password", no_argument, NULL, OPT_NO_CONNINFO_PASSWORD},
|
||||||
/* legacy alias for -D/--pgdata*/
|
/* legacy alias for -D/--pgdata */
|
||||||
{"data-dir", required_argument, NULL, OPT_DATA_DIR},
|
{"data-dir", required_argument, NULL, OPT_DATA_DIR},
|
||||||
/* --node-id */
|
/* --node-id */
|
||||||
{"node", required_argument, NULL, OPT_NODE},
|
{"node", required_argument, NULL, OPT_NODE},
|
||||||
|
|||||||
17
repmgr.c
17
repmgr.c
@@ -49,7 +49,8 @@
|
|||||||
|
|
||||||
PG_MODULE_MAGIC;
|
PG_MODULE_MAGIC;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
LEADER_NODE,
|
LEADER_NODE,
|
||||||
FOLLOWER_NODE,
|
FOLLOWER_NODE,
|
||||||
CANDIDATE_NODE
|
CANDIDATE_NODE
|
||||||
@@ -81,40 +82,52 @@ void _PG_fini(void);
|
|||||||
static void repmgr_shmem_startup(void);
|
static void repmgr_shmem_startup(void);
|
||||||
|
|
||||||
Datum set_local_node_id(PG_FUNCTION_ARGS);
|
Datum set_local_node_id(PG_FUNCTION_ARGS);
|
||||||
|
|
||||||
PG_FUNCTION_INFO_V1(set_local_node_id);
|
PG_FUNCTION_INFO_V1(set_local_node_id);
|
||||||
|
|
||||||
Datum standby_set_last_updated(PG_FUNCTION_ARGS);
|
Datum standby_set_last_updated(PG_FUNCTION_ARGS);
|
||||||
|
|
||||||
PG_FUNCTION_INFO_V1(standby_set_last_updated);
|
PG_FUNCTION_INFO_V1(standby_set_last_updated);
|
||||||
|
|
||||||
Datum standby_get_last_updated(PG_FUNCTION_ARGS);
|
Datum standby_get_last_updated(PG_FUNCTION_ARGS);
|
||||||
|
|
||||||
PG_FUNCTION_INFO_V1(standby_get_last_updated);
|
PG_FUNCTION_INFO_V1(standby_get_last_updated);
|
||||||
|
|
||||||
|
|
||||||
Datum request_vote(PG_FUNCTION_ARGS);
|
Datum request_vote(PG_FUNCTION_ARGS);
|
||||||
|
|
||||||
PG_FUNCTION_INFO_V1(request_vote);
|
PG_FUNCTION_INFO_V1(request_vote);
|
||||||
|
|
||||||
Datum get_voting_status(PG_FUNCTION_ARGS);
|
Datum get_voting_status(PG_FUNCTION_ARGS);
|
||||||
|
|
||||||
PG_FUNCTION_INFO_V1(get_voting_status);
|
PG_FUNCTION_INFO_V1(get_voting_status);
|
||||||
|
|
||||||
Datum set_voting_status_initiated(PG_FUNCTION_ARGS);
|
Datum set_voting_status_initiated(PG_FUNCTION_ARGS);
|
||||||
|
|
||||||
PG_FUNCTION_INFO_V1(set_voting_status_initiated);
|
PG_FUNCTION_INFO_V1(set_voting_status_initiated);
|
||||||
|
|
||||||
Datum other_node_is_candidate(PG_FUNCTION_ARGS);
|
Datum other_node_is_candidate(PG_FUNCTION_ARGS);
|
||||||
|
|
||||||
PG_FUNCTION_INFO_V1(other_node_is_candidate);
|
PG_FUNCTION_INFO_V1(other_node_is_candidate);
|
||||||
|
|
||||||
Datum notify_follow_primary(PG_FUNCTION_ARGS);
|
Datum notify_follow_primary(PG_FUNCTION_ARGS);
|
||||||
|
|
||||||
PG_FUNCTION_INFO_V1(notify_follow_primary);
|
PG_FUNCTION_INFO_V1(notify_follow_primary);
|
||||||
|
|
||||||
Datum get_new_primary(PG_FUNCTION_ARGS);
|
Datum get_new_primary(PG_FUNCTION_ARGS);
|
||||||
|
|
||||||
PG_FUNCTION_INFO_V1(get_new_primary);
|
PG_FUNCTION_INFO_V1(get_new_primary);
|
||||||
|
|
||||||
Datum reset_voting_status(PG_FUNCTION_ARGS);
|
Datum reset_voting_status(PG_FUNCTION_ARGS);
|
||||||
|
|
||||||
PG_FUNCTION_INFO_V1(reset_voting_status);
|
PG_FUNCTION_INFO_V1(reset_voting_status);
|
||||||
|
|
||||||
Datum am_bdr_failover_handler(PG_FUNCTION_ARGS);
|
Datum am_bdr_failover_handler(PG_FUNCTION_ARGS);
|
||||||
|
|
||||||
PG_FUNCTION_INFO_V1(am_bdr_failover_handler);
|
PG_FUNCTION_INFO_V1(am_bdr_failover_handler);
|
||||||
|
|
||||||
Datum unset_bdr_failover_handler(PG_FUNCTION_ARGS);
|
Datum unset_bdr_failover_handler(PG_FUNCTION_ARGS);
|
||||||
|
|
||||||
PG_FUNCTION_INFO_V1(unset_bdr_failover_handler);
|
PG_FUNCTION_INFO_V1(unset_bdr_failover_handler);
|
||||||
|
|
||||||
|
|
||||||
@@ -331,7 +344,7 @@ request_vote(PG_FUNCTION_ARGS)
|
|||||||
|
|
||||||
LWLockRelease(shared_state->lock);
|
LWLockRelease(shared_state->lock);
|
||||||
|
|
||||||
// should we free "query" here?
|
/* should we free "query" here? */
|
||||||
SPI_finish();
|
SPI_finish();
|
||||||
|
|
||||||
PG_RETURN_LSN(our_lsn);
|
PG_RETURN_LSN(our_lsn);
|
||||||
|
|||||||
@@ -65,8 +65,7 @@ monitor_bdr(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Verify that database is a BDR one
|
* Verify that database is a BDR one TODO: check if supported BDR version?
|
||||||
* TODO: check if supported BDR version?
|
|
||||||
*/
|
*/
|
||||||
log_info(_("connected to database, checking for BDR"));
|
log_info(_("connected to database, checking for BDR"));
|
||||||
|
|
||||||
@@ -81,7 +80,10 @@ monitor_bdr(void)
|
|||||||
log_error(_("repmgr metadata table 'repmgr.%s' is not in the 'repmgr' replication set"),
|
log_error(_("repmgr metadata table 'repmgr.%s' is not in the 'repmgr' replication set"),
|
||||||
"nodes");
|
"nodes");
|
||||||
|
|
||||||
/* TODO: add `repmgr bdr sync` or similar for this situation, and hint here */
|
/*
|
||||||
|
* TODO: add `repmgr bdr sync` or similar for this situation, and hint
|
||||||
|
* here
|
||||||
|
*/
|
||||||
|
|
||||||
exit(ERR_BAD_CONFIG);
|
exit(ERR_BAD_CONFIG);
|
||||||
}
|
}
|
||||||
@@ -100,8 +102,8 @@ monitor_bdr(void)
|
|||||||
record_status = get_node_record(local_conn, config_file_options.node_id, &local_node_info);
|
record_status = get_node_record(local_conn, config_file_options.node_id, &local_node_info);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Terminate if we can't find the local node record. This is a "fix-the-config"
|
* Terminate if we can't find the local node record. This is a
|
||||||
* situation, not a lot else we can do.
|
* "fix-the-config" situation, not a lot else we can do.
|
||||||
*/
|
*/
|
||||||
if (record_status != RECORD_FOUND)
|
if (record_status != RECORD_FOUND)
|
||||||
{
|
{
|
||||||
@@ -139,7 +141,8 @@ monitor_bdr(void)
|
|||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* retrieve list of all nodes - we'll need these if the DB connection goes away
|
* retrieve list of all nodes - we'll need these if the DB connection goes
|
||||||
|
* away
|
||||||
*/
|
*/
|
||||||
get_all_node_records(local_conn, &nodes);
|
get_all_node_records(local_conn, &nodes);
|
||||||
|
|
||||||
@@ -191,6 +194,7 @@ monitor_bdr(void)
|
|||||||
if (cell->node_info->node_status == NODE_STATUS_UP)
|
if (cell->node_info->node_status == NODE_STATUS_UP)
|
||||||
{
|
{
|
||||||
instr_time node_unreachable_start;
|
instr_time node_unreachable_start;
|
||||||
|
|
||||||
INSTR_TIME_SET_CURRENT(node_unreachable_start);
|
INSTR_TIME_SET_CURRENT(node_unreachable_start);
|
||||||
|
|
||||||
cell->node_info->node_status = NODE_STATUS_DOWN;
|
cell->node_info->node_status = NODE_STATUS_DOWN;
|
||||||
@@ -252,7 +256,7 @@ monitor_bdr(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
loop:
|
loop:
|
||||||
|
|
||||||
/* emit "still alive" log message at regular intervals, if requested */
|
/* emit "still alive" log message at regular intervals, if requested */
|
||||||
if (config_file_options.log_status_interval > 0)
|
if (config_file_options.log_status_interval > 0)
|
||||||
@@ -282,8 +286,7 @@ monitor_bdr(void)
|
|||||||
if (got_SIGHUP)
|
if (got_SIGHUP)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* if we can reload, then could need to change
|
* if we can reload, then could need to change local_conn
|
||||||
* local_conn
|
|
||||||
*/
|
*/
|
||||||
if (reload_config(&config_file_options))
|
if (reload_config(&config_file_options))
|
||||||
{
|
{
|
||||||
@@ -372,7 +375,10 @@ do_bdr_failover(NodeInfoList *nodes, t_node_info *monitored_node)
|
|||||||
{
|
{
|
||||||
log_debug("do_bdr_failover() %s", cell->node_info->node_name);
|
log_debug("do_bdr_failover() %s", cell->node_info->node_name);
|
||||||
|
|
||||||
/* don't attempt to connect to the current monitored node, as that's the one which has failed */
|
/*
|
||||||
|
* don't attempt to connect to the current monitored node, as that's
|
||||||
|
* the one which has failed
|
||||||
|
*/
|
||||||
if (cell->node_info->node_id == monitored_node->node_id)
|
if (cell->node_info->node_id == monitored_node->node_id)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -459,11 +465,11 @@ do_bdr_failover(NodeInfoList *nodes, t_node_info *monitored_node)
|
|||||||
/*
|
/*
|
||||||
* Create an event record
|
* Create an event record
|
||||||
*
|
*
|
||||||
* If we were able to connect to another node, we'll update the
|
* If we were able to connect to another node, we'll update the event log
|
||||||
* event log there.
|
* there.
|
||||||
*
|
*
|
||||||
* In any case the event notification command will be triggered
|
* In any case the event notification command will be triggered with the
|
||||||
* with the event "bdr_failover"
|
* event "bdr_failover"
|
||||||
*/
|
*/
|
||||||
|
|
||||||
create_event_notification_extended(
|
create_event_notification_extended(
|
||||||
|
|||||||
@@ -24,7 +24,8 @@
|
|||||||
#include "repmgrd-physical.h"
|
#include "repmgrd-physical.h"
|
||||||
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
FAILOVER_STATE_UNKNOWN = -1,
|
FAILOVER_STATE_UNKNOWN = -1,
|
||||||
FAILOVER_STATE_NONE,
|
FAILOVER_STATE_NONE,
|
||||||
FAILOVER_STATE_PROMOTED,
|
FAILOVER_STATE_PROMOTED,
|
||||||
@@ -41,7 +42,8 @@ typedef enum {
|
|||||||
} FailoverState;
|
} FailoverState;
|
||||||
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
ELECTION_NOT_CANDIDATE = -1,
|
ELECTION_NOT_CANDIDATE = -1,
|
||||||
ELECTION_WON,
|
ELECTION_WON,
|
||||||
ELECTION_LOST,
|
ELECTION_LOST,
|
||||||
@@ -91,14 +93,14 @@ do_physical_node_check(void)
|
|||||||
{
|
{
|
||||||
#ifndef BDR_ONLY
|
#ifndef BDR_ONLY
|
||||||
/*
|
/*
|
||||||
* Check if node record is active - if not, and `failover=automatic`, the node
|
* Check if node record is active - if not, and `failover=automatic`, the
|
||||||
* won't be considered as a promotion candidate; this often happens when
|
* node won't be considered as a promotion candidate; this often happens
|
||||||
* a failed primary is recloned and the node was not re-registered, giving
|
* when a failed primary is recloned and the node was not re-registered,
|
||||||
* the impression failover capability is there when it's not. In this case
|
* giving the impression failover capability is there when it's not. In
|
||||||
* abort with an error and a hint about registering.
|
* this case abort with an error and a hint about registering.
|
||||||
*
|
*
|
||||||
* If `failover=manual`, repmgrd can continue to passively monitor the node, but
|
* If `failover=manual`, repmgrd can continue to passively monitor the
|
||||||
* we should nevertheless issue a warning and the same hint.
|
* node, but we should nevertheless issue a warning and the same hint.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (local_node_info.active == false)
|
if (local_node_info.active == false)
|
||||||
@@ -138,8 +140,8 @@ do_physical_node_check(void)
|
|||||||
if (config_file_options.service_promote_command[0] != '\0')
|
if (config_file_options.service_promote_command[0] != '\0')
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* if repmgrd executes "service_promote_command" directly, repmgr metadata
|
* if repmgrd executes "service_promote_command" directly,
|
||||||
* won't get updated
|
* repmgr metadata won't get updated
|
||||||
*/
|
*/
|
||||||
log_hint(_("\"service_promote_command\" is set, but can only be executed by \"repmgr standby promote\""));
|
log_hint(_("\"service_promote_command\" is set, but can only be executed by \"repmgr standby promote\""));
|
||||||
}
|
}
|
||||||
@@ -242,8 +244,8 @@ monitor_streaming_primary(void)
|
|||||||
PQfinish(local_conn);
|
PQfinish(local_conn);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* as we're monitoring the primary, no point in trying to write
|
* as we're monitoring the primary, no point in trying to
|
||||||
* the event to the database
|
* write the event to the database
|
||||||
*
|
*
|
||||||
* XXX possible pre-action event
|
* XXX possible pre-action event
|
||||||
*/
|
*/
|
||||||
@@ -346,12 +348,12 @@ monitor_streaming_primary(void)
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* possibly attempt to find another node from cached list
|
* possibly attempt to find another node from cached list check if
|
||||||
* check if there's a new primary - if so add hook for fencing?
|
* there's a new primary - if so add hook for fencing? loop, if
|
||||||
* loop, if starts up check status, switch monitoring mode
|
* starts up check status, switch monitoring mode
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
loop:
|
loop:
|
||||||
/* emit "still alive" log message at regular intervals, if requested */
|
/* emit "still alive" log message at regular intervals, if requested */
|
||||||
if (config_file_options.log_status_interval > 0)
|
if (config_file_options.log_status_interval > 0)
|
||||||
{
|
{
|
||||||
@@ -421,9 +423,9 @@ monitor_streaming_standby(void)
|
|||||||
log_debug("monitor_streaming_standby()");
|
log_debug("monitor_streaming_standby()");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If no upstream node id is specified in the metadata, we'll try
|
* If no upstream node id is specified in the metadata, we'll try and
|
||||||
* and determine the current cluster primary in the assumption we
|
* determine the current cluster primary in the assumption we should
|
||||||
* should connect to that by default.
|
* connect to that by default.
|
||||||
*/
|
*/
|
||||||
if (local_node_info.upstream_node_id == UNKNOWN_NODE_ID)
|
if (local_node_info.upstream_node_id == UNKNOWN_NODE_ID)
|
||||||
{
|
{
|
||||||
@@ -431,9 +433,9 @@ monitor_streaming_standby(void)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Terminate if there doesn't appear to be an active cluster primary.
|
* Terminate if there doesn't appear to be an active cluster primary.
|
||||||
* There could be one or more nodes marked as inactive primaries, and one
|
* There could be one or more nodes marked as inactive primaries, and
|
||||||
* of them could actually be a primary, but we can't sensibly monitor
|
* one of them could actually be a primary, but we can't sensibly
|
||||||
* in that state.
|
* monitor in that state.
|
||||||
*/
|
*/
|
||||||
if (local_node_info.upstream_node_id == NODE_NOT_FOUND)
|
if (local_node_info.upstream_node_id == NODE_NOT_FOUND)
|
||||||
{
|
{
|
||||||
@@ -446,9 +448,9 @@ monitor_streaming_standby(void)
|
|||||||
record_status = get_node_record(local_conn, local_node_info.upstream_node_id, &upstream_node_info);
|
record_status = get_node_record(local_conn, local_node_info.upstream_node_id, &upstream_node_info);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Terminate if we can't find the record for the node we're supposed
|
* Terminate if we can't find the record for the node we're supposed to
|
||||||
* to monitor. This is a "fix-the-config" situation, not a lot else we
|
* monitor. This is a "fix-the-config" situation, not a lot else we can
|
||||||
* can do.
|
* do.
|
||||||
*/
|
*/
|
||||||
if (record_status == RECORD_NOT_FOUND)
|
if (record_status == RECORD_NOT_FOUND)
|
||||||
{
|
{
|
||||||
@@ -473,8 +475,8 @@ monitor_streaming_standby(void)
|
|||||||
/*
|
/*
|
||||||
* Upstream node must be running at repmgrd startup.
|
* Upstream node must be running at repmgrd startup.
|
||||||
*
|
*
|
||||||
* We could possibly have repmgrd skip to degraded monitoring mode until it
|
* We could possibly have repmgrd skip to degraded monitoring mode until
|
||||||
* comes up, but there doesn't seem to be much point in doing that.
|
* it comes up, but there doesn't seem to be much point in doing that.
|
||||||
*/
|
*/
|
||||||
if (PQstatus(upstream_conn) != CONNECTION_OK)
|
if (PQstatus(upstream_conn) != CONNECTION_OK)
|
||||||
{
|
{
|
||||||
@@ -486,15 +488,18 @@ monitor_streaming_standby(void)
|
|||||||
exit(ERR_DB_CONN);
|
exit(ERR_DB_CONN);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* refresh upstream node record from upstream node, so it's as up-to-date as possible */
|
/*
|
||||||
|
* refresh upstream node record from upstream node, so it's as up-to-date
|
||||||
|
* as possible
|
||||||
|
*/
|
||||||
record_status = get_node_record(upstream_conn, upstream_node_info.node_id, &upstream_node_info);
|
record_status = get_node_record(upstream_conn, upstream_node_info.node_id, &upstream_node_info);
|
||||||
|
|
||||||
if (upstream_node_info.type == STANDBY)
|
if (upstream_node_info.type == STANDBY)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Currently cascaded standbys need to be able to connect to the primary.
|
* Currently cascaded standbys need to be able to connect to the
|
||||||
* We could possibly add a limited connection mode for cases where this isn't
|
* primary. We could possibly add a limited connection mode for cases
|
||||||
* possible.
|
* where this isn't possible.
|
||||||
*/
|
*/
|
||||||
primary_conn = establish_primary_db_connection(upstream_conn, false);
|
primary_conn = establish_primary_db_connection(upstream_conn, false);
|
||||||
|
|
||||||
@@ -518,6 +523,7 @@ monitor_streaming_standby(void)
|
|||||||
if (startup_event_logged == false)
|
if (startup_event_logged == false)
|
||||||
{
|
{
|
||||||
PQExpBufferData event_details;
|
PQExpBufferData event_details;
|
||||||
|
|
||||||
initPQExpBuffer(&event_details);
|
initPQExpBuffer(&event_details);
|
||||||
|
|
||||||
appendPQExpBuffer(&event_details,
|
appendPQExpBuffer(&event_details,
|
||||||
@@ -617,7 +623,10 @@ monitor_streaming_standby(void)
|
|||||||
failover_done = do_upstream_standby_failover();
|
failover_done = do_upstream_standby_failover();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* XXX it's possible it will make sense to return in all cases to restart monitoring */
|
/*
|
||||||
|
* XXX it's possible it will make sense to return in all
|
||||||
|
* cases to restart monitoring
|
||||||
|
*/
|
||||||
if (failover_done == true)
|
if (failover_done == true)
|
||||||
{
|
{
|
||||||
primary_node_id = get_primary_node_id(local_conn);
|
primary_node_id = get_primary_node_id(local_conn);
|
||||||
@@ -641,10 +650,13 @@ monitor_streaming_standby(void)
|
|||||||
|
|
||||||
if (PQstatus(upstream_conn) == CONNECTION_OK)
|
if (PQstatus(upstream_conn) == CONNECTION_OK)
|
||||||
{
|
{
|
||||||
// XXX check here if upstream is still primary
|
/* XXX check here if upstream is still primary */
|
||||||
// -> will be a problem if another node was promoted in the meantime
|
/*
|
||||||
// and upstream is now former primary
|
* -> will be a problem if another node was promoted in
|
||||||
// XXX scan other nodes to see if any has become primary
|
* the meantime
|
||||||
|
*/
|
||||||
|
/* and upstream is now former primary */
|
||||||
|
/* XXX scan other nodes to see if any has become primary */
|
||||||
|
|
||||||
upstream_node_info.node_status = NODE_STATUS_UP;
|
upstream_node_info.node_status = NODE_STATUS_UP;
|
||||||
monitoring_state = MS_NORMAL;
|
monitoring_state = MS_NORMAL;
|
||||||
@@ -684,8 +696,8 @@ monitor_streaming_standby(void)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* unable to connect to former primary - check if another node has
|
* unable to connect to former primary - check if another node
|
||||||
* been promoted
|
* has been promoted
|
||||||
*/
|
*/
|
||||||
|
|
||||||
NodeInfoListCell *cell;
|
NodeInfoListCell *cell;
|
||||||
@@ -697,12 +709,13 @@ monitor_streaming_standby(void)
|
|||||||
log_notice(_("local node is primary, checking local node record"));
|
log_notice(_("local node is primary, checking local node record"));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* There may be a delay between the node being promoted and the local
|
* There may be a delay between the node being promoted
|
||||||
* record being updated, so if the node record still shows it as a
|
* and the local record being updated, so if the node
|
||||||
* standby, do nothing, we'll catch the update during the next loop.
|
* record still shows it as a standby, do nothing, we'll
|
||||||
* (e.g. node was manually
|
* catch the update during the next loop. (e.g. node was
|
||||||
* promoted) we'll do nothing, as the repmgr metadata is now out-of-sync.
|
* manually promoted) we'll do nothing, as the repmgr
|
||||||
* If it does get fixed, we'll catch it here on a future iteration.
|
* metadata is now out-of-sync. If it does get fixed,
|
||||||
|
* we'll catch it here on a future iteration.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* refresh own internal node record */
|
/* refresh own internal node record */
|
||||||
@@ -769,7 +782,7 @@ monitor_streaming_standby(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
loop:
|
loop:
|
||||||
|
|
||||||
/* emit "still alive" log message at regular intervals, if requested */
|
/* emit "still alive" log message at regular intervals, if requested */
|
||||||
if (config_file_options.log_status_interval > 0)
|
if (config_file_options.log_status_interval > 0)
|
||||||
@@ -779,6 +792,7 @@ monitor_streaming_standby(void)
|
|||||||
if (log_status_interval_elapsed >= config_file_options.log_status_interval)
|
if (log_status_interval_elapsed >= config_file_options.log_status_interval)
|
||||||
{
|
{
|
||||||
PQExpBufferData monitoring_summary;
|
PQExpBufferData monitoring_summary;
|
||||||
|
|
||||||
initPQExpBuffer(&monitoring_summary);
|
initPQExpBuffer(&monitoring_summary);
|
||||||
|
|
||||||
appendPQExpBuffer(
|
appendPQExpBuffer(
|
||||||
@@ -827,6 +841,7 @@ monitor_streaming_standby(void)
|
|||||||
if (update_node_record_set_active(primary_conn, local_node_info.node_id, false) == true)
|
if (update_node_record_set_active(primary_conn, local_node_info.node_id, false) == true)
|
||||||
{
|
{
|
||||||
PQExpBufferData event_details;
|
PQExpBufferData event_details;
|
||||||
|
|
||||||
initPQExpBuffer(&event_details);
|
initPQExpBuffer(&event_details);
|
||||||
|
|
||||||
local_node_info.active = false;
|
local_node_info.active = false;
|
||||||
@@ -853,7 +868,8 @@ monitor_streaming_standby(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
if (local_node_info.active == false)
|
if (local_node_info.active == false)
|
||||||
{
|
{
|
||||||
if (PQstatus(primary_conn) == CONNECTION_OK)
|
if (PQstatus(primary_conn) == CONNECTION_OK)
|
||||||
@@ -861,6 +877,7 @@ monitor_streaming_standby(void)
|
|||||||
if (update_node_record_set_active(primary_conn, local_node_info.node_id, true) == true)
|
if (update_node_record_set_active(primary_conn, local_node_info.node_id, true) == true)
|
||||||
{
|
{
|
||||||
PQExpBufferData event_details;
|
PQExpBufferData event_details;
|
||||||
|
|
||||||
initPQExpBuffer(&event_details);
|
initPQExpBuffer(&event_details);
|
||||||
|
|
||||||
local_node_info.active = true;
|
local_node_info.active = true;
|
||||||
@@ -954,8 +971,8 @@ do_primary_failover(void)
|
|||||||
best_candidate = poll_best_candidate(&standby_nodes);
|
best_candidate = poll_best_candidate(&standby_nodes);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* this can occur in a tie-break situation, where this node establishes
|
* this can occur in a tie-break situation, where this node
|
||||||
* it is the best candidate
|
* establishes it is the best candidate
|
||||||
*/
|
*/
|
||||||
if (best_candidate->node_id == local_node_info.node_id)
|
if (best_candidate->node_id == local_node_info.node_id)
|
||||||
{
|
{
|
||||||
@@ -1012,8 +1029,8 @@ do_primary_failover(void)
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* node has decided it is a follower, so will await notification
|
* node has decided it is a follower, so will await notification from the
|
||||||
* from the candidate that it has promoted itself and can be followed
|
* candidate that it has promoted itself and can be followed
|
||||||
*/
|
*/
|
||||||
if (failover_state == FAILOVER_STATE_WAITING_NEW_PRIMARY)
|
if (failover_state == FAILOVER_STATE_WAITING_NEW_PRIMARY)
|
||||||
{
|
{
|
||||||
@@ -1060,6 +1077,7 @@ do_primary_failover(void)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
PQExpBufferData event_details;
|
PQExpBufferData event_details;
|
||||||
|
|
||||||
initPQExpBuffer(&event_details);
|
initPQExpBuffer(&event_details);
|
||||||
appendPQExpBuffer(&event_details,
|
appendPQExpBuffer(&event_details,
|
||||||
_("node %i is in manual failover mode and is now disconnected from streaming replication"),
|
_("node %i is in manual failover mode and is now disconnected from streaming replication"),
|
||||||
@@ -1072,7 +1090,11 @@ do_primary_failover(void)
|
|||||||
&config_file_options,
|
&config_file_options,
|
||||||
local_node_info.node_id,
|
local_node_info.node_id,
|
||||||
"standby_disconnect_manual",
|
"standby_disconnect_manual",
|
||||||
/* here "true" indicates the action has occurred as expected */
|
|
||||||
|
/*
|
||||||
|
* here "true" indicates the action has occurred as
|
||||||
|
* expected
|
||||||
|
*/
|
||||||
true,
|
true,
|
||||||
event_details.data);
|
event_details.data);
|
||||||
PQfinish(new_primary_conn);
|
PQfinish(new_primary_conn);
|
||||||
@@ -1092,7 +1114,7 @@ do_primary_failover(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(failover_state)
|
switch (failover_state)
|
||||||
{
|
{
|
||||||
case FAILOVER_STATE_PROMOTED:
|
case FAILOVER_STATE_PROMOTED:
|
||||||
log_debug("failover state is PROMOTED");
|
log_debug("failover state is PROMOTED");
|
||||||
@@ -1112,7 +1134,10 @@ do_primary_failover(void)
|
|||||||
case FAILOVER_STATE_PRIMARY_REAPPEARED:
|
case FAILOVER_STATE_PRIMARY_REAPPEARED:
|
||||||
log_debug("failover state is PRIMARY_REAPPEARED");
|
log_debug("failover state is PRIMARY_REAPPEARED");
|
||||||
|
|
||||||
/* notify siblings that they should resume following the original primary */
|
/*
|
||||||
|
* notify siblings that they should resume following the original
|
||||||
|
* primary
|
||||||
|
*/
|
||||||
notify_followers(&standby_nodes, upstream_node_info.node_id);
|
notify_followers(&standby_nodes, upstream_node_info.node_id);
|
||||||
|
|
||||||
/* we no longer care about our former siblings */
|
/* we no longer care about our former siblings */
|
||||||
@@ -1151,6 +1176,7 @@ do_primary_failover(void)
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
case FAILOVER_STATE_FOLLOW_FAIL:
|
case FAILOVER_STATE_FOLLOW_FAIL:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* for whatever reason we were unable to follow the new primary -
|
* for whatever reason we were unable to follow the new primary -
|
||||||
* continue monitoring in degraded state
|
* continue monitoring in degraded state
|
||||||
@@ -1229,11 +1255,14 @@ update_monitoring_history(void)
|
|||||||
|
|
||||||
if (primary_last_wal_location >= replication_info.last_wal_receive_lsn)
|
if (primary_last_wal_location >= replication_info.last_wal_receive_lsn)
|
||||||
{
|
{
|
||||||
replication_lag_bytes = (long long unsigned int)(primary_last_wal_location - replication_info.last_wal_receive_lsn);
|
replication_lag_bytes = (long long unsigned int) (primary_last_wal_location - replication_info.last_wal_receive_lsn);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* This should never happen, but in case it does set replication lag to zero */
|
/*
|
||||||
|
* This should never happen, but in case it does set replication lag
|
||||||
|
* to zero
|
||||||
|
*/
|
||||||
log_warning("primary xlog (%X/%X) location appears less than standby receive location (%X/%X)",
|
log_warning("primary xlog (%X/%X) location appears less than standby receive location (%X/%X)",
|
||||||
format_lsn(primary_last_wal_location),
|
format_lsn(primary_last_wal_location),
|
||||||
format_lsn(replication_info.last_wal_receive_lsn));
|
format_lsn(replication_info.last_wal_receive_lsn));
|
||||||
@@ -1286,9 +1315,10 @@ do_upstream_standby_failover(void)
|
|||||||
log_error(_("unable to retrieve primary node record"));
|
log_error(_("unable to retrieve primary node record"));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Verify that we can still talk to the cluster primary, even though
|
* Verify that we can still talk to the cluster primary, even though the
|
||||||
* the node's upstream is not available
|
* node's upstream is not available
|
||||||
*/
|
*/
|
||||||
|
|
||||||
check_connection(&primary_node_info, &primary_conn);
|
check_connection(&primary_node_info, &primary_conn);
|
||||||
@@ -1344,9 +1374,9 @@ do_upstream_standby_failover(void)
|
|||||||
|
|
||||||
log_error("%s", event_details.data);
|
log_error("%s", event_details.data);
|
||||||
|
|
||||||
/* It may not possible to write to the event notification
|
/*
|
||||||
* table but we should be able to generate an external notification
|
* It may not possible to write to the event notification table but we
|
||||||
* if required.
|
* should be able to generate an external notification if required.
|
||||||
*/
|
*/
|
||||||
create_event_notification(
|
create_event_notification(
|
||||||
primary_conn,
|
primary_conn,
|
||||||
@@ -1390,8 +1420,9 @@ do_upstream_standby_failover(void)
|
|||||||
record_status = get_node_record(primary_conn, local_node_info.node_id, &local_node_info);
|
record_status = get_node_record(primary_conn, local_node_info.node_id, &local_node_info);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* highly improbable this will happen, but in case we're unable to retrieve
|
* highly improbable this will happen, but in case we're unable to
|
||||||
* our node record from the primary, update it ourselves, and hope for the best
|
* retrieve our node record from the primary, update it ourselves, and
|
||||||
|
* hope for the best
|
||||||
*/
|
*/
|
||||||
if (record_status != RECORD_FOUND)
|
if (record_status != RECORD_FOUND)
|
||||||
{
|
{
|
||||||
@@ -1434,8 +1465,8 @@ promote_self(void)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* optionally add a delay before promoting the standby; this is mainly
|
* optionally add a delay before promoting the standby; this is mainly
|
||||||
* useful for testing (e.g. for reappearance of the original primary)
|
* useful for testing (e.g. for reappearance of the original primary) and
|
||||||
* and is not documented.
|
* is not documented.
|
||||||
*/
|
*/
|
||||||
if (config_file_options.promote_delay > 0)
|
if (config_file_options.promote_delay > 0)
|
||||||
{
|
{
|
||||||
@@ -1467,15 +1498,15 @@ promote_self(void)
|
|||||||
r = system(promote_command);
|
r = system(promote_command);
|
||||||
|
|
||||||
/* connection should stay up, but check just in case */
|
/* connection should stay up, but check just in case */
|
||||||
if(PQstatus(local_conn) != CONNECTION_OK)
|
if (PQstatus(local_conn) != CONNECTION_OK)
|
||||||
{
|
{
|
||||||
local_conn = establish_db_connection(local_node_info.conninfo, true);
|
local_conn = establish_db_connection(local_node_info.conninfo, true);
|
||||||
|
|
||||||
/* assume node failed */
|
/* assume node failed */
|
||||||
if(PQstatus(local_conn) != CONNECTION_OK)
|
if (PQstatus(local_conn) != CONNECTION_OK)
|
||||||
{
|
{
|
||||||
log_error(_("unable to reconnect to local node"));
|
log_error(_("unable to reconnect to local node"));
|
||||||
// XXX handle this
|
/* XXX handle this */
|
||||||
return FAILOVER_STATE_LOCAL_NODE_FAILURE;
|
return FAILOVER_STATE_LOCAL_NODE_FAILURE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1507,10 +1538,10 @@ promote_self(void)
|
|||||||
|
|
||||||
termPQExpBuffer(&event_details);
|
termPQExpBuffer(&event_details);
|
||||||
|
|
||||||
//primary_conn = NULL;
|
/* primary_conn = NULL; */
|
||||||
|
|
||||||
// XXX handle this!
|
/* XXX handle this! */
|
||||||
// -> we'll need to let the other nodes know too....
|
/* -> we'll need to let the other nodes know too.... */
|
||||||
/* no failover occurred but we'll want to restart connections */
|
/* no failover occurred but we'll want to restart connections */
|
||||||
|
|
||||||
return FAILOVER_STATE_PRIMARY_REAPPEARED;
|
return FAILOVER_STATE_PRIMARY_REAPPEARED;
|
||||||
@@ -1610,8 +1641,7 @@ poll_best_candidate(NodeInfoList *standby_nodes)
|
|||||||
* cases we could end up with two candidate nodes, so they should each
|
* cases we could end up with two candidate nodes, so they should each
|
||||||
* come to the same conclusion.
|
* come to the same conclusion.
|
||||||
*
|
*
|
||||||
* XXX check there are no cases where the standby node's LSN is
|
* XXX check there are no cases where the standby node's LSN is not set
|
||||||
* not set
|
|
||||||
*/
|
*/
|
||||||
for (cell = standby_nodes->head; cell; cell = cell->next)
|
for (cell = standby_nodes->head; cell; cell = cell->next)
|
||||||
{
|
{
|
||||||
@@ -1709,7 +1739,7 @@ follow_new_primary(int new_primary_id)
|
|||||||
return FAILOVER_STATE_FOLLOW_FAIL;
|
return FAILOVER_STATE_FOLLOW_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// XXX check if new_primary_id == failed_primary.node_id?
|
/* XXX check if new_primary_id == failed_primary.node_id? */
|
||||||
|
|
||||||
if (log_type == REPMGR_STDERR && *config_file_options.log_file)
|
if (log_type == REPMGR_STDERR && *config_file_options.log_file)
|
||||||
{
|
{
|
||||||
@@ -1721,6 +1751,7 @@ follow_new_primary(int new_primary_id)
|
|||||||
if (PQstatus(upstream_conn) == CONNECTION_OK)
|
if (PQstatus(upstream_conn) == CONNECTION_OK)
|
||||||
{
|
{
|
||||||
RecoveryType primary_recovery_type = get_recovery_type(upstream_conn);
|
RecoveryType primary_recovery_type = get_recovery_type(upstream_conn);
|
||||||
|
|
||||||
if (primary_recovery_type == RECTYPE_PRIMARY)
|
if (primary_recovery_type == RECTYPE_PRIMARY)
|
||||||
{
|
{
|
||||||
new_primary_ok = true;
|
new_primary_ok = true;
|
||||||
@@ -1739,8 +1770,8 @@ follow_new_primary(int new_primary_id)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* disconnect from local node, as follow operation will result in
|
* disconnect from local node, as follow operation will result in a server
|
||||||
* a server restart
|
* restart
|
||||||
*/
|
*/
|
||||||
|
|
||||||
PQfinish(local_conn);
|
PQfinish(local_conn);
|
||||||
@@ -1762,24 +1793,27 @@ follow_new_primary(int new_primary_id)
|
|||||||
if (r != 0)
|
if (r != 0)
|
||||||
{
|
{
|
||||||
PGconn *old_primary_conn;
|
PGconn *old_primary_conn;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The follow action could still fail due to the original primary reappearing
|
* The follow action could still fail due to the original primary
|
||||||
* before the candidate could promote itself ("repmgr standby follow" will
|
* reappearing before the candidate could promote itself ("repmgr
|
||||||
* refuse to promote another node if the primary is available). However
|
* standby follow" will refuse to promote another node if the primary
|
||||||
* the new primary will only instruct use to follow it after it's successfully
|
* is available). However the new primary will only instruct use to
|
||||||
* promoted itself, so that very likely won't be the reason for the failure.
|
* follow it after it's successfully promoted itself, so that very
|
||||||
|
* likely won't be the reason for the failure.
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* TODO: check the new primary too - we could have a split-brain
|
* TODO: check the new primary too - we could have a split-brain
|
||||||
* situation where the old primary reappeared just after the new
|
* situation where the old primary reappeared just after the new one
|
||||||
* one promoted itself.
|
* promoted itself.
|
||||||
*/
|
*/
|
||||||
old_primary_conn = establish_db_connection(failed_primary.conninfo, false);
|
old_primary_conn = establish_db_connection(failed_primary.conninfo, false);
|
||||||
|
|
||||||
if (PQstatus(old_primary_conn) == CONNECTION_OK)
|
if (PQstatus(old_primary_conn) == CONNECTION_OK)
|
||||||
{
|
{
|
||||||
// XXX add event notifications
|
/* XXX add event notifications */
|
||||||
RecoveryType upstream_recovery_type = get_recovery_type(old_primary_conn);
|
RecoveryType upstream_recovery_type = get_recovery_type(old_primary_conn);
|
||||||
|
|
||||||
PQfinish(old_primary_conn);
|
PQfinish(old_primary_conn);
|
||||||
|
|
||||||
if (upstream_recovery_type == RECTYPE_PRIMARY)
|
if (upstream_recovery_type == RECTYPE_PRIMARY)
|
||||||
@@ -1842,7 +1876,7 @@ follow_new_primary(int new_primary_id)
|
|||||||
static const char *
|
static const char *
|
||||||
_print_voting_status(NodeVotingStatus voting_status)
|
_print_voting_status(NodeVotingStatus voting_status)
|
||||||
{
|
{
|
||||||
switch(voting_status)
|
switch (voting_status)
|
||||||
{
|
{
|
||||||
case VS_NO_VOTE:
|
case VS_NO_VOTE:
|
||||||
return "NO VOTE";
|
return "NO VOTE";
|
||||||
@@ -1863,7 +1897,7 @@ _print_voting_status(NodeVotingStatus voting_status)
|
|||||||
static const char *
|
static const char *
|
||||||
_print_election_result(ElectionResult result)
|
_print_election_result(ElectionResult result)
|
||||||
{
|
{
|
||||||
switch(result)
|
switch (result)
|
||||||
{
|
{
|
||||||
case ELECTION_NOT_CANDIDATE:
|
case ELECTION_NOT_CANDIDATE:
|
||||||
return "NOT CANDIDATE";
|
return "NOT CANDIDATE";
|
||||||
@@ -1898,8 +1932,8 @@ do_election(void)
|
|||||||
int visible_nodes = 1;
|
int visible_nodes = 1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* get voting status from shared memory - should be one of "VS_NO_VOTE"
|
* get voting status from shared memory - should be one of "VS_NO_VOTE" or
|
||||||
* or "VS_VOTE_REQUEST_RECEIVED". If VS_NO_VOTE, we declare ourselves as
|
* "VS_VOTE_REQUEST_RECEIVED". If VS_NO_VOTE, we declare ourselves as
|
||||||
* candidate and initiate the voting process.
|
* candidate and initiate the voting process.
|
||||||
*/
|
*/
|
||||||
NodeVotingStatus voting_status;
|
NodeVotingStatus voting_status;
|
||||||
@@ -1910,13 +1944,13 @@ do_election(void)
|
|||||||
bool other_node_is_ahead = false;
|
bool other_node_is_ahead = false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check if at least one server in the primary's location is visible;
|
* Check if at least one server in the primary's location is visible; if
|
||||||
* if not we'll assume a network split between this node and the primary
|
* not we'll assume a network split between this node and the primary
|
||||||
* location, and not promote any standby.
|
* location, and not promote any standby.
|
||||||
*
|
*
|
||||||
* NOTE: this function is only ever called by standbys attached to the current
|
* NOTE: this function is only ever called by standbys attached to the
|
||||||
* (unreachable) primary, so "upstream_node_info" will always contain the
|
* current (unreachable) primary, so "upstream_node_info" will always
|
||||||
* primary node record.
|
* contain the primary node record.
|
||||||
*/
|
*/
|
||||||
bool primary_location_seen = false;
|
bool primary_location_seen = false;
|
||||||
|
|
||||||
@@ -1968,10 +2002,10 @@ do_election(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Here we mark ourselves as candidate, so any further vote requests
|
* Here we mark ourselves as candidate, so any further vote requests are
|
||||||
* are rejected. However it's possible another node has done the
|
* rejected. However it's possible another node has done the same thing,
|
||||||
* same thing, so when announcing ourselves as candidate to the other
|
* so when announcing ourselves as candidate to the other nodes, we'll
|
||||||
* nodes, we'll check for that and withdraw our candidature.
|
* check for that and withdraw our candidature.
|
||||||
*/
|
*/
|
||||||
electoral_term = set_voting_status_initiated(local_conn);
|
electoral_term = set_voting_status_initiated(local_conn);
|
||||||
|
|
||||||
@@ -2007,15 +2041,17 @@ do_election(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* tell the other node we're candidate - if the node has already declared
|
* tell the other node we're candidate - if the node has already
|
||||||
* itself, we withdraw
|
* declared itself, we withdraw
|
||||||
*
|
*
|
||||||
* XXX check for situations where more than one node could end up as candidate?
|
* XXX check for situations where more than one node could end up as
|
||||||
|
* candidate?
|
||||||
*
|
*
|
||||||
* XXX note it's possible some nodes accepted our candidature before we
|
* XXX note it's possible some nodes accepted our candidature before
|
||||||
* found out about the other candidate, check what happens in that situation
|
* we found out about the other candidate, check what happens in that
|
||||||
* -> other node will have info from all the nodes, even if not the vote,
|
* situation -> other node will have info from all the nodes, even if
|
||||||
* so it should be able to determine the best node anyway
|
* not the vote, so it should be able to determine the best node
|
||||||
|
* anyway
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (announce_candidature(cell->node_info->conn, &local_node_info, cell->node_info, electoral_term) == false)
|
if (announce_candidature(cell->node_info->conn, &local_node_info, cell->node_info, electoral_term) == false)
|
||||||
@@ -2028,8 +2064,8 @@ do_election(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* see if the node is in the primary's location (but skip the check
|
* see if the node is in the primary's location (but skip the check if
|
||||||
* if we've seen
|
* we've seen
|
||||||
*/
|
*/
|
||||||
if (primary_location_seen == false)
|
if (primary_location_seen == false)
|
||||||
{
|
{
|
||||||
@@ -2040,7 +2076,7 @@ do_election(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
cell->node_info->node_status = NODE_STATUS_UP;
|
cell->node_info->node_status = NODE_STATUS_UP;
|
||||||
visible_nodes ++;
|
visible_nodes++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (other_node_is_candidate == true)
|
if (other_node_is_candidate == true)
|
||||||
|
|||||||
50
repmgrd.c
50
repmgrd.c
@@ -46,7 +46,7 @@ PGconn *local_conn = NULL;
|
|||||||
|
|
||||||
|
|
||||||
/* Collate command line errors here for friendlier reporting */
|
/* Collate command line errors here for friendlier reporting */
|
||||||
static ItemList cli_errors = { NULL, NULL };
|
static ItemList cli_errors = {NULL, NULL};
|
||||||
|
|
||||||
bool startup_event_logged = false;
|
bool startup_event_logged = false;
|
||||||
|
|
||||||
@@ -54,7 +54,7 @@ MonitoringState monitoring_state = MS_NORMAL;
|
|||||||
instr_time degraded_monitoring_start;
|
instr_time degraded_monitoring_start;
|
||||||
|
|
||||||
static void close_connections(void);
|
static void close_connections(void);
|
||||||
void (*_close_connections)(void) = NULL;
|
void (*_close_connections) (void) = NULL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Record receipt of SIGHUP; will cause configuration file to be reread
|
* Record receipt of SIGHUP; will cause configuration file to be reread
|
||||||
@@ -116,7 +116,7 @@ main(int argc, char **argv)
|
|||||||
|
|
||||||
set_progname(argv[0]);
|
set_progname(argv[0]);
|
||||||
|
|
||||||
srand ( time(NULL) );
|
srand(time(NULL));
|
||||||
|
|
||||||
/* Disallow running as root */
|
/* Disallow running as root */
|
||||||
if (geteuid() == 0)
|
if (geteuid() == 0)
|
||||||
@@ -154,9 +154,11 @@ main(int argc, char **argv)
|
|||||||
exit(SUCCESS);
|
exit(SUCCESS);
|
||||||
|
|
||||||
case 'V':
|
case 'V':
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* in contrast to repmgr3 and earlier, we only display the repmgr version
|
* in contrast to repmgr3 and earlier, we only display the
|
||||||
* as it's not specific to a particular PostgreSQL version
|
* repmgr version as it's not specific to a particular
|
||||||
|
* PostgreSQL version
|
||||||
*/
|
*/
|
||||||
printf("%s %s\n", progname(), REPMGR_VERSION);
|
printf("%s %s\n", progname(), REPMGR_VERSION);
|
||||||
exit(SUCCESS);
|
exit(SUCCESS);
|
||||||
@@ -183,6 +185,7 @@ main(int argc, char **argv)
|
|||||||
case 'L':
|
case 'L':
|
||||||
{
|
{
|
||||||
int detected_cli_log_level = detect_log_level(optarg);
|
int detected_cli_log_level = detect_log_level(optarg);
|
||||||
|
|
||||||
if (detected_cli_log_level != -1)
|
if (detected_cli_log_level != -1)
|
||||||
{
|
{
|
||||||
strncpy(cli_log_level, optarg, MAXLEN);
|
strncpy(cli_log_level, optarg, MAXLEN);
|
||||||
@@ -190,6 +193,7 @@ main(int argc, char **argv)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
PQExpBufferData invalid_log_level;
|
PQExpBufferData invalid_log_level;
|
||||||
|
|
||||||
initPQExpBuffer(&invalid_log_level);
|
initPQExpBuffer(&invalid_log_level);
|
||||||
appendPQExpBuffer(&invalid_log_level,
|
appendPQExpBuffer(&invalid_log_level,
|
||||||
_("invalid log level \"%s\" provided"),
|
_("invalid log level \"%s\" provided"),
|
||||||
@@ -223,6 +227,7 @@ main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
startup_event_logged = false;
|
startup_event_logged = false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Tell the logger we're a daemon - this will ensure any output logged
|
* Tell the logger we're a daemon - this will ensure any output logged
|
||||||
* before the logger is initialized will be formatted correctly
|
* before the logger is initialized will be formatted correctly
|
||||||
@@ -230,15 +235,19 @@ main(int argc, char **argv)
|
|||||||
logger_output_mode = OM_DAEMON;
|
logger_output_mode = OM_DAEMON;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Parse the configuration file, if provided. If no configuration file
|
* Parse the configuration file, if provided. If no configuration file was
|
||||||
* was provided, or one was but was incomplete, parse_config() will
|
* provided, or one was but was incomplete, parse_config() will abort
|
||||||
* abort anyway, with an appropriate message.
|
* anyway, with an appropriate message.
|
||||||
*/
|
*/
|
||||||
load_config(config_file, verbose, false, &config_file_options, argv[0]);
|
load_config(config_file, verbose, false, &config_file_options, argv[0]);
|
||||||
|
|
||||||
|
|
||||||
/* Some configuration file items can be overriden by command line options */
|
/* Some configuration file items can be overriden by command line options */
|
||||||
/* Command-line parameter -L/--log-level overrides any setting in config file*/
|
|
||||||
|
/*
|
||||||
|
* Command-line parameter -L/--log-level overrides any setting in config
|
||||||
|
* file
|
||||||
|
*/
|
||||||
if (*cli_log_level != '\0')
|
if (*cli_log_level != '\0')
|
||||||
{
|
{
|
||||||
strncpy(config_file_options.log_level, cli_log_level, MAXLEN);
|
strncpy(config_file_options.log_level, cli_log_level, MAXLEN);
|
||||||
@@ -304,8 +313,8 @@ main(int argc, char **argv)
|
|||||||
* point, but we'll skip that and assume the presence of a node record
|
* point, but we'll skip that and assume the presence of a node record
|
||||||
* means we're dealing with a supported installation.
|
* means we're dealing with a supported installation.
|
||||||
*
|
*
|
||||||
* The absence of a node record will also indicate that either the node
|
* The absence of a node record will also indicate that either the node or
|
||||||
* or repmgr has not been properly configured.
|
* repmgr has not been properly configured.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Retrieve record for this node from the local database */
|
/* Retrieve record for this node from the local database */
|
||||||
@@ -368,7 +377,7 @@ start_monitoring(void)
|
|||||||
local_node_info.node_name,
|
local_node_info.node_name,
|
||||||
local_node_info.node_id);
|
local_node_info.node_id);
|
||||||
|
|
||||||
while(true)
|
while (true)
|
||||||
{
|
{
|
||||||
switch (local_node_info.type)
|
switch (local_node_info.type)
|
||||||
{
|
{
|
||||||
@@ -400,11 +409,13 @@ update_registration(PGconn *conn)
|
|||||||
{
|
{
|
||||||
bool success = update_node_record_conn_priority(local_conn,
|
bool success = update_node_record_conn_priority(local_conn,
|
||||||
&config_file_options);
|
&config_file_options);
|
||||||
// check values have actually changed
|
|
||||||
|
/* check values have actually changed */
|
||||||
|
|
||||||
if (success == false)
|
if (success == false)
|
||||||
{
|
{
|
||||||
PQExpBufferData errmsg;
|
PQExpBufferData errmsg;
|
||||||
|
|
||||||
initPQExpBuffer(&errmsg);
|
initPQExpBuffer(&errmsg);
|
||||||
|
|
||||||
appendPQExpBuffer(&errmsg,
|
appendPQExpBuffer(&errmsg,
|
||||||
@@ -635,10 +646,9 @@ try_reconnect(t_node_info *node_info)
|
|||||||
log_notice(_("node has recovered, reconnecting"));
|
log_notice(_("node has recovered, reconnecting"));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* XXX we should also handle the case where node is pingable
|
* XXX we should also handle the case where node is pingable but
|
||||||
* but connection denied due to connection exhaustion
|
* connection denied due to connection exhaustion - fall back to
|
||||||
* - fall back to degraded monitoring?
|
* degraded monitoring? - make that configurable
|
||||||
* - make that configurable
|
|
||||||
*/
|
*/
|
||||||
conn = establish_db_connection(node_info->conninfo, false);
|
conn = establish_db_connection(node_info->conninfo, false);
|
||||||
if (PQstatus(conn) == CONNECTION_OK)
|
if (PQstatus(conn) == CONNECTION_OK)
|
||||||
@@ -680,14 +690,14 @@ calculate_elapsed(instr_time start_time)
|
|||||||
|
|
||||||
INSTR_TIME_SUBTRACT(current_time, start_time);
|
INSTR_TIME_SUBTRACT(current_time, start_time);
|
||||||
|
|
||||||
return (int)INSTR_TIME_GET_DOUBLE(current_time);
|
return (int) INSTR_TIME_GET_DOUBLE(current_time);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const char *
|
const char *
|
||||||
print_monitoring_state(MonitoringState monitoring_state)
|
print_monitoring_state(MonitoringState monitoring_state)
|
||||||
{
|
{
|
||||||
switch(monitoring_state)
|
switch (monitoring_state)
|
||||||
{
|
{
|
||||||
case MS_NORMAL:
|
case MS_NORMAL:
|
||||||
return "normal";
|
return "normal";
|
||||||
@@ -730,5 +740,3 @@ terminate(int retval)
|
|||||||
|
|
||||||
exit(retval);
|
exit(retval);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
14
strutil.c
14
strutil.c
@@ -76,7 +76,7 @@ maxpath_snprintf(char *str, const char *format,...)
|
|||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
append_where_clause(PQExpBufferData *where_clause, const char *format, ...)
|
append_where_clause(PQExpBufferData *where_clause, const char *format,...)
|
||||||
{
|
{
|
||||||
va_list arglist;
|
va_list arglist;
|
||||||
char stringbuf[MAXLEN];
|
char stringbuf[MAXLEN];
|
||||||
@@ -85,7 +85,7 @@ append_where_clause(PQExpBufferData *where_clause, const char *format, ...)
|
|||||||
(void) xvsnprintf(stringbuf, MAXLEN, format, arglist);
|
(void) xvsnprintf(stringbuf, MAXLEN, format, arglist);
|
||||||
va_end(arglist);
|
va_end(arglist);
|
||||||
|
|
||||||
if(where_clause->data[0] == '\0')
|
if (where_clause->data[0] == '\0')
|
||||||
{
|
{
|
||||||
appendPQExpBuffer(where_clause,
|
appendPQExpBuffer(where_clause,
|
||||||
" WHERE ");
|
" WHERE ");
|
||||||
@@ -110,7 +110,7 @@ item_list_append(ItemList *item_list, const char *message)
|
|||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
item_list_append_format(ItemList *item_list, const char *format, ...)
|
item_list_append_format(ItemList *item_list, const char *format,...)
|
||||||
{
|
{
|
||||||
ItemListCell *cell;
|
ItemListCell *cell;
|
||||||
va_list arglist;
|
va_list arglist;
|
||||||
@@ -166,7 +166,7 @@ key_value_list_set(KeyValueList *item_list, const char *key, const char *value)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
key_value_list_set_format(KeyValueList *item_list, const char *key, const char *value, ...)
|
key_value_list_set_format(KeyValueList *item_list, const char *key, const char *value,...)
|
||||||
{
|
{
|
||||||
KeyValueListCell *cell = NULL;
|
KeyValueListCell *cell = NULL;
|
||||||
va_list arglist;
|
va_list arglist;
|
||||||
@@ -205,7 +205,7 @@ key_value_list_set_format(KeyValueList *item_list, const char *key, const char *
|
|||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
key_value_list_set_output_mode (KeyValueList *item_list, const char *key, OutputMode mode)
|
key_value_list_set_output_mode(KeyValueList *item_list, const char *key, OutputMode mode)
|
||||||
{
|
{
|
||||||
KeyValueListCell *cell = NULL;
|
KeyValueListCell *cell = NULL;
|
||||||
|
|
||||||
@@ -250,7 +250,7 @@ check_status_list_set(CheckStatusList *list, const char *item, CheckStatus statu
|
|||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
check_status_list_set_format(CheckStatusList *list, const char *item, CheckStatus status, const char *details, ...)
|
check_status_list_set_format(CheckStatusList *list, const char *item, CheckStatus status, const char *details,...)
|
||||||
{
|
{
|
||||||
CheckStatusListCell *cell;
|
CheckStatusListCell *cell;
|
||||||
va_list arglist;
|
va_list arglist;
|
||||||
@@ -436,7 +436,7 @@ parse_follow_command(char *parsed_command, char *template, int node_id)
|
|||||||
end_ptr = parsed_command + MAXPGPATH - 1;
|
end_ptr = parsed_command + MAXPGPATH - 1;
|
||||||
*end_ptr = '\0';
|
*end_ptr = '\0';
|
||||||
|
|
||||||
for(src_ptr = template; *src_ptr; src_ptr++)
|
for (src_ptr = template; *src_ptr; src_ptr++)
|
||||||
{
|
{
|
||||||
if (*src_ptr == '%')
|
if (*src_ptr == '%')
|
||||||
{
|
{
|
||||||
|
|||||||
46
strutil.h
46
strutil.h
@@ -33,14 +33,16 @@
|
|||||||
#define MAXLEN_STR STR(MAXLEN)
|
#define MAXLEN_STR STR(MAXLEN)
|
||||||
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
CHECK_STATUS_OK = 0,
|
CHECK_STATUS_OK = 0,
|
||||||
CHECK_STATUS_WARNING,
|
CHECK_STATUS_WARNING,
|
||||||
CHECK_STATUS_CRITICAL,
|
CHECK_STATUS_CRITICAL,
|
||||||
CHECK_STATUS_UNKNOWN
|
CHECK_STATUS_UNKNOWN
|
||||||
} CheckStatus;
|
} CheckStatus;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
OM_NOT_SET = -1,
|
OM_NOT_SET = -1,
|
||||||
OM_TEXT,
|
OM_TEXT,
|
||||||
OM_CSV,
|
OM_CSV,
|
||||||
@@ -100,62 +102,58 @@ maxpath_snprintf(char *str, const char *format,...)
|
|||||||
__attribute__((format(PG_PRINTF_ATTRIBUTE, 2, 3)));
|
__attribute__((format(PG_PRINTF_ATTRIBUTE, 2, 3)));
|
||||||
|
|
||||||
extern void
|
extern void
|
||||||
item_list_append(ItemList *item_list, const char *message);
|
item_list_append(ItemList *item_list, const char *message);
|
||||||
|
|
||||||
extern void
|
extern void
|
||||||
item_list_append_format(ItemList *item_list, const char *format, ...)
|
item_list_append_format(ItemList *item_list, const char *format,...)
|
||||||
__attribute__((format(PG_PRINTF_ATTRIBUTE, 2, 3)));
|
__attribute__((format(PG_PRINTF_ATTRIBUTE, 2, 3)));
|
||||||
|
|
||||||
extern void
|
extern void
|
||||||
item_list_free(ItemList *item_list);
|
item_list_free(ItemList *item_list);
|
||||||
|
|
||||||
extern void
|
extern void
|
||||||
key_value_list_set(KeyValueList *item_list, const char *key, const char *value);
|
key_value_list_set(KeyValueList *item_list, const char *key, const char *value);
|
||||||
|
|
||||||
extern void
|
extern void
|
||||||
key_value_list_set_format(KeyValueList *item_list, const char *key, const char *value, ...)
|
key_value_list_set_format(KeyValueList *item_list, const char *key, const char *value,...)
|
||||||
__attribute__((format(PG_PRINTF_ATTRIBUTE, 3, 4)));
|
__attribute__((format(PG_PRINTF_ATTRIBUTE, 3, 4)));
|
||||||
|
|
||||||
extern void
|
extern void
|
||||||
key_value_list_set_output_mode(KeyValueList *item_list, const char *key, OutputMode mode);
|
key_value_list_set_output_mode(KeyValueList *item_list, const char *key, OutputMode mode);
|
||||||
|
|
||||||
extern const char *
|
extern const char *key_value_list_get(KeyValueList *item_list, const char *key);
|
||||||
key_value_list_get(KeyValueList *item_list, const char *key);
|
|
||||||
|
|
||||||
extern void
|
extern void
|
||||||
key_value_list_free(KeyValueList *item_list);
|
key_value_list_free(KeyValueList *item_list);
|
||||||
|
|
||||||
extern void
|
extern void
|
||||||
check_status_list_set(CheckStatusList *list, const char *item, CheckStatus status, const char *details);
|
check_status_list_set(CheckStatusList *list, const char *item, CheckStatus status, const char *details);
|
||||||
|
|
||||||
extern void
|
extern void
|
||||||
check_status_list_set_format(CheckStatusList *list, const char *item, CheckStatus status, const char *details, ...)
|
check_status_list_set_format(CheckStatusList *list, const char *item, CheckStatus status, const char *details,...)
|
||||||
__attribute__((format(PG_PRINTF_ATTRIBUTE, 4, 5)));
|
__attribute__((format(PG_PRINTF_ATTRIBUTE, 4, 5)));
|
||||||
|
|
||||||
extern void
|
extern void
|
||||||
check_status_list_free(CheckStatusList *list);
|
check_status_list_free(CheckStatusList *list);
|
||||||
|
|
||||||
extern const char * output_check_status(CheckStatus status);
|
extern const char *output_check_status(CheckStatus status);
|
||||||
|
|
||||||
extern char *
|
extern char *escape_recovery_conf_value(const char *src);
|
||||||
escape_recovery_conf_value(const char *src);
|
|
||||||
|
|
||||||
extern char *
|
extern char *escape_string(PGconn *conn, const char *string);
|
||||||
escape_string(PGconn *conn, const char *string);
|
|
||||||
|
|
||||||
extern void
|
extern void
|
||||||
append_where_clause(PQExpBufferData *where_clause, const char *clause, ...)
|
append_where_clause(PQExpBufferData *where_clause, const char *clause,...)
|
||||||
__attribute__((format(PG_PRINTF_ATTRIBUTE, 2, 3)));
|
__attribute__((format(PG_PRINTF_ATTRIBUTE, 2, 3)));
|
||||||
|
|
||||||
extern char *
|
extern char *string_skip_prefix(const char *prefix, char *string);
|
||||||
string_skip_prefix(const char *prefix, char *string);
|
|
||||||
|
|
||||||
extern char
|
extern char
|
||||||
*string_remove_trailing_newlines(char *string);
|
*string_remove_trailing_newlines(char *string);
|
||||||
|
|
||||||
extern char *trim(char *s);
|
extern char *trim(char *s);
|
||||||
|
|
||||||
extern void
|
extern void
|
||||||
parse_follow_command(char *parsed_command, char *template, int node_id);
|
parse_follow_command(char *parsed_command, char *template, int node_id);
|
||||||
|
|
||||||
#endif /* _STRUTIL_H_ */
|
#endif /* _STRUTIL_H_ */
|
||||||
|
|||||||
Reference in New Issue
Block a user