mirror of
https://github.com/EnterpriseDB/repmgr.git
synced 2026-03-23 15:16:29 +00:00
Compare commits
15 Commits
REL3_3_STA
...
v1.1.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d36ee899dc | ||
|
|
d790ef740b | ||
|
|
aa6633b027 | ||
|
|
c3bffce379 | ||
|
|
78aea00a6d | ||
|
|
91601204b5 | ||
|
|
c91ddc2f5e | ||
|
|
72f74dd7a7 | ||
|
|
901d07fa92 | ||
|
|
f0e609bcd4 | ||
|
|
94c9c3a5c6 | ||
|
|
3af5243bcc | ||
|
|
85bbae462a | ||
|
|
14e49d41c2 | ||
|
|
1bd8a703c8 |
7
HISTORY
7
HISTORY
@@ -31,3 +31,10 @@
|
|||||||
1.1.0 2011-03-09
|
1.1.0 2011-03-09
|
||||||
Make options -U, -R and -p not mandatory (Jaime)
|
Make options -U, -R and -p not mandatory (Jaime)
|
||||||
|
|
||||||
|
1.1.1 2012-04-18
|
||||||
|
Add --ignore-rsync-warning (Cédric)
|
||||||
|
Add strnlen for compatibility with OS X (Greg)
|
||||||
|
Improve performance of repl_status view (Jaime)
|
||||||
|
Remove last argument from log_err (Jaime, Reported by Jeroen Dekkers)
|
||||||
|
Complete documentation about possible error conditions (Jaime)
|
||||||
|
Document how to clean history (Jaime)
|
||||||
|
|||||||
19
README.rst
19
README.rst
@@ -814,6 +814,23 @@ and on "prime."
|
|||||||
|
|
||||||
The servers are now again acting as primary on "prime" and standby on "standby".
|
The servers are now again acting as primary on "prime" and standby on "standby".
|
||||||
|
|
||||||
|
Maintainance of monitor history
|
||||||
|
-------------------------------
|
||||||
|
|
||||||
|
Once you have changed roles (with a failover or to restore original roles)
|
||||||
|
you would end up with records saying that node1 is primary and other records
|
||||||
|
saying that node2 is the primary. Which could be confusing.
|
||||||
|
Also, if you don't do anything about it the monitor history will keep growing.
|
||||||
|
For both of those reasons you sometime want to make some maintainance of the
|
||||||
|
``repl_monitor`` table.
|
||||||
|
|
||||||
|
If you want to clean the history after a few days you can execute a
|
||||||
|
truncate/delete (wheter you want to completely clean history or want to keep
|
||||||
|
a few days of history) in a cron. For example to keep just one day of history
|
||||||
|
you can put this in your crontab::
|
||||||
|
|
||||||
|
0 1 * * * psql -c "DELETE FROM repmgr_schema.repl_monitor where now() - last_monitor_time >= '1 day'::interval;" postgres
|
||||||
|
|
||||||
Configuration and command reference
|
Configuration and command reference
|
||||||
===================================
|
===================================
|
||||||
|
|
||||||
@@ -863,6 +880,7 @@ The output from this program looks like this::
|
|||||||
-R, --remote-user=USERNAME database server username for rsync
|
-R, --remote-user=USERNAME database server username for rsync
|
||||||
-w, --wal-keep-segments=VALUE minimum value for the GUC wal_keep_segments (default: 5000)
|
-w, --wal-keep-segments=VALUE minimum value for the GUC wal_keep_segments (default: 5000)
|
||||||
-F, --force force potentially dangerous operations to happen
|
-F, --force force potentially dangerous operations to happen
|
||||||
|
-I, --ignore-rsync-warning Ignore partial transfert warning
|
||||||
|
|
||||||
repmgr performs some tasks like clone a node, promote it or making follow another node and then exits.
|
repmgr performs some tasks like clone a node, promote it or making follow another node and then exits.
|
||||||
COMMANDS:
|
COMMANDS:
|
||||||
@@ -1023,6 +1041,7 @@ following
|
|||||||
* ERR_DB_QUERY 7: Error executing a database query.
|
* ERR_DB_QUERY 7: Error executing a database query.
|
||||||
* ERR_PROMOTED 8: Exiting program because the node has been promoted to master.
|
* ERR_PROMOTED 8: Exiting program because the node has been promoted to master.
|
||||||
* ERR_BAD_PASSWORD 9: Password used to connect to a database was rejected.
|
* ERR_BAD_PASSWORD 9: Password used to connect to a database was rejected.
|
||||||
|
* ERR_STR_OVERFLOW 10: A string was larger than expected.
|
||||||
|
|
||||||
License and Contributions
|
License and Contributions
|
||||||
=========================
|
=========================
|
||||||
|
|||||||
@@ -20,6 +20,8 @@
|
|||||||
#ifndef _REPMGR_DBUTILS_H_
|
#ifndef _REPMGR_DBUTILS_H_
|
||||||
#define _REPMGR_DBUTILS_H_
|
#define _REPMGR_DBUTILS_H_
|
||||||
|
|
||||||
|
#include "strutil.h"
|
||||||
|
|
||||||
PGconn *establishDBConnection(const char *conninfo, const bool exit_on_error);
|
PGconn *establishDBConnection(const char *conninfo, const bool exit_on_error);
|
||||||
PGconn *establishDBConnectionByParams(const char *keywords[],
|
PGconn *establishDBConnectionByParams(const char *keywords[],
|
||||||
const char *values[],
|
const char *values[],
|
||||||
|
|||||||
79
repmgr.c
79
repmgr.c
@@ -71,7 +71,7 @@ bool need_a_node = true;
|
|||||||
bool require_password = false;
|
bool require_password = false;
|
||||||
|
|
||||||
/* Initialization of runtime options */
|
/* Initialization of runtime options */
|
||||||
t_runtime_options runtime_options = { "", "", "", "", "", "", DEFAULT_WAL_KEEP_SEGMENTS, false, false, "" };
|
t_runtime_options runtime_options = { "", "", "", "", "", "", DEFAULT_WAL_KEEP_SEGMENTS, false, false, false, "" };
|
||||||
t_configuration_options options = { "", -1, "", "", "" };
|
t_configuration_options options = { "", -1, "", "", "" };
|
||||||
|
|
||||||
static char *server_mode = NULL;
|
static char *server_mode = NULL;
|
||||||
@@ -91,6 +91,7 @@ main(int argc, char **argv)
|
|||||||
{"remote-user", required_argument, NULL, 'R'},
|
{"remote-user", required_argument, NULL, 'R'},
|
||||||
{"wal-keep-segments", required_argument, NULL, 'w'},
|
{"wal-keep-segments", required_argument, NULL, 'w'},
|
||||||
{"force", no_argument, NULL, 'F'},
|
{"force", no_argument, NULL, 'F'},
|
||||||
|
{"ignore-rsync-warning", no_argument, NULL, 'I'},
|
||||||
{"verbose", no_argument, NULL, 'v'},
|
{"verbose", no_argument, NULL, 'v'},
|
||||||
{NULL, 0, NULL, 0}
|
{NULL, 0, NULL, 0}
|
||||||
};
|
};
|
||||||
@@ -116,7 +117,7 @@ main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
while ((c = getopt_long(argc, argv, "d:h:p:U:D:f:R:w:F:v", long_options,
|
while ((c = getopt_long(argc, argv, "d:h:p:U:D:f:R:w:F:I:v", long_options,
|
||||||
&optindex)) != -1)
|
&optindex)) != -1)
|
||||||
{
|
{
|
||||||
switch (c)
|
switch (c)
|
||||||
@@ -150,6 +151,9 @@ main(int argc, char **argv)
|
|||||||
case 'F':
|
case 'F':
|
||||||
runtime_options.force = true;
|
runtime_options.force = true;
|
||||||
break;
|
break;
|
||||||
|
case 'I':
|
||||||
|
runtime_options.ignore_rsync_warn = true;
|
||||||
|
break;
|
||||||
case 'v':
|
case 'v':
|
||||||
runtime_options.verbose = true;
|
runtime_options.verbose = true;
|
||||||
break;
|
break;
|
||||||
@@ -346,7 +350,7 @@ do_master_register(void)
|
|||||||
log_info(_("%s connected to master, checking its state\n"), progname);
|
log_info(_("%s connected to master, checking its state\n"), progname);
|
||||||
if (is_standby(conn))
|
if (is_standby(conn))
|
||||||
{
|
{
|
||||||
log_err(_("%s needs master to be PostgreSQL 9.0 or better\n"), progname);
|
log_err(_("Trying to register a standby node as a master\n"));
|
||||||
PQfinish(conn);
|
PQfinish(conn);
|
||||||
exit(ERR_BAD_CONFIG);
|
exit(ERR_BAD_CONFIG);
|
||||||
}
|
}
|
||||||
@@ -438,14 +442,13 @@ do_master_register(void)
|
|||||||
|
|
||||||
/* and the view */
|
/* and the view */
|
||||||
sqlquery_snprintf(sqlquery, "CREATE VIEW %s.repl_status AS "
|
sqlquery_snprintf(sqlquery, "CREATE VIEW %s.repl_status AS "
|
||||||
" WITH monitor_info AS (SELECT *, ROW_NUMBER() OVER (PARTITION BY primary_node, standby_node "
|
|
||||||
" ORDER BY last_monitor_time desc) "
|
|
||||||
" FROM %s.repl_monitor) "
|
|
||||||
" SELECT primary_node, standby_node, last_monitor_time, last_wal_primary_location, "
|
" SELECT primary_node, standby_node, last_monitor_time, last_wal_primary_location, "
|
||||||
" last_wal_standby_location, pg_size_pretty(replication_lag) replication_lag, "
|
" last_wal_standby_location, pg_size_pretty(replication_lag) replication_lag, "
|
||||||
" pg_size_pretty(apply_lag) apply_lag, age(now(), last_monitor_time) AS time_lag "
|
" pg_size_pretty(apply_lag) apply_lag, age(now(), last_monitor_time) AS time_lag "
|
||||||
" FROM monitor_info a "
|
" FROM %s.repl_monitor "
|
||||||
" WHERE row_number = 1", repmgr_schema, repmgr_schema);
|
" WHERE (standby_node, last_monitor_time) IN (SELECT standby_node, MAX(last_monitor_time) "
|
||||||
|
" FROM %s.repl_monitor GROUP BY 1)",
|
||||||
|
repmgr_schema, repmgr_schema, repmgr_schema);
|
||||||
log_debug("master register: %s\n", sqlquery);
|
log_debug("master register: %s\n", sqlquery);
|
||||||
if (!PQexec(conn, sqlquery))
|
if (!PQexec(conn, sqlquery))
|
||||||
{
|
{
|
||||||
@@ -454,6 +457,19 @@ do_master_register(void)
|
|||||||
PQfinish(conn);
|
PQfinish(conn);
|
||||||
exit(ERR_BAD_CONFIG);
|
exit(ERR_BAD_CONFIG);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* an index to improve performance of the view */
|
||||||
|
sqlquery_snprintf(sqlquery, "CREATE INDEX idx_repl_status_sort "
|
||||||
|
" ON %s.repl_monitor (last_monitor_time, standby_node) ",
|
||||||
|
repmgr_schema);
|
||||||
|
log_debug(_("master register: %s\n"), sqlquery);
|
||||||
|
if (!PQexec(conn, sqlquery))
|
||||||
|
{
|
||||||
|
log_err(_("Cannot indexing table %s.repl_monitor: %s\n"),
|
||||||
|
repmgr_schema, PQerrorMessage(conn));
|
||||||
|
PQfinish(conn);
|
||||||
|
exit(ERR_BAD_CONFIG);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -886,6 +902,20 @@ do_standby_clone(void)
|
|||||||
}
|
}
|
||||||
PQclear(res);
|
PQclear(res);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* in pg 9.1 default is to wait for a sync standby to ack,
|
||||||
|
* avoid that by turning off sync rep for this session
|
||||||
|
*/
|
||||||
|
sqlquery_snprintf(sqlquery, "SET synchronous_commit TO OFF");
|
||||||
|
res = PQexec(conn, sqlquery);
|
||||||
|
if (PQresultStatus(res) != PGRES_COMMAND_OK)
|
||||||
|
{
|
||||||
|
log_err("Can't set synchronous_commit: %s\n", PQerrorMessage(conn));
|
||||||
|
PQclear(res);
|
||||||
|
PQfinish(conn);
|
||||||
|
exit(ERR_BAD_CONFIG);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* inform the master we will start a backup and get the first XLog filename
|
* inform the master we will start a backup and get the first XLog filename
|
||||||
* so we can say to the user we need those files
|
* so we can say to the user we need those files
|
||||||
@@ -1022,9 +1052,6 @@ stop_backup:
|
|||||||
* Don't have this one exit if it fails, so that a more informative
|
* Don't have this one exit if it fails, so that a more informative
|
||||||
* error message will also appear about the backup not being stopped.
|
* error message will also appear about the backup not being stopped.
|
||||||
*/
|
*/
|
||||||
log_info(_("%s connecting to master database to stop backup\n"), progname);
|
|
||||||
conn=establishDBConnectionByParams(keywords,values,false);
|
|
||||||
|
|
||||||
log_notice("Finishing backup...\n");
|
log_notice("Finishing backup...\n");
|
||||||
sqlquery_snprintf(sqlquery, "SELECT pg_xlogfile_name(pg_stop_backup())");
|
sqlquery_snprintf(sqlquery, "SELECT pg_xlogfile_name(pg_stop_backup())");
|
||||||
log_debug("standby clone: %s\n", sqlquery);
|
log_debug("standby clone: %s\n", sqlquery);
|
||||||
@@ -1039,8 +1066,10 @@ stop_backup:
|
|||||||
}
|
}
|
||||||
last_wal_segment = PQgetvalue(res, 0, 0);
|
last_wal_segment = PQgetvalue(res, 0, 0);
|
||||||
|
|
||||||
log_info(_("%s requires primary to keep WAL files %s until at least %s\n"),
|
/* don't show this message if rsync failed */
|
||||||
progname, first_wal_segment, last_wal_segment);
|
if (r == 0)
|
||||||
|
log_info(_("%s requires primary to keep WAL files %s until at least %s\n"),
|
||||||
|
progname, first_wal_segment, last_wal_segment);
|
||||||
|
|
||||||
/* Finished with the database connection now */
|
/* Finished with the database connection now */
|
||||||
PQclear(res);
|
PQclear(res);
|
||||||
@@ -1337,6 +1366,7 @@ void help(const char *progname)
|
|||||||
printf(_(" -R, --remote-user=USERNAME database server username for rsync\n"));
|
printf(_(" -R, --remote-user=USERNAME database server username for rsync\n"));
|
||||||
printf(_(" -w, --wal-keep-segments=VALUE minimum value for the GUC wal_keep_segments (default: 5000)\n"));
|
printf(_(" -w, --wal-keep-segments=VALUE minimum value for the GUC wal_keep_segments (default: 5000)\n"));
|
||||||
printf(_(" -F, --force force potentially dangerous operations to happen\n"));
|
printf(_(" -F, --force force potentially dangerous operations to happen\n"));
|
||||||
|
printf(_(" -I, --ignore-rsync-warning Ignore partial transfert warning\n"));
|
||||||
|
|
||||||
printf(_("\n%s performs some tasks like clone a node, promote it "), progname);
|
printf(_("\n%s performs some tasks like clone a node, promote it "), progname);
|
||||||
printf(_("or making follow another node and then exits.\n"));
|
printf(_("or making follow another node and then exits.\n"));
|
||||||
@@ -1473,6 +1503,29 @@ copy_remote_files(char *host, char *remote_user, char *remote_path,
|
|||||||
|
|
||||||
r = system(script);
|
r = system(script);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we are transfering a directory (ie: data directory, tablespace directories)
|
||||||
|
* then we can ignore some rsync warning, so if we get some of those errors we
|
||||||
|
* treat them as 0 if we have --ignore-rsync-warning commandline option set
|
||||||
|
* List of ignorable rsync errors:
|
||||||
|
* 24 Partial transfer due to vanished source files
|
||||||
|
*/
|
||||||
|
if ((WEXITSTATUS(r) == 24) && is_directory)
|
||||||
|
{
|
||||||
|
if (!runtime_options.ignore_rsync_warn)
|
||||||
|
{
|
||||||
|
log_warning( _("\nrsync completed with return code 24 "
|
||||||
|
"\"Partial transfer due to vanished source files\".\n"
|
||||||
|
"This can happen because of normal operation "
|
||||||
|
"on the master server, but it may indicate an "
|
||||||
|
"issue during cloning. If you are certain no "
|
||||||
|
"changes were made to the master, try cloning "
|
||||||
|
"again using \"repmgr --force --ignore-rsync-warning\"."));
|
||||||
|
exit(ERR_BAD_RSYNC);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
r = 0;
|
||||||
|
}
|
||||||
if (r != 0)
|
if (r != 0)
|
||||||
log_err(_("Can't rsync from remote file or directory (%s:%s)\n"),
|
log_err(_("Can't rsync from remote file or directory (%s:%s)\n"),
|
||||||
host_string, remote_path);
|
host_string, remote_path);
|
||||||
|
|||||||
1
repmgr.h
1
repmgr.h
@@ -55,6 +55,7 @@ typedef struct
|
|||||||
char wal_keep_segments[MAXLEN];
|
char wal_keep_segments[MAXLEN];
|
||||||
bool verbose;
|
bool verbose;
|
||||||
bool force;
|
bool force;
|
||||||
|
bool ignore_rsync_warn;
|
||||||
|
|
||||||
char masterport[MAXLEN];
|
char masterport[MAXLEN];
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,15 @@
|
|||||||
|
|
||||||
static int xvsnprintf(char *str, size_t size, const char *format, va_list ap);
|
static int xvsnprintf(char *str, size_t size, const char *format, va_list ap);
|
||||||
|
|
||||||
|
/* Add strnlen on platforms that don't have it, like OS X */
|
||||||
|
#ifndef strnlen
|
||||||
|
size_t
|
||||||
|
strnlen(const char *s, size_t n)
|
||||||
|
{
|
||||||
|
const char *end = (const char *) memchr(s, '\0', n);
|
||||||
|
return(end ? end - s : n);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static int
|
static int
|
||||||
xvsnprintf(char *str, size_t size, const char *format, va_list ap)
|
xvsnprintf(char *str, size_t size, const char *format, va_list ap)
|
||||||
|
|||||||
@@ -35,4 +35,9 @@ extern int xsnprintf(char *str, size_t size, const char *format, ...);
|
|||||||
extern int sqlquery_snprintf(char *str, const char *format, ...);
|
extern int sqlquery_snprintf(char *str, const char *format, ...);
|
||||||
extern int maxlen_snprintf(char *str, const char *format, ...);
|
extern int maxlen_snprintf(char *str, const char *format, ...);
|
||||||
|
|
||||||
|
/* Add strnlen on platforms that don't have it, like OS X */
|
||||||
|
#ifndef strnlen
|
||||||
|
extern size_t strnlen(const char *s, size_t n);
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* _STRUTIL_H_ */
|
#endif /* _STRUTIL_H_ */
|
||||||
|
|||||||
Reference in New Issue
Block a user