mirror of
https://github.com/EnterpriseDB/repmgr.git
synced 2026-03-24 15:46:29 +00:00
Compare commits
61 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d10f1f289e | ||
|
|
5731ba6043 | ||
|
|
3d6437c8f8 | ||
|
|
54b5c8ad94 | ||
|
|
0eca08ffaf | ||
|
|
05c1dc2b92 | ||
|
|
2bd300073d | ||
|
|
01e020df8e | ||
|
|
ae7963dc64 | ||
|
|
faffb2a6e7 | ||
|
|
5d57044118 | ||
|
|
07a88c78a5 | ||
|
|
f7df8b9c80 | ||
|
|
20920b3da1 | ||
|
|
683f4de182 | ||
|
|
0c62821ffb | ||
|
|
6b70e8bbe6 | ||
|
|
6b223698c9 | ||
|
|
aee12dc2c7 | ||
|
|
c5c86e1ada | ||
|
|
7476dc84f2 | ||
|
|
f6d63f5216 | ||
|
|
a608b0bc18 | ||
|
|
469ebba656 | ||
|
|
647c21ad0e | ||
|
|
3d2530d6f9 | ||
|
|
b26e400199 | ||
|
|
152e9545a4 | ||
|
|
83b8f05221 | ||
|
|
486f8e5a2c | ||
|
|
e517cc74d1 | ||
|
|
26285b470f | ||
|
|
1521657965 | ||
|
|
041604e303 | ||
|
|
0be0100a7c | ||
|
|
2133834dda | ||
|
|
d5fd93c350 | ||
|
|
5804778b58 | ||
|
|
407a7ea2f4 | ||
|
|
4d2eca0978 | ||
|
|
9d25544ab5 | ||
|
|
8506607388 | ||
|
|
e8e059c26d | ||
|
|
38d293694d | ||
|
|
54a10a0c3f | ||
|
|
a8016f602f | ||
|
|
de57ecdad1 | ||
|
|
1fde81cf3f | ||
|
|
146c412061 | ||
|
|
e9cb61ae7a | ||
|
|
50e9460b3e | ||
|
|
47e7cbe147 | ||
|
|
bf0be3eb43 | ||
|
|
270da1294c | ||
|
|
d3c47f450f | ||
|
|
c20475f94a | ||
|
|
e0560c3e70 | ||
|
|
3fa2bef6f4 | ||
|
|
f8a0b051c8 | ||
|
|
3e4a5e6ff5 | ||
|
|
020b5b6982 |
@@ -2,7 +2,7 @@ License and Contributions
|
|||||||
=========================
|
=========================
|
||||||
|
|
||||||
`repmgr` is licensed under the GPL v3. All of its code and documentation is
|
`repmgr` is licensed under the GPL v3. All of its code and documentation is
|
||||||
Copyright 2010-2017, 2ndQuadrant Limited. See the files COPYRIGHT and LICENSE for
|
Copyright 2010-2018, 2ndQuadrant Limited. See the files COPYRIGHT and LICENSE for
|
||||||
details.
|
details.
|
||||||
|
|
||||||
The development of repmgr has primarily been sponsored by 2ndQuadrant customers.
|
The development of repmgr has primarily been sponsored by 2ndQuadrant customers.
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
Copyright (c) 2010-2017, 2ndQuadrant Limited
|
Copyright (c) 2010-2018, 2ndQuadrant Limited
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
|||||||
27
HISTORY
27
HISTORY
@@ -1,6 +1,31 @@
|
|||||||
|
4.0.2 2018-01-18
|
||||||
|
repmgr: add missing -W option to getopt_long() invocation; GitHub #350 (Ian)
|
||||||
|
repmgr: automatically create slot name if missing; GitHub #343 (Ian)
|
||||||
|
repmgr: fixes to parsing output of remote repmgr invocations; GitHub #349 (Ian)
|
||||||
|
repmgr: BDR support - create missing connection replication set
|
||||||
|
if required; GitHub #347 (Ian)
|
||||||
|
repmgr: handle missing node record in "repmgr node rejoin"; GitHub #358 (Ian)
|
||||||
|
repmgr: enable documentation to be build as single HTML file; GitHub #353 (fanf2)
|
||||||
|
repmgr: recognize "--terse" option for "repmgr cluster event"; GitHub #360 (Ian)
|
||||||
|
repmgr: add "--wait-start" option for "repmgr standby register"; GitHub #356 (Ian)
|
||||||
|
repmgr: add "%p" event notification parameter for "repmgr standby switchover"
|
||||||
|
containing the node ID of the demoted primary (Ian)
|
||||||
|
docs: various fixes and updates (Ian, Daymel, Martín, ams)
|
||||||
|
|
||||||
|
4.0.1 2017-12-13
|
||||||
|
repmgr: ensure "repmgr node check --action=" returns appropriate return
|
||||||
|
code; GitHub #340 (Ian)
|
||||||
|
repmgr: add missing schema qualification in get_all_node_records_with_upstream()
|
||||||
|
query GitHub #341 (Martín)
|
||||||
|
repmgr: initialise "voting_term" table in application, not extension SQL;
|
||||||
|
GitHub #344 (Ian)
|
||||||
|
repmgr: delete any replication slots copied by pg_rewind; GitHub #334 (Ian)
|
||||||
|
repmgr: fix configuration file sanity check; GitHub #342 (Ian)
|
||||||
|
Improve event notification documentation (Ian)
|
||||||
|
|
||||||
4.0.0 2017-11-21
|
4.0.0 2017-11-21
|
||||||
Complete rewrite with many changes; for details see the repmgr 4.0.0 release
|
Complete rewrite with many changes; for details see the repmgr 4.0.0 release
|
||||||
notes at: https://repmgr.org/docs/4.0/release-4.0.html
|
notes at: https://repmgr.org/docs/4.0/release-4.0.0.html
|
||||||
|
|
||||||
3.3.2 2017-06-01
|
3.3.2 2017-06-01
|
||||||
Add support for PostgreSQL 10 (Ian)
|
Add support for PostgreSQL 10 (Ian)
|
||||||
|
|||||||
2
compat.c
2
compat.c
@@ -6,7 +6,7 @@
|
|||||||
* supported PostgreSQL versions. They're unlikely to change but
|
* supported PostgreSQL versions. They're unlikely to change but
|
||||||
* it would be worth keeping an eye on them for any fixes/improvements.
|
* it would be worth keeping an eye on them for any fixes/improvements.
|
||||||
*
|
*
|
||||||
* Copyright (c) 2ndQuadrant, 2010-2017
|
* Copyright (c) 2ndQuadrant, 2010-2018
|
||||||
*
|
*
|
||||||
* Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
|
|||||||
2
compat.h
2
compat.h
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* compat.h
|
* compat.h
|
||||||
* Copyright (c) 2ndQuadrant, 2010-2017
|
* Copyright (c) 2ndQuadrant, 2010-2018
|
||||||
*
|
*
|
||||||
* Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* config.c - parse repmgr.conf and other configuration-related functionality
|
* config.c - parse repmgr.conf and other configuration-related functionality
|
||||||
*
|
*
|
||||||
* Copyright (c) 2ndQuadrant, 2010-2017
|
* Copyright (c) 2ndQuadrant, 2010-2018
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* configfile.h
|
* configfile.h
|
||||||
*
|
*
|
||||||
* Copyright (c) 2ndQuadrant, 2010-2017
|
* Copyright (c) 2ndQuadrant, 2010-2018
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
|||||||
22
configure
vendored
22
configure
vendored
@@ -1,6 +1,6 @@
|
|||||||
#! /bin/sh
|
#! /bin/sh
|
||||||
# Guess values for system-dependent variables and create Makefiles.
|
# Guess values for system-dependent variables and create Makefiles.
|
||||||
# Generated by GNU Autoconf 2.69 for repmgr 4.0.0.
|
# Generated by GNU Autoconf 2.69 for repmgr 4.0.2.
|
||||||
#
|
#
|
||||||
# Report bugs to <pgsql-bugs@postgresql.org>.
|
# Report bugs to <pgsql-bugs@postgresql.org>.
|
||||||
#
|
#
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
# This configure script is free software; the Free Software Foundation
|
# This configure script is free software; the Free Software Foundation
|
||||||
# gives unlimited permission to copy, distribute and modify it.
|
# gives unlimited permission to copy, distribute and modify it.
|
||||||
#
|
#
|
||||||
# Copyright (c) 2010-2017, 2ndQuadrant Ltd.
|
# Copyright (c) 2010-2018, 2ndQuadrant Ltd.
|
||||||
## -------------------- ##
|
## -------------------- ##
|
||||||
## M4sh Initialization. ##
|
## M4sh Initialization. ##
|
||||||
## -------------------- ##
|
## -------------------- ##
|
||||||
@@ -582,8 +582,8 @@ MAKEFLAGS=
|
|||||||
# Identity of this package.
|
# Identity of this package.
|
||||||
PACKAGE_NAME='repmgr'
|
PACKAGE_NAME='repmgr'
|
||||||
PACKAGE_TARNAME='repmgr'
|
PACKAGE_TARNAME='repmgr'
|
||||||
PACKAGE_VERSION='4.0.0'
|
PACKAGE_VERSION='4.0.2'
|
||||||
PACKAGE_STRING='repmgr 4.0.0'
|
PACKAGE_STRING='repmgr 4.0.2'
|
||||||
PACKAGE_BUGREPORT='pgsql-bugs@postgresql.org'
|
PACKAGE_BUGREPORT='pgsql-bugs@postgresql.org'
|
||||||
PACKAGE_URL='https://2ndquadrant.com/en/resources/repmgr/'
|
PACKAGE_URL='https://2ndquadrant.com/en/resources/repmgr/'
|
||||||
|
|
||||||
@@ -1179,7 +1179,7 @@ if test "$ac_init_help" = "long"; then
|
|||||||
# Omit some internal or obsolete options to make the list less imposing.
|
# Omit some internal or obsolete options to make the list less imposing.
|
||||||
# This message is too long to be a string in the A/UX 3.1 sh.
|
# This message is too long to be a string in the A/UX 3.1 sh.
|
||||||
cat <<_ACEOF
|
cat <<_ACEOF
|
||||||
\`configure' configures repmgr 4.0.0 to adapt to many kinds of systems.
|
\`configure' configures repmgr 4.0.2 to adapt to many kinds of systems.
|
||||||
|
|
||||||
Usage: $0 [OPTION]... [VAR=VALUE]...
|
Usage: $0 [OPTION]... [VAR=VALUE]...
|
||||||
|
|
||||||
@@ -1240,7 +1240,7 @@ fi
|
|||||||
|
|
||||||
if test -n "$ac_init_help"; then
|
if test -n "$ac_init_help"; then
|
||||||
case $ac_init_help in
|
case $ac_init_help in
|
||||||
short | recursive ) echo "Configuration of repmgr 4.0.0:";;
|
short | recursive ) echo "Configuration of repmgr 4.0.2:";;
|
||||||
esac
|
esac
|
||||||
cat <<\_ACEOF
|
cat <<\_ACEOF
|
||||||
|
|
||||||
@@ -1319,14 +1319,14 @@ fi
|
|||||||
test -n "$ac_init_help" && exit $ac_status
|
test -n "$ac_init_help" && exit $ac_status
|
||||||
if $ac_init_version; then
|
if $ac_init_version; then
|
||||||
cat <<\_ACEOF
|
cat <<\_ACEOF
|
||||||
repmgr configure 4.0.0
|
repmgr configure 4.0.2
|
||||||
generated by GNU Autoconf 2.69
|
generated by GNU Autoconf 2.69
|
||||||
|
|
||||||
Copyright (C) 2012 Free Software Foundation, Inc.
|
Copyright (C) 2012 Free Software Foundation, Inc.
|
||||||
This configure script is free software; the Free Software Foundation
|
This configure script is free software; the Free Software Foundation
|
||||||
gives unlimited permission to copy, distribute and modify it.
|
gives unlimited permission to copy, distribute and modify it.
|
||||||
|
|
||||||
Copyright (c) 2010-2017, 2ndQuadrant Ltd.
|
Copyright (c) 2010-2018, 2ndQuadrant Ltd.
|
||||||
_ACEOF
|
_ACEOF
|
||||||
exit
|
exit
|
||||||
fi
|
fi
|
||||||
@@ -1338,7 +1338,7 @@ cat >config.log <<_ACEOF
|
|||||||
This file contains any messages produced by compilers while
|
This file contains any messages produced by compilers while
|
||||||
running configure, to aid debugging if configure makes a mistake.
|
running configure, to aid debugging if configure makes a mistake.
|
||||||
|
|
||||||
It was created by repmgr $as_me 4.0.0, which was
|
It was created by repmgr $as_me 4.0.2, which was
|
||||||
generated by GNU Autoconf 2.69. Invocation command line was
|
generated by GNU Autoconf 2.69. Invocation command line was
|
||||||
|
|
||||||
$ $0 $@
|
$ $0 $@
|
||||||
@@ -2379,7 +2379,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
|
|||||||
# report actual input values of CONFIG_FILES etc. instead of their
|
# report actual input values of CONFIG_FILES etc. instead of their
|
||||||
# values after options handling.
|
# values after options handling.
|
||||||
ac_log="
|
ac_log="
|
||||||
This file was extended by repmgr $as_me 4.0.0, which was
|
This file was extended by repmgr $as_me 4.0.2, which was
|
||||||
generated by GNU Autoconf 2.69. Invocation command line was
|
generated by GNU Autoconf 2.69. Invocation command line was
|
||||||
|
|
||||||
CONFIG_FILES = $CONFIG_FILES
|
CONFIG_FILES = $CONFIG_FILES
|
||||||
@@ -2442,7 +2442,7 @@ _ACEOF
|
|||||||
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
||||||
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
|
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
|
||||||
ac_cs_version="\\
|
ac_cs_version="\\
|
||||||
repmgr config.status 4.0.0
|
repmgr config.status 4.0.2
|
||||||
configured by $0, generated by GNU Autoconf 2.69,
|
configured by $0, generated by GNU Autoconf 2.69,
|
||||||
with options \\"\$ac_cs_config\\"
|
with options \\"\$ac_cs_config\\"
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
AC_INIT([repmgr], [4.0.0], [pgsql-bugs@postgresql.org], [repmgr], [https://2ndquadrant.com/en/resources/repmgr/])
|
AC_INIT([repmgr], [4.0.2], [pgsql-bugs@postgresql.org], [repmgr], [https://2ndquadrant.com/en/resources/repmgr/])
|
||||||
|
|
||||||
AC_COPYRIGHT([Copyright (c) 2010-2017, 2ndQuadrant Ltd.])
|
AC_COPYRIGHT([Copyright (c) 2010-2018, 2ndQuadrant Ltd.])
|
||||||
|
|
||||||
AC_CONFIG_HEADER(config.h)
|
AC_CONFIG_HEADER(config.h)
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* controldata.c
|
* controldata.c
|
||||||
* Copyright (c) 2ndQuadrant, 2010-2017
|
* Copyright (c) 2ndQuadrant, 2010-2018
|
||||||
*
|
*
|
||||||
* Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* controldata.h
|
* controldata.h
|
||||||
* Copyright (c) 2ndQuadrant, 2010-2017
|
* Copyright (c) 2ndQuadrant, 2010-2018
|
||||||
*
|
*
|
||||||
* Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
|
|||||||
318
dbutils.c
318
dbutils.c
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* dbutils.c - Database connection/management functions
|
* dbutils.c - Database connection/management functions
|
||||||
*
|
*
|
||||||
* Copyright (c) 2ndQuadrant, 2010-2017
|
* Copyright (c) 2ndQuadrant, 2010-2018
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
@@ -1608,7 +1608,12 @@ repmgrd_get_local_node_id(PGconn *conn)
|
|||||||
|
|
||||||
res = PQexec(conn, "SELECT repmgr.get_local_node_id()");
|
res = PQexec(conn, "SELECT repmgr.get_local_node_id()");
|
||||||
|
|
||||||
if (!PQgetisnull(res, 0, 0))
|
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
||||||
|
{
|
||||||
|
log_error(_("unable to execute \"SELECT repmgr.get_local_node_id()\""));
|
||||||
|
log_detail("%s", PQerrorMessage(conn));
|
||||||
|
}
|
||||||
|
else if (!PQgetisnull(res, 0, 0))
|
||||||
{
|
{
|
||||||
local_node_id = atoi(PQgetvalue(res, 0, 0));
|
local_node_id = atoi(PQgetvalue(res, 0, 0));
|
||||||
}
|
}
|
||||||
@@ -2130,7 +2135,7 @@ get_all_node_records_with_upstream(PGconn *conn, NodeInfoList *node_list)
|
|||||||
" 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 "
|
||||||
" LEFT JOIN nodes un "
|
" LEFT JOIN repmgr.nodes un "
|
||||||
" ON un.node_id = n.upstream_node_id"
|
" ON un.node_id = n.upstream_node_id"
|
||||||
" ORDER BY n.node_id ");
|
" ORDER BY n.node_id ");
|
||||||
|
|
||||||
@@ -2592,6 +2597,36 @@ truncate_node_records(PGconn *conn)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
update_node_record_slot_name(PGconn *primary_conn, int node_id, char *slot_name)
|
||||||
|
{
|
||||||
|
PQExpBufferData query;
|
||||||
|
PGresult *res = NULL;
|
||||||
|
|
||||||
|
initPQExpBuffer(&query);
|
||||||
|
|
||||||
|
appendPQExpBuffer(&query,
|
||||||
|
" UPDATE repmgr.nodes "
|
||||||
|
" SET slot_name = '%s' "
|
||||||
|
" WHERE node_id = %i ",
|
||||||
|
slot_name,
|
||||||
|
node_id);
|
||||||
|
res = PQexec(primary_conn, query.data);
|
||||||
|
termPQExpBuffer(&query);
|
||||||
|
|
||||||
|
if (PQresultStatus(res) != PGRES_COMMAND_OK)
|
||||||
|
{
|
||||||
|
log_error(_("unable to set node record slot name:\n %s"),
|
||||||
|
PQerrorMessage(primary_conn));
|
||||||
|
PQclear(res);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
PQclear(res);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
get_node_replication_stats(PGconn *conn, int server_version_num, t_node_info *node_info)
|
get_node_replication_stats(PGconn *conn, int server_version_num, t_node_info *node_info)
|
||||||
{
|
{
|
||||||
@@ -2962,7 +2997,6 @@ create_event_record(PGconn *conn, t_configuration_options *options, int node_id,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* create_event_notification()
|
* create_event_notification()
|
||||||
*
|
*
|
||||||
@@ -3063,7 +3097,7 @@ _create_event(PGconn *conn, t_configuration_options *options, int node_id, char
|
|||||||
|
|
||||||
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
||||||
{
|
{
|
||||||
/* we don't treat this as an error */
|
/* we don't treat this as a fatal error */
|
||||||
log_warning(_("unable to create event record:\n %s"),
|
log_warning(_("unable to create event record:\n %s"),
|
||||||
PQerrorMessage(conn));
|
PQerrorMessage(conn));
|
||||||
|
|
||||||
@@ -3216,6 +3250,20 @@ _create_event(PGconn *conn, t_configuration_options *options, int node_id, char
|
|||||||
dst_ptr += strlen(dst_ptr);
|
dst_ptr += strlen(dst_ptr);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'p':
|
||||||
|
/* %p: former primary id ("repmgr standby switchover") */
|
||||||
|
src_ptr++;
|
||||||
|
if (event_info->former_primary_id != UNKNOWN_NODE_ID)
|
||||||
|
{
|
||||||
|
PQExpBufferData node_id;
|
||||||
|
initPQExpBuffer(&node_id);
|
||||||
|
appendPQExpBuffer(&node_id,
|
||||||
|
"%i", event_info->former_primary_id);
|
||||||
|
strlcpy(dst_ptr, node_id.data, end_ptr - dst_ptr);
|
||||||
|
dst_ptr += strlen(dst_ptr);
|
||||||
|
termPQExpBuffer(&node_id);
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
/* otherwise treat the % as not special */
|
/* otherwise treat the % as not special */
|
||||||
if (dst_ptr < end_ptr)
|
if (dst_ptr < end_ptr)
|
||||||
@@ -3249,10 +3297,102 @@ _create_event(PGconn *conn, t_configuration_options *options, int node_id, char
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PGresult *
|
||||||
|
get_event_records(PGconn *conn, int node_id, const char *node_name, const char *event, bool all, int limit)
|
||||||
|
{
|
||||||
|
PGresult *res;
|
||||||
|
|
||||||
|
PQExpBufferData query;
|
||||||
|
PQExpBufferData where_clause;
|
||||||
|
|
||||||
|
|
||||||
|
initPQExpBuffer(&query);
|
||||||
|
initPQExpBuffer(&where_clause);
|
||||||
|
|
||||||
|
/* LEFT JOIN used here as a node record may have been removed */
|
||||||
|
appendPQExpBuffer(&query,
|
||||||
|
" SELECT e.node_id, n.node_name, e.event, e.successful, "
|
||||||
|
" TO_CHAR(e.event_timestamp, 'YYYY-MM-DD HH24:MI:SS') AS timestamp, "
|
||||||
|
" e.details "
|
||||||
|
" FROM repmgr.events e "
|
||||||
|
"LEFT JOIN repmgr.nodes n ON e.node_id = n.node_id ");
|
||||||
|
|
||||||
|
if (node_id != UNKNOWN_NODE_ID)
|
||||||
|
{
|
||||||
|
append_where_clause(&where_clause,
|
||||||
|
"n.node_id=%i", node_id);
|
||||||
|
}
|
||||||
|
else if (node_name[0] != '\0')
|
||||||
|
{
|
||||||
|
char *escaped = escape_string(conn, node_name);
|
||||||
|
|
||||||
|
if (escaped == NULL)
|
||||||
|
{
|
||||||
|
log_error(_("unable to escape value provided for node name"));
|
||||||
|
log_detail(_("node name is: \"%s\""), node_name);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
append_where_clause(&where_clause,
|
||||||
|
"n.node_name='%s'",
|
||||||
|
escaped);
|
||||||
|
pfree(escaped);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event[0] != '\0')
|
||||||
|
{
|
||||||
|
char *escaped = escape_string(conn, event);
|
||||||
|
|
||||||
|
if (escaped == NULL)
|
||||||
|
{
|
||||||
|
log_error(_("unable to escape value provided for event"));
|
||||||
|
log_detail(_("event is: \"%s\""), event);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
append_where_clause(&where_clause,
|
||||||
|
"e.event='%s'",
|
||||||
|
escaped);
|
||||||
|
pfree(escaped);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
appendPQExpBuffer(&query, "\n%s\n",
|
||||||
|
where_clause.data);
|
||||||
|
|
||||||
|
appendPQExpBuffer(&query,
|
||||||
|
" ORDER BY e.event_timestamp DESC");
|
||||||
|
|
||||||
|
if (all == false && limit > 0)
|
||||||
|
{
|
||||||
|
appendPQExpBuffer(&query, " LIMIT %i",
|
||||||
|
limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
log_debug("do_cluster_event():\n%s", query.data);
|
||||||
|
res = PQexec(conn, query.data);
|
||||||
|
|
||||||
|
termPQExpBuffer(&query);
|
||||||
|
termPQExpBuffer(&where_clause);
|
||||||
|
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ========================== */
|
/* ========================== */
|
||||||
/* replication slot functions */
|
/* replication slot functions */
|
||||||
/* ========================== */
|
/* ========================== */
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
create_slot_name(char *slot_name, int node_id)
|
||||||
|
{
|
||||||
|
maxlen_snprintf(slot_name, "repmgr_slot_%i", node_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
create_replication_slot(PGconn *conn, char *slot_name, int server_version_num, PQExpBufferData *error_msg)
|
create_replication_slot(PGconn *conn, char *slot_name, int server_version_num, PQExpBufferData *error_msg)
|
||||||
{
|
{
|
||||||
@@ -3735,7 +3875,7 @@ int
|
|||||||
get_current_term(PGconn *conn)
|
get_current_term(PGconn *conn)
|
||||||
{
|
{
|
||||||
PGresult *res = NULL;
|
PGresult *res = NULL;
|
||||||
int term = -1;
|
int term = VOTING_TERM_NOT_SET;
|
||||||
|
|
||||||
res = PQexec(conn, "SELECT term FROM repmgr.voting_term");
|
res = PQexec(conn, "SELECT term FROM repmgr.voting_term");
|
||||||
|
|
||||||
@@ -3747,13 +3887,43 @@ get_current_term(PGconn *conn)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (PQntuples(res) > 0)
|
||||||
|
{
|
||||||
term = atoi(PQgetvalue(res, 0, 0));
|
term = atoi(PQgetvalue(res, 0, 0));
|
||||||
|
}
|
||||||
|
|
||||||
PQclear(res);
|
PQclear(res);
|
||||||
return term;
|
return term;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
initialize_voting_term(PGconn *conn)
|
||||||
|
{
|
||||||
|
PGresult *res = NULL;
|
||||||
|
|
||||||
|
int current_term = get_current_term(conn);
|
||||||
|
|
||||||
|
if (current_term == VOTING_TERM_NOT_SET)
|
||||||
|
{
|
||||||
|
res = PQexec(conn, "INSERT INTO repmgr.voting_term (term) VALUES (1)");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
res = PQexec(conn, "UPDATE repmgr.voting_term SET term = 1");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PQresultStatus(res) != PGRES_COMMAND_OK)
|
||||||
|
{
|
||||||
|
log_error(_("unable to initialize repmgr.voting_term:\n %s"),
|
||||||
|
PQerrorMessage(conn));
|
||||||
|
}
|
||||||
|
|
||||||
|
PQclear(res);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
increment_current_term(PGconn *conn)
|
increment_current_term(PGconn *conn)
|
||||||
{
|
{
|
||||||
@@ -3765,8 +3935,6 @@ increment_current_term(PGconn *conn)
|
|||||||
{
|
{
|
||||||
log_error(_("unable to increment repmgr.voting_term:\n %s"),
|
log_error(_("unable to increment repmgr.voting_term:\n %s"),
|
||||||
PQerrorMessage(conn));
|
PQerrorMessage(conn));
|
||||||
PQclear(res);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PQclear(res);
|
PQclear(res);
|
||||||
@@ -4050,21 +4218,24 @@ is_active_bdr_node(PGconn *conn, const char *node_name)
|
|||||||
appendPQExpBuffer(&query,
|
appendPQExpBuffer(&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_catalog.pg_replication_slots s "
|
||||||
" ON slot_name=bdr.bdr_format_slot_name(n.node_sysid, n.node_timeline, n.node_dboid, (SELECT oid FROM pg_database WHERE datname = current_database())) "
|
" ON s.slot_name=bdr.bdr_format_slot_name(n.node_sysid, n.node_timeline, n.node_dboid, (SELECT oid FROM pg_catalog.pg_database WHERE datname = pg_catalog.current_database())) "
|
||||||
" WHERE node_name='%s' ",
|
" WHERE n.node_name='%s' ",
|
||||||
node_name);
|
node_name);
|
||||||
|
|
||||||
|
log_verbose(LOG_DEBUG, "is_active_bdr_node():\n %s", query.data);
|
||||||
|
|
||||||
res = PQexec(conn, query.data);
|
res = PQexec(conn, query.data);
|
||||||
termPQExpBuffer(&query);
|
termPQExpBuffer(&query);
|
||||||
|
|
||||||
|
/* we don't care if the query fails */
|
||||||
if (PQresultStatus(res) != PGRES_TUPLES_OK || PQntuples(res) == 0)
|
if (PQresultStatus(res) != PGRES_TUPLES_OK || PQntuples(res) == 0)
|
||||||
{
|
{
|
||||||
is_active_bdr_node = false;
|
is_active_bdr_node = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
is_active_bdr_node = atoi(PQgetvalue(res, 0, 0)) == 1 ? true : false;
|
is_active_bdr_node = atobool(PQgetvalue(res, 0, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
PQclear(res);
|
PQclear(res);
|
||||||
@@ -4174,7 +4345,7 @@ add_table_to_bdr_replication_set(PGconn *conn, const char *tablename, const char
|
|||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
bdr_node_exists(PGconn *conn, const char *node_name)
|
bdr_node_name_matches(PGconn *conn, const char *node_name, PQExpBufferData *bdr_local_node_name)
|
||||||
{
|
{
|
||||||
PQExpBufferData query;
|
PQExpBufferData query;
|
||||||
PGresult *res = NULL;
|
PGresult *res = NULL;
|
||||||
@@ -4183,10 +4354,7 @@ bdr_node_exists(PGconn *conn, const char *node_name)
|
|||||||
initPQExpBuffer(&query);
|
initPQExpBuffer(&query);
|
||||||
|
|
||||||
appendPQExpBuffer(&query,
|
appendPQExpBuffer(&query,
|
||||||
"SELECT COUNT(*)"
|
"SELECT bdr.bdr_get_local_node_name() AS node_name");
|
||||||
" FROM bdr.bdr_nodes"
|
|
||||||
" WHERE node_name = '%s'",
|
|
||||||
node_name);
|
|
||||||
|
|
||||||
res = PQexec(conn, query.data);
|
res = PQexec(conn, query.data);
|
||||||
termPQExpBuffer(&query);
|
termPQExpBuffer(&query);
|
||||||
@@ -4197,7 +4365,9 @@ bdr_node_exists(PGconn *conn, const char *node_name)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
node_exists = atoi(PQgetvalue(res, 0, 0)) == 1 ? true : false;
|
node_exists = true;
|
||||||
|
appendPQExpBuffer(bdr_local_node_name,
|
||||||
|
"%s", PQgetvalue(res, 0, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
PQclear(res);
|
PQclear(res);
|
||||||
@@ -4482,3 +4652,115 @@ unset_bdr_failover_handler(PGconn *conn)
|
|||||||
PQclear(res);
|
PQclear(res);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
bdr_node_has_repmgr_set(PGconn *conn, const char *node_name)
|
||||||
|
{
|
||||||
|
PQExpBufferData query;
|
||||||
|
PGresult *res = NULL;
|
||||||
|
bool has_repmgr_set = false;
|
||||||
|
|
||||||
|
initPQExpBuffer(&query);
|
||||||
|
|
||||||
|
appendPQExpBuffer(&query,
|
||||||
|
" SELECT COUNT(*) "
|
||||||
|
" FROM UNNEST(bdr.connection_get_replication_sets('%s') AS repset "
|
||||||
|
" WHERE repset = 'repmgr'",
|
||||||
|
node_name);
|
||||||
|
|
||||||
|
res = PQexec(conn, query.data);
|
||||||
|
termPQExpBuffer(&query);
|
||||||
|
|
||||||
|
if (PQresultStatus(res) != PGRES_TUPLES_OK || PQntuples(res) == 0)
|
||||||
|
{
|
||||||
|
has_repmgr_set = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
has_repmgr_set = atoi(PQgetvalue(res, 0, 0)) == 1 ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
PQclear(res);
|
||||||
|
|
||||||
|
return has_repmgr_set;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
bdr_node_set_repmgr_set(PGconn *conn, const char *node_name)
|
||||||
|
{
|
||||||
|
PQExpBufferData query;
|
||||||
|
PGresult *res = NULL;
|
||||||
|
bool success = true;
|
||||||
|
|
||||||
|
initPQExpBuffer(&query);
|
||||||
|
|
||||||
|
appendPQExpBuffer(&query,
|
||||||
|
" SELECT bdr.connection_set_replication_sets( "
|
||||||
|
" ARRAY( "
|
||||||
|
" SELECT repset::TEXT "
|
||||||
|
" FROM UNNEST(bdr.connection_get_replication_sets('%s')) AS repset "
|
||||||
|
" UNION "
|
||||||
|
" SELECT 'repmgr'::TEXT "
|
||||||
|
" ), "
|
||||||
|
" '%s' "
|
||||||
|
" ) ",
|
||||||
|
node_name,
|
||||||
|
node_name);
|
||||||
|
|
||||||
|
res = PQexec(conn, query.data);
|
||||||
|
termPQExpBuffer(&query);
|
||||||
|
|
||||||
|
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
||||||
|
{
|
||||||
|
success = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
PQclear(res);
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* miscellaneous debugging functions */
|
||||||
|
|
||||||
|
const char *
|
||||||
|
print_node_status(NodeStatus node_status)
|
||||||
|
{
|
||||||
|
switch (node_status)
|
||||||
|
{
|
||||||
|
case NODE_STATUS_UNKNOWN:
|
||||||
|
return "UNKNOWN";
|
||||||
|
case NODE_STATUS_UP:
|
||||||
|
return "UP";
|
||||||
|
case NODE_STATUS_SHUTTING_DOWN:
|
||||||
|
return "SHUTTING_DOWN";
|
||||||
|
case NODE_STATUS_DOWN:
|
||||||
|
return "DOWN";
|
||||||
|
case NODE_STATUS_UNCLEAN_SHUTDOWN:
|
||||||
|
return "UNCLEAN_SHUTDOWN";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "UNIDENTIFIED_STATUS";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const char *
|
||||||
|
print_pqping_status(PGPing ping_status)
|
||||||
|
{
|
||||||
|
switch (ping_status)
|
||||||
|
{
|
||||||
|
case PQPING_OK:
|
||||||
|
return "PQPING_OK";
|
||||||
|
case PQPING_REJECT:
|
||||||
|
return "PQPING_REJECT";
|
||||||
|
case PQPING_NO_RESPONSE:
|
||||||
|
return "PQPING_NO_RESPONSE";
|
||||||
|
case PQPING_NO_ATTEMPT:
|
||||||
|
return "PQPING_NO_ATTEMPT";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "PQPING_UNKNOWN_STATUS";
|
||||||
|
}
|
||||||
|
|||||||
27
dbutils.h
27
dbutils.h
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* dbutils.h
|
* dbutils.h
|
||||||
*
|
*
|
||||||
* Copyright (c) 2ndQuadrant, 2010-2017
|
* Copyright (c) 2ndQuadrant, 2010-2018
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -74,6 +74,7 @@ typedef enum
|
|||||||
{
|
{
|
||||||
NODE_STATUS_UNKNOWN = -1,
|
NODE_STATUS_UNKNOWN = -1,
|
||||||
NODE_STATUS_UP,
|
NODE_STATUS_UP,
|
||||||
|
NODE_STATUS_SHUTTING_DOWN,
|
||||||
NODE_STATUS_DOWN,
|
NODE_STATUS_DOWN,
|
||||||
NODE_STATUS_UNCLEAN_SHUTDOWN
|
NODE_STATUS_UNCLEAN_SHUTDOWN
|
||||||
} NodeStatus;
|
} NodeStatus;
|
||||||
@@ -174,11 +175,13 @@ typedef struct s_event_info
|
|||||||
{
|
{
|
||||||
char *node_name;
|
char *node_name;
|
||||||
char *conninfo_str;
|
char *conninfo_str;
|
||||||
|
int former_primary_id;
|
||||||
} t_event_info;
|
} t_event_info;
|
||||||
|
|
||||||
#define T_EVENT_INFO_INITIALIZER { \
|
#define T_EVENT_INFO_INITIALIZER { \
|
||||||
NULL, \
|
NULL, \
|
||||||
NULL \
|
NULL, \
|
||||||
|
UNKNOWN_NODE_ID \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -369,10 +372,8 @@ bool check_cluster_schema(PGconn *conn);
|
|||||||
/* GUC manipulation functions */
|
/* GUC manipulation functions */
|
||||||
bool set_config(PGconn *conn, const char *config_param, const char *config_value);
|
bool set_config(PGconn *conn, const char *config_param, const char *config_value);
|
||||||
bool set_config_bool(PGconn *conn, const char *config_param, bool state);
|
bool set_config_bool(PGconn *conn, const char *config_param, bool state);
|
||||||
int guc_set(PGconn *conn, const char *parameter, const char *op,
|
int guc_set(PGconn *conn, const char *parameter, const char *op, const char *value);
|
||||||
const char *value);
|
int guc_set_typed(PGconn *conn, const char *parameter, const char *op, const char *value, const char *datatype);
|
||||||
int guc_set_typed(PGconn *conn, const char *parameter, const char *op,
|
|
||||||
const char *value, const char *datatype);
|
|
||||||
bool get_pg_setting(PGconn *conn, const char *setting, char *output);
|
bool get_pg_setting(PGconn *conn, const char *setting, char *output);
|
||||||
|
|
||||||
/* server information functions */
|
/* server information functions */
|
||||||
@@ -421,10 +422,10 @@ bool update_node_record_set_primary(PGconn *conn, int this_node_id);
|
|||||||
bool update_node_record_set_upstream(PGconn *conn, int this_node_id, int new_upstream_node_id);
|
bool update_node_record_set_upstream(PGconn *conn, int this_node_id, int new_upstream_node_id);
|
||||||
bool update_node_record_status(PGconn *conn, int this_node_id, char *type, int upstream_node_id, bool active);
|
bool update_node_record_status(PGconn *conn, int this_node_id, char *type, int upstream_node_id, bool active);
|
||||||
bool update_node_record_conn_priority(PGconn *conn, t_configuration_options *options);
|
bool update_node_record_conn_priority(PGconn *conn, t_configuration_options *options);
|
||||||
|
bool update_node_record_slot_name(PGconn *primary_conn, int node_id, char *slot_name);
|
||||||
|
|
||||||
bool witness_copy_node_records(PGconn *primary_conn, PGconn *witness_conn);
|
bool witness_copy_node_records(PGconn *primary_conn, PGconn *witness_conn);
|
||||||
|
|
||||||
|
|
||||||
void clear_node_info_list(NodeInfoList *nodes);
|
void clear_node_info_list(NodeInfoList *nodes);
|
||||||
|
|
||||||
/* PostgreSQL configuration file location functions */
|
/* PostgreSQL configuration file location functions */
|
||||||
@@ -437,8 +438,10 @@ void config_file_list_add(t_configfile_list *list, const char *file, const char
|
|||||||
bool create_event_record(PGconn *conn, t_configuration_options *options, int node_id, char *event, bool successful, char *details);
|
bool create_event_record(PGconn *conn, t_configuration_options *options, int node_id, char *event, bool successful, char *details);
|
||||||
bool create_event_notification(PGconn *conn, t_configuration_options *options, int node_id, char *event, bool successful, char *details);
|
bool create_event_notification(PGconn *conn, t_configuration_options *options, int node_id, char *event, bool successful, char *details);
|
||||||
bool create_event_notification_extended(PGconn *conn, t_configuration_options *options, int node_id, char *event, bool successful, char *details, t_event_info *event_info);
|
bool create_event_notification_extended(PGconn *conn, t_configuration_options *options, int node_id, char *event, bool successful, char *details, t_event_info *event_info);
|
||||||
|
PGresult *get_event_records(PGconn *conn, int node_id, const char *node_name, const char *event, bool all, int limit);
|
||||||
|
|
||||||
/* replication slot functions */
|
/* replication slot functions */
|
||||||
|
void create_slot_name(char *slot_name, int node_id);
|
||||||
bool create_replication_slot(PGconn *conn, char *slot_name, int server_version_num, PQExpBufferData *error_msg);
|
bool create_replication_slot(PGconn *conn, char *slot_name, int server_version_num, PQExpBufferData *error_msg);
|
||||||
bool drop_replication_slot(PGconn *conn, char *slot_name);
|
bool drop_replication_slot(PGconn *conn, char *slot_name);
|
||||||
RecordStatus get_slot_record(PGconn *conn, char *slot_name, t_replication_slot *record);
|
RecordStatus get_slot_record(PGconn *conn, char *slot_name, t_replication_slot *record);
|
||||||
@@ -473,6 +476,7 @@ bool delete_monitoring_records(PGconn *primary_conn, int keep_history);
|
|||||||
|
|
||||||
|
|
||||||
/* node voting functions */
|
/* node voting functions */
|
||||||
|
void initialize_voting_term(PGconn *conn);
|
||||||
int get_current_term(PGconn *conn);
|
int get_current_term(PGconn *conn);
|
||||||
void increment_current_term(PGconn *conn);
|
void increment_current_term(PGconn *conn);
|
||||||
bool announce_candidature(PGconn *conn, t_node_info *this_node, t_node_info *other_node, int electoral_term);
|
bool announce_candidature(PGconn *conn, t_node_info *this_node, t_node_info *other_node, int electoral_term);
|
||||||
@@ -498,12 +502,17 @@ bool is_bdr_repmgr(PGconn *conn);
|
|||||||
bool is_table_in_bdr_replication_set(PGconn *conn, const char *tablename, const char *set);
|
bool is_table_in_bdr_replication_set(PGconn *conn, const char *tablename, const char *set);
|
||||||
bool add_table_to_bdr_replication_set(PGconn *conn, const char *tablename, const char *set);
|
bool add_table_to_bdr_replication_set(PGconn *conn, const char *tablename, const char *set);
|
||||||
void add_extension_tables_to_bdr_replication_set(PGconn *conn);
|
void add_extension_tables_to_bdr_replication_set(PGconn *conn);
|
||||||
|
bool bdr_node_name_matches(PGconn *conn, const char *node_name, PQExpBufferData *bdr_local_node_name);
|
||||||
bool bdr_node_exists(PGconn *conn, const char *node_name);
|
|
||||||
ReplSlotStatus get_bdr_node_replication_slot_status(PGconn *conn, const char *node_name);
|
ReplSlotStatus get_bdr_node_replication_slot_status(PGconn *conn, const char *node_name);
|
||||||
void get_bdr_other_node_name(PGconn *conn, int node_id, char *name_buf);
|
void get_bdr_other_node_name(PGconn *conn, int node_id, char *name_buf);
|
||||||
|
|
||||||
bool am_bdr_failover_handler(PGconn *conn, int node_id);
|
bool am_bdr_failover_handler(PGconn *conn, int node_id);
|
||||||
void unset_bdr_failover_handler(PGconn *conn);
|
void unset_bdr_failover_handler(PGconn *conn);
|
||||||
|
bool bdr_node_has_repmgr_set(PGconn *conn, const char *node_name);
|
||||||
|
bool bdr_node_set_repmgr_set(PGconn *conn, const char *node_name);
|
||||||
|
|
||||||
|
/* miscellaneous debugging functions */
|
||||||
|
const char *print_node_status(NodeStatus node_status);
|
||||||
|
const char *print_pqping_status(PGPing ping_status);
|
||||||
|
|
||||||
#endif /* _REPMGR_DBUTILS_H_ */
|
#endif /* _REPMGR_DBUTILS_H_ */
|
||||||
|
|||||||
10
dirutil.c
10
dirutil.c
@@ -3,7 +3,7 @@
|
|||||||
* dirmod.c
|
* dirmod.c
|
||||||
* directory handling functions
|
* directory handling functions
|
||||||
*
|
*
|
||||||
* Copyright (c) 2ndQuadrant, 2010-2017
|
* Copyright (c) 2ndQuadrant, 2010-2018
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -311,6 +311,14 @@ create_pg_dir(char *path, bool force)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
rmdir_recursive(char *path)
|
||||||
|
{
|
||||||
|
return nftw(path, unlink_dir_callback, 64, FTW_DEPTH | FTW_PHYS);
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
unlink_dir_callback(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf)
|
unlink_dir_callback(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* dirutil.h
|
* dirutil.h
|
||||||
* Copyright (c) 2ndQuadrant, 2010-2017
|
* Copyright (c) 2ndQuadrant, 2010-2018
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -26,5 +26,5 @@ extern int check_dir(char *path);
|
|||||||
extern bool create_dir(char *path);
|
extern bool create_dir(char *path);
|
||||||
extern bool is_pg_dir(char *path);
|
extern bool is_pg_dir(char *path);
|
||||||
extern bool create_pg_dir(char *path, bool force);
|
extern bool create_pg_dir(char *path, bool force);
|
||||||
|
extern int rmdir_recursive(char *path);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
2
doc/.gitignore
vendored
2
doc/.gitignore
vendored
@@ -2,4 +2,6 @@ HTML.index
|
|||||||
bookindex.sgml
|
bookindex.sgml
|
||||||
html-stamp
|
html-stamp
|
||||||
html/
|
html/
|
||||||
|
nochunks.dsl
|
||||||
|
repmgr.html
|
||||||
version.sgml
|
version.sgml
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ SGMLINCLUDE = -D . -D ${srcdir}
|
|||||||
|
|
||||||
SPFLAGS += -wall -wno-unused-param -wno-empty -wfully-tagged
|
SPFLAGS += -wall -wno-unused-param -wno-empty -wfully-tagged
|
||||||
|
|
||||||
JADE.html.call = $(JADE) $(JADEFLAGS) $(SPFLAGS) $(SGMLINCLUDE) $(CATALOG) -d stylesheet.dsl -t sgml -i output-html
|
JADE.html.call = $(JADE) $(JADEFLAGS) $(SPFLAGS) $(SGMLINCLUDE) $(CATALOG) -t sgml -i output-html
|
||||||
|
|
||||||
ALLSGML := $(wildcard $(srcdir)/*.sgml)
|
ALLSGML := $(wildcard $(srcdir)/*.sgml)
|
||||||
# to build bookindex
|
# to build bookindex
|
||||||
@@ -26,10 +26,15 @@ html: html-stamp
|
|||||||
|
|
||||||
html-stamp: repmgr.sgml $(ALLSGML) $(GENERATED_SGML) stylesheet.dsl website-docs.css
|
html-stamp: repmgr.sgml $(ALLSGML) $(GENERATED_SGML) stylesheet.dsl website-docs.css
|
||||||
$(MKDIR_P) html
|
$(MKDIR_P) html
|
||||||
$(JADE.html.call) -i include-index $<
|
$(JADE.html.call) -d stylesheet.dsl -i include-index $<
|
||||||
cp $(srcdir)/stylesheet.css $(srcdir)/website-docs.css html/
|
cp $(srcdir)/stylesheet.css $(srcdir)/website-docs.css html/
|
||||||
touch $@
|
touch $@
|
||||||
|
|
||||||
|
repmgr.html: repmgr.sgml $(ALLSGML) $(GENERATED_SGML) stylesheet.dsl website-docs.css
|
||||||
|
sed '/html-index-filename/a\
|
||||||
|
(define nochunks #t)' <stylesheet.dsl >nochunks.dsl
|
||||||
|
$(JADE.html.call) -d nochunks.dsl -i include-index $< >repmgr.html
|
||||||
|
|
||||||
version.sgml: ${repmgr_top_builddir}/repmgr_version.h
|
version.sgml: ${repmgr_top_builddir}/repmgr_version.h
|
||||||
{ \
|
{ \
|
||||||
echo "<!ENTITY repmgrversion \"$(REPMGR_VERSION)\">"; \
|
echo "<!ENTITY repmgrversion \"$(REPMGR_VERSION)\">"; \
|
||||||
@@ -37,7 +42,7 @@ version.sgml: ${repmgr_top_builddir}/repmgr_version.h
|
|||||||
|
|
||||||
HTML.index: repmgr.sgml $(ALMOSTALLSGML) stylesheet.dsl
|
HTML.index: repmgr.sgml $(ALMOSTALLSGML) stylesheet.dsl
|
||||||
@$(MKDIR_P) html
|
@$(MKDIR_P) html
|
||||||
$(JADE.html.call) -V html-index $<
|
$(JADE.html.call) -d stylesheet.dsl -V html-index $<
|
||||||
|
|
||||||
website-docs.css:
|
website-docs.css:
|
||||||
@$(MKDIR_P) html
|
@$(MKDIR_P) html
|
||||||
|
|||||||
158
doc/appendix-packages.sgml
Normal file
158
doc/appendix-packages.sgml
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
<appendix id="appendix-packages" xreflabel="Package details">
|
||||||
|
<indexterm>
|
||||||
|
<primary>packages</primary>
|
||||||
|
</indexterm>
|
||||||
|
|
||||||
|
<title>&repmgr; package details</title>
|
||||||
|
<para>
|
||||||
|
This section provides technical details about various &repmgr; binary
|
||||||
|
packages, such as location of the installed binaries and
|
||||||
|
configuration files.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<sect1 id="packages-centos" xreflabel="CentOS packages">
|
||||||
|
<title>CentOS, RHEL, Scientific Linux etc.</title>
|
||||||
|
<para>
|
||||||
|
Currently packages are provided for versions 6.x and 7.x of CentOS et al.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<note>
|
||||||
|
<para>
|
||||||
|
For PostgreSQL 9.6 and lower, the CentOS packages use a mixture of <literal>9.6</literal>
|
||||||
|
and <literal>96</literal> in various places to designate the major version;
|
||||||
|
from PostgreSQL 10, the first part of the version number (e.g. <literal>10</literal>) is
|
||||||
|
the major version, so there is more consistency in file/path/package naming.
|
||||||
|
</para>
|
||||||
|
</note>
|
||||||
|
|
||||||
|
<table id="centos-7-packages">
|
||||||
|
<title>CentOS 7 packages</title>
|
||||||
|
|
||||||
|
<tgroup cols="2">
|
||||||
|
<tbody>
|
||||||
|
<row>
|
||||||
|
<entry>Repository URL:</entry>
|
||||||
|
<entry><ulink url="https://yum.postgresql.org/repopackages.php">https://yum.postgresql.org/repopackages.php</ulink></entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry>Repository documentation:</entry>
|
||||||
|
<entry><ulink url="https://yum.postgresql.org/">https://yum.postgresql.org/</ulink></entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry>Package name example:</entry>
|
||||||
|
<entry><filename>repmgr10-4.0.0-1.rhel7.x86_64</filename></entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry>Metapackage:</entry>
|
||||||
|
<entry>(none)</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry>Installation command:</entry>
|
||||||
|
<entry><literal>yum install -y repmgr10</literal></entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry>Binary location:</entry>
|
||||||
|
<entry><filename>/usr/pgsql-10/bin</filename></entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry>In default path:</entry>
|
||||||
|
<entry>NO</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry>Configuration file location:</entry>
|
||||||
|
<entry><filename>/etc/repmgr/10/repmgr.conf</filename></entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry>repmgrd service command:</entry>
|
||||||
|
<entry><literal>service repmgr10</literal></entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry>repmgrd service file location:</entry>
|
||||||
|
<entry><filename>/usr/lib/systemd/system/repmgr10.service</filename></entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry>repmgrd log file location:</entry>
|
||||||
|
<entry>(not specified)</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
</tgroup>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<table id="centos-6-packages">
|
||||||
|
<title>CentOS 6 packages</title>
|
||||||
|
|
||||||
|
<tgroup cols="2">
|
||||||
|
<tbody>
|
||||||
|
<row>
|
||||||
|
<entry>Repository URL:</entry>
|
||||||
|
<entry><ulink url="https://yum.postgresql.org/repopackages.php">https://yum.postgresql.org/repopackages.php</ulink></entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry>Repository documentation:</entry>
|
||||||
|
<entry><ulink url="https://yum.postgresql.org/">https://yum.postgresql.org/</ulink></entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry>Package name example:</entry>
|
||||||
|
<entry><filename>repmgr96-4.0.0-1.rhel6.x86_64</filename></entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry>Metapackage:</entry>
|
||||||
|
<entry>NO</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry>Installation command:</entry>
|
||||||
|
<entry><literal>yum install -y repmgr96</literal></entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry>Binary location:</entry>
|
||||||
|
<entry><filename>/usr/pgsql-9.6/bin</filename></entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry>In default path:</entry>
|
||||||
|
<entry>NO</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry>Configuration file location:</entry>
|
||||||
|
<entry><filename>/etc/repmgr/9.6/repmgr.conf</filename></entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry>repmgrd service command:</entry>
|
||||||
|
<entry>service repmgr-9.6</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry>repmgrd service file location:</entry>
|
||||||
|
<entry><literal>/etc/init.d/repmgr-9.6</literal></entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry>repmgrd log file location:</entry>
|
||||||
|
<entry><filename>/var/log/repmgr/repmgrd-9.6.log</filename></entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
</tgroup>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
|
||||||
|
</sect1>
|
||||||
|
</appendix>
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
<appendix id="appendix-release-notes" xreflabel="Release notes">
|
<appendix id="appendix-release-notes">
|
||||||
<title>Release notes</title>
|
<title>Release notes</title>
|
||||||
<indexterm>
|
<indexterm>
|
||||||
<primary>Release notes</primary>
|
<primary>Release notes</primary>
|
||||||
@@ -16,30 +16,309 @@
|
|||||||
See also: <xref linkend="upgrading-repmgr">
|
See also: <xref linkend="upgrading-repmgr">
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<sect1 id="release-4.0">
|
<sect1 id="release-4.0.2">
|
||||||
<title>Release 4.0beta1</title>
|
<title>Release 4.0.2</title>
|
||||||
|
<para><emphasis>Thu Jan 18, 2018</emphasis></para>
|
||||||
<para><emphasis>Thu Oct 5, 2017</emphasis></para>
|
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
repmgr 4.0 is an entirely new version of &repmgr;, providing many
|
repmgr 4.0.2 contains some bug fixes and minor usability enhancements.
|
||||||
improvements together with some changes in the way it works.
|
|
||||||
In particular changes have been made to some configuration file
|
|
||||||
settings and command line options for consistency and clarity.
|
|
||||||
</para>
|
</para>
|
||||||
|
<sect2>
|
||||||
|
<title>Usability enhancements</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
For detailed instructions on upgrading from repmgr 3.x, see
|
<itemizedlist>
|
||||||
<xref linkend="upgrading-from-repmgr-3">.
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Recognize the <option>-t</option>/<option>--terse</option> option for
|
||||||
|
<command><link linkend="repmgr-cluster-event">repmgr cluster event</link></command> to hide
|
||||||
|
the <literal>Details</literal> column (GitHub #360)
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Add "--wait-start" option for
|
||||||
|
<command><link linkend="repmgr-standby-register">repmgr standby register</link></command>
|
||||||
|
(GitHub #356)
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Add <literal>%p</literal> <link linkend="event-notifications">event notification parameter</link>
|
||||||
|
for <command><link linkend="repmgr-standby-switchover">repmgr standby switchover</link></command>
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</itemizedlist>
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
</sect2>
|
||||||
|
|
||||||
|
<sect2>
|
||||||
|
<title>Bug fixes</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Add missing -W option to <literal>getopt_long()</literal> invocation (GitHub #350)
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Automatically create slot name if missing (GitHub #343)
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Fixes to parsing output of remote repmgr invocations (GitHub #349)
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
When registering BDR nodes, automatically create missing connection replication set (GitHub #347)
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Handle missing node record in <command><link linkend="repmgr-node-rejoin">repmgr node rejoin</link></command>
|
||||||
|
(GitHub #358)
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
|
||||||
|
</itemizedlist>
|
||||||
|
</para>
|
||||||
|
|
||||||
|
</sect2>
|
||||||
|
|
||||||
|
<sect2>
|
||||||
|
<title>Documentation</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
The documentation can now be built as a single HTML file (GitHub pull request #353)
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
</para>
|
||||||
|
</sect2>
|
||||||
|
|
||||||
|
</sect1>
|
||||||
|
|
||||||
|
<sect1 id="release-4.0.1">
|
||||||
|
<title>Release 4.0.1</title>
|
||||||
|
|
||||||
|
<para><emphasis>Wed Dec 13, 2017</emphasis></para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
repmgr 4.0.1 is a bugfix release.
|
||||||
|
</para>
|
||||||
|
<sect2>
|
||||||
|
<title>Bug fixes</title>
|
||||||
|
<para>
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
ensure correct return codes are returned for
|
||||||
|
<command><link linkend="repmgr-node-check">repmgr node check --action=</link></command> operations
|
||||||
|
(GitHub #340)
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Fix <xref linkend="repmgr-cluster-show"> when <literal>repmgr</literal> schema not set in search path
|
||||||
|
(GitHub #341)
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
When using <literal>--force-rewind</literal> with <xref linkend="repmgr-node-rejoin">
|
||||||
|
delete any replication slots copied by <application>pg_rewind</application>
|
||||||
|
(GitHub #334)
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Only perform sanity check on accessibility of configuration files outside
|
||||||
|
the data directory when <literal>--copy-external-config-files</literal>
|
||||||
|
provided (GitHub #342)
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Initialise "voting_term" table in application, not extension SQL
|
||||||
|
(GitHub #344)
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
</itemizedlist>
|
||||||
|
</para>
|
||||||
|
</sect2>
|
||||||
|
</sect1>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<sect1 id="release-4.0.0">
|
||||||
|
<title>Release 4.0.0</title>
|
||||||
|
|
||||||
|
<para><emphasis>Tue Nov 21, 2017</emphasis></para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
repmgr 4.0 is an entirely new version of &repmgr;, implementing &repmgr;
|
||||||
|
as a native PostgreSQL extension, adding new and improving existing features,
|
||||||
|
and making &repmgr; more user-friendly and intuitive to use. The new code base
|
||||||
|
will make it easier to add additional functionality for future releases.
|
||||||
|
</para>
|
||||||
<note>
|
<note>
|
||||||
<para>
|
<simpara>
|
||||||
|
With the new version, the opportunity has been taken to
|
||||||
|
make some changes in the way &repmgr; is set up and
|
||||||
|
configured. In particular changes have been made to some
|
||||||
|
configuration file settings consistency for and clarity.
|
||||||
|
Changes are covered in detail below
|
||||||
|
</simpara>
|
||||||
|
<simpara>
|
||||||
To standardise terminology, from this release <literal>primary</literal> is used to
|
To standardise terminology, from this release <literal>primary</literal> is used to
|
||||||
denote the read/write node in a streaming replication cluster. <literal>master</literal>
|
denote the read/write node in a streaming replication cluster. <literal>master</literal>
|
||||||
is still accepted as an alias for &repmgr; commands
|
is still accepted as an alias for &repmgr; commands
|
||||||
(e.g. <link linkend="repmgr-primary-register"><command>repmgr master register</command></link>).
|
(e.g. <link linkend="repmgr-primary-register"><command>repmgr master register</command></link>).
|
||||||
</para>
|
</simpara>
|
||||||
</note>
|
</note>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
For detailed instructions on upgrading from repmgr 3.x, see <xref linkend="upgrading-from-repmgr-3">.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<sect2>
|
||||||
|
<title>Features and improvements</title>
|
||||||
|
<para>
|
||||||
|
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
<emphasis>improved switchover</emphasis>:
|
||||||
|
the <command>switchover</command> process has been improved and streamlined,
|
||||||
|
speeding up the switchover process and can also instruct other standbys
|
||||||
|
to follow the new primary once the switchover has completed. See
|
||||||
|
<xref linkend="performing-switchover"> for more details.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
<emphasis>"--dry-run" option</emphasis>: many &repmgr; commands now provide
|
||||||
|
a <literal>--dry-run</literal> option which will execute the command as far
|
||||||
|
as possible without making any changes, which will enable possible issues
|
||||||
|
to be identified before the intended operation is actually carried out.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
<emphasis>easier upgrades</emphasis>: &repmgr; is now implemented as a native
|
||||||
|
PostgreSQL extension, which means future upgrades can be carried out by
|
||||||
|
installing the upgraded package and issuing
|
||||||
|
<ulink url="https://www.postgresql.org/docs/current/static/sql-alterextension.html">ALTER EXTENSION repmgr UPDATE</ulink>.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
<emphasis>improved logging output</emphasis>:
|
||||||
|
&repmgr; (and <application>repmgrd</application>) now provide more explicit
|
||||||
|
logging output giving a better picture of what is going on. Where appropriate,
|
||||||
|
<literal>DETAIL</literal> and <literal>HINT</literal> log lines provide additional
|
||||||
|
detail and suggestions for resolving problems. Additionally, <application>repmgrd</application>
|
||||||
|
now emits informational log lines at regular, configurable intervals
|
||||||
|
to confirm that it's running correctly and which node(s) it's monitoring.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
<emphasis>automatic configuration file location in packages</emphasis>:
|
||||||
|
Many operating system packages place the &repmgr; configuration files
|
||||||
|
in a version-specific subdirectory, e.g. <filename>/etc/repmgr/9.6/repmgr.conf</filename>;
|
||||||
|
&repmgr; now makes it easy for package maintainers to provide a patch
|
||||||
|
with the actual file location, meaning <filename>repmgr.conf</filename>
|
||||||
|
does not need to be provided explicitly. This is currently the case
|
||||||
|
for 2ndQuadrant-provided <literal>.deb</literal> and <literal>.rpm</literal> packages.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
<emphasis>monitoring and status checks</emphasis>:
|
||||||
|
New commands <xref linkend="repmgr-node-check"> and
|
||||||
|
<xref linkend="repmgr-node-status"> providing information
|
||||||
|
about a node's status and replication-related monitoring
|
||||||
|
output.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
<emphasis>node rejoin</emphasis>:
|
||||||
|
New commands <xref linkend="repmgr-node-rejoin"> enables a failed
|
||||||
|
primary to be rejoined to a replication cluster, optionally using
|
||||||
|
<application>pg_rewind</application> to synchronise its data,
|
||||||
|
(note that <application>pg_rewind</application> may not be useable
|
||||||
|
in some circumstances).
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
<emphasis>automatic failover</emphasis>:
|
||||||
|
improved detection of node status; promotion decision based on a consensual
|
||||||
|
model, with the promoted primary explicitly informing other standbys to
|
||||||
|
follow it. The <application>repmgrd</application> daemon will continue
|
||||||
|
functioning even if the monitored PostgreSQL instance is down, and resume
|
||||||
|
monitoring if it reappears. Additionally, if the instance's role has changed
|
||||||
|
(typically from a primary to a standby, e.g. following reintegration of a
|
||||||
|
failed primary using <xref linkend="repmgr-node-rejoin">) <application>repmgrd</application>
|
||||||
|
will automatically resume monitoring it as a standby.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
<emphasis>new documentation</emphasis>:
|
||||||
|
the existing documentation spread over multiple text files
|
||||||
|
has been consolidated into DocBook format (as used by the
|
||||||
|
main PostgreSQL project) and is now available online in
|
||||||
|
HTML format.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
The DocBook files can easily be used to create versions
|
||||||
|
of the documentation in other formats such as PDF.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
</itemizedlist>
|
||||||
|
|
||||||
|
</para>
|
||||||
|
</sect2>
|
||||||
<sect2>
|
<sect2>
|
||||||
<title>New command line options</title>
|
<title>New command line options</title>
|
||||||
<para>
|
<para>
|
||||||
@@ -236,7 +515,7 @@
|
|||||||
<sect2>
|
<sect2>
|
||||||
<title>repmgrd</title>
|
<title>repmgrd</title>
|
||||||
<para>
|
<para>
|
||||||
The `repmgr` shared library has been renamed from <literal>repmgr_funcs</literal> to
|
The shared library has been renamed from <literal>repmgr_funcs</literal> to
|
||||||
<literal>repmgr</literal>, meaning <varname>shared_preload_libraries</varname>
|
<literal>repmgr</literal>, meaning <varname>shared_preload_libraries</varname>
|
||||||
in <filename>postgresql.conf</filename> needs to be updated to the new name:
|
in <filename>postgresql.conf</filename> needs to be updated to the new name:
|
||||||
<programlisting>
|
<programlisting>
|
||||||
|
|||||||
@@ -60,10 +60,10 @@
|
|||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><option>%t</option></term>
|
<term><option>%s</option></term>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
success (1 or 0)
|
success (1) or failure (0)
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
@@ -84,6 +84,17 @@
|
|||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>%p</option></term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
node ID of the demoted standby (<xref linkend="repmgr-standby-switchover"> only)
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
</variablelist>
|
</variablelist>
|
||||||
<para>
|
<para>
|
||||||
The values provided for <literal>%t</literal> and <literal>%d</literal>
|
The values provided for <literal>%t</literal> and <literal>%d</literal>
|
||||||
@@ -121,11 +132,15 @@
|
|||||||
<para>
|
<para>
|
||||||
By default, all notification types will be passed to the designated script;
|
By default, all notification types will be passed to the designated script;
|
||||||
the notification types can be filtered to explicitly named ones:
|
the notification types can be filtered to explicitly named ones:
|
||||||
|
|
||||||
<itemizedlist spacing="compact" mark="bullet">
|
<itemizedlist spacing="compact" mark="bullet">
|
||||||
|
|
||||||
<listitem>
|
<listitem>
|
||||||
<simpara><literal>primary_register</literal></simpara>
|
<simpara><literal>primary_register</literal></simpara>
|
||||||
</listitem>
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<simpara><literal>primary_unregister</literal></simpara>
|
||||||
|
</listitem>
|
||||||
<listitem>
|
<listitem>
|
||||||
<simpara><literal>standby_register</literal></simpara>
|
<simpara><literal>standby_register</literal></simpara>
|
||||||
</listitem>
|
</listitem>
|
||||||
@@ -144,6 +159,21 @@
|
|||||||
<listitem>
|
<listitem>
|
||||||
<simpara><literal>standby_disconnect_manual</literal></simpara>
|
<simpara><literal>standby_disconnect_manual</literal></simpara>
|
||||||
</listitem>
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<simpara><literal>standby_failure</literal></simpara>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<simpara><literal>standby_recovery</literal></simpara>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<simpara><literal>witness_register</literal></simpara>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<simpara><literal>witness_unregister</literal></simpara>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<simpara><literal>node_rejoin</literal></simpara>
|
||||||
|
</listitem>
|
||||||
<listitem>
|
<listitem>
|
||||||
<simpara><literal>repmgrd_start</literal></simpara>
|
<simpara><literal>repmgrd_start</literal></simpara>
|
||||||
</listitem>
|
</listitem>
|
||||||
|
|||||||
@@ -80,6 +80,7 @@
|
|||||||
<!ENTITY appendix-release-notes SYSTEM "appendix-release-notes.sgml">
|
<!ENTITY appendix-release-notes SYSTEM "appendix-release-notes.sgml">
|
||||||
<!ENTITY appendix-faq SYSTEM "appendix-faq.sgml">
|
<!ENTITY appendix-faq SYSTEM "appendix-faq.sgml">
|
||||||
<!ENTITY appendix-signatures SYSTEM "appendix-signatures.sgml">
|
<!ENTITY appendix-signatures SYSTEM "appendix-signatures.sgml">
|
||||||
|
<!ENTITY appendix-packages SYSTEM "appendix-packages.sgml">
|
||||||
|
|
||||||
<!ENTITY bookindex SYSTEM "bookindex.sgml">
|
<!ENTITY bookindex SYSTEM "bookindex.sgml">
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
<para>
|
<para>
|
||||||
RPM packages for &repmgr; are available via Yum through
|
RPM packages for &repmgr; are available via Yum through
|
||||||
the PostgreSQL Global Development Group RPM repository
|
the PostgreSQL Global Development Group RPM repository
|
||||||
(<ulink url="https://yum.postgresql.org/">http://yum.postgresql.org/</>).
|
(<ulink url="https://yum.postgresql.org/">http://yum.postgresql.org/</ulink>).
|
||||||
Follow the instructions for your distribution (RedHat, CentOS,
|
Follow the instructions for your distribution (RedHat, CentOS,
|
||||||
Fedora, etc.) and architecture as detailed there.
|
Fedora, etc.) and architecture as detailed there.
|
||||||
</para>
|
</para>
|
||||||
@@ -24,11 +24,117 @@
|
|||||||
<ulink url="https://2ndquadrant.com">2ndQuadrant</ulink> also provides its
|
<ulink url="https://2ndquadrant.com">2ndQuadrant</ulink> also provides its
|
||||||
own RPM packages which are made available
|
own RPM packages which are made available
|
||||||
at the same time as each &repmgr; release, as it can take some days for
|
at the same time as each &repmgr; release, as it can take some days for
|
||||||
them to become available via the main PGDG repository. See here for details:
|
them to become available via the main PGDG repository. See following section for details:
|
||||||
<ulink url="http://repmgr.org/yum-repository.html">http://repmgr.org/yum-repository.html</>
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
|
||||||
|
<sect3 id="installation-packages-redhat-2ndq">
|
||||||
|
<title>2ndQuadrant repmgr yum repository</title>
|
||||||
|
<para>
|
||||||
|
Beginning with <ulink url="http://repmgr.org/release-notes-3.1.3.html">repmgr 3.1.3</ulink>,
|
||||||
|
<ulink url="https://2ndquadrant.com/">2ndQuadrant</ulink> provides a dedicated <literal>yum</literal>
|
||||||
|
repository for &repmgr; releases. This repository complements the main
|
||||||
|
<ulink url="https://yum.postgresql.org/repopackages.php">PGDG community repository</ulink>,
|
||||||
|
but enables repmgr users to access the latest &repmgr; packages before they are
|
||||||
|
available via the PGDG repository, which can take several days to be updated following
|
||||||
|
a fresh &repmgr; release.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
<emphasis>Installation</emphasis>
|
||||||
|
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Import the repository public key (optional but recommended):
|
||||||
|
<programlisting>
|
||||||
|
rpm --import http://packages.2ndquadrant.com/repmgr/RPM-GPG-KEY-repmgr</programlisting>
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Install the repository RPM for your distribution (this enables the 2ndQuadrant
|
||||||
|
repository as a source of repmgr packages):
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem>
|
||||||
|
<simpara>
|
||||||
|
<emphasis>Fedora:</emphasis>
|
||||||
|
<ulink url="http://packages.2ndquadrant.com/repmgr/yum-repo-rpms/repmgr-fedora-1.0-1.noarch.rpm">http://packages.2ndquadrant.com/repmgr/yum-repo-rpms/repmgr-fedora-1.0-1.noarch.rpm</ulink>
|
||||||
|
</simpara>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<simpara>
|
||||||
|
<emphasis>RHEL, CentOS etc:</emphasis>
|
||||||
|
<ulink url="http://packages.2ndquadrant.com/repmgr/yum-repo-rpms/repmgr-rhel-1.0-1.noarch.rpm">http://packages.2ndquadrant.com/repmgr/yum-repo-rpms/repmgr-rhel-1.0-1.noarch.rpm</ulink>
|
||||||
|
</simpara>
|
||||||
|
</listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
e.g.:
|
||||||
|
<programlisting>
|
||||||
|
$ yum install http://packages.2ndquadrant.com/repmgr/yum-repo-rpms/repmgr-rhel-1.0-1.noarch.rpm</programlisting>
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Install the repmgr version appropriate for your PostgreSQL version (e.g. <literal>repmgr96</literal>), e.g.:
|
||||||
|
<programlisting>
|
||||||
|
$ yum install repmgr96</programlisting>
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
<emphasis>Compatibility with PGDG Repositories</emphasis>
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
The 2ndQuadrant &repmgr; yum repository uses exactly the same package definitions as the
|
||||||
|
main PGDG repository and is effectively a selective mirror for &repmgr; packages only.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
Normally yum should prioritize the repository with the most recent &repmgr; version.
|
||||||
|
Once the PGDG repository has been updated, it doesn't matter which repository
|
||||||
|
the packages are installed from.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
To ensure the 2ndQuadrant repository is always prioritised, install <literal>yum-plugin-priorities</literal>
|
||||||
|
and set the repository priorities accordingly.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
<emphasis>Installing a specific package version</emphasis>
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
To install a specific package version, execute <command>yum --showduplicates list</command>
|
||||||
|
for the package in question:
|
||||||
|
<programlisting>
|
||||||
|
[root@localhost ~]# yum --showduplicates list repmgr96
|
||||||
|
Loaded plugins: fastestmirror
|
||||||
|
Loading mirror speeds from cached hostfile
|
||||||
|
* base: ftp.iij.ad.jp
|
||||||
|
* extras: ftp.iij.ad.jp
|
||||||
|
* updates: ftp.iij.ad.jp
|
||||||
|
Available Packages
|
||||||
|
repmgr96.x86_64 3.2-1.el6 2ndquadrant-repmgr
|
||||||
|
repmgr96.x86_64 3.2.1-1.el6 2ndquadrant-repmgr
|
||||||
|
repmgr96.x86_64 3.3-1.el6 2ndquadrant-repmgr
|
||||||
|
repmgr96.x86_64 3.3.1-1.el6 2ndquadrant-repmgr
|
||||||
|
repmgr96.x86_64 3.3.2-1.el6 2ndquadrant-repmgr
|
||||||
|
repmgr96.x86_64 3.3.2-1.rhel6 pgdg96
|
||||||
|
repmgr96.x86_64 4.0.0-1.el6 2ndquadrant-repmgr
|
||||||
|
repmgr96.x86_64 4.0.0-1.rhel6 pgdg96</programlisting>
|
||||||
|
then append the appropriate version number to the package name with a hyphen, e.g.:
|
||||||
|
<programlisting>
|
||||||
|
[root@localhost ~]# yum install repmgr96-3.3.2-1.el6</programlisting>
|
||||||
|
</para>
|
||||||
|
</sect3>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<sect2 id="installation-packages-debian" xreflabel="Installing from packages on Debian or Ubuntu">
|
<sect2 id="installation-packages-debian" xreflabel="Installing from packages on Debian or Ubuntu">
|
||||||
|
|
||||||
<indexterm>
|
<indexterm>
|
||||||
@@ -38,9 +144,9 @@
|
|||||||
|
|
||||||
<title>Debian/Ubuntu</title>
|
<title>Debian/Ubuntu</title>
|
||||||
<para>.deb packages for &repmgr; are available from the
|
<para>.deb packages for &repmgr; are available from the
|
||||||
PostgreSQL Community APT repository (<ulink url="http://apt.postgresql.org/">http://apt.postgresql.org/</>).
|
PostgreSQL Community APT repository (<ulink url="http://apt.postgresql.org/">http://apt.postgresql.org/</ulink>).
|
||||||
Instructions can be found in the APT section of the PostgreSQL Wiki
|
Instructions can be found in the APT section of the PostgreSQL Wiki
|
||||||
(<ulink url="https://wiki.postgresql.org/wiki/Apt">https://wiki.postgresql.org/wiki/Apt</>).
|
(<ulink url="https://wiki.postgresql.org/wiki/Apt">https://wiki.postgresql.org/wiki/Apt</ulink>).
|
||||||
</para>
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
|
|||||||
@@ -155,6 +155,20 @@
|
|||||||
The generated HTML files will be placed in the <filename>doc/html</filename>
|
The generated HTML files will be placed in the <filename>doc/html</filename>
|
||||||
subdirectory of your source tree.
|
subdirectory of your source tree.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
To build the documentation as a single HTML file, execute:
|
||||||
|
<programlisting>
|
||||||
|
cd doc/ && make repmgr.html</programlisting>
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<note>
|
||||||
|
<simpara>
|
||||||
|
Due to changes in PostgreSQL's documentation build system from PostgreSQL 10,
|
||||||
|
the documentation can currently only be built agains PostgreSQL 9.6 or earlier.
|
||||||
|
This limitation will be fixed when time and resources permit.
|
||||||
|
</simpara>
|
||||||
|
</note>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<date>2017</date>
|
<date>2017</date>
|
||||||
|
|
||||||
<copyright>
|
<copyright>
|
||||||
<year>2010-2017</year>
|
<year>2010-2018</year>
|
||||||
<holder>2ndQuadrant, Ltd.</holder>
|
<holder>2ndQuadrant, Ltd.</holder>
|
||||||
</copyright>
|
</copyright>
|
||||||
|
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
<title>Legal Notice</title>
|
<title>Legal Notice</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
<productname>repmgr</productname> is Copyright © 2010-2017
|
<productname>repmgr</productname> is Copyright © 2010-2018
|
||||||
by 2ndQuadrant, Ltd. All rights reserved.
|
by 2ndQuadrant, Ltd. All rights reserved.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
|||||||
@@ -103,11 +103,11 @@
|
|||||||
# ignores archiving. Use something more sensible.
|
# ignores archiving. Use something more sensible.
|
||||||
archive_command = '/bin/true'
|
archive_command = '/bin/true'
|
||||||
|
|
||||||
# If you have configured `pg_basebackup_options`
|
# If you have configured "pg_basebackup_options"
|
||||||
# in `repmgr.conf` to include the setting `--xlog-method=fetch` (from
|
# in "repmgr.conf" to include the setting "--xlog-method=fetch" (from
|
||||||
# PostgreSQL 10 `--wal-method=fetch`), *and* you have not set
|
# PostgreSQL 10 "--wal-method=fetch"), *and* you have not set
|
||||||
# `restore_command` in `repmgr.conf`to fetch WAL files from another
|
# "restore_command" in "repmgr.conf"to fetch WAL files from another
|
||||||
# source such as Barman, you'll need to set `wal_keep_segments` to a
|
# source such as Barman, you'll need to set "wal_keep_segments" to a
|
||||||
# high enough value to ensure that all WAL files generated while
|
# high enough value to ensure that all WAL files generated while
|
||||||
# the standby is being cloned are retained until the standby starts up.
|
# the standby is being cloned are retained until the standby starts up.
|
||||||
#
|
#
|
||||||
@@ -121,6 +121,11 @@
|
|||||||
<command>include 'postgresql.replication.conf</command>.
|
<command>include 'postgresql.replication.conf</command>.
|
||||||
</simpara>
|
</simpara>
|
||||||
</tip>
|
</tip>
|
||||||
|
<para>
|
||||||
|
Additionally, if you are intending to use <application>pg_rewind</application>,
|
||||||
|
and the cluster was not initialised using data checksums, you may want to consider enabling
|
||||||
|
<varname>wal_log_hints</varname>; for more details see <xref linkend="repmgr-node-rejoin-pg-rewind">.
|
||||||
|
</para>
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
<sect1 id="quickstart-repmgr-user-database">
|
<sect1 id="quickstart-repmgr-user-database">
|
||||||
@@ -306,11 +311,10 @@
|
|||||||
(and possibly <literal>data_directory</literal>) adjusted accordingly, e.g.:
|
(and possibly <literal>data_directory</literal>) adjusted accordingly, e.g.:
|
||||||
</para>
|
</para>
|
||||||
<programlisting>
|
<programlisting>
|
||||||
node=2
|
node_id=2
|
||||||
node_name=node2
|
node_name=node2
|
||||||
conninfo='host=node2 user=repmgr dbname=repmgr connect_timeout=2'
|
conninfo='host=node2 user=repmgr dbname=repmgr connect_timeout=2'
|
||||||
data_directory='/var/lib/postgresql/data'
|
data_directory='/var/lib/postgresql/data'</programlisting>
|
||||||
</programlisting>
|
|
||||||
<para>
|
<para>
|
||||||
Use the <command>--dry-run</command> option to check the standby can be cloned:
|
Use the <command>--dry-run</command> option to check the standby can be cloned:
|
||||||
</para>
|
</para>
|
||||||
|
|||||||
@@ -40,10 +40,13 @@
|
|||||||
<simpara><literal>--node-name</literal>: restrict entries to node with this name</simpara>
|
<simpara><literal>--node-name</literal>: restrict entries to node with this name</simpara>
|
||||||
</listitem>
|
</listitem>
|
||||||
<listitem>
|
<listitem>
|
||||||
<simpara><literal>--event</literal>: filter specific event</simpara>
|
<simpara><literal>--event</literal>: filter specific event (see <xref linkend="event-notifications"> for a full list)</simpara>
|
||||||
</listitem>
|
</listitem>
|
||||||
</itemizedlist>
|
</itemizedlist>
|
||||||
</para>
|
</para>
|
||||||
|
<para>
|
||||||
|
The "Details" column can be omitted by providing <literal>--terse</literal>.
|
||||||
|
</para>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
<refsect1>
|
<refsect1>
|
||||||
|
|||||||
@@ -45,6 +45,13 @@
|
|||||||
</para>
|
</para>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
|
<refsect1>
|
||||||
|
<title>Event notifications</title>
|
||||||
|
<para>
|
||||||
|
A <literal>node_rejoin</literal> <link linkend="event-notifications">event notification</link> will be generated.
|
||||||
|
</para>
|
||||||
|
</refsect1>
|
||||||
|
|
||||||
<refsect1>
|
<refsect1>
|
||||||
<title>Notes</title>
|
<title>Notes</title>
|
||||||
<para>
|
<para>
|
||||||
@@ -69,7 +76,7 @@
|
|||||||
</tip>
|
</tip>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
<refsect1 id="repmgr-node-rejoin-pg-rewind">
|
<refsect1 id="repmgr-node-rejoin-pg-rewind" xreflabel="Using pg_rewind">
|
||||||
<title>Using <command>pg_rewind</command></title>
|
<title>Using <command>pg_rewind</command></title>
|
||||||
<para>
|
<para>
|
||||||
<command>repmgr node rejoin</command> can optionally use <command>pg_rewind</command> to re-integrate a
|
<command>repmgr node rejoin</command> can optionally use <command>pg_rewind</command> to re-integrate a
|
||||||
@@ -78,7 +85,8 @@
|
|||||||
</para>
|
</para>
|
||||||
<note>
|
<note>
|
||||||
<para>
|
<para>
|
||||||
<command>pg_rewind</command> *requires* that either <varname>wal_log_hints</varname> is enabled, or that
|
<command>pg_rewind</command> <emphasis>requires</emphasis> that either
|
||||||
|
<varname>wal_log_hints</varname> is enabled, or that
|
||||||
data checksums were enabled when the cluster was initialized. See the
|
data checksums were enabled when the cluster was initialized. See the
|
||||||
<ulink url="https://www.postgresql.org/docs/current/static/app-pgrewind.html"><command>pg_rewind</command> documentation</ulink> for details.
|
<ulink url="https://www.postgresql.org/docs/current/static/app-pgrewind.html"><command>pg_rewind</command> documentation</ulink> for details.
|
||||||
</para>
|
</para>
|
||||||
|
|||||||
@@ -48,4 +48,11 @@
|
|||||||
</note>
|
</note>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
|
<refsect1>
|
||||||
|
<title>Event notifications</title>
|
||||||
|
<para>
|
||||||
|
A <literal>primary_register</literal> <link linkend="event-notifications">event notification</link> will be generated.
|
||||||
|
</para>
|
||||||
|
</refsect1>
|
||||||
|
|
||||||
</refentry>
|
</refentry>
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
<refsect1>
|
<refsect1>
|
||||||
<title>Description</title>
|
<title>Description</title>
|
||||||
<para>
|
<para>
|
||||||
<command>repmgr primary register</command> unregisters an inactive primary node
|
<command>repmgr primary unregister</command> unregisters an inactive primary node
|
||||||
from the &repmgr; metadata. This is typically when the primary has failed and is
|
from the &repmgr; metadata. This is typically when the primary has failed and is
|
||||||
being removed from the cluster after a new primary has been promoted.
|
being removed from the cluster after a new primary has been promoted.
|
||||||
</para>
|
</para>
|
||||||
@@ -28,7 +28,15 @@
|
|||||||
|
|
||||||
<para>
|
<para>
|
||||||
<command>repmgr master unregister</command> can be used as an alias for
|
<command>repmgr master unregister</command> can be used as an alias for
|
||||||
<command>repmgr primary unregister</command>/
|
<command>repmgr primary unregister</command>.
|
||||||
</para>
|
</para>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
|
<refsect1>
|
||||||
|
<title>Event notifications</title>
|
||||||
|
<para>
|
||||||
|
A <literal>primary_unregister</literal> <link linkend="event-notifications">event notification</link> will be generated.
|
||||||
|
</para>
|
||||||
|
</refsect1>
|
||||||
|
|
||||||
</refentry>
|
</refentry>
|
||||||
|
|||||||
@@ -99,5 +99,13 @@
|
|||||||
</simpara>
|
</simpara>
|
||||||
</note>
|
</note>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
|
<refsect1>
|
||||||
|
<title>Event notifications</title>
|
||||||
|
<para>
|
||||||
|
A <literal>standby_clone</literal> <link linkend="event-notifications">event notification</link> will be generated.
|
||||||
|
</para>
|
||||||
|
</refsect1>
|
||||||
|
|
||||||
</refentry>
|
</refentry>
|
||||||
|
|
||||||
|
|||||||
@@ -48,6 +48,13 @@
|
|||||||
</para>
|
</para>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
|
<refsect1>
|
||||||
|
<title>Event notifications</title>
|
||||||
|
<para>
|
||||||
|
A <literal>standby_follow</literal> <link linkend="event-notifications">event notification</link> will be generated.
|
||||||
|
</para>
|
||||||
|
</refsect1>
|
||||||
|
|
||||||
<refsect1>
|
<refsect1>
|
||||||
<title>See also</title>
|
<title>See also</title>
|
||||||
<para>
|
<para>
|
||||||
|
|||||||
@@ -41,4 +41,12 @@
|
|||||||
DETAIL: server "node2" (ID: 2) was successfully promoted to primary</programlisting>
|
DETAIL: server "node2" (ID: 2) was successfully promoted to primary</programlisting>
|
||||||
</para>
|
</para>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
|
<refsect1>
|
||||||
|
<title>Event notifications</title>
|
||||||
|
<para>
|
||||||
|
A <literal>standby_promote</literal> <link linkend="event-notifications">event notification</link> will be generated.
|
||||||
|
</para>
|
||||||
|
</refsect1>
|
||||||
|
|
||||||
</refentry>
|
</refentry>
|
||||||
|
|||||||
@@ -37,7 +37,24 @@
|
|||||||
</note>
|
</note>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
<refsect1 id="repmgr-standby-register-wait" xreflabel="repmgr standby register --wait">
|
<refsect1 id="repmgr-standby-register-wait-start" xreflabel="repmgr standby register --wait-start">
|
||||||
|
<title>Waiting for the the standby to start</title>
|
||||||
|
<para>
|
||||||
|
By default, &repmgr; will wait 30 seconds for the standby to become available before
|
||||||
|
aborting with a connection error. This is useful when setting up a standby from a script,
|
||||||
|
as the standby may not have fully started up by the time <command>repmgr standby register</command>
|
||||||
|
is executed.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
To change the timeout, pass the desired value with the <literal>--wait-start</literal> option.
|
||||||
|
A value of <literal>0</literal> will disable the timeout.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
The timeout will be ignored if <literal>-F/--force</literal> was provided.
|
||||||
|
</para>
|
||||||
|
</refsect1>
|
||||||
|
|
||||||
|
<refsect1 id="repmgr-standby-register-wait-sync" xreflabel="repmgr standby register --wait-sync">
|
||||||
<title>Waiting for the registration to propagate to the standby</title>
|
<title>Waiting for the registration to propagate to the standby</title>
|
||||||
<para>
|
<para>
|
||||||
Depending on your environment and workload, it may take some time for
|
Depending on your environment and workload, it may take some time for
|
||||||
@@ -74,4 +91,13 @@
|
|||||||
<literal>-F/--force</literal> option does not result in an incorrectly configured cluster.
|
<literal>-F/--force</literal> option does not result in an incorrectly configured cluster.
|
||||||
</para>
|
</para>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
|
<refsect1>
|
||||||
|
<title>Event notifications</title>
|
||||||
|
<para>
|
||||||
|
A <literal>standby_register</literal> <link linkend="event-notifications">event notification</link>
|
||||||
|
will be generated.
|
||||||
|
</para>
|
||||||
|
</refsect1>
|
||||||
|
|
||||||
</refentry>
|
</refentry>
|
||||||
|
|||||||
@@ -27,6 +27,71 @@
|
|||||||
</para>
|
</para>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
|
<refsect1>
|
||||||
|
<title>Options</title>
|
||||||
|
<variablelist>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>--always-promote</option></term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Promote standby to primary, even if it is behind original primary
|
||||||
|
(original primary will be shut down in any case).
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>--dry-run</option></term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Check prerequisites but don't actually execute a switchover.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>-F</option></term>
|
||||||
|
<term><option>--force</option></term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Ignore warnings and continue anyway.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>--force-rewind</option></term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Use <application>pg_rewind</application> to reintegrate the old primary if necessary
|
||||||
|
(PostgreSQL 9.5 and later).
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>-R</option></term>
|
||||||
|
<term><option>--remote-user</option></term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
System username for remote SSH operations (defaults to local system user).
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>--siblings-follow</option></term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Have standbys attached to the old primary follow the new primary.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
</variablelist>
|
||||||
|
|
||||||
|
</refsect1>
|
||||||
|
|
||||||
<refsect1>
|
<refsect1>
|
||||||
<title>Execution</title>
|
<title>Execution</title>
|
||||||
|
|
||||||
@@ -40,6 +105,21 @@
|
|||||||
</para>
|
</para>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
|
<refsect1>
|
||||||
|
<title>Event notifications</title>
|
||||||
|
<para>
|
||||||
|
<literal>standby_switchover</literal> and <literal>standby_promote</literal>
|
||||||
|
<link linkend="event-notifications">event notifications</link> will be generated for the new primary,
|
||||||
|
and a <literal>node_rejoin</literal> event notification for the former primary (new standby).
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
If using an event notification script, <literal>standby_switchover</literal>
|
||||||
|
will populate the placeholder parameter <literal>%p</literal> with the node ID of
|
||||||
|
the former standby.
|
||||||
|
</para>
|
||||||
|
</refsect1>
|
||||||
|
|
||||||
|
|
||||||
<refsect1>
|
<refsect1>
|
||||||
<title>See also</title>
|
<title>See also</title>
|
||||||
<para>
|
<para>
|
||||||
|
|||||||
@@ -42,5 +42,13 @@
|
|||||||
repmgr standby unregister -f /etc/repmgr.conf --node-id=3</programlisting>
|
repmgr standby unregister -f /etc/repmgr.conf --node-id=3</programlisting>
|
||||||
</para>
|
</para>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
|
<refsect1>
|
||||||
|
<title>Event notifications</title>
|
||||||
|
<para>
|
||||||
|
A <literal>standby_unregister</literal> <link linkend="event-notifications">event notification</link> will be generated.
|
||||||
|
</para>
|
||||||
|
</refsect1>
|
||||||
|
|
||||||
</refentry>
|
</refentry>
|
||||||
|
|
||||||
|
|||||||
@@ -49,4 +49,12 @@
|
|||||||
</para>
|
</para>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
|
|
||||||
|
<refsect1>
|
||||||
|
<title>Event notifications</title>
|
||||||
|
<para>
|
||||||
|
A <literal>witness_register</literal> <link linkend="event-notifications">event notification</link> will be generated.
|
||||||
|
</para>
|
||||||
|
</refsect1>
|
||||||
|
|
||||||
</refentry>
|
</refentry>
|
||||||
|
|||||||
@@ -41,7 +41,7 @@
|
|||||||
<para>
|
<para>
|
||||||
Unregistering a non-running witness node:
|
Unregistering a non-running witness node:
|
||||||
<programlisting>
|
<programlisting>
|
||||||
$ repmgr -f /etc/repmgr.conf witness unregister -h localhost -p 5501 -F
|
$ repmgr -f /etc/repmgr.conf witness unregister -h node1 -p 5501 -F
|
||||||
INFO: connecting to witness node "node3" (ID: 3)
|
INFO: connecting to witness node "node3" (ID: 3)
|
||||||
NOTICE: unable to connect to witness node "node3" (ID: 3), removing node record on cluster primary only
|
NOTICE: unable to connect to witness node "node3" (ID: 3), removing node record on cluster primary only
|
||||||
INFO: unregistering witness node 3
|
INFO: unregistering witness node 3
|
||||||
@@ -61,4 +61,13 @@
|
|||||||
<link linkend="repmgr-witness-register">repmgr witness register --force</link>.
|
<link linkend="repmgr-witness-register">repmgr witness register --force</link>.
|
||||||
</para>
|
</para>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
|
|
||||||
|
<refsect1>
|
||||||
|
<title>Event notifications</title>
|
||||||
|
<para>
|
||||||
|
A <literal>witness_unregister</literal> <link linkend="event-notifications">event notification</link> will be generated.
|
||||||
|
</para>
|
||||||
|
</refsect1>
|
||||||
|
|
||||||
</refentry>
|
</refentry>
|
||||||
|
|||||||
@@ -117,6 +117,7 @@
|
|||||||
&appendix-release-notes;
|
&appendix-release-notes;
|
||||||
&appendix-signatures;
|
&appendix-signatures;
|
||||||
&appendix-faq;
|
&appendix-faq;
|
||||||
|
&appendix-packages;
|
||||||
|
|
||||||
<![%include-index;[&bookindex;]]>
|
<![%include-index;[&bookindex;]]>
|
||||||
<![%include-xslt-index;[<index id="bookindex"></index>]]>
|
<![%include-xslt-index;[<index id="bookindex"></index>]]>
|
||||||
|
|||||||
@@ -54,45 +54,77 @@
|
|||||||
<secondary>preparation</secondary>
|
<secondary>preparation</secondary>
|
||||||
</indexterm>
|
</indexterm>
|
||||||
<title>Preparing for switchover</title>
|
<title>Preparing for switchover</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
As mentioned above, success of the switchover operation depends on &repmgr;
|
As mentioned in the previous section, success of the switchover operation depends on
|
||||||
being able to shut down the current primary server quickly and cleanly.
|
&repmgr; being able to shut down the current primary server quickly and cleanly.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Double-check which commands will be used to stop/start/restart the current
|
Double-check which commands will be used to stop/start/restart the current
|
||||||
primary; on the primary execute:
|
primary; on the primary execute:
|
||||||
<programlisting>
|
<programlisting>
|
||||||
repmgr -f /etc/repmgr.conf node service --list --action=stop
|
repmgr -f /etc/repmgr.conf node service --list --action=stop
|
||||||
repmgr -f /etc/repmgr.conf node service --list --action=start
|
repmgr -f /etc/repmgr.conf node service --list --action=start
|
||||||
repmgr -f /etc/repmgr.conf node service --list --action=restart
|
repmgr -f /etc/repmgr.conf node service --list --action=restart</programlisting>
|
||||||
</programlisting>
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
These commands can be defined in <filename>repmgr.conf</filename> with
|
||||||
|
<option>service_start_command</option>, <option>service_stop_command</option>
|
||||||
|
and <option>service_restart_command</option>.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<important>
|
||||||
|
<para>
|
||||||
|
If &repmgr; is installed from a package. you should set these commands
|
||||||
|
to use the appropriate service commands defined by the package/operating
|
||||||
|
system as these will ensure PostgreSQL is stopped/started properly
|
||||||
|
taking into account configuration and log file locations etc.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
If the <option>service_*_command</option> options aren't defined, &repmgr; will
|
||||||
|
fall back to using <application>pg_ctl</application> to stop/start/restart
|
||||||
|
PostgreSQL, which may not work properly.
|
||||||
|
</para>
|
||||||
|
</important>
|
||||||
|
|
||||||
<note>
|
<note>
|
||||||
<simpara>
|
<simpara>
|
||||||
On <literal>systemd</literal> systems we strongly recommend using the appropriate
|
On <literal>systemd</literal> systems we strongly recommend using the appropriate
|
||||||
<command>systemctl</command> commands (typically run via <command>sudo</command>) to ensure
|
<command>systemctl</command> commands (typically run via <command>sudo</command>) to ensure
|
||||||
<literal>systemd</literal> informed about the status of the PostgreSQL service.
|
<literal>systemd</literal> is informed about the status of the PostgreSQL service.
|
||||||
|
</simpara>
|
||||||
|
<simpara>
|
||||||
|
If using <command>sudo</command> for the <command>systemctl</command> calls, make sure the
|
||||||
|
<command>sudo</command> specification doesn't require a real tty for the user. If not set
|
||||||
|
this way, <command>repmgr</command> will fail to stop the primary.
|
||||||
</simpara>
|
</simpara>
|
||||||
</note>
|
</note>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Check that access from applications is minimalized or preferably blocked
|
Check that access from applications is minimalized or preferably blocked
|
||||||
completely, so applications are not unexpectedly interrupted.
|
completely, so applications are not unexpectedly interrupted.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Check there is no significant replication lag on standbys attached to the
|
Check there is no significant replication lag on standbys attached to the
|
||||||
current primary.
|
current primary.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
If WAL file archiving is set up, check that there is no backlog of files waiting
|
If WAL file archiving is set up, check that there is no backlog of files waiting
|
||||||
to be archived, as PostgreSQL will not finally shut down until all these have been
|
to be archived, as PostgreSQL will not finally shut down until all of these have been
|
||||||
archived. If there is a backlog exceeding <varname>archive_ready_warning</varname> WAL files,
|
archived. If there is a backlog exceeding <varname>archive_ready_warning</varname> WAL files,
|
||||||
&repmgr; will emit a warning before attempting to perform a switchover; you can also check
|
&repmgr; will emit a warning before attempting to perform a switchover; you can also check
|
||||||
manually with <command>repmgr node check --archive-ready</command>.
|
manually with <command>repmgr node check --archive-ready</command>.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Ensure that <application>repmgrd</application> is *not* running anywhere to prevent it unintentionally
|
Ensure that <application>repmgrd</application> is *not* running anywhere to prevent it unintentionally
|
||||||
promoting a node.
|
promoting a node.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Finally, consider executing <command>repmgr standby switchover</command> with the
|
Finally, consider executing <command>repmgr standby switchover</command> with the
|
||||||
<literal>--dry-run</literal> option; this will perform any necessary checks and inform you about
|
<literal>--dry-run</literal> option; this will perform any necessary checks and inform you about
|
||||||
@@ -101,7 +133,7 @@
|
|||||||
<programlisting>
|
<programlisting>
|
||||||
$ repmgr standby switchover -f /etc/repmgr.conf --siblings-follow --dry-run
|
$ repmgr standby switchover -f /etc/repmgr.conf --siblings-follow --dry-run
|
||||||
NOTICE: checking switchover on node "node2" (ID: 2) in --dry-run mode
|
NOTICE: checking switchover on node "node2" (ID: 2) in --dry-run mode
|
||||||
INFO: SSH connection to host "localhost" succeeded
|
INFO: SSH connection to host "node1" succeeded
|
||||||
INFO: archive mode is "off"
|
INFO: archive mode is "off"
|
||||||
INFO: replication lag on this standby is 0 seconds
|
INFO: replication lag on this standby is 0 seconds
|
||||||
INFO: all sibling nodes are reachable via SSH
|
INFO: all sibling nodes are reachable via SSH
|
||||||
@@ -110,6 +142,48 @@
|
|||||||
"pg_ctl -l /var/log/postgresql/startup.log -D '/var/lib/postgresql/data' -m fast -W stop"
|
"pg_ctl -l /var/log/postgresql/startup.log -D '/var/lib/postgresql/data' -m fast -W stop"
|
||||||
</programlisting>
|
</programlisting>
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
<important>
|
||||||
|
<para>
|
||||||
|
Be aware that <option>--dry-run</option> checks the prerequisites
|
||||||
|
for performing the switchover and some basic sanity checks on the
|
||||||
|
state of the database which might effect the switchover operation
|
||||||
|
(e.g. replication lag); it cannot however guarantee the switchover
|
||||||
|
operation will succeed. In particular, if the current primary
|
||||||
|
does not shut down cleanly, &repmgr; will not be able to reliably
|
||||||
|
execute the switchover (as there would be a danger of divergence
|
||||||
|
between the former and new primary nodes).
|
||||||
|
</para>
|
||||||
|
</important>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Note that following parameters in <filename>repmgr.conf</filename> are relevant to the
|
||||||
|
switchover operation:
|
||||||
|
<itemizedlist spacing="compact" mark="bullet">
|
||||||
|
<listitem>
|
||||||
|
<simpara>
|
||||||
|
<literal>reconnect_attempts</literal>: number of times to check the original primary
|
||||||
|
for a clean shutdown after executing the shutdown command, before aborting
|
||||||
|
</simpara>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<simpara>
|
||||||
|
<literal>reconnect_interval</literal>: interval (in seconds) to check the original
|
||||||
|
primary for a clean shutdown after executing the shutdown command (up to a maximum
|
||||||
|
of <literal>reconnect_attempts</literal> tries)
|
||||||
|
</simpara>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<simpara>
|
||||||
|
<literal>replication_lag_critical</literal>:
|
||||||
|
if replication lag (in seconds) on the standby exceeds this value, the
|
||||||
|
switchover will be aborted (unless the <literal>-F/--force</literal> option
|
||||||
|
is provided)
|
||||||
|
</simpara>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
</itemizedlist>
|
||||||
|
</para>
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
<sect1 id="switchover-execution" xreflabel="Executing the switchover command">
|
<sect1 id="switchover-execution" xreflabel="Executing the switchover command">
|
||||||
@@ -133,7 +207,7 @@
|
|||||||
INFO: searching for primary node
|
INFO: searching for primary node
|
||||||
INFO: checking if node 1 is primary
|
INFO: checking if node 1 is primary
|
||||||
INFO: current primary node is 1
|
INFO: current primary node is 1
|
||||||
INFO: SSH connection to host "localhost" succeeded
|
INFO: SSH connection to host "node1" succeeded
|
||||||
INFO: archive mode is "off"
|
INFO: archive mode is "off"
|
||||||
INFO: replication lag on this standby is 0 seconds
|
INFO: replication lag on this standby is 0 seconds
|
||||||
NOTICE: local node "node2" (ID: 2) will be promoted to primary; current primary "node1" (ID: 1) will be demoted to standby
|
NOTICE: local node "node2" (ID: 2) will be promoted to primary; current primary "node1" (ID: 1) will be demoted to standby
|
||||||
|
|||||||
@@ -45,7 +45,7 @@
|
|||||||
</listitem>
|
</listitem>
|
||||||
<listitem>
|
<listitem>
|
||||||
<simpara>
|
<simpara>
|
||||||
upgrading the repmgr schema
|
upgrading the repmgr schema using <command>CREATE EXTENSION</command>
|
||||||
</simpara>
|
</simpara>
|
||||||
</listitem>
|
</listitem>
|
||||||
</orderedlist>
|
</orderedlist>
|
||||||
@@ -58,11 +58,19 @@
|
|||||||
a packaged PostgreSQL extension) is normally carried out
|
a packaged PostgreSQL extension) is normally carried out
|
||||||
automatically when the &repmgr; extension is created.
|
automatically when the &repmgr; extension is created.
|
||||||
</para>
|
</para>
|
||||||
|
<para>
|
||||||
|
The shared library has been renamed from <literal>repmgr_funcs</literal> to
|
||||||
|
<literal>repmgr</literal> - if it's set in <varname>shared_preload_libraries</varname>
|
||||||
|
in <filename>postgresql.conf</filename> it will need to be updated to the new name:
|
||||||
|
<programlisting>
|
||||||
|
shared_preload_libraries = 'repmgr'</programlisting>
|
||||||
|
</para>
|
||||||
|
|
||||||
<sect2 id="converting-repmgr-conf">
|
<sect2 id="converting-repmgr-conf">
|
||||||
<title>Converting repmgr.conf configuration files</title>
|
<title>Converting repmgr.conf configuration files</title>
|
||||||
<para>
|
<para>
|
||||||
With a completely new repmgr version, we've taken the opportunity
|
With a completely new repmgr version, we've taken the opportunity
|
||||||
to rename some configuration items have had their names changed for
|
to rename some configuration items for
|
||||||
clarity and consistency, both between the configuration file and
|
clarity and consistency, both between the configuration file and
|
||||||
the column names in <structname>repmgr.nodes</structname>
|
the column names in <structname>repmgr.nodes</structname>
|
||||||
(e.g. <varname>node</varname> to <varname>node_id</varname>), and
|
(e.g. <varname>node</varname> to <varname>node_id</varname>), and
|
||||||
@@ -151,7 +159,7 @@
|
|||||||
be ignored.</simpara>
|
be ignored.</simpara>
|
||||||
</listitem>
|
</listitem>
|
||||||
<listitem>
|
<listitem>
|
||||||
<simpara><varname>upstream_node_id</varname>: is replaced by the
|
<simpara><varname>upstream_node</varname>: is replaced by the
|
||||||
command-line parameter <literal>--upstream-node-id</literal></simpara>
|
command-line parameter <literal>--upstream-node-id</literal></simpara>
|
||||||
</listitem>
|
</listitem>
|
||||||
</itemizedlist>
|
</itemizedlist>
|
||||||
@@ -167,7 +175,7 @@
|
|||||||
$ ./convert-config.pl /etc/repmgr.conf
|
$ ./convert-config.pl /etc/repmgr.conf
|
||||||
node_id=2
|
node_id=2
|
||||||
node_name=node2
|
node_name=node2
|
||||||
conninfo=host=localhost dbname=repmgr user=repmgr connect_timeout=2
|
conninfo=host=node2 dbname=repmgr user=repmgr connect_timeout=2
|
||||||
pg_ctl_options='-l /var/log/postgres/startup.log'
|
pg_ctl_options='-l /var/log/postgres/startup.log'
|
||||||
rsync_options=--exclude=postgresql.local.conf --archive
|
rsync_options=--exclude=postgresql.local.conf --archive
|
||||||
log_level=INFO
|
log_level=INFO
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
<!ENTITY repmgrversion "4.0.0">
|
<!ENTITY repmgrversion "4.0.2">
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* errcode.h
|
* errcode.h
|
||||||
* Copyright (c) 2ndQuadrant, 2010-2017
|
* Copyright (c) 2ndQuadrant, 2010-2018
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
2
log.c
2
log.c
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* log.c - Logging methods
|
* log.c - Logging methods
|
||||||
* Copyright (c) 2ndQuadrant, 2010-2017
|
* Copyright (c) 2ndQuadrant, 2010-2018
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
2
log.h
2
log.h
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* log.h
|
* log.h
|
||||||
* Copyright (c) 2ndQuadrant, 2010-2017
|
* Copyright (c) 2ndQuadrant, 2010-2018
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
@@ -91,9 +91,6 @@ CREATE RULE voting_term_delete AS
|
|||||||
ON DELETE TO repmgr.voting_term
|
ON DELETE TO repmgr.voting_term
|
||||||
DO INSTEAD NOTHING;
|
DO INSTEAD NOTHING;
|
||||||
|
|
||||||
/* XXX do this in "repmgr primary register" */
|
|
||||||
INSERT INTO repmgr.voting_term (term) VALUES (1);
|
|
||||||
|
|
||||||
|
|
||||||
/* ================= */
|
/* ================= */
|
||||||
/* repmgrd functions */
|
/* repmgrd functions */
|
||||||
|
|||||||
@@ -71,6 +71,17 @@ INSERT INTO repmgr.voting_term (term) VALUES (1);
|
|||||||
|
|
||||||
-- convert "repmgr_$cluster.repl_monitor" to "monitoring_history"
|
-- convert "repmgr_$cluster.repl_monitor" to "monitoring_history"
|
||||||
|
|
||||||
|
|
||||||
|
DO $repmgr$
|
||||||
|
DECLARE
|
||||||
|
DECLARE server_version_num INT;
|
||||||
|
BEGIN
|
||||||
|
SELECT setting
|
||||||
|
FROM pg_catalog.pg_settings
|
||||||
|
WHERE name = 'server_version_num'
|
||||||
|
INTO server_version_num;
|
||||||
|
IF server_version_num >= 90400 THEN
|
||||||
|
EXECUTE $repmgr_func$
|
||||||
CREATE TABLE repmgr.monitoring_history (
|
CREATE TABLE repmgr.monitoring_history (
|
||||||
primary_node_id INTEGER NOT NULL,
|
primary_node_id INTEGER NOT NULL,
|
||||||
standby_node_id INTEGER NOT NULL,
|
standby_node_id INTEGER NOT NULL,
|
||||||
@@ -80,12 +91,32 @@ CREATE TABLE repmgr.monitoring_history (
|
|||||||
last_wal_standby_location PG_LSN,
|
last_wal_standby_location PG_LSN,
|
||||||
replication_lag BIGINT NOT NULL,
|
replication_lag BIGINT NOT NULL,
|
||||||
apply_lag BIGINT NOT NULL
|
apply_lag BIGINT NOT NULL
|
||||||
);
|
)
|
||||||
|
$repmgr_func$;
|
||||||
INSERT INTO repmgr.monitoring_history
|
INSERT INTO repmgr.monitoring_history
|
||||||
(primary_node_id, standby_node_id, last_monitor_time, last_apply_time, last_wal_primary_location, last_wal_standby_location, replication_lag, apply_lag)
|
(primary_node_id, standby_node_id, last_monitor_time, last_apply_time, last_wal_primary_location, last_wal_standby_location, replication_lag, apply_lag)
|
||||||
SELECT primary_node, standby_node, last_monitor_time, last_apply_time, last_wal_primary_location::pg_lsn, last_wal_standby_location::pg_lsn, replication_lag, apply_lag
|
SELECT primary_node, standby_node, last_monitor_time, last_apply_time, last_wal_primary_location::pg_lsn, last_wal_standby_location::pg_lsn, replication_lag, apply_lag
|
||||||
FROM repmgr.repl_monitor;
|
FROM repmgr.repl_monitor;
|
||||||
|
ELSE
|
||||||
|
EXECUTE $repmgr_func$
|
||||||
|
CREATE TABLE repmgr.monitoring_history (
|
||||||
|
primary_node_id INTEGER NOT NULL,
|
||||||
|
standby_node_id INTEGER NOT NULL,
|
||||||
|
last_monitor_time TIMESTAMP WITH TIME ZONE NOT NULL,
|
||||||
|
last_apply_time TIMESTAMP WITH TIME ZONE,
|
||||||
|
last_wal_primary_location TEXT NOT NULL,
|
||||||
|
last_wal_standby_location TEXT,
|
||||||
|
replication_lag BIGINT NOT NULL,
|
||||||
|
apply_lag BIGINT NOT NULL
|
||||||
|
)
|
||||||
|
$repmgr_func$;
|
||||||
|
INSERT INTO repmgr.monitoring_history
|
||||||
|
(primary_node_id, standby_node_id, last_monitor_time, last_apply_time, last_wal_primary_location, last_wal_standby_location, replication_lag, apply_lag)
|
||||||
|
SELECT primary_node, standby_node, last_monitor_time, last_apply_time, last_wal_primary_location, last_wal_standby_location, replication_lag, apply_lag
|
||||||
|
FROM repmgr.repl_monitor;
|
||||||
|
|
||||||
|
END IF;
|
||||||
|
END$repmgr$;
|
||||||
|
|
||||||
CREATE INDEX idx_monitoring_history_time
|
CREATE INDEX idx_monitoring_history_time
|
||||||
ON repmgr.monitoring_history (last_monitor_time, standby_node_id);
|
ON repmgr.monitoring_history (last_monitor_time, standby_node_id);
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
/*
|
/*
|
||||||
* repmgr-action-standby.c
|
* repmgr-action-bdr.c
|
||||||
*
|
*
|
||||||
* Implements BDR-related actions for the repmgr command line utility
|
* Implements BDR-related actions for the repmgr command line utility
|
||||||
*
|
*
|
||||||
* Copyright (c) 2ndQuadrant, 2010-2017
|
* Copyright (c) 2ndQuadrant, 2010-2018
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -92,7 +92,39 @@ do_bdr_register(void)
|
|||||||
exit(ERR_BAD_CONFIG);
|
exit(ERR_BAD_CONFIG);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check whether repmgr extension exists, and that any other nodes are BDR */
|
/* check for a matching BDR node */
|
||||||
|
{
|
||||||
|
PQExpBufferData bdr_local_node_name;
|
||||||
|
bool node_match = false;
|
||||||
|
|
||||||
|
initPQExpBuffer(&bdr_local_node_name);
|
||||||
|
node_match = bdr_node_name_matches(conn, config_file_options.node_name, &bdr_local_node_name);
|
||||||
|
|
||||||
|
if (node_match == false)
|
||||||
|
{
|
||||||
|
if (strlen(bdr_local_node_name.data))
|
||||||
|
{
|
||||||
|
log_error(_("local node BDR node name is \"%s\", expected: \"%s\""),
|
||||||
|
bdr_local_node_name.data,
|
||||||
|
config_file_options.node_name);
|
||||||
|
log_hint(_("\"node_name\" in repmgr.conf must match \"node_name\" in bdr.bdr_nodes"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
log_error(_("local node does not report BDR node name"));
|
||||||
|
log_hint(_("ensure this is an active BDR node"));
|
||||||
|
}
|
||||||
|
|
||||||
|
PQfinish(conn);
|
||||||
|
pfree(dbname);
|
||||||
|
termPQExpBuffer(&bdr_local_node_name);
|
||||||
|
exit(ERR_BAD_CONFIG);
|
||||||
|
}
|
||||||
|
|
||||||
|
termPQExpBuffer(&bdr_local_node_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check whether repmgr extension exists, and there are no non-BDR nodes registered */
|
||||||
extension_status = get_repmgr_extension_status(conn);
|
extension_status = get_repmgr_extension_status(conn);
|
||||||
|
|
||||||
if (extension_status == REPMGR_UNKNOWN)
|
if (extension_status == REPMGR_UNKNOWN)
|
||||||
@@ -142,17 +174,9 @@ do_bdr_register(void)
|
|||||||
|
|
||||||
pfree(dbname);
|
pfree(dbname);
|
||||||
|
|
||||||
/* check for a matching BDR node */
|
if (bdr_node_has_repmgr_set(conn, config_file_options.node_name) == false)
|
||||||
{
|
{
|
||||||
bool node_exists = bdr_node_exists(conn, config_file_options.node_name);
|
bdr_node_set_repmgr_set(conn, config_file_options.node_name);
|
||||||
|
|
||||||
if (node_exists == false)
|
|
||||||
{
|
|
||||||
log_error(_("no BDR node with node_name \"%s\" found"), config_file_options.node_name);
|
|
||||||
log_hint(_("\"node_name\" in repmgr.conf must match \"node_name\" in bdr.bdr_nodes"));
|
|
||||||
PQfinish(conn);
|
|
||||||
exit(ERR_BAD_CONFIG);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* repmgr-action-bdr.h
|
* repmgr-action-bdr.h
|
||||||
* Copyright (c) 2ndQuadrant, 2010-2017
|
* Copyright (c) 2ndQuadrant, 2010-2018
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Implements cluster information actions for the repmgr command line utility
|
* Implements cluster information actions for the repmgr command line utility
|
||||||
*
|
*
|
||||||
* Copyright (c) 2ndQuadrant, 2010-2017
|
* Copyright (c) 2ndQuadrant, 2010-2018
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -436,82 +436,18 @@ void
|
|||||||
do_cluster_event(void)
|
do_cluster_event(void)
|
||||||
{
|
{
|
||||||
PGconn *conn = NULL;
|
PGconn *conn = NULL;
|
||||||
PQExpBufferData query;
|
|
||||||
PQExpBufferData where_clause;
|
|
||||||
PGresult *res;
|
PGresult *res;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
int column_count = EVENT_HEADER_COUNT;
|
||||||
|
|
||||||
conn = establish_db_connection(config_file_options.conninfo, true);
|
conn = establish_db_connection(config_file_options.conninfo, true);
|
||||||
|
|
||||||
initPQExpBuffer(&query);
|
res = get_event_records(conn,
|
||||||
initPQExpBuffer(&where_clause);
|
runtime_options.node_id,
|
||||||
|
runtime_options.node_name,
|
||||||
/* LEFT JOIN used here as a node record may have been removed */
|
runtime_options.event,
|
||||||
appendPQExpBuffer(
|
runtime_options.all,
|
||||||
&query,
|
|
||||||
" SELECT e.node_id, n.node_name, e.event, e.successful, \n"
|
|
||||||
" TO_CHAR(e.event_timestamp, 'YYYY-MM-DD HH24:MI:SS') AS timestamp, \n"
|
|
||||||
" e.details \n"
|
|
||||||
" FROM repmgr.events e \n"
|
|
||||||
"LEFT JOIN repmgr.nodes n ON e.node_id = n.node_id ");
|
|
||||||
|
|
||||||
if (runtime_options.node_id != UNKNOWN_NODE_ID)
|
|
||||||
{
|
|
||||||
|
|
||||||
append_where_clause(&where_clause,
|
|
||||||
"n.node_id=%i", runtime_options.node_id);
|
|
||||||
}
|
|
||||||
else if (runtime_options.node_name[0] != '\0')
|
|
||||||
{
|
|
||||||
char *escaped = escape_string(conn, runtime_options.node_name);
|
|
||||||
|
|
||||||
if (escaped == NULL)
|
|
||||||
{
|
|
||||||
log_error(_("unable to escape value provided for node name"));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
append_where_clause(&where_clause,
|
|
||||||
"n.node_name='%s'",
|
|
||||||
escaped);
|
|
||||||
pfree(escaped);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (runtime_options.event[0] != '\0')
|
|
||||||
{
|
|
||||||
char *escaped = escape_string(conn, runtime_options.event);
|
|
||||||
|
|
||||||
if (escaped == NULL)
|
|
||||||
{
|
|
||||||
log_error(_("unable to escape value provided for event"));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
append_where_clause(&where_clause,
|
|
||||||
"e.event='%s'",
|
|
||||||
escaped);
|
|
||||||
pfree(escaped);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
appendPQExpBuffer(&query, "\n%s\n",
|
|
||||||
where_clause.data);
|
|
||||||
|
|
||||||
appendPQExpBuffer(&query,
|
|
||||||
" ORDER BY e.event_timestamp DESC");
|
|
||||||
|
|
||||||
if (runtime_options.all == false && runtime_options.limit > 0)
|
|
||||||
{
|
|
||||||
appendPQExpBuffer(&query, " LIMIT %i",
|
|
||||||
runtime_options.limit);
|
runtime_options.limit);
|
||||||
}
|
|
||||||
|
|
||||||
log_debug("do_cluster_event():\n%s", query.data);
|
|
||||||
res = PQexec(conn, query.data);
|
|
||||||
|
|
||||||
termPQExpBuffer(&query);
|
|
||||||
termPQExpBuffer(&where_clause);
|
|
||||||
|
|
||||||
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
||||||
{
|
{
|
||||||
@@ -538,7 +474,11 @@ do_cluster_event(void)
|
|||||||
strncpy(headers_event[EV_TIMESTAMP].title, _("Timestamp"), MAXLEN);
|
strncpy(headers_event[EV_TIMESTAMP].title, _("Timestamp"), MAXLEN);
|
||||||
strncpy(headers_event[EV_DETAILS].title, _("Details"), MAXLEN);
|
strncpy(headers_event[EV_DETAILS].title, _("Details"), MAXLEN);
|
||||||
|
|
||||||
for (i = 0; i < EVENT_HEADER_COUNT; i++)
|
/* if --terse provided, simply omit the "Details" column */
|
||||||
|
if (runtime_options.terse == true)
|
||||||
|
column_count --;
|
||||||
|
|
||||||
|
for (i = 0; i < column_count; i++)
|
||||||
{
|
{
|
||||||
headers_event[i].max_length = strlen(headers_event[i].title);
|
headers_event[i].max_length = strlen(headers_event[i].title);
|
||||||
}
|
}
|
||||||
@@ -547,7 +487,7 @@ do_cluster_event(void)
|
|||||||
{
|
{
|
||||||
int j;
|
int j;
|
||||||
|
|
||||||
for (j = 0; j < EVENT_HEADER_COUNT; j++)
|
for (j = 0; j < column_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)
|
||||||
@@ -558,7 +498,7 @@ do_cluster_event(void)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < EVENT_HEADER_COUNT; i++)
|
for (i = 0; i < column_count; i++)
|
||||||
{
|
{
|
||||||
if (i == 0)
|
if (i == 0)
|
||||||
printf(" ");
|
printf(" ");
|
||||||
@@ -571,14 +511,14 @@ do_cluster_event(void)
|
|||||||
}
|
}
|
||||||
printf("\n");
|
printf("\n");
|
||||||
printf("-");
|
printf("-");
|
||||||
for (i = 0; i < EVENT_HEADER_COUNT; i++)
|
for (i = 0; i < column_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("-");
|
||||||
|
|
||||||
if (i < (EVENT_HEADER_COUNT - 1))
|
if (i < (column_count - 1))
|
||||||
printf("-+-");
|
printf("-+-");
|
||||||
else
|
else
|
||||||
printf("-");
|
printf("-");
|
||||||
@@ -591,13 +531,13 @@ do_cluster_event(void)
|
|||||||
int j;
|
int j;
|
||||||
|
|
||||||
printf(" ");
|
printf(" ");
|
||||||
for (j = 0; j < EVENT_HEADER_COUNT; j++)
|
for (j = 0; j < column_count; j++)
|
||||||
{
|
{
|
||||||
printf("%-*s",
|
printf("%-*s",
|
||||||
headers_event[j].max_length,
|
headers_event[j].max_length,
|
||||||
PQgetvalue(res, i, j));
|
PQgetvalue(res, i, j));
|
||||||
|
|
||||||
if (j < (EVENT_HEADER_COUNT - 1))
|
if (j < (column_count - 1))
|
||||||
printf(" | ");
|
printf(" | ");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* repmgr-action-cluster.h
|
* repmgr-action-cluster.h
|
||||||
* Copyright (c) 2ndQuadrant, 2010-2017
|
* Copyright (c) 2ndQuadrant, 2010-2018
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Implements actions available for any kind of node
|
* Implements actions available for any kind of node
|
||||||
*
|
*
|
||||||
* Copyright (c) 2ndQuadrant, 2010-2017
|
* Copyright (c) 2ndQuadrant, 2010-2018
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -496,16 +496,19 @@ _do_node_status_is_shutdown_cleanly(void)
|
|||||||
|
|
||||||
db_state = get_db_state(config_file_options.data_directory);
|
db_state = get_db_state(config_file_options.data_directory);
|
||||||
|
|
||||||
|
log_verbose(LOG_DEBUG, "db state now: %s", describe_db_state(db_state));
|
||||||
|
|
||||||
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
|
|
||||||
*/
|
|
||||||
if (node_status != NODE_STATUS_UP)
|
if (node_status != NODE_STATUS_UP)
|
||||||
{
|
{
|
||||||
node_status = NODE_STATUS_UNCLEAN_SHUTDOWN;
|
node_status = NODE_STATUS_UNCLEAN_SHUTDOWN;
|
||||||
}
|
}
|
||||||
|
/* server is still responding but shutting down */
|
||||||
|
else if (db_state == DB_SHUTDOWNING)
|
||||||
|
{
|
||||||
|
node_status = NODE_STATUS_SHUTTING_DOWN;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
checkPoint = get_latest_checkpoint_location(config_file_options.data_directory);
|
checkPoint = get_latest_checkpoint_location(config_file_options.data_directory);
|
||||||
@@ -525,19 +528,24 @@ _do_node_status_is_shutdown_cleanly(void)
|
|||||||
node_status = NODE_STATUS_DOWN;
|
node_status = NODE_STATUS_DOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log_verbose(LOG_DEBUG, "node status determined as: %s", print_node_status(node_status));
|
||||||
|
|
||||||
switch (node_status)
|
switch (node_status)
|
||||||
{
|
{
|
||||||
case NODE_STATUS_UP:
|
case NODE_STATUS_UP:
|
||||||
appendPQExpBuffer(&output, "RUNNING");
|
appendPQExpBuffer(&output, "RUNNING");
|
||||||
break;
|
break;
|
||||||
case NODE_STATUS_UNCLEAN_SHUTDOWN:
|
case NODE_STATUS_SHUTTING_DOWN:
|
||||||
appendPQExpBuffer(&output, "UNCLEAN_SHUTDOWN");
|
appendPQExpBuffer(&output, "SHUTTING_DOWN");
|
||||||
break;
|
break;
|
||||||
case NODE_STATUS_DOWN:
|
case NODE_STATUS_DOWN:
|
||||||
appendPQExpBuffer(&output,
|
appendPQExpBuffer(&output,
|
||||||
"SHUTDOWN --last-checkpoint-lsn=%X/%X",
|
"SHUTDOWN --last-checkpoint-lsn=%X/%X",
|
||||||
format_lsn(checkPoint));
|
format_lsn(checkPoint));
|
||||||
break;
|
break;
|
||||||
|
case NODE_STATUS_UNCLEAN_SHUTDOWN:
|
||||||
|
appendPQExpBuffer(&output, "UNCLEAN_SHUTDOWN");
|
||||||
|
break;
|
||||||
case NODE_STATUS_UNKNOWN:
|
case NODE_STATUS_UNKNOWN:
|
||||||
appendPQExpBuffer(&output, "UNKNOWN");
|
appendPQExpBuffer(&output, "UNKNOWN");
|
||||||
break;
|
break;
|
||||||
@@ -559,10 +567,20 @@ do_node_check(void)
|
|||||||
|
|
||||||
t_node_info node_info = T_NODE_INFO_INITIALIZER;
|
t_node_info node_info = T_NODE_INFO_INITIALIZER;
|
||||||
|
|
||||||
|
CheckStatus return_code;
|
||||||
CheckStatusList status_list = {NULL, NULL};
|
CheckStatusList status_list = {NULL, NULL};
|
||||||
CheckStatusListCell *cell = NULL;
|
CheckStatusListCell *cell = NULL;
|
||||||
|
|
||||||
|
|
||||||
|
/* internal */
|
||||||
|
if (runtime_options.has_passfile == true)
|
||||||
|
{
|
||||||
|
return_code = has_passfile() ? 0 : 1;
|
||||||
|
|
||||||
|
exit(return_code);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (strlen(config_file_options.conninfo))
|
if (strlen(config_file_options.conninfo))
|
||||||
conn = establish_db_connection(config_file_options.conninfo, true);
|
conn = establish_db_connection(config_file_options.conninfo, true);
|
||||||
else
|
else
|
||||||
@@ -585,38 +603,51 @@ do_node_check(void)
|
|||||||
*/
|
*/
|
||||||
if (runtime_options.archive_ready == true)
|
if (runtime_options.archive_ready == true)
|
||||||
{
|
{
|
||||||
(void) do_node_check_archive_ready(conn, runtime_options.output_mode, NULL);
|
return_code = do_node_check_archive_ready(conn,
|
||||||
|
runtime_options.output_mode,
|
||||||
|
NULL);
|
||||||
PQfinish(conn);
|
PQfinish(conn);
|
||||||
return;
|
exit(return_code);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (runtime_options.downstream == true)
|
if (runtime_options.downstream == true)
|
||||||
{
|
{
|
||||||
(void) do_node_check_downstream(conn, runtime_options.output_mode, NULL);
|
return_code = do_node_check_downstream(conn,
|
||||||
|
runtime_options.output_mode,
|
||||||
|
NULL);
|
||||||
PQfinish(conn);
|
PQfinish(conn);
|
||||||
return;
|
exit(return_code);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (runtime_options.replication_lag == true)
|
if (runtime_options.replication_lag == true)
|
||||||
{
|
{
|
||||||
(void) do_node_check_replication_lag(conn, runtime_options.output_mode, &node_info, NULL);
|
return_code = do_node_check_replication_lag(conn,
|
||||||
|
runtime_options.output_mode,
|
||||||
|
&node_info,
|
||||||
|
NULL);
|
||||||
PQfinish(conn);
|
PQfinish(conn);
|
||||||
return;
|
exit(return_code);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (runtime_options.role == true)
|
if (runtime_options.role == true)
|
||||||
{
|
{
|
||||||
(void) do_node_check_role(conn, runtime_options.output_mode, &node_info, NULL);
|
return_code = do_node_check_role(conn,
|
||||||
|
runtime_options.output_mode,
|
||||||
|
&node_info,
|
||||||
|
NULL);
|
||||||
PQfinish(conn);
|
PQfinish(conn);
|
||||||
return;
|
exit(return_code);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (runtime_options.slots == true)
|
if (runtime_options.slots == true)
|
||||||
{
|
{
|
||||||
(void) do_node_check_slots(conn, runtime_options.output_mode, &node_info, NULL);
|
return_code = do_node_check_slots(conn,
|
||||||
|
runtime_options.output_mode,
|
||||||
|
&node_info,
|
||||||
|
NULL);
|
||||||
PQfinish(conn);
|
PQfinish(conn);
|
||||||
return;
|
exit(return_code);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (runtime_options.output_mode == OM_NAGIOS)
|
if (runtime_options.output_mode == OM_NAGIOS)
|
||||||
@@ -705,8 +736,7 @@ do_node_check_role(PGconn *conn, OutputMode mode, t_node_info *node_info, CheckS
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
appendPQExpBuffer(
|
appendPQExpBuffer(&details,
|
||||||
&details,
|
|
||||||
_("node is primary"));
|
_("node is primary"));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -731,8 +761,7 @@ do_node_check_role(PGconn *conn, OutputMode mode, t_node_info *node_info, CheckS
|
|||||||
if (is_bdr_db(conn, &output) == false)
|
if (is_bdr_db(conn, &output) == false)
|
||||||
{
|
{
|
||||||
status = CHECK_STATUS_CRITICAL;
|
status = CHECK_STATUS_CRITICAL;
|
||||||
appendPQExpBuffer(
|
appendPQExpBuffer(&details,
|
||||||
&details,
|
|
||||||
"%s", output.data);
|
"%s", output.data);
|
||||||
}
|
}
|
||||||
termPQExpBuffer(&output);
|
termPQExpBuffer(&output);
|
||||||
@@ -745,6 +774,11 @@ do_node_check_role(PGconn *conn, OutputMode mode, t_node_info *node_info, CheckS
|
|||||||
appendPQExpBuffer(&details,
|
appendPQExpBuffer(&details,
|
||||||
_("node is not an active BDR node"));
|
_("node is not an active BDR node"));
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
appendPQExpBuffer(&details,
|
||||||
|
_("node is an active BDR node"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@@ -1533,13 +1567,11 @@ parse_server_action(const char *action_name)
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Intended mainly for "internal" use by "standby switchover", which
|
* Rejoin a dormant (shut down) node to the replication cluster; this
|
||||||
* calls this on the target server to excute pg_rewind on a demoted
|
* is typically a former primary which needs to be demoted to a standby.
|
||||||
* primary with a forked (sic) timeline. This function does not
|
|
||||||
* currently check whether this is a useful thing to do (however
|
|
||||||
* "standby switchover" will perform a check before calling it).
|
|
||||||
*
|
*
|
||||||
* TODO: make this into a more generally useful function.
|
* Note that "repmgr node rejoin" is also executed by
|
||||||
|
* "repmgr standby switchover" after promoting the new primary.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
do_node_rejoin(void)
|
do_node_rejoin(void)
|
||||||
@@ -1591,6 +1623,12 @@ do_node_rejoin(void)
|
|||||||
|
|
||||||
/* check if cleanly shut down */
|
/* check if cleanly shut down */
|
||||||
if (db_state != DB_SHUTDOWNED && db_state != DB_SHUTDOWNED_IN_RECOVERY)
|
if (db_state != DB_SHUTDOWNED && db_state != DB_SHUTDOWNED_IN_RECOVERY)
|
||||||
|
{
|
||||||
|
if (db_state == DB_SHUTDOWNING)
|
||||||
|
{
|
||||||
|
log_error(_("database is still shutting down"));
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
log_error(_("database is not shut down cleanly"));
|
log_error(_("database is not shut down cleanly"));
|
||||||
|
|
||||||
@@ -1598,15 +1636,16 @@ do_node_rejoin(void)
|
|||||||
{
|
{
|
||||||
log_detail(_("pg_rewind will not be able to run"));
|
log_detail(_("pg_rewind will not be able to run"));
|
||||||
}
|
}
|
||||||
log_hint(_("database should be restarted and shut down cleanly after crash recovery completes"));
|
log_hint(_("database should be restarted then shut down cleanly after crash recovery completes"));
|
||||||
exit(ERR_BAD_CONFIG);
|
exit(ERR_BAD_CONFIG);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* check provided upstream connection */
|
/* check provided upstream connection */
|
||||||
upstream_conn = establish_db_connection_by_params(&source_conninfo, true);
|
upstream_conn = establish_db_connection_by_params(&source_conninfo, true);
|
||||||
|
|
||||||
/* sanity-checks for 9.3 */
|
/* sanity checks for 9.3 */
|
||||||
server_version_num = get_server_version(upstream_conn, NULL);
|
server_version_num = get_server_version(upstream_conn, NULL);
|
||||||
|
|
||||||
if (server_version_num < 90400)
|
if (server_version_num < 90400)
|
||||||
@@ -1615,7 +1654,9 @@ do_node_rejoin(void)
|
|||||||
if (get_primary_node_record(upstream_conn, &primary_node_record) == false)
|
if (get_primary_node_record(upstream_conn, &primary_node_record) == false)
|
||||||
{
|
{
|
||||||
log_error(_("unable to retrieve primary node record"));
|
log_error(_("unable to retrieve primary node record"));
|
||||||
|
log_hint(_("check the provided database connection string is for a \"repmgr\" database"));
|
||||||
PQfinish(upstream_conn);
|
PQfinish(upstream_conn);
|
||||||
|
exit(ERR_BAD_CONFIG);
|
||||||
}
|
}
|
||||||
|
|
||||||
PQfinish(upstream_conn);
|
PQfinish(upstream_conn);
|
||||||
@@ -1755,19 +1796,72 @@ do_node_rejoin(void)
|
|||||||
log_detail("%s", strerror(errno));
|
log_detail("%s", strerror(errno));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
termPQExpBuffer(&filebuf);
|
termPQExpBuffer(&filebuf);
|
||||||
|
|
||||||
|
/* delete any replication slots copied in by pg_rewind */
|
||||||
|
{
|
||||||
|
PQExpBufferData slotdir_path;
|
||||||
|
DIR *slotdir;
|
||||||
|
struct dirent *slotdir_ent;
|
||||||
|
|
||||||
|
initPQExpBuffer(&slotdir_path);
|
||||||
|
|
||||||
|
appendPQExpBuffer(&slotdir_path,
|
||||||
|
"%s/pg_replslot",
|
||||||
|
config_file_options.data_directory);
|
||||||
|
|
||||||
|
slotdir = opendir(slotdir_path.data);
|
||||||
|
|
||||||
|
if (slotdir == NULL)
|
||||||
|
{
|
||||||
|
log_warning(_("unable to open replication slot directory \"%s\""),
|
||||||
|
slotdir_path.data);
|
||||||
|
log_detail("%s", strerror(errno));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while ((slotdir_ent = readdir(slotdir)) != NULL) {
|
||||||
|
struct stat statbuf;
|
||||||
|
PQExpBufferData slotdir_ent_path;
|
||||||
|
|
||||||
|
if(strcmp(slotdir_ent->d_name, ".") == 0 || strcmp(slotdir_ent->d_name, "..") == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
initPQExpBuffer(&slotdir_ent_path);
|
||||||
|
|
||||||
|
appendPQExpBuffer(&slotdir_ent_path,
|
||||||
|
"%s/%s",
|
||||||
|
slotdir_path.data,
|
||||||
|
slotdir_ent->d_name);
|
||||||
|
|
||||||
|
if (stat(slotdir_ent_path.data, &statbuf) == 0 && !S_ISDIR(statbuf.st_mode))
|
||||||
|
{
|
||||||
|
termPQExpBuffer(&slotdir_ent_path);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_debug("deleting slot directory \"%s\"", slotdir_ent_path.data);
|
||||||
|
if (rmdir_recursive(slotdir_ent_path.data) != 0 && errno != EEXIST)
|
||||||
|
{
|
||||||
|
log_warning(_("unable to delete replication slot directory \"%s\""), slotdir_ent_path.data);
|
||||||
|
log_detail("%s", strerror(errno));
|
||||||
|
log_hint(_("directory may need to be manually removed"));
|
||||||
|
}
|
||||||
|
|
||||||
|
termPQExpBuffer(&slotdir_ent_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
termPQExpBuffer(&slotdir_path);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
initPQExpBuffer(&follow_output);
|
initPQExpBuffer(&follow_output);
|
||||||
|
|
||||||
success = do_standby_follow_internal(
|
success = do_standby_follow_internal(upstream_conn,
|
||||||
upstream_conn,
|
|
||||||
&primary_node_record,
|
&primary_node_record,
|
||||||
&follow_output);
|
&follow_output);
|
||||||
|
|
||||||
create_event_notification(
|
create_event_notification(upstream_conn,
|
||||||
upstream_conn,
|
|
||||||
&config_file_options,
|
&config_file_options,
|
||||||
config_file_options.node_id,
|
config_file_options.node_id,
|
||||||
"node_rejoin",
|
"node_rejoin",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* repmgr-action-node.h
|
* repmgr-action-node.h
|
||||||
* Copyright (c) 2ndQuadrant, 2010-2017
|
* Copyright (c) 2ndQuadrant, 2010-2018
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -22,7 +22,6 @@
|
|||||||
extern void do_node_status(void);
|
extern void do_node_status(void);
|
||||||
extern void do_node_check(void);
|
extern void do_node_check(void);
|
||||||
|
|
||||||
|
|
||||||
extern void do_node_rejoin(void);
|
extern void do_node_rejoin(void);
|
||||||
extern void do_node_service(void);
|
extern void do_node_service(void);
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Implements primary actions for the repmgr command line utility
|
* Implements primary actions for the repmgr command line utility
|
||||||
*
|
*
|
||||||
* Copyright (c) 2ndQuadrant, 2010-2017
|
* Copyright (c) 2ndQuadrant, 2010-2018
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -74,7 +74,11 @@ do_primary_register(void)
|
|||||||
|
|
||||||
log_verbose(LOG_INFO, _("server is not in recovery"));
|
log_verbose(LOG_INFO, _("server is not in recovery"));
|
||||||
|
|
||||||
/* create the repmgr extension if it doesn't already exist */
|
/*
|
||||||
|
* create the repmgr extension if it doesn't already exist;
|
||||||
|
* note that create_repmgr_extension() will take into account
|
||||||
|
* the --dry-run option
|
||||||
|
*/
|
||||||
if (!create_repmgr_extension(conn))
|
if (!create_repmgr_extension(conn))
|
||||||
{
|
{
|
||||||
PQfinish(conn);
|
PQfinish(conn);
|
||||||
@@ -92,6 +96,7 @@ do_primary_register(void)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
initialize_voting_term(conn);
|
||||||
|
|
||||||
/* Ensure there isn't another registered node which is primary */
|
/* Ensure there isn't another registered node which is primary */
|
||||||
primary_conn = get_primary_connection(conn, ¤t_primary_id, NULL);
|
primary_conn = get_primary_connection(conn, ¤t_primary_id, NULL);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* repmgr-action-primary.h
|
* repmgr-action-primary.h
|
||||||
* Copyright (c) 2ndQuadrant, 2010-2017
|
* Copyright (c) 2ndQuadrant, 2010-2018
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Implements standby actions for the repmgr command line utility
|
* Implements standby actions for the repmgr command line utility
|
||||||
*
|
*
|
||||||
* Copyright (c) 2ndQuadrant, 2010-2017
|
* Copyright (c) 2ndQuadrant, 2010-2018
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -99,7 +99,8 @@ static bool create_recovery_file(t_node_info *node_record, t_conninfo_param_list
|
|||||||
static void write_primary_conninfo(char *line, t_conninfo_param_list *param_list);
|
static void write_primary_conninfo(char *line, t_conninfo_param_list *param_list);
|
||||||
static bool write_recovery_file_line(FILE *recovery_file, char *recovery_file_path, char *line);
|
static bool write_recovery_file_line(FILE *recovery_file, char *recovery_file_path, char *line);
|
||||||
|
|
||||||
|
static int parse_output_to_argv(const char *string, char ***argv_array);
|
||||||
|
static void free_parsed_argv(char ***argv_array);
|
||||||
static NodeStatus parse_node_status_is_shutdown_cleanly(const char *node_status_output, XLogRecPtr *checkPoint);
|
static NodeStatus parse_node_status_is_shutdown_cleanly(const char *node_status_output, XLogRecPtr *checkPoint);
|
||||||
static CheckStatus parse_node_check_archiver(const char *node_check_output, int *files, int *threshold);
|
static CheckStatus parse_node_check_archiver(const char *node_check_output, int *files, int *threshold);
|
||||||
|
|
||||||
@@ -359,7 +360,7 @@ do_standby_clone(void)
|
|||||||
* If copying of external configuration files requested, and any are
|
* If copying of external configuration files requested, and any are
|
||||||
* detected, perform sanity checks
|
* detected, perform sanity checks
|
||||||
*/
|
*/
|
||||||
if (PQstatus(source_conn) == CONNECTION_OK)
|
if (PQstatus(source_conn) == CONNECTION_OK && runtime_options.copy_external_config_files == true)
|
||||||
{
|
{
|
||||||
PGconn *superuser_conn = NULL;
|
PGconn *superuser_conn = NULL;
|
||||||
PGconn *privileged_conn = NULL;
|
PGconn *privileged_conn = NULL;
|
||||||
@@ -549,7 +550,7 @@ do_standby_clone(void)
|
|||||||
* This won't run in Barman mode as "config_files" is only populated in
|
* This won't run in Barman mode as "config_files" is only populated in
|
||||||
* "initialise_direct_clone()", which isn't called in Barman mode.
|
* "initialise_direct_clone()", which isn't called in Barman mode.
|
||||||
*/
|
*/
|
||||||
if (runtime_options.copy_external_config_files && config_files.entries)
|
if (runtime_options.copy_external_config_files == true && config_files.entries > 0)
|
||||||
{
|
{
|
||||||
copy_configuration_files();
|
copy_configuration_files();
|
||||||
}
|
}
|
||||||
@@ -783,9 +784,52 @@ do_standby_register(void)
|
|||||||
|
|
||||||
conn = establish_db_connection_quiet(config_file_options.conninfo);
|
conn = establish_db_connection_quiet(config_file_options.conninfo);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* if --force provided, don't wait for the node to start, as the
|
||||||
|
* normal use case will be re-registering an existing node, or
|
||||||
|
* registering an inactive/not-yet-extant one; we'll do the
|
||||||
|
* error handling for those cases in the next code block
|
||||||
|
*/
|
||||||
|
if (PQstatus(conn) != CONNECTION_OK && runtime_options.force == false)
|
||||||
|
{
|
||||||
|
bool conn_ok = false;
|
||||||
|
int timer = 0;
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
if (timer == runtime_options.wait_start)
|
||||||
|
break;
|
||||||
|
|
||||||
|
sleep(1);
|
||||||
|
|
||||||
|
log_verbose(LOG_INFO, _("%i of %i connection attempts"),
|
||||||
|
timer + 1,
|
||||||
|
runtime_options.wait_start);
|
||||||
|
|
||||||
|
conn = establish_db_connection_quiet(config_file_options.conninfo);
|
||||||
|
|
||||||
|
if (PQstatus(conn) == CONNECTION_OK)
|
||||||
|
{
|
||||||
|
conn_ok = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
timer++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (conn_ok == true)
|
||||||
|
{
|
||||||
|
log_info(_("connected to local node \"%s\" (ID: %i) after %i seconds"),
|
||||||
|
config_file_options.node_name,
|
||||||
|
config_file_options.node_id,
|
||||||
|
timer);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
if (PQstatus(conn) != CONNECTION_OK)
|
if (PQstatus(conn) != CONNECTION_OK)
|
||||||
{
|
{
|
||||||
if (!runtime_options.force)
|
if (runtime_options.force == false)
|
||||||
{
|
{
|
||||||
log_error(_("unable to connect to local node \"%s\" (ID: %i)"),
|
log_error(_("unable to connect to local node \"%s\" (ID: %i)"),
|
||||||
config_file_options.node_name,
|
config_file_options.node_name,
|
||||||
@@ -797,7 +841,7 @@ do_standby_register(void)
|
|||||||
exit(ERR_BAD_CONFIG);
|
exit(ERR_BAD_CONFIG);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!runtime_options.connection_param_provided)
|
if (runtime_options.connection_param_provided == false)
|
||||||
{
|
{
|
||||||
log_error(_("unable to connect to local node \"%s\" (ID: %i) and no primary connection parameters provided"),
|
log_error(_("unable to connect to local node \"%s\" (ID: %i) and no primary connection parameters provided"),
|
||||||
config_file_options.node_name,
|
config_file_options.node_name,
|
||||||
@@ -821,8 +865,8 @@ do_standby_register(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* User is forcing a registration and must have supplied primary
|
* otherwise user is forcing a registration of a (potentially) inactive (or
|
||||||
* connection info
|
* not-yet-extant) node and must have supplied primary connection info
|
||||||
*/
|
*/
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -1731,6 +1775,26 @@ do_standby_follow_internal(PGconn *primary_conn, t_node_info *primary_node_recor
|
|||||||
{
|
{
|
||||||
int primary_server_version_num = get_server_version(primary_conn, NULL);
|
int primary_server_version_num = get_server_version(primary_conn, NULL);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Here we add a sanity check for the "slot_name" field - it's possible
|
||||||
|
* the node was initially registered with "use_replication_slots=false"
|
||||||
|
* but the configuration was subsequently changed, leaving the field NULL.
|
||||||
|
*
|
||||||
|
* To avoid annoying failures we can just update the node record and proceed.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!strlen(local_node_record.slot_name))
|
||||||
|
{
|
||||||
|
create_slot_name(local_node_record.slot_name, config_file_options.node_id);
|
||||||
|
|
||||||
|
log_notice(_("setting node %i's slot name to \"%s\""),
|
||||||
|
config_file_options.node_id,
|
||||||
|
local_node_record.slot_name);
|
||||||
|
|
||||||
|
update_node_record_slot_name(primary_conn, config_file_options.node_id, local_node_record.slot_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (create_replication_slot(primary_conn,
|
if (create_replication_slot(primary_conn,
|
||||||
local_node_record.slot_name,
|
local_node_record.slot_name,
|
||||||
primary_server_version_num,
|
primary_server_version_num,
|
||||||
@@ -1823,7 +1887,7 @@ do_standby_follow_internal(PGconn *primary_conn, t_node_info *primary_node_recor
|
|||||||
/* Set the replication user from the primary node record */
|
/* Set the replication user from the primary node record */
|
||||||
param_set(&recovery_conninfo, "user", primary_node_record->repluser);
|
param_set(&recovery_conninfo, "user", primary_node_record->repluser);
|
||||||
|
|
||||||
log_info(_("setting node %i's primary to node %i"),
|
log_notice(_("setting node %i's primary to node %i"),
|
||||||
config_file_options.node_id, primary_node_record->node_id);
|
config_file_options.node_id, primary_node_record->node_id);
|
||||||
|
|
||||||
if (!create_recovery_file(&local_node_record, &recovery_conninfo, config_file_options.data_directory))
|
if (!create_recovery_file(&local_node_record, &recovery_conninfo, config_file_options.data_directory))
|
||||||
@@ -1927,14 +1991,11 @@ do_standby_follow_internal(PGconn *primary_conn, t_node_info *primary_node_recor
|
|||||||
* - promoting this standby node to primary
|
* - promoting this standby node to primary
|
||||||
* - forcing previous primary node to follow this node
|
* - forcing previous primary node to follow this node
|
||||||
*
|
*
|
||||||
* Caveats:
|
* Caveat:
|
||||||
* - repmgrd must not be running, otherwise it may
|
* - repmgrd must not be running, otherwise it may
|
||||||
* attempt a failover
|
* attempt a failover
|
||||||
* (TODO: find some way of notifying repmgrd of planned
|
* (TODO: find some way of notifying repmgrd of planned
|
||||||
* activity like this)
|
* activity like this)
|
||||||
* - currently only set up for two-node operation; any other
|
|
||||||
* standbys will probably become downstream cascaded standbys
|
|
||||||
* of the old primary once it's restarted
|
|
||||||
*
|
*
|
||||||
* TODO:
|
* TODO:
|
||||||
* - make connection test timeouts/intervals configurable (see below)
|
* - make connection test timeouts/intervals configurable (see below)
|
||||||
@@ -1975,6 +2036,8 @@ do_standby_switchover(void)
|
|||||||
NodeInfoList sibling_nodes = T_NODE_INFO_LIST_INITIALIZER;
|
NodeInfoList sibling_nodes = T_NODE_INFO_LIST_INITIALIZER;
|
||||||
int unreachable_sibling_node_count = 0;
|
int unreachable_sibling_node_count = 0;
|
||||||
|
|
||||||
|
t_event_info event_info = T_EVENT_INFO_INITIALIZER;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SANITY CHECKS
|
* SANITY CHECKS
|
||||||
*
|
*
|
||||||
@@ -2073,6 +2136,8 @@ do_standby_switchover(void)
|
|||||||
|
|
||||||
log_verbose(LOG_DEBUG, "remote node name is \"%s\"", remote_node_record.node_name);
|
log_verbose(LOG_DEBUG, "remote node name is \"%s\"", remote_node_record.node_name);
|
||||||
|
|
||||||
|
/* this will fill the %p event notification parameter */
|
||||||
|
event_info.former_primary_id = remote_node_record.node_id;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If --force-rewind specified, check pg_rewind can be used, and
|
* If --force-rewind specified, check pg_rewind can be used, and
|
||||||
@@ -2603,6 +2668,7 @@ do_standby_switchover(void)
|
|||||||
i + 1, config_file_options.reconnect_attempts);
|
i + 1, config_file_options.reconnect_attempts);
|
||||||
ping_res = PQping(remote_conninfo);
|
ping_res = PQping(remote_conninfo);
|
||||||
|
|
||||||
|
log_debug("ping status is: %s", print_pqping_status(ping_res));
|
||||||
|
|
||||||
/* database server could not be contacted */
|
/* database server could not be contacted */
|
||||||
if (ping_res == PQPING_NO_RESPONSE || ping_res == PQPING_NO_ATTEMPT)
|
if (ping_res == PQPING_NO_RESPONSE || ping_res == PQPING_NO_ATTEMPT)
|
||||||
@@ -2623,8 +2689,7 @@ do_standby_switchover(void)
|
|||||||
|
|
||||||
initPQExpBuffer(&command_output);
|
initPQExpBuffer(&command_output);
|
||||||
|
|
||||||
command_success = remote_command(
|
command_success = remote_command(remote_host,
|
||||||
remote_host,
|
|
||||||
runtime_options.remote_user,
|
runtime_options.remote_user,
|
||||||
remote_command_str.data,
|
remote_command_str.data,
|
||||||
&command_output);
|
&command_output);
|
||||||
@@ -2635,6 +2700,8 @@ do_standby_switchover(void)
|
|||||||
{
|
{
|
||||||
NodeStatus status = parse_node_status_is_shutdown_cleanly(command_output.data, &remote_last_checkpoint_lsn);
|
NodeStatus status = parse_node_status_is_shutdown_cleanly(command_output.data, &remote_last_checkpoint_lsn);
|
||||||
|
|
||||||
|
log_verbose(LOG_DEBUG, "remote node status is: %s", print_node_status(status));
|
||||||
|
|
||||||
if (status == NODE_STATUS_DOWN && remote_last_checkpoint_lsn != InvalidXLogRecPtr)
|
if (status == NODE_STATUS_DOWN && remote_last_checkpoint_lsn != InvalidXLogRecPtr)
|
||||||
{
|
{
|
||||||
shutdown_success = true;
|
shutdown_success = true;
|
||||||
@@ -2644,11 +2711,30 @@ do_standby_switchover(void)
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
/* remote node did not shut down cleanly */
|
||||||
|
else if (status == NODE_STATUS_UNCLEAN_SHUTDOWN)
|
||||||
|
{
|
||||||
|
if (!runtime_options.force)
|
||||||
|
{
|
||||||
|
log_error(_("current primary did not shut down cleanly, aborting"));
|
||||||
|
log_hint(_("use -F/--force to promote current standby"));
|
||||||
|
termPQExpBuffer(&command_output);
|
||||||
|
exit(ERR_SWITCHOVER_FAIL);
|
||||||
|
}
|
||||||
|
log_error(_("current primary did not shut down cleanly, continuing anyway"));
|
||||||
|
shutdown_success = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (status == NODE_STATUS_SHUTTING_DOWN)
|
||||||
|
{
|
||||||
|
log_info(_("remote node is still shutting down"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
termPQExpBuffer(&command_output);
|
termPQExpBuffer(&command_output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log_debug("sleeping %i seconds until next check", config_file_options.reconnect_interval);
|
||||||
sleep(config_file_options.reconnect_interval);
|
sleep(config_file_options.reconnect_interval);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2662,7 +2748,7 @@ do_standby_switchover(void)
|
|||||||
/* this is unlikely to happen, but check and handle gracefully anyway */
|
/* this is unlikely to happen, but check and handle gracefully anyway */
|
||||||
if (PQstatus(local_conn) != CONNECTION_OK)
|
if (PQstatus(local_conn) != CONNECTION_OK)
|
||||||
{
|
{
|
||||||
log_warning(_("connection to local node lost, reconnecting.."));
|
log_warning(_("connection to local node lost, reconnecting..."));
|
||||||
local_conn = establish_db_connection(config_file_options.conninfo, false);
|
local_conn = establish_db_connection(config_file_options.conninfo, false);
|
||||||
|
|
||||||
if (PQstatus(local_conn) != CONNECTION_OK)
|
if (PQstatus(local_conn) != CONNECTION_OK)
|
||||||
@@ -2749,8 +2835,7 @@ do_standby_switchover(void)
|
|||||||
log_debug("executing:\n %s", remote_command_str.data);
|
log_debug("executing:\n %s", remote_command_str.data);
|
||||||
initPQExpBuffer(&command_output);
|
initPQExpBuffer(&command_output);
|
||||||
|
|
||||||
command_success = remote_command(
|
command_success = remote_command(remote_host,
|
||||||
remote_host,
|
|
||||||
runtime_options.remote_user,
|
runtime_options.remote_user,
|
||||||
remote_command_str.data,
|
remote_command_str.data,
|
||||||
&command_output);
|
&command_output);
|
||||||
@@ -2766,21 +2851,33 @@ do_standby_switchover(void)
|
|||||||
if (strlen(command_output.data) > 2)
|
if (strlen(command_output.data) > 2)
|
||||||
log_detail("%s", command_output.data);
|
log_detail("%s", command_output.data);
|
||||||
|
|
||||||
create_event_record(local_conn,
|
create_event_notification_extended(local_conn,
|
||||||
&config_file_options,
|
&config_file_options,
|
||||||
config_file_options.node_id,
|
config_file_options.node_id,
|
||||||
"standby_switchover",
|
"standby_switchover",
|
||||||
false,
|
false,
|
||||||
command_output.data);
|
command_output.data,
|
||||||
|
&event_info);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
create_event_record(local_conn,
|
PQExpBufferData event_details;
|
||||||
|
|
||||||
|
initPQExpBuffer(&event_details);
|
||||||
|
|
||||||
|
appendPQExpBuffer(&event_details,
|
||||||
|
"node %i promoted to primary, node %i demoted to standby",
|
||||||
|
config_file_options.node_id,
|
||||||
|
remote_node_record.node_id);
|
||||||
|
|
||||||
|
create_event_notification_extended(local_conn,
|
||||||
&config_file_options,
|
&config_file_options,
|
||||||
config_file_options.node_id,
|
config_file_options.node_id,
|
||||||
"standby_switchover",
|
"standby_switchover",
|
||||||
true,
|
true,
|
||||||
NULL);
|
event_details.data,
|
||||||
|
&event_info);
|
||||||
|
termPQExpBuffer(&event_details);
|
||||||
}
|
}
|
||||||
|
|
||||||
termPQExpBuffer(&command_output);
|
termPQExpBuffer(&command_output);
|
||||||
@@ -2850,8 +2947,7 @@ do_standby_switchover(void)
|
|||||||
|
|
||||||
initPQExpBuffer(&command_output);
|
initPQExpBuffer(&command_output);
|
||||||
|
|
||||||
success = remote_command(
|
success = remote_command(host,
|
||||||
host,
|
|
||||||
runtime_options.remote_user,
|
runtime_options.remote_user,
|
||||||
remote_command_str.data,
|
remote_command_str.data,
|
||||||
&command_output);
|
&command_output);
|
||||||
@@ -3680,8 +3776,7 @@ initialise_direct_clone(t_node_info *node_record)
|
|||||||
{
|
{
|
||||||
log_error("%s", event_details.data);
|
log_error("%s", event_details.data);
|
||||||
|
|
||||||
create_event_notification(
|
create_event_notification(primary_conn,
|
||||||
primary_conn,
|
|
||||||
&config_file_options,
|
&config_file_options,
|
||||||
config_file_options.node_id,
|
config_file_options.node_id,
|
||||||
"standby_clone",
|
"standby_clone",
|
||||||
@@ -4989,32 +5084,18 @@ write_primary_conninfo(char *line, t_conninfo_param_list *param_list)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* TODO: consolidate code in below functions */
|
|
||||||
static NodeStatus
|
static NodeStatus
|
||||||
parse_node_status_is_shutdown_cleanly(const char *node_status_output, XLogRecPtr *checkPoint)
|
parse_node_status_is_shutdown_cleanly(const char *node_status_output, XLogRecPtr *checkPoint)
|
||||||
{
|
{
|
||||||
int options_len = 0;
|
|
||||||
char *options_string = NULL;
|
|
||||||
char *options_string_ptr = NULL;
|
|
||||||
NodeStatus node_status = NODE_STATUS_UNKNOWN;
|
NodeStatus node_status = NODE_STATUS_UNKNOWN;
|
||||||
|
|
||||||
/*
|
int c = 0,
|
||||||
* Add parsed options to this list, then copy to an array to pass to
|
argc_item = 0;
|
||||||
* getopt
|
char **argv_array = NULL;
|
||||||
*/
|
|
||||||
static ItemList option_argv = {NULL, NULL};
|
|
||||||
|
|
||||||
char *argv_item;
|
|
||||||
int c,
|
|
||||||
argc_item = 1;
|
|
||||||
|
|
||||||
char **argv_array;
|
|
||||||
ItemListCell *cell;
|
|
||||||
|
|
||||||
int optindex = 0;
|
int optindex = 0;
|
||||||
|
|
||||||
/* We're only interested in these options */
|
/* We're only interested in these options */
|
||||||
static struct option long_options[] =
|
struct option node_status_options[] =
|
||||||
{
|
{
|
||||||
{"last-checkpoint-lsn", required_argument, NULL, 'L'},
|
{"last-checkpoint-lsn", required_argument, NULL, 'L'},
|
||||||
{"state", required_argument, NULL, 'S'},
|
{"state", required_argument, NULL, 'S'},
|
||||||
@@ -5028,51 +5109,7 @@ parse_node_status_is_shutdown_cleanly(const char *node_status_output, XLogRecPtr
|
|||||||
return node_status;
|
return node_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
options_len = strlen(node_status_output) + 1;
|
argc_item = parse_output_to_argv(node_status_output, &argv_array);
|
||||||
options_string = pg_malloc(options_len);
|
|
||||||
options_string_ptr = options_string;
|
|
||||||
|
|
||||||
/* Copy the string before operating on it with strtok() */
|
|
||||||
strncpy(options_string, node_status_output, options_len);
|
|
||||||
|
|
||||||
/* Extract arguments into a list and keep a count of the total */
|
|
||||||
while ((argv_item = strtok(options_string_ptr, " ")) != NULL)
|
|
||||||
{
|
|
||||||
item_list_append(&option_argv, argv_item);
|
|
||||||
|
|
||||||
argc_item++;
|
|
||||||
|
|
||||||
if (options_string_ptr != NULL)
|
|
||||||
options_string_ptr = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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 the
|
|
||||||
* program name)
|
|
||||||
*/
|
|
||||||
argv_array = pg_malloc0(sizeof(char *) * (argc_item + 2));
|
|
||||||
|
|
||||||
/* Insert a blank dummy program name at the start of the array */
|
|
||||||
argv_array[0] = pg_malloc0(1);
|
|
||||||
|
|
||||||
c = 1;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copy the previously extracted arguments from our list to the array
|
|
||||||
*/
|
|
||||||
for (cell = option_argv.head; cell; cell = cell->next)
|
|
||||||
{
|
|
||||||
int argv_len = strlen(cell->string) + 1;
|
|
||||||
|
|
||||||
argv_array[c] = pg_malloc0(argv_len);
|
|
||||||
|
|
||||||
strncpy(argv_array[c], cell->string, argv_len);
|
|
||||||
|
|
||||||
c++;
|
|
||||||
}
|
|
||||||
|
|
||||||
argv_array[c] = NULL;
|
|
||||||
|
|
||||||
/* Reset getopt's optind variable */
|
/* Reset getopt's optind variable */
|
||||||
optind = 0;
|
optind = 0;
|
||||||
@@ -5080,7 +5117,7 @@ parse_node_status_is_shutdown_cleanly(const char *node_status_output, XLogRecPtr
|
|||||||
/* Prevent getopt from emitting errors */
|
/* Prevent getopt from emitting errors */
|
||||||
opterr = 0;
|
opterr = 0;
|
||||||
|
|
||||||
while ((c = getopt_long(argc_item, argv_array, "L:S:", long_options,
|
while ((c = getopt_long(argc_item, argv_array, "L:S:", node_status_options,
|
||||||
&optindex)) != -1)
|
&optindex)) != -1)
|
||||||
{
|
{
|
||||||
switch (c)
|
switch (c)
|
||||||
@@ -5113,16 +5150,7 @@ parse_node_status_is_shutdown_cleanly(const char *node_status_output, XLogRecPtr
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pfree(options_string);
|
free_parsed_argv(&argv_array);
|
||||||
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < argc_item + 2; i++)
|
|
||||||
pfree(argv_array[i]);
|
|
||||||
}
|
|
||||||
pfree(argv_array);
|
|
||||||
|
|
||||||
|
|
||||||
return node_status;
|
return node_status;
|
||||||
}
|
}
|
||||||
@@ -5131,30 +5159,15 @@ parse_node_status_is_shutdown_cleanly(const char *node_status_output, XLogRecPtr
|
|||||||
static CheckStatus
|
static CheckStatus
|
||||||
parse_node_check_archiver(const char *node_check_output, int *files, int *threshold)
|
parse_node_check_archiver(const char *node_check_output, int *files, int *threshold)
|
||||||
{
|
{
|
||||||
int options_len = 0;
|
|
||||||
char *options_string = NULL;
|
|
||||||
char *options_string_ptr = NULL;
|
|
||||||
|
|
||||||
CheckStatus status = CHECK_STATUS_UNKNOWN;
|
CheckStatus status = CHECK_STATUS_UNKNOWN;
|
||||||
|
|
||||||
|
int c = 0,
|
||||||
/*
|
argc_item = 0;
|
||||||
* Add parsed options to this list, then copy to an array to pass to
|
char **argv_array = NULL;
|
||||||
* getopt
|
|
||||||
*/
|
|
||||||
static ItemList option_argv = {NULL, NULL};
|
|
||||||
|
|
||||||
char *argv_item;
|
|
||||||
int c,
|
|
||||||
argc_item = 1;
|
|
||||||
|
|
||||||
char **argv_array;
|
|
||||||
ItemListCell *cell;
|
|
||||||
|
|
||||||
int optindex = 0;
|
int optindex = 0;
|
||||||
|
|
||||||
/* We're only interested in these options */
|
/* We're only interested in these options */
|
||||||
static struct option long_options[] =
|
struct option node_check_options[] =
|
||||||
{
|
{
|
||||||
{"status", required_argument, NULL, 'S'},
|
{"status", required_argument, NULL, 'S'},
|
||||||
{"files", required_argument, NULL, 'f'},
|
{"files", required_argument, NULL, 'f'},
|
||||||
@@ -5171,51 +5184,8 @@ parse_node_check_archiver(const char *node_check_output, int *files, int *thresh
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
options_len = strlen(node_check_output) + 1;
|
argc_item = parse_output_to_argv(node_check_output, &argv_array);
|
||||||
options_string = pg_malloc(options_len);
|
|
||||||
options_string_ptr = options_string;
|
|
||||||
|
|
||||||
/* Copy the string before operating on it with strtok() */
|
|
||||||
strncpy(options_string, node_check_output, options_len);
|
|
||||||
|
|
||||||
/* Extract arguments into a list and keep a count of the total */
|
|
||||||
while ((argv_item = strtok(options_string_ptr, " ")) != NULL)
|
|
||||||
{
|
|
||||||
item_list_append(&option_argv, argv_item);
|
|
||||||
|
|
||||||
argc_item++;
|
|
||||||
|
|
||||||
if (options_string_ptr != NULL)
|
|
||||||
options_string_ptr = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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 the
|
|
||||||
* program name)
|
|
||||||
*/
|
|
||||||
argv_array = pg_malloc0(sizeof(char *) * (argc_item + 2));
|
|
||||||
|
|
||||||
/* Insert a blank dummy program name at the start of the array */
|
|
||||||
argv_array[0] = pg_malloc0(1);
|
|
||||||
|
|
||||||
c = 1;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copy the previously extracted arguments from our list to the array
|
|
||||||
*/
|
|
||||||
for (cell = option_argv.head; cell; cell = cell->next)
|
|
||||||
{
|
|
||||||
int argv_len = strlen(cell->string) + 1;
|
|
||||||
|
|
||||||
argv_array[c] = pg_malloc0(argv_len);
|
|
||||||
|
|
||||||
strncpy(argv_array[c], cell->string, argv_len);
|
|
||||||
|
|
||||||
c++;
|
|
||||||
}
|
|
||||||
|
|
||||||
argv_array[c] = NULL;
|
|
||||||
|
|
||||||
/* Reset getopt's optind variable */
|
/* Reset getopt's optind variable */
|
||||||
optind = 0;
|
optind = 0;
|
||||||
@@ -5223,7 +5193,7 @@ parse_node_check_archiver(const char *node_check_output, int *files, int *thresh
|
|||||||
/* Prevent getopt from emitting errors */
|
/* Prevent getopt from emitting errors */
|
||||||
opterr = 0;
|
opterr = 0;
|
||||||
|
|
||||||
while ((c = getopt_long(argc_item, argv_array, "f:S:t:", long_options,
|
while ((c = getopt_long(argc_item, argv_array, "f:S:t:", node_check_options,
|
||||||
&optindex)) != -1)
|
&optindex)) != -1)
|
||||||
{
|
{
|
||||||
switch (c)
|
switch (c)
|
||||||
@@ -5265,11 +5235,99 @@ parse_node_check_archiver(const char *node_check_output, int *files, int *thresh
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free_parsed_argv(&argv_array);
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
parse_output_to_argv(const char *string, char ***argv_array)
|
||||||
|
{
|
||||||
|
int options_len = 0;
|
||||||
|
char *options_string = NULL;
|
||||||
|
char *options_string_ptr = NULL;
|
||||||
|
int c = 1,
|
||||||
|
argc_item = 1;
|
||||||
|
char *argv_item = NULL;
|
||||||
|
char **local_argv_array = NULL;
|
||||||
|
ItemListCell *cell;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add parsed options to this list, then copy to an array to pass to
|
||||||
|
* getopt
|
||||||
|
*/
|
||||||
|
ItemList option_argv = {NULL, NULL};
|
||||||
|
|
||||||
|
options_len = strlen(string) + 1;
|
||||||
|
options_string = pg_malloc(options_len);
|
||||||
|
options_string_ptr = options_string;
|
||||||
|
|
||||||
|
/* Copy the string before operating on it with strtok() */
|
||||||
|
strncpy(options_string, string, options_len);
|
||||||
|
|
||||||
|
/* Extract arguments into a list and keep a count of the total */
|
||||||
|
while ((argv_item = strtok(options_string_ptr, " ")) != NULL)
|
||||||
|
{
|
||||||
|
item_list_append(&option_argv, trim(argv_item));
|
||||||
|
|
||||||
|
argc_item++;
|
||||||
|
|
||||||
|
if (options_string_ptr != NULL)
|
||||||
|
options_string_ptr = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
pfree(options_string);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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 the
|
||||||
|
* program name)
|
||||||
|
*/
|
||||||
|
local_argv_array = pg_malloc0(sizeof(char *) * (argc_item + 2));
|
||||||
|
|
||||||
|
/* Insert a blank dummy program name at the start of the array */
|
||||||
|
local_argv_array[0] = pg_malloc0(1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copy the previously extracted arguments from our list to the array
|
||||||
|
*/
|
||||||
|
for (cell = option_argv.head; cell; cell = cell->next)
|
||||||
|
{
|
||||||
|
int argv_len = strlen(cell->string) + 1;
|
||||||
|
|
||||||
|
local_argv_array[c] = (char *)pg_malloc0(argv_len);
|
||||||
|
|
||||||
|
strncpy(local_argv_array[c], cell->string, argv_len);
|
||||||
|
|
||||||
|
c++;
|
||||||
|
}
|
||||||
|
|
||||||
|
local_argv_array[c] = NULL;
|
||||||
|
|
||||||
|
item_list_free(&option_argv);
|
||||||
|
|
||||||
|
*argv_array = local_argv_array;
|
||||||
|
|
||||||
|
return argc_item;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
free_parsed_argv(char ***argv_array)
|
||||||
|
{
|
||||||
|
char **local_argv_array = *argv_array;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
while (local_argv_array[i] != NULL)
|
||||||
|
{
|
||||||
|
pfree((char *)local_argv_array[i]);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
pfree((char **)local_argv_array);
|
||||||
|
*argv_array = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -5313,6 +5371,8 @@ do_standby_help(void)
|
|||||||
printf(_(" -F, --force overwrite an existing node record, or if primary connection\n" \
|
printf(_(" -F, --force overwrite an existing node record, or if primary connection\n" \
|
||||||
" parameters supplied, create record even if standby offline\n"));
|
" parameters supplied, create record even if standby offline\n"));
|
||||||
printf(_(" --upstream-node-id ID of the upstream node to replicate from (optional)\n"));
|
printf(_(" --upstream-node-id ID of the upstream node to replicate from (optional)\n"));
|
||||||
|
printf(_(" --wait-start=VALUE wait for the standby to start (timeout in seconds, default %i)\n"), DEFAULT_WAIT_START);
|
||||||
|
|
||||||
printf(_(" --wait-sync[=VALUE] wait for the node record to synchronise to the standby\n" \
|
printf(_(" --wait-sync[=VALUE] wait for the node record to synchronise to the standby\n" \
|
||||||
" (optional timeout in seconds)\n"));
|
" (optional timeout in seconds)\n"));
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* repmgr-action-standby.h
|
* repmgr-action-standby.h
|
||||||
* Copyright (c) 2ndQuadrant, 2010-2017
|
* Copyright (c) 2ndQuadrant, 2010-2018
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Implements witness actions for the repmgr command line utility
|
* Implements witness actions for the repmgr command line utility
|
||||||
*
|
*
|
||||||
* Copyright (c) 2ndQuadrant, 2010-2017
|
* Copyright (c) 2ndQuadrant, 2010-2018
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* repmgr-action-witness.h
|
* repmgr-action-witness.h
|
||||||
* Copyright (c) 2ndQuadrant, 2010-2017
|
* Copyright (c) 2ndQuadrant, 2010-2018
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* repmgr-client-global.h
|
* repmgr-client-global.h
|
||||||
* Copyright (c) 2ndQuadrant, 2010-2017
|
* Copyright (c) 2ndQuadrant, 2010-2018
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -86,6 +86,7 @@ typedef struct
|
|||||||
/* "standby register" options */
|
/* "standby register" options */
|
||||||
bool wait_register_sync;
|
bool wait_register_sync;
|
||||||
int wait_register_sync_seconds;
|
int wait_register_sync_seconds;
|
||||||
|
int wait_start;
|
||||||
|
|
||||||
/* "standby switchover" options */
|
/* "standby switchover" options */
|
||||||
bool always_promote;
|
bool always_promote;
|
||||||
@@ -101,6 +102,7 @@ typedef struct
|
|||||||
bool replication_lag;
|
bool replication_lag;
|
||||||
bool role;
|
bool role;
|
||||||
bool slots;
|
bool slots;
|
||||||
|
bool has_passfile;
|
||||||
|
|
||||||
/* "node join" options */
|
/* "node join" options */
|
||||||
char config_files[MAXLEN];
|
char config_files[MAXLEN];
|
||||||
@@ -145,13 +147,13 @@ typedef struct
|
|||||||
/* "standby clone"/"standby follow" options */ \
|
/* "standby clone"/"standby follow" options */ \
|
||||||
NO_UPSTREAM_NODE, \
|
NO_UPSTREAM_NODE, \
|
||||||
/* "standby register" options */ \
|
/* "standby register" options */ \
|
||||||
false, 0, \
|
false, 0, DEFAULT_WAIT_START, \
|
||||||
/* "standby switchover" options */ \
|
/* "standby switchover" options */ \
|
||||||
false, false, false, \
|
false, false, false, \
|
||||||
/* "node status" options */ \
|
/* "node status" options */ \
|
||||||
false, \
|
false, \
|
||||||
/* "node check" options */ \
|
/* "node check" options */ \
|
||||||
false, false, false, false, false, \
|
false, false, false, false, false, false, \
|
||||||
/* "node join" options */ \
|
/* "node join" options */ \
|
||||||
"", \
|
"", \
|
||||||
/* "node service" options */ \
|
/* "node service" options */ \
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* repmgr-client.c - Command interpreter for the repmgr package
|
* repmgr-client.c - Command interpreter for the repmgr package
|
||||||
*
|
*
|
||||||
* Copyright (c) 2ndQuadrant, 2010-2017
|
* Copyright (c) 2ndQuadrant, 2010-2018
|
||||||
*
|
*
|
||||||
* This module is a command-line utility to easily setup a cluster of
|
* This module is a command-line utility to easily setup a cluster of
|
||||||
* hot standby servers for an HA environment
|
* hot standby servers for an HA environment
|
||||||
@@ -177,7 +177,7 @@ main(int argc, char **argv)
|
|||||||
strncpy(runtime_options.username, pw->pw_name, MAXLEN);
|
strncpy(runtime_options.username, pw->pw_name, MAXLEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
while ((c = getopt_long(argc, argv, "?Vb:f:Fd:h:p:U:R:S:L:vtD:crC:", long_options,
|
while ((c = getopt_long(argc, argv, "?Vb:f:FWd:h:p:U:R:S:D:ckL:tvC:", long_options,
|
||||||
&optindex)) != -1)
|
&optindex)) != -1)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
@@ -389,7 +389,11 @@ main(int argc, char **argv)
|
|||||||
*---------------------------
|
*---------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
case OPT_REGISTER_WAIT:
|
case OPT_WAIT_START:
|
||||||
|
runtime_options.wait_start = repmgr_atoi(optarg, "--wait-start", &cli_errors, false);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OPT_WAIT_SYNC:
|
||||||
runtime_options.wait_register_sync = true;
|
runtime_options.wait_register_sync = true;
|
||||||
if (optarg != NULL)
|
if (optarg != NULL)
|
||||||
{
|
{
|
||||||
@@ -447,6 +451,10 @@ main(int argc, char **argv)
|
|||||||
runtime_options.slots = true;
|
runtime_options.slots = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case OPT_HAS_PASSFILE:
|
||||||
|
runtime_options.has_passfile = true;
|
||||||
|
break;
|
||||||
|
|
||||||
/*--------------------
|
/*--------------------
|
||||||
* "node rejoin" options
|
* "node rejoin" options
|
||||||
*--------------------
|
*--------------------
|
||||||
@@ -1316,7 +1324,7 @@ check_cli_parameters(const int action)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* XXX if -D/--pgdata provided, and also
|
* XXX if -D/--pgdata provided, and also
|
||||||
* config_file_options.pgdaga, warn -D/--pgdata will be
|
* config_file_options.pgdata, warn -D/--pgdata will be
|
||||||
* ignored
|
* ignored
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -1356,6 +1364,12 @@ check_cli_parameters(const int action)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case NODE_CHECK:
|
||||||
|
if (runtime_options.has_passfile == true)
|
||||||
|
{
|
||||||
|
config_file_required = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case NODE_STATUS:
|
case NODE_STATUS:
|
||||||
if (runtime_options.node_id != UNKNOWN_NODE_ID)
|
if (runtime_options.node_id != UNKNOWN_NODE_ID)
|
||||||
{
|
{
|
||||||
@@ -2715,6 +2729,6 @@ init_node_record(t_node_info *node_record)
|
|||||||
|
|
||||||
if (config_file_options.use_replication_slots == true)
|
if (config_file_options.use_replication_slots == true)
|
||||||
{
|
{
|
||||||
maxlen_snprintf(node_record->slot_name, "repmgr_slot_%i", config_file_options.node_id);
|
create_slot_name(node_record->slot_name, config_file_options.node_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* repmgr-client.h
|
* repmgr-client.h
|
||||||
* Copyright (c) 2ndQuadrant, 2010-2017
|
* Copyright (c) 2ndQuadrant, 2010-2018
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -56,7 +56,7 @@
|
|||||||
#define OPT_NODE_NAME 1007
|
#define OPT_NODE_NAME 1007
|
||||||
#define OPT_WITHOUT_BARMAN 1008
|
#define OPT_WITHOUT_BARMAN 1008
|
||||||
#define OPT_NO_UPSTREAM_CONNECTION 1009
|
#define OPT_NO_UPSTREAM_CONNECTION 1009
|
||||||
#define OPT_REGISTER_WAIT 1010
|
#define OPT_WAIT_SYNC 1010
|
||||||
#define OPT_LOG_TO_FILE 1011
|
#define OPT_LOG_TO_FILE 1011
|
||||||
#define OPT_UPSTREAM_CONNINFO 1012
|
#define OPT_UPSTREAM_CONNINFO 1012
|
||||||
#define OPT_REPLICATION_USER 1013
|
#define OPT_REPLICATION_USER 1013
|
||||||
@@ -81,6 +81,9 @@
|
|||||||
#define OPT_DOWNSTREAM 1032
|
#define OPT_DOWNSTREAM 1032
|
||||||
#define OPT_SLOTS 1033
|
#define OPT_SLOTS 1033
|
||||||
#define OPT_CONFIG_ARCHIVE_DIR 1034
|
#define OPT_CONFIG_ARCHIVE_DIR 1034
|
||||||
|
#define OPT_HAS_PASSFILE 1035
|
||||||
|
#define OPT_WAIT_START 1036
|
||||||
|
|
||||||
/* deprecated since 3.3 */
|
/* deprecated since 3.3 */
|
||||||
#define OPT_DATA_DIR 999
|
#define OPT_DATA_DIR 999
|
||||||
#define OPT_NO_CONNINFO_PASSWORD 998
|
#define OPT_NO_CONNINFO_PASSWORD 998
|
||||||
@@ -135,7 +138,8 @@ static struct option long_options[] =
|
|||||||
{"without-barman", no_argument, NULL, OPT_WITHOUT_BARMAN},
|
{"without-barman", no_argument, NULL, OPT_WITHOUT_BARMAN},
|
||||||
|
|
||||||
/* "standby register" options */
|
/* "standby register" options */
|
||||||
{"wait-sync", optional_argument, NULL, OPT_REGISTER_WAIT},
|
{"wait-start", required_argument, NULL, OPT_WAIT_START},
|
||||||
|
{"wait-sync", optional_argument, NULL, OPT_WAIT_SYNC},
|
||||||
|
|
||||||
/* "standby switchover" options
|
/* "standby switchover" options
|
||||||
*
|
*
|
||||||
@@ -153,6 +157,7 @@ static struct option long_options[] =
|
|||||||
{"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},
|
||||||
|
{"has-passfile", no_argument, NULL, OPT_HAS_PASSFILE},
|
||||||
|
|
||||||
/* "node rejoin" options */
|
/* "node rejoin" options */
|
||||||
{"config-files", required_argument, NULL, OPT_CONFIG_FILES},
|
{"config-files", required_argument, NULL, OPT_CONFIG_FILES},
|
||||||
|
|||||||
2
repmgr.c
2
repmgr.c
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* repmgr.c - repmgr extension
|
* repmgr.c - repmgr extension
|
||||||
*
|
*
|
||||||
* Copyright (c) 2ndQuadrant, 2010-2017
|
* Copyright (c) 2ndQuadrant, 2010-2018
|
||||||
*
|
*
|
||||||
* This is the actual extension code; see repmgr-client.c for the code which
|
* This is the actual extension code; see repmgr-client.c for the code which
|
||||||
* generates the repmgr binary
|
* generates the repmgr binary
|
||||||
|
|||||||
@@ -35,12 +35,12 @@
|
|||||||
# connection attempt is abandoned; for details see:
|
# connection attempt is abandoned; for details see:
|
||||||
# https://www.postgresql.org/docs/current/static/libpq-connect.html#LIBPQ-CONNECT-CONNECT-TIMEOUT
|
# https://www.postgresql.org/docs/current/static/libpq-connect.html#LIBPQ-CONNECT-CONNECT-TIMEOUT
|
||||||
|
|
||||||
#data_directory # The node's data directory. This is needed by repmgr
|
#data_directory='' # The node's data directory. This is needed by repmgr
|
||||||
# when performing operations when the PostgreSQL instance
|
# when performing operations when the PostgreSQL instance
|
||||||
# is not running and there's no other way of determining
|
# is not running and there's no other way of determining
|
||||||
# the data directory.
|
# the data directory.
|
||||||
|
|
||||||
#replication_user # User to make replication connections with, if not set defaults
|
#replication_user='repmgr' # User to make replication connections with, if not set defaults
|
||||||
# to the user defined in "conninfo".
|
# to the user defined in "conninfo".
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
@@ -160,7 +160,6 @@ ssh_options='-q -o ConnectTimeout=10' # Options to append to "ssh"
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#------------------------------------------------------------------------------
|
#------------------------------------------------------------------------------
|
||||||
# Standby clone settings
|
# Standby clone settings
|
||||||
#------------------------------------------------------------------------------
|
#------------------------------------------------------------------------------
|
||||||
@@ -287,7 +286,7 @@ ssh_options='-q -o ConnectTimeout=10' # Options to append to "ssh"
|
|||||||
|
|
||||||
# Various warning/critical thresholds used by "repmgr node check".
|
# Various warning/critical thresholds used by "repmgr node check".
|
||||||
|
|
||||||
#archive_ready_warning=16 # repmgr node check --archiver
|
#archive_ready_warning=16 # repmgr node check --archive-ready
|
||||||
#archive_ready_critical=128 #
|
#archive_ready_critical=128 #
|
||||||
# Numbers of files pending archiving via PostgreSQL's
|
# Numbers of files pending archiving via PostgreSQL's
|
||||||
# "archive_command" configuration parameter. If
|
# "archive_command" configuration parameter. If
|
||||||
|
|||||||
4
repmgr.h
4
repmgr.h
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* repmgr.h
|
* repmgr.h
|
||||||
* Copyright (c) 2ndQuadrant, 2010-2017
|
* Copyright (c) 2ndQuadrant, 2010-2018
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -56,6 +56,7 @@
|
|||||||
#define NO_UPSTREAM_NODE -1
|
#define NO_UPSTREAM_NODE -1
|
||||||
#define UNKNOWN_NODE_ID -1
|
#define UNKNOWN_NODE_ID -1
|
||||||
|
|
||||||
|
#define VOTING_TERM_NOT_SET -1
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* various default values - ensure repmgr.conf.sample is update
|
* various default values - ensure repmgr.conf.sample is update
|
||||||
@@ -75,6 +76,7 @@
|
|||||||
#define DEFAULT_REPLICATION_LAG_WARNING 300 /* seconds */
|
#define DEFAULT_REPLICATION_LAG_WARNING 300 /* seconds */
|
||||||
#define DEFAULT_REPLICATION_LAG_CRITICAL 600 /* seconds */
|
#define DEFAULT_REPLICATION_LAG_CRITICAL 600 /* seconds */
|
||||||
#define DEFAULT_WITNESS_SYNC_INTERVAL 15 /* seconds */
|
#define DEFAULT_WITNESS_SYNC_INTERVAL 15 /* seconds */
|
||||||
|
#define DEFAULT_WAIT_START 30 /* seconds */
|
||||||
|
|
||||||
#ifndef RECOVERY_COMMAND_FILE
|
#ifndef RECOVERY_COMMAND_FILE
|
||||||
#define RECOVERY_COMMAND_FILE "recovery.conf"
|
#define RECOVERY_COMMAND_FILE "recovery.conf"
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
#define REPMGR_VERSION_DATE ""
|
#define REPMGR_VERSION_DATE ""
|
||||||
#define REPMGR_VERSION "4.0.0"
|
#define REPMGR_VERSION "4.0.2"
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* repmgrd-bdr.c - BDR functionality for repmgrd
|
* repmgrd-bdr.c - BDR functionality for repmgrd
|
||||||
*
|
*
|
||||||
* Copyright (c) 2ndQuadrant, 2010-2017
|
* Copyright (c) 2ndQuadrant, 2010-2018
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -124,9 +124,9 @@ monitor_bdr(void)
|
|||||||
exit(ERR_BAD_CONFIG);
|
exit(ERR_BAD_CONFIG);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_active_bdr_node(local_conn, local_node_info.node_name))
|
if (is_active_bdr_node(local_conn, local_node_info.node_name) == false)
|
||||||
{
|
{
|
||||||
log_error(_("BDR node %s is not active, terminating"),
|
log_error(_("BDR node \"%s\" is not active, terminating"),
|
||||||
local_node_info.node_name);
|
local_node_info.node_name);
|
||||||
PQfinish(local_conn);
|
PQfinish(local_conn);
|
||||||
exit(ERR_BAD_CONFIG);
|
exit(ERR_BAD_CONFIG);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* repmgrd-bdr.h
|
* repmgrd-bdr.h
|
||||||
* Copyright (c) 2ndQuadrant, 2010-2017
|
* Copyright (c) 2ndQuadrant, 2010-2018
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* repmgrd-physical.c - physical replication functionality for repmgrd
|
* repmgrd-physical.c - physical (streaming) replication functionality for repmgrd
|
||||||
*
|
*
|
||||||
* Copyright (c) 2ndQuadrant, 2010-2017
|
* Copyright (c) 2ndQuadrant, 2010-2018
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -107,7 +107,7 @@ do_physical_node_check(void)
|
|||||||
|
|
||||||
if (local_node_info.active == false)
|
if (local_node_info.active == false)
|
||||||
{
|
{
|
||||||
char *hint = "Check that 'repmgr (primary|standby) register' was executed for this node";
|
char *hint = "Check that \"repmgr (primary|standby) register\" was executed for this node";
|
||||||
|
|
||||||
switch (config_file_options.failover)
|
switch (config_file_options.failover)
|
||||||
{
|
{
|
||||||
@@ -935,17 +935,14 @@ loop:
|
|||||||
|
|
||||||
local_node_info.active = false;
|
local_node_info.active = false;
|
||||||
|
|
||||||
appendPQExpBuffer(
|
appendPQExpBuffer(&event_details,
|
||||||
&event_details,
|
|
||||||
_("unable to connect to local node \"%s\" (ID: %i), marking inactive"),
|
_("unable to connect to local node \"%s\" (ID: %i), marking inactive"),
|
||||||
local_node_info.node_name,
|
local_node_info.node_name,
|
||||||
local_node_info.node_id);
|
local_node_info.node_id);
|
||||||
|
|
||||||
log_warning("%s", event_details.data)
|
log_warning("%s", event_details.data);
|
||||||
|
|
||||||
|
create_event_notification(primary_conn,
|
||||||
create_event_notification(
|
|
||||||
primary_conn,
|
|
||||||
&config_file_options,
|
&config_file_options,
|
||||||
local_node_info.node_id,
|
local_node_info.node_id,
|
||||||
"standby_failure",
|
"standby_failure",
|
||||||
@@ -971,8 +968,7 @@ loop:
|
|||||||
|
|
||||||
local_node_info.active = true;
|
local_node_info.active = true;
|
||||||
|
|
||||||
appendPQExpBuffer(
|
appendPQExpBuffer(&event_details,
|
||||||
&event_details,
|
|
||||||
_("reconnected to local node \"%s\" (ID: %i), marking active"),
|
_("reconnected to local node \"%s\" (ID: %i), marking active"),
|
||||||
local_node_info.node_name,
|
local_node_info.node_name,
|
||||||
local_node_info.node_id);
|
local_node_info.node_id);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* repmgrd-physical.h
|
* repmgrd-physical.h
|
||||||
* Copyright (c) 2ndQuadrant, 2010-2017
|
* Copyright (c) 2ndQuadrant, 2010-2018
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* repmgrd.c - Replication manager daemon
|
* repmgrd.c - Replication manager daemon
|
||||||
*
|
*
|
||||||
* Copyright (c) 2ndQuadrant, 2010-2017
|
* Copyright (c) 2ndQuadrant, 2010-2018
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* repmgrd.h
|
* repmgrd.h
|
||||||
* Copyright (c) 2ndQuadrant, 2010-2017
|
* Copyright (c) 2ndQuadrant, 2010-2018
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* strutil.c
|
* strutil.c
|
||||||
*
|
*
|
||||||
* Copyright (c) 2ndQuadrant, 2010-2017
|
* Copyright (c) 2ndQuadrant, 2010-2018
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
13
strutil.h
13
strutil.h
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* strutil.h
|
* strutil.h
|
||||||
* Copyright (c) 2ndQuadrant, 2010-2017
|
* Copyright (c) 2ndQuadrant, 2010-2018
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -33,12 +33,17 @@
|
|||||||
#define MAXLEN_STR STR(MAXLEN)
|
#define MAXLEN_STR STR(MAXLEN)
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* These values must match the Nagios return codes defined here:
|
||||||
|
*
|
||||||
|
* https://assets.nagios.com/downloads/nagioscore/docs/nagioscore/3/en/pluginapi.html
|
||||||
|
*/
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
CHECK_STATUS_OK = 0,
|
CHECK_STATUS_OK = 0,
|
||||||
CHECK_STATUS_WARNING,
|
CHECK_STATUS_WARNING = 1,
|
||||||
CHECK_STATUS_CRITICAL,
|
CHECK_STATUS_CRITICAL = 2,
|
||||||
CHECK_STATUS_UNKNOWN
|
CHECK_STATUS_UNKNOWN = 3
|
||||||
} CheckStatus;
|
} CheckStatus;
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
|
|||||||
2
voting.h
2
voting.h
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* voting.h
|
* voting.h
|
||||||
* Copyright (c) 2ndQuadrant, 2010-2017
|
* Copyright (c) 2ndQuadrant, 2010-2018
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
Reference in New Issue
Block a user