mirror of
https://github.com/EnterpriseDB/repmgr.git
synced 2026-03-22 22:56:29 +00:00
Compare commits
106 Commits
v5.2.1epas
...
v5.3.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
78cc278639 | ||
|
|
ceb65027c6 | ||
|
|
e6caa14ea2 | ||
|
|
88a11f36ca | ||
|
|
7f371b11a5 | ||
|
|
349eacd4b7 | ||
|
|
9f2afe9643 | ||
|
|
356f65531f | ||
|
|
2a7579c770 | ||
|
|
820d972d41 | ||
|
|
d0add49c84 | ||
|
|
9a84fa84f9 | ||
|
|
ff2c56f5cb | ||
|
|
3b860bad80 | ||
|
|
70c79aeaec | ||
|
|
afd876377c | ||
|
|
277910cb31 | ||
|
|
9554154677 | ||
|
|
2bbfb5daa0 | ||
|
|
82b0e85a66 | ||
|
|
3320eb0983 | ||
|
|
7862941300 | ||
|
|
f152fc3016 | ||
|
|
9c260e605d | ||
|
|
7ad06530e4 | ||
|
|
c787273f91 | ||
|
|
d40055c8dd | ||
|
|
bf0478088c | ||
|
|
efd5792de4 | ||
|
|
17987a2690 | ||
|
|
5f1ba6db3d | ||
|
|
55efbe60ea | ||
|
|
132f5ebc08 | ||
|
|
c901f36f81 | ||
|
|
edb49b2747 | ||
|
|
a35d85ed70 | ||
|
|
b6b91425d9 | ||
|
|
32329ca55a | ||
|
|
79d1f005db | ||
|
|
f64f498afb | ||
|
|
f10c013e89 | ||
|
|
2059a55a99 | ||
|
|
99ed17b838 | ||
|
|
078b4ad863 | ||
|
|
2af71c6426 | ||
|
|
9349520530 | ||
|
|
14851e61de | ||
|
|
888e1d7a3b | ||
|
|
1b4c2a60bb | ||
|
|
da163e811c | ||
|
|
80d1beef7e | ||
|
|
4f009548f6 | ||
|
|
d266df3143 | ||
|
|
dd8204e013 | ||
|
|
d34b4e71a6 | ||
|
|
12749c3f63 | ||
|
|
ce59d92731 | ||
|
|
cfbeed50d6 | ||
|
|
da3eaee127 | ||
|
|
b37a599fc6 | ||
|
|
f011e552d0 | ||
|
|
d1cc05faf9 | ||
|
|
7ceba84e32 | ||
|
|
842c67ca18 | ||
|
|
f619c3a8ff | ||
|
|
5a88858596 | ||
|
|
02bc143c75 | ||
|
|
c480d01f9c | ||
|
|
e762200a12 | ||
|
|
2133e1097e | ||
|
|
77d7a098a1 | ||
|
|
4e9cdf0267 | ||
|
|
0d8bf2a935 | ||
|
|
debbda6074 | ||
|
|
d5b94431f2 | ||
|
|
93187e9743 | ||
|
|
f7e45863ad | ||
|
|
89556d6488 | ||
|
|
4ad868d119 | ||
|
|
a93c6dfca7 | ||
|
|
4d8bc63834 | ||
|
|
7bca9df223 | ||
|
|
1ac62a4352 | ||
|
|
8f7a32a9a2 | ||
|
|
9c04de11fc | ||
|
|
040b1ae4e3 | ||
|
|
703aed3fa3 | ||
|
|
7ee0098771 | ||
|
|
430d12b870 | ||
|
|
c8b2d23361 | ||
|
|
8543c0bcf6 | ||
|
|
674c06d01c | ||
|
|
970d7a136f | ||
|
|
7bde686796 | ||
|
|
ab1447aeca | ||
|
|
293e37688f | ||
|
|
96718151a6 | ||
|
|
65ffe51bb4 | ||
|
|
b6d0288a82 | ||
|
|
f888407ad8 | ||
|
|
1512c7b761 | ||
|
|
8877d4d508 | ||
|
|
f18b2e900d | ||
|
|
5c4aa1856c | ||
|
|
091a2df167 | ||
|
|
17a1732eb0 |
@@ -2,7 +2,7 @@ License and Contributions
|
||||
=========================
|
||||
|
||||
`repmgr` is licensed under the GPL v3. All of its code and documentation is
|
||||
Copyright 2010-2020, 2ndQuadrant Limited. See the files COPYRIGHT and LICENSE for
|
||||
Copyright 2010-2021, EnterpriseDB Corporation. See the files COPYRIGHT and LICENSE for
|
||||
details.
|
||||
|
||||
The development of repmgr has primarily been sponsored by 2ndQuadrant customers.
|
||||
@@ -12,10 +12,10 @@ which has received funding from the European Union's Seventh Framework Programme
|
||||
(FP7/2007-2013) under grant agreement 258862.
|
||||
|
||||
Contributions to `repmgr` are welcome, and will be listed in the file `CREDITS`.
|
||||
2ndQuadrant Limited requires that any contributions provide a copyright
|
||||
EnterpriseDB Corporation requires that any contributions provide a copyright
|
||||
assignment and a disclaimer of any work-for-hire ownership claims from the
|
||||
employer of the developer. This lets us make sure that all of the repmgr
|
||||
distribution remains free code. Please contact info@2ndQuadrant.com for a
|
||||
distribution remains free code. Please contact info@enterprise.com for a
|
||||
copy of the relevant Copyright Assignment Form.
|
||||
|
||||
Code style
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2010-2020, 2ndQuadrant Limited
|
||||
Copyright (c) 2010-2021, EnterpriseDB Corporation
|
||||
All rights reserved.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
|
||||
2
FAQ.md
2
FAQ.md
@@ -5,6 +5,6 @@ The repmgr 4 FAQ is located here: [repmgr FAQ (Frequently Asked Questions)](http
|
||||
|
||||
The repmgr 3.x FAQ can be found here:
|
||||
|
||||
https://github.com/2ndQuadrant/repmgr/blob/REL3_3_STABLE/FAQ.md
|
||||
https://github.com/EnterpriseDB/repmgr/blob/REL3_3_STABLE/FAQ.md
|
||||
|
||||
Note that repmgr 3.x is no longer supported.
|
||||
|
||||
15
HISTORY
15
HISTORY
@@ -1,3 +1,16 @@
|
||||
5.3.1 2022-??-??
|
||||
repmgrd: fixes for potential connection leaks (hslightdb)
|
||||
|
||||
5.3.0 2021-10-12
|
||||
standby switchover: improve handling of node rejoin failure (Ian)
|
||||
repmgrd: prefix all shared library functions with "repmgr_" to
|
||||
minimize the risk of clashes with other shared libraries (Ian)
|
||||
repmgrd: at startup, if node record is marked as "inactive", attempt
|
||||
to set it to "active" (Ian)
|
||||
standby clone: set "slot_name" in node record if required (Ian)
|
||||
node rejoin: emit rejoin target note information as NOTICE (Ian)
|
||||
repmgrd: ensure short option "-s" is accepted (Ian)
|
||||
|
||||
5.2.1 2020-12-07
|
||||
config: fix parsing of "replication_type"; GitHub #672 (Ian)
|
||||
standby clone: handle missing "postgresql.auto.conf" (Ian)
|
||||
@@ -43,7 +56,7 @@
|
||||
repmgr: ensure postgresql.auto.conf is created with correct permissions (Ian)
|
||||
repmgr: minimize requirement to check upstream data directory location
|
||||
during "standby clone" (Ian)
|
||||
repmgr: warn about missing pg_rewind prerequisites when excuting
|
||||
repmgr: warn about missing pg_rewind prerequisites when executing
|
||||
"standby clone" (Ian)
|
||||
repmgr: add --upstream option to "node check"
|
||||
repmgr: report error code on follow/rejoin failure due to non-available
|
||||
|
||||
@@ -13,6 +13,7 @@ DATA = \
|
||||
repmgr--unpackaged--4.0.sql \
|
||||
repmgr--unpackaged--5.1.sql \
|
||||
repmgr--unpackaged--5.2.sql \
|
||||
repmgr--unpackaged--5.3.sql \
|
||||
repmgr--4.0.sql \
|
||||
repmgr--4.0--4.1.sql \
|
||||
repmgr--4.1.sql \
|
||||
@@ -27,7 +28,9 @@ DATA = \
|
||||
repmgr--5.0--5.1.sql \
|
||||
repmgr--5.1.sql \
|
||||
repmgr--5.1--5.2.sql \
|
||||
repmgr--5.2.sql
|
||||
repmgr--5.2.sql \
|
||||
repmgr--5.2--5.3.sql \
|
||||
repmgr--5.3.sql
|
||||
|
||||
REGRESS = repmgr_extension
|
||||
|
||||
|
||||
24
README.md
24
README.md
@@ -7,10 +7,10 @@ replication capabilities with utilities to set up standby servers, monitor
|
||||
replication, and perform administrative tasks such as failover or switchover
|
||||
operations.
|
||||
|
||||
The most recent `repmgr` version (5.2.0) supports all PostgreSQL versions from
|
||||
The most recent `repmgr` version (5.2.1) supports all PostgreSQL versions from
|
||||
9.5 to 13. PostgreSQL 9.4 is also supported, with some restrictions.
|
||||
|
||||
`repmgr` is distributed under the GNU GPL 3 and maintained by 2ndQuadrant.
|
||||
`repmgr` is distributed under the GNU GPL 3 and maintained by EnterpriseDB.
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
@@ -21,7 +21,7 @@ The full `repmgr` documentation is available here:
|
||||
|
||||
The old `README` file for `repmgr` 3.x is available here:
|
||||
|
||||
> https://github.com/2ndQuadrant/repmgr/blob/REL3_3_STABLE/README.md
|
||||
> https://github.com/EnterpriseDB/repmgr/blob/REL3_3_STABLE/README.md
|
||||
|
||||
Note that the `repmgr` 3.x series is no longer supported and contains known bugs;
|
||||
please upgrade to the [current repmgr version](https://repmgr.org/docs/current/appendix-release-notes.html)
|
||||
@@ -55,11 +55,11 @@ Directories
|
||||
Support and Assistance
|
||||
----------------------
|
||||
|
||||
2ndQuadrant provides 24x7 production support for `repmgr`, including
|
||||
EnterpriseDB provides 24x7 production support for `repmgr`, including
|
||||
configuration assistance, installation verification and training for
|
||||
running a robust replication cluster. For further details see:
|
||||
|
||||
* https://2ndquadrant.com/en/support/
|
||||
* [EDB Support Services](https://www.enterprisedb.com/support/postgresql-support-overview-get-the-most-out-of-postgresql)
|
||||
|
||||
There is a mailing list/forum to discuss contributions or issues:
|
||||
|
||||
@@ -69,21 +69,12 @@ The IRC channel #repmgr is registered with freenode.
|
||||
|
||||
Please report bugs and other issues to:
|
||||
|
||||
* https://github.com/2ndQuadrant/repmgr
|
||||
* https://github.com/EnterpriseDB/repmgr
|
||||
|
||||
Further information is available at https://repmgr.org/
|
||||
|
||||
We'd love to hear from you about how you use repmgr. Case studies and
|
||||
news are always welcome. Send us an email at info@2ndQuadrant.com, or
|
||||
send a postcard to
|
||||
|
||||
repmgr
|
||||
c/o 2ndQuadrant
|
||||
7200 The Quorum
|
||||
Oxford Business Park North
|
||||
Oxford
|
||||
OX4 2JZ
|
||||
United Kingdom
|
||||
news are always welcome.
|
||||
|
||||
Thanks from the repmgr core team.
|
||||
|
||||
@@ -99,3 +90,4 @@ Further reading
|
||||
* [repmgr documentation](https://repmgr.org/docs/current/index.html)
|
||||
* [How to Automate PostgreSQL 12 Replication and Failover with repmgr - Part 1](https://www.2ndquadrant.com/en/blog/how-to-automate-postgresql-12-replication-and-failover-with-repmgr-part-1/)
|
||||
* [How to Automate PostgreSQL 12 Replication and Failover with repmgr - Part 2](https://www.2ndquadrant.com/en/blog/how-to-automate-postgresql-12-replication-and-failover-with-repmgr-part-2/)
|
||||
* [How to implement repmgr for PostgreSQL automatic failover](https://www.enterprisedb.com/postgres-tutorials/how-implement-repmgr-postgresql-automatic-failover)
|
||||
|
||||
4
TODO.md
4
TODO.md
@@ -1,7 +1,7 @@
|
||||
TODO
|
||||
====
|
||||
|
||||
This file contains a list of improvements which are desireable and/or have
|
||||
This file contains a list of improvements which are desirable and/or have
|
||||
been requested, and which we aim to address/implement when time and resources
|
||||
permit.
|
||||
|
||||
@@ -17,4 +17,4 @@ repmgrd nodes to prevent unintended failover; this is obviously inconvenient.
|
||||
We'll need to implement some way of notifying each repmgrd to suspend automatic
|
||||
failover until further notice.
|
||||
|
||||
Requested in GitHub #410 ( https://github.com/2ndQuadrant/repmgr/issues/410 )
|
||||
Requested in GitHub #410 ( https://github.com/EnterpriseDB/repmgr/issues/410 )
|
||||
|
||||
2
compat.c
2
compat.c
@@ -6,7 +6,7 @@
|
||||
* supported PostgreSQL versions. They're unlikely to change but
|
||||
* it would be worth keeping an eye on them for any fixes/improvements.
|
||||
*
|
||||
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
||||
*
|
||||
* Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
|
||||
2
compat.h
2
compat.h
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* compat.h
|
||||
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
||||
*
|
||||
* Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
|
||||
12
configdata.c
12
configdata.c
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* configdata.c - contains structs with parsed configuration data
|
||||
*
|
||||
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
||||
*
|
||||
* 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
|
||||
@@ -581,6 +581,16 @@ struct ConfigFileSetting config_file_settings[] =
|
||||
{ .strmaxlen = sizeof(config_file_options.repmgrd_pid_file) },
|
||||
{ .postprocess_func = &repmgr_canonicalize_path }
|
||||
},
|
||||
/* repmgrd_exit_on_inactive_node */
|
||||
{
|
||||
"repmgrd_exit_on_inactive_node",
|
||||
CONFIG_BOOL,
|
||||
{ .boolptr = &config_file_options.repmgrd_exit_on_inactive_node},
|
||||
{ .booldefault = DEFAULT_REPMGRD_EXIT_ON_INACTIVE_NODE },
|
||||
{},
|
||||
{},
|
||||
{}
|
||||
},
|
||||
/* standby_disconnect_on_failover */
|
||||
{
|
||||
"standby_disconnect_on_failover",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* configfile.c - parse repmgr.conf and other configuration-related functionality
|
||||
*
|
||||
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
||||
*
|
||||
* 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
|
||||
@@ -1889,7 +1889,7 @@ modify_auto_conf(const char *data_dir, KeyValueList *items)
|
||||
/*
|
||||
* Note: durable_rename() is not exposed to frontend code before Pg 10.
|
||||
* We only really need to be modifying postgresql.auto.conf from Pg 12,
|
||||
* but provide backwards compatibitilty for Pg 9.6 and earlier for the
|
||||
* but provide backwards compatibility for Pg 9.6 and earlier for the
|
||||
* (unlikely) event that a repmgr built against one of those versions
|
||||
* is being used against Pg 12 and later.
|
||||
*/
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* configfile.h
|
||||
*
|
||||
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
||||
*
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
@@ -206,6 +206,7 @@ typedef struct
|
||||
int primary_notification_timeout;
|
||||
int repmgrd_standby_startup_timeout;
|
||||
char repmgrd_pid_file[MAXPGPATH];
|
||||
bool repmgrd_exit_on_inactive_node;
|
||||
bool standby_disconnect_on_failover;
|
||||
int sibling_nodes_disconnect_timeout;
|
||||
ConnectionCheckType connection_check_type;
|
||||
@@ -249,7 +250,7 @@ typedef struct
|
||||
/*
|
||||
* undocumented settings
|
||||
*
|
||||
* These settings are for testing or experimential features
|
||||
* These settings are for testing or experimental features
|
||||
* and may be changed without notice.
|
||||
*/
|
||||
|
||||
|
||||
28
configure
vendored
28
configure
vendored
@@ -1,6 +1,6 @@
|
||||
#! /bin/sh
|
||||
# Guess values for system-dependent variables and create Makefiles.
|
||||
# Generated by GNU Autoconf 2.69 for repmgr 5.2.1.
|
||||
# Generated by GNU Autoconf 2.69 for repmgr 5.3.0.
|
||||
#
|
||||
# Report bugs to <repmgr@googlegroups.com>.
|
||||
#
|
||||
@@ -11,7 +11,7 @@
|
||||
# This configure script is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy, distribute and modify it.
|
||||
#
|
||||
# Copyright (c) 2010-2020, 2ndQuadrant Ltd.
|
||||
# Copyright (c) 2010-2021, EnterpriseDB Corporation
|
||||
## -------------------- ##
|
||||
## M4sh Initialization. ##
|
||||
## -------------------- ##
|
||||
@@ -582,8 +582,8 @@ MAKEFLAGS=
|
||||
# Identity of this package.
|
||||
PACKAGE_NAME='repmgr'
|
||||
PACKAGE_TARNAME='repmgr'
|
||||
PACKAGE_VERSION='5.2.1'
|
||||
PACKAGE_STRING='repmgr 5.2.1'
|
||||
PACKAGE_VERSION='5.3.0'
|
||||
PACKAGE_STRING='repmgr 5.3.0'
|
||||
PACKAGE_BUGREPORT='repmgr@googlegroups.com'
|
||||
PACKAGE_URL='https://repmgr.org/'
|
||||
|
||||
@@ -1181,7 +1181,7 @@ if test "$ac_init_help" = "long"; then
|
||||
# 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.
|
||||
cat <<_ACEOF
|
||||
\`configure' configures repmgr 5.2.1 to adapt to many kinds of systems.
|
||||
\`configure' configures repmgr 5.3.0 to adapt to many kinds of systems.
|
||||
|
||||
Usage: $0 [OPTION]... [VAR=VALUE]...
|
||||
|
||||
@@ -1242,7 +1242,7 @@ fi
|
||||
|
||||
if test -n "$ac_init_help"; then
|
||||
case $ac_init_help in
|
||||
short | recursive ) echo "Configuration of repmgr 5.2.1:";;
|
||||
short | recursive ) echo "Configuration of repmgr 5.3.0:";;
|
||||
esac
|
||||
cat <<\_ACEOF
|
||||
|
||||
@@ -1316,14 +1316,14 @@ fi
|
||||
test -n "$ac_init_help" && exit $ac_status
|
||||
if $ac_init_version; then
|
||||
cat <<\_ACEOF
|
||||
repmgr configure 5.2.1
|
||||
repmgr configure 5.3.0
|
||||
generated by GNU Autoconf 2.69
|
||||
|
||||
Copyright (C) 2012 Free Software Foundation, Inc.
|
||||
This configure script is free software; the Free Software Foundation
|
||||
gives unlimited permission to copy, distribute and modify it.
|
||||
|
||||
Copyright (c) 2010-2020, 2ndQuadrant Ltd.
|
||||
Copyright (c) 2010-2021, EnterpriseDB Corporation
|
||||
_ACEOF
|
||||
exit
|
||||
fi
|
||||
@@ -1335,7 +1335,7 @@ cat >config.log <<_ACEOF
|
||||
This file contains any messages produced by compilers while
|
||||
running configure, to aid debugging if configure makes a mistake.
|
||||
|
||||
It was created by repmgr $as_me 5.2.1, which was
|
||||
It was created by repmgr $as_me 5.3.0, which was
|
||||
generated by GNU Autoconf 2.69. Invocation command line was
|
||||
|
||||
$ $0 $@
|
||||
@@ -1811,11 +1811,11 @@ fi
|
||||
pgac_pg_config_version=$($PG_CONFIG --version 2>/dev/null)
|
||||
|
||||
major_version_num=$(echo "$pgac_pg_config_version"|
|
||||
$SED -e 's/^PostgreSQL \([0-9]\{1,2\}\).*$/\1/')
|
||||
$SED -e 's/^[^0-9]\+ \([0-9]\{1,2\}\).*$/\1/')
|
||||
|
||||
if test "$major_version_num" -lt '10'; then
|
||||
version_num=$(echo "$pgac_pg_config_version"|
|
||||
$SED -e 's/^PostgreSQL \([0-9]*\)\.\([0-9]*\)\([a-zA-Z0-9.]*\)$/\1.\2/')
|
||||
$SED -e 's/^[^0-9]\+ \([0-9]*\)\.\([0-9]*\)\([a-zA-Z0-9.]*\)$/\1.\2/')
|
||||
|
||||
if test -z "$version_num"; then
|
||||
as_fn_error $? "could not detect the PostgreSQL version, wrong or broken pg_config?" "$LINENO" 5
|
||||
@@ -1829,7 +1829,7 @@ if test "$major_version_num" -lt '10'; then
|
||||
fi
|
||||
else
|
||||
version_num=$(echo "$pgac_pg_config_version"|
|
||||
$SED -e 's/^PostgreSQL \(.\+\)$/\1/')
|
||||
$SED -e 's/^[^0-9]\+ \(.\+\)$/\1/')
|
||||
|
||||
if test -z "$version_num"; then
|
||||
as_fn_error $? "could not detect the PostgreSQL version, wrong or broken pg_config?" "$LINENO" 5
|
||||
@@ -2487,7 +2487,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
|
||||
# report actual input values of CONFIG_FILES etc. instead of their
|
||||
# values after options handling.
|
||||
ac_log="
|
||||
This file was extended by repmgr $as_me 5.2.1, which was
|
||||
This file was extended by repmgr $as_me 5.3.0, which was
|
||||
generated by GNU Autoconf 2.69. Invocation command line was
|
||||
|
||||
CONFIG_FILES = $CONFIG_FILES
|
||||
@@ -2550,7 +2550,7 @@ _ACEOF
|
||||
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
||||
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
|
||||
ac_cs_version="\\
|
||||
repmgr config.status 5.2.1
|
||||
repmgr config.status 5.3.0
|
||||
configured by $0, generated by GNU Autoconf 2.69,
|
||||
with options \\"\$ac_cs_config\\"
|
||||
|
||||
|
||||
10
configure.in
10
configure.in
@@ -1,6 +1,6 @@
|
||||
AC_INIT([repmgr], [5.2.1], [repmgr@googlegroups.com], [repmgr], [https://repmgr.org/])
|
||||
AC_INIT([repmgr], [5.3.1], [repmgr@googlegroups.com], [repmgr], [https://repmgr.org/])
|
||||
|
||||
AC_COPYRIGHT([Copyright (c) 2010-2020, 2ndQuadrant Ltd.])
|
||||
AC_COPYRIGHT([Copyright (c) 2010-2021, EnterpriseDB Corporation])
|
||||
|
||||
AC_CONFIG_HEADER(config.h)
|
||||
|
||||
@@ -19,11 +19,11 @@ fi
|
||||
pgac_pg_config_version=$($PG_CONFIG --version 2>/dev/null)
|
||||
|
||||
major_version_num=$(echo "$pgac_pg_config_version"|
|
||||
$SED -e 's/^PostgreSQL \([[0-9]]\{1,2\}\).*$/\1/')
|
||||
$SED -e 's/^[[^0-9]]\+ \([[0-9]]\{1,2\}\).*$/\1/')
|
||||
|
||||
if test "$major_version_num" -lt '10'; then
|
||||
version_num=$(echo "$pgac_pg_config_version"|
|
||||
$SED -e 's/^PostgreSQL \([[0-9]]*\)\.\([[0-9]]*\)\([[a-zA-Z0-9.]]*\)$/\1.\2/')
|
||||
$SED -e 's/^[[^0-9]]\+ \([[0-9]]*\)\.\([[0-9]]*\)\([[a-zA-Z0-9.]]*\)$/\1.\2/')
|
||||
|
||||
if test -z "$version_num"; then
|
||||
AC_MSG_ERROR([could not detect the PostgreSQL version, wrong or broken pg_config?])
|
||||
@@ -37,7 +37,7 @@ if test "$major_version_num" -lt '10'; then
|
||||
fi
|
||||
else
|
||||
version_num=$(echo "$pgac_pg_config_version"|
|
||||
$SED -e 's/^PostgreSQL \(.\+\)$/\1/')
|
||||
$SED -e 's/^[[^0-9]]\+ \(.\+\)$/\1/')
|
||||
|
||||
if test -z "$version_num"; then
|
||||
AC_MSG_ERROR([could not detect the PostgreSQL version, wrong or broken pg_config?])
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
* controldata.c - functions for reading the pg_control file
|
||||
*
|
||||
* The functions provided here enable repmgr to read a pg_control file
|
||||
* in a version-indepent way, even if the PostgreSQL instance is not
|
||||
* in a version-independent way, even if the PostgreSQL instance is not
|
||||
* running. For that reason we can't use on the pg_control_*() functions
|
||||
* provided in PostgreSQL 9.6 and later.
|
||||
*
|
||||
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
||||
*
|
||||
* Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* controldata.h
|
||||
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
||||
*
|
||||
* Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
|
||||
45
dbutils.c
45
dbutils.c
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* dbutils.c - Database connection/management functions
|
||||
*
|
||||
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
||||
*
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
@@ -730,6 +730,8 @@ validate_conninfo_string(const char *conninfo_str, char **errmsg)
|
||||
if (connOptions == NULL)
|
||||
return false;
|
||||
|
||||
PQconninfoFree(connOptions);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -4240,7 +4242,7 @@ _create_event(PGconn *conn, t_configuration_options *options, int node_id, char
|
||||
}
|
||||
break;
|
||||
case 'p':
|
||||
/* %p: primary id ("standby_switchover": former primary id) */
|
||||
/* %p: primary id ("standby_switchover"/"repmgrd_failover_promote": former primary id) */
|
||||
src_ptr++;
|
||||
if (event_info->node_id != UNKNOWN_NODE_ID)
|
||||
{
|
||||
@@ -4825,7 +4827,7 @@ cancel_query(PGconn *conn, int timeout)
|
||||
* Wait until current query finishes, ignoring any results.
|
||||
* Usually this will be an async query or query cancellation.
|
||||
*
|
||||
* Returns 1 for success; 0 if any error ocurred; -1 if timeout reached.
|
||||
* Returns 1 for success; 0 if any error occurred; -1 if timeout reached.
|
||||
*/
|
||||
int
|
||||
wait_connection_availability(PGconn *conn, int timeout)
|
||||
@@ -6006,6 +6008,43 @@ is_wal_replay_paused(PGconn *conn, bool check_pending_wal)
|
||||
return is_paused;
|
||||
}
|
||||
|
||||
/* repmgrd status functions */
|
||||
|
||||
CheckStatus
|
||||
get_repmgrd_status(PGconn *conn)
|
||||
{
|
||||
PQExpBufferData query;
|
||||
PGresult *res = NULL;
|
||||
CheckStatus repmgrd_status = CHECK_STATUS_CRITICAL;
|
||||
|
||||
initPQExpBuffer(&query);
|
||||
|
||||
appendPQExpBufferStr(&query,
|
||||
" SELECT "
|
||||
" CASE "
|
||||
" WHEN repmgr.repmgrd_is_running() "
|
||||
" THEN "
|
||||
" CASE "
|
||||
" WHEN repmgr.repmgrd_is_paused() THEN 1 ELSE 0 "
|
||||
" END "
|
||||
" ELSE 2 "
|
||||
" END AS repmgrd_status");
|
||||
res = PQexec(conn, query.data);
|
||||
|
||||
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
||||
{
|
||||
log_db_error(conn, query.data, _("unable to execute repmgrd status query"));
|
||||
}
|
||||
else
|
||||
{
|
||||
repmgrd_status = atoi(PQgetvalue(res, 0, 0));
|
||||
}
|
||||
|
||||
termPQExpBuffer(&query);
|
||||
PQclear(res);
|
||||
return repmgrd_status;
|
||||
}
|
||||
|
||||
|
||||
/* miscellaneous debugging functions */
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* dbutils.h
|
||||
*
|
||||
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
||||
*
|
||||
* 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
|
||||
@@ -602,6 +602,9 @@ int get_upstream_last_seen(PGconn *conn, t_server_type node_type);
|
||||
|
||||
bool is_wal_replay_paused(PGconn *conn, bool check_pending_wal);
|
||||
|
||||
/* repmgrd status functions */
|
||||
CheckStatus get_repmgrd_status(PGconn *conn);
|
||||
|
||||
/* miscellaneous debugging functions */
|
||||
const char *print_node_status(NodeStatus node_status);
|
||||
const char *print_pqping_status(PGPing ping_status);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* dirmod.c
|
||||
* directory handling functions
|
||||
*
|
||||
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
||||
*
|
||||
* 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
|
||||
@@ -205,7 +205,7 @@ mkdir_p(char *path, mode_t omode)
|
||||
/*
|
||||
* POSIX 1003.2: For each dir operand that does not name an
|
||||
* existing directory, effects equivalent to those caused by the
|
||||
* following command shall occcur:
|
||||
* following command shall occur:
|
||||
*
|
||||
* mkdir -p -m $(umask -S),u+wx $(dirname dir) && mkdir [-m mode]
|
||||
* dir
|
||||
@@ -289,7 +289,7 @@ is_pg_running(const char *path)
|
||||
{
|
||||
/*
|
||||
* No PID file - PostgreSQL shouldn't be running. From 9.3 (the
|
||||
* earliesty version we care about) removal of the PID file will
|
||||
* earliest version we care about) removal of the PID file will
|
||||
* cause the postmaster to shut down, so it's highly unlikely
|
||||
* that PostgreSQL will still be running.
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* dirutil.h
|
||||
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
||||
*
|
||||
* 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
|
||||
|
||||
@@ -95,6 +95,7 @@ clean:
|
||||
rm -f repmgr.html
|
||||
rm -f repmgr-A4.pdf
|
||||
rm -f repmgr-US.pdf
|
||||
rm -f *.fo
|
||||
rm -f html/*
|
||||
|
||||
maintainer-clean:
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
|
||||
<tip>
|
||||
<para>
|
||||
2ndQuadrant's recommended configuration is to configure
|
||||
Our recommended configuration is to configure
|
||||
<ulink url="https://www.pgbarman.org/">Barman</ulink> as a fallback
|
||||
source of WAL files, rather than maintain replication slots for
|
||||
each standby. See also: <link linkend="cloning-from-barman-restore-command">Using Barman as a WAL file source</link>.
|
||||
@@ -127,7 +127,7 @@
|
||||
filesystem layouts.
|
||||
</para>
|
||||
<para>
|
||||
Either use PostgreSQL packages provided by the community or 2ndQuadrant; if this
|
||||
Either use PostgreSQL packages provided by the community or EnterpriseDB; if this
|
||||
is not possible, contact your vendor for assistance.
|
||||
</para>
|
||||
</sect2>
|
||||
@@ -170,7 +170,7 @@
|
||||
<para>
|
||||
If different "minor" &repmgr; versions (e.g. 4.1.1 and 4.1.6) are installed,
|
||||
&repmgr; will function, but we strongly recommend always running the same version
|
||||
to ensure there are no unexpected suprises, e.g. a newer version behaving slightly
|
||||
to ensure there are no unexpected surprises, e.g. a newer version behaving slightly
|
||||
differently to the older version.
|
||||
</para>
|
||||
<para>
|
||||
@@ -212,11 +212,11 @@
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="faq-third-party-packages" xreflabel="Compatability with third party vendor packages">
|
||||
<sect2 id="faq-third-party-packages" xreflabel="Compatibility with third party vendor packages">
|
||||
<title>Are &repmgr; packages compatible with <literal>$third_party_vendor</literal>'s packages?</title>
|
||||
<para>
|
||||
&repmgr; packages provided by 2ndQuadrant are compatible with the community-provided PostgreSQL
|
||||
packages and any software provided by 2ndQuadrant.
|
||||
&repmgr; packages provided by EnterpriseDB are compatible with the community-provided PostgreSQL
|
||||
packages and specified software provided by EnterpriseDB.
|
||||
</para>
|
||||
<para>
|
||||
A number of other vendors provide their own versions of PostgreSQL packages, often with different
|
||||
@@ -311,7 +311,7 @@
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="faq-repmgr-shared-preload-libaries-no-repmgrd" xreflabel="shared_preload_libraries without repmgrd">
|
||||
<sect2 id="faq-repmgr-shared-preload-libraries-no-repmgrd" xreflabel="shared_preload_libraries without repmgrd">
|
||||
<title>Do I need to include <literal>shared_preload_libraries = 'repmgr'</literal>
|
||||
in <filename>postgresql.conf</filename> if I'm not using &repmgrd;?</title>
|
||||
<para>
|
||||
@@ -459,7 +459,7 @@
|
||||
</title>
|
||||
<para>
|
||||
<varname>promote_command</varname> or <varname>follow_command</varname> can be user-defined scripts,
|
||||
so &repmgr; will not apply <option>pg_bindir</option> even if excuting &repmgr;. Always provide the full
|
||||
so &repmgr; will not apply <option>pg_bindir</option> even if executing &repmgr;. Always provide the full
|
||||
path; see <xref linkend="repmgrd-automatic-failover-configuration"/> for more details.
|
||||
</para>
|
||||
</sect2>
|
||||
@@ -479,7 +479,7 @@
|
||||
is out-of-date, which may lead to incorrect failover behaviour.
|
||||
</para>
|
||||
<para>
|
||||
The onus is therefore on the adminstrator to manually set the cluster to a stable, healthy state before
|
||||
The onus is therefore on the administrator to manually set the cluster to a stable, healthy state before
|
||||
starting &repmgrd;.
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
@@ -52,8 +52,7 @@
|
||||
<para>
|
||||
&repmgr; packages are available from the public 2ndQuadrant repository, and also the
|
||||
PostgreSQL community repository. The 2ndQuadrant repository is updated immediately
|
||||
after each
|
||||
&repmgr; release.
|
||||
after each &repmgr; release.
|
||||
</para>
|
||||
|
||||
<table id="centos-2ndquadrant-repository">
|
||||
@@ -398,7 +397,7 @@
|
||||
</indexterm>
|
||||
<indexterm>
|
||||
<primary>packages</primary>
|
||||
<secondary>snaphots</secondary>
|
||||
<secondary>snapshots</secondary>
|
||||
</indexterm>
|
||||
|
||||
<para>
|
||||
@@ -439,7 +438,7 @@ curl https://dl.2ndquadrant.com/default/snapshot/get/9.6/rpm | sudo bash</progra
|
||||
The package name will be formatted like this:
|
||||
<programlisting>
|
||||
repmgr96-4.1.1-0.0git320.g5113ab0.1.el7.x86_64.rpm</programlisting>
|
||||
containg the snapshot build number (here: <literal>320</literal>) and the hash
|
||||
containing the snapshot build number (here: <literal>320</literal>) and the hash
|
||||
of the <application>git</application> commit it was built from (here: <literal>g5113ab0</literal>).
|
||||
</para>
|
||||
|
||||
|
||||
@@ -16,9 +16,149 @@
|
||||
</para>
|
||||
|
||||
<!-- remember to update the release date in ../repmgr_version.h.in -->
|
||||
<sect1 id="release-5.3.1">
|
||||
<title id="release-current">Release 5.3.1</title>
|
||||
<para><emphasis>Tue 15 February, 2022</emphasis></para>
|
||||
<para>
|
||||
&repmgr; 5.3.1 is a minor release.
|
||||
</para>
|
||||
<sect2>
|
||||
<title>Bug fixes</title>
|
||||
<para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
Fix upgrade path from &repmgr; 4.2 and 4.3 to &repmgr; 5.3.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
&repmgrd;: ensure potentially open connections are closed.
|
||||
</para>
|
||||
<para>
|
||||
In some cases, when recovering from degraded state in local node monitoring,
|
||||
new connection was opened to the local node without closing
|
||||
the old one, which will result in memory leakage.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
</sect2>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="release-5.3.0">
|
||||
<title>Release 5.3.0</title>
|
||||
<para><emphasis>Tue 12 October, 2021</emphasis></para>
|
||||
<para>
|
||||
&repmgr; 5.3.0 is a major release.
|
||||
</para>
|
||||
<para>
|
||||
This release provides support for <ulink url="https://www.postgresql.org/docs/14/release-14.html">PostgreSQL 14</ulink>,
|
||||
released in September 2021.
|
||||
</para>
|
||||
<sect2>
|
||||
<title>Improvements</title>
|
||||
<para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
<link linkend="repmgr-standby-switchover"><command>repmgr standby switchover</command></link>:
|
||||
Improve handling of node rejoin failure on the demotion candidate.
|
||||
</para>
|
||||
<para>
|
||||
Previously &repmgr; did not check whether <command>repmgr node rejoin</command> actually
|
||||
succeeded on the demotion candidate, and would always wait up to <varname>node_rejoin_timeout</varname>
|
||||
seconds for it to attach to the promotion candidate, even if this would never happen.
|
||||
</para>
|
||||
<para>
|
||||
This makes it easier to identify unexpected events during a switchover operation, such as
|
||||
the demotion candidate being unexpectedly restarted by an external process.
|
||||
</para>
|
||||
<para>
|
||||
Note that the output of the <link linkend="repmgr-node-rejoin"><command>repmgr node rejoin</command></link>
|
||||
operation on the demotion candidate will now be logged to a temporary file on that node;
|
||||
the location of the file will be reported in the error message, if one is emitted.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
&repmgrd;: at startup, if node record is marked as "inactive", attempt
|
||||
to set it to "active".
|
||||
</para>
|
||||
<para>
|
||||
This behaviour can be overridden by setting the configuration parameter
|
||||
<varname>repmgrd_exit_on_inactive_node</varname> to <literal>true</literal>.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<command><link linkend="repmgr-node-rejoin">repmgr node rejoin</link></command>:
|
||||
emit rejoin target note information as <literal>NOTICE</literal>.
|
||||
</para>
|
||||
<para>
|
||||
This makes it clearer what &repmgr; is trying to do.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
<link linkend="repmgr-node-check">repmgr node check</link>:
|
||||
option <option>--repmgrd</option> added to check &repmgrd;
|
||||
status.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
Add <literal>%p</literal> <link linkend="event-notifications">event notification parameter</link>
|
||||
providing the node ID of the former primary for the <literal>repmgrd_failover_promote</literal> event.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
</itemizedlist>
|
||||
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
<sect2>
|
||||
<title>Bug fixes</title>
|
||||
<para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
<command><link linkend="repmgr-standby-clone">repmgr standby clone</link></command>:
|
||||
if using <option>--replication-conf-only</option> on a node
|
||||
which was set up without replication slots, but the &repmgr; configuration
|
||||
was since changed to <option>use_replication_slots=1</option>,
|
||||
&repmgr; will now set <varname>slot_name</varname> in the
|
||||
node record, if it was previously empty.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
&repmgrd;: rename internal shared library functions to minimize the
|
||||
risk of clashes with other shared libraries.
|
||||
</para>
|
||||
<para>
|
||||
This does not affect user-facing SQL functions. However an upgrade
|
||||
of the installed extension version is required.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
&repmgrd;: ensure short option <option>-s</option> is accepted.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
</sect2>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="release-5.2.1">
|
||||
<title id="release-current">Release 5.2.1</title>
|
||||
<title>Release 5.2.1</title>
|
||||
<para><emphasis>Mon 7 December, 2020</emphasis></para>
|
||||
|
||||
<para>
|
||||
@@ -1199,7 +1339,7 @@ REPMGRD_OPTS="--daemonize=false"</programlisting>
|
||||
</para>
|
||||
<para>
|
||||
Possible values are <literal>ping</literal> (default; uses <command>PQping()</command> to
|
||||
determine server availability), <literal>connection</literal> (attempst to make a new connection to
|
||||
determine server availability), <literal>connection</literal> (attempts to make a new connection to
|
||||
the upstream node), and <literal>query</literal> (determines server availability
|
||||
by executing an SQL statement on the node via the existing connection).
|
||||
</para>
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
A mailing list/forum is provided via Google groups to discuss contributions or issues: <ulink url="https://groups.google.com/group/repmgr">https://groups.google.com/group/repmgr</ulink>.
|
||||
</para>
|
||||
<para>
|
||||
Please report bugs and other issues to: <ulink url="https://github.com/2ndQuadrant/repmgr">https://github.com/2ndQuadrant/repmgr</ulink>.
|
||||
Please report bugs and other issues to: <ulink url="https://github.com/EnterpriseDB/repmgr">https://github.com/EnterpriseDB/repmgr</ulink>.
|
||||
</para>
|
||||
|
||||
<important>
|
||||
@@ -64,7 +64,7 @@
|
||||
|
||||
<listitem>
|
||||
<simpara>
|
||||
<filename>repmpgr.conf</filename> files (suitably anonymized if necessary)
|
||||
<filename>repmgr.conf</filename> files (suitably anonymized if necessary)
|
||||
</simpara>
|
||||
</listitem>
|
||||
|
||||
|
||||
@@ -319,7 +319,7 @@ description = "Main cluster"
|
||||
Cascading replication, introduced with PostgreSQL 9.2, enables a standby server
|
||||
to replicate from another standby server rather than directly from the primary,
|
||||
meaning replication changes "cascade" down through a hierarchy of servers. This
|
||||
can be used to reduce load on the primary and minimize bandwith usage between
|
||||
can be used to reduce load on the primary and minimize bandwidth usage between
|
||||
sites. For more details, see the
|
||||
<ulink url="https://www.postgresql.org/docs/current/warm-standby.html#CASCADING-REPLICATION">
|
||||
PostgreSQL cascading replication documentation</ulink>.
|
||||
@@ -391,7 +391,7 @@ description = "Main cluster"
|
||||
cluster, you may wish to clone a downstream standby whose upstream node
|
||||
does not yet exist. In this case you can clone from the primary (or
|
||||
another upstream node); provide the parameter <literal>--upstream-conninfo</literal>
|
||||
to explictly set the upstream's <varname>primary_conninfo</varname> string
|
||||
to explicitly set the upstream's <varname>primary_conninfo</varname> string
|
||||
in <filename>recovery.conf</filename>.
|
||||
</simpara>
|
||||
</tip>
|
||||
|
||||
@@ -7,6 +7,14 @@
|
||||
<secondary>optional settings</secondary>
|
||||
</indexterm>
|
||||
|
||||
<note>
|
||||
<simpara>
|
||||
This section documents a subset of optional configuration settings; for a full
|
||||
for a full and annotated view of all configuration options see the
|
||||
see the <ulink url="https://raw.githubusercontent.com/EnterpriseDB/repmgr/master/repmgr.conf.sample">sample repmgr.conf file</ulink>
|
||||
</simpara>
|
||||
</note>
|
||||
|
||||
<variablelist>
|
||||
|
||||
|
||||
@@ -132,5 +140,50 @@ ssh_options='-q -o ConnectTimeout=10'</programlisting>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry id="repmgr-conf-pg-bindir" xreflabel="pg_bindir">
|
||||
<term><varname>pg_bindir</varname> (<type>string</type>)
|
||||
<indexterm>
|
||||
<primary><varname>pg_bindir</varname> configuration file parameter</primary>
|
||||
</indexterm>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Path to the PostgreSQL binary directory (location of <application>pg_ctl</application>,
|
||||
<application>pg_basebackup</application> etc.). Only required
|
||||
if these are not in the system <varname>PATH</varname>.
|
||||
</para>
|
||||
<tip>
|
||||
<para>
|
||||
When &repmgr; is executed via <application>SSH</application> (e.g. when running
|
||||
<command><link linkend="repmgr-standby-switchover">repmgr standby switchover</link></command>,
|
||||
<command><link linkend="repmgr-cluster-matrix">repmgr cluster matrix</link></command> or
|
||||
<command><link linkend="repmgr-cluster-crosscheck">repmgr cluster crosscheck</link></command>,
|
||||
or if it is executed as cronjob), a login shell will not be used and only the
|
||||
default system <varname>PATH</varname> will be set. Therefore it's recommended to set
|
||||
<varname>pg_bindir</varname> so &repmgr; can correctly invoke binaries on a remote
|
||||
system and avoid potential path issues.
|
||||
</para>
|
||||
</tip>
|
||||
|
||||
<para>
|
||||
Debian/Ubuntu users: you will probably need to set this to the directory where
|
||||
<application>pg_ctl</application> is located, e.g. <filename>/usr/lib/postgresql/9.6/bin/</filename>.
|
||||
</para>
|
||||
<para>
|
||||
<emphasis>NOTE</emphasis>: <varname>pg_bindir</varname> is only used when &repmgr; directly
|
||||
executes PostgreSQL binaries; any user-defined scripts
|
||||
<emphasis>must</emphasis> be specified with the full path.
|
||||
</para>
|
||||
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
|
||||
<tip>
|
||||
<simpara>
|
||||
See the <ulink url="https://raw.githubusercontent.com/EnterpriseDB/repmgr/master/repmgr.conf.sample">sample repmgr.conf file</ulink>
|
||||
for a full and annotated view of all configuration options.
|
||||
</simpara>
|
||||
</tip>
|
||||
|
||||
</sect1>
|
||||
|
||||
@@ -96,6 +96,9 @@
|
||||
</variablelist>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
See <xref linkend="configuration-file-optional-settings"/> for further configuration options.
|
||||
</para>
|
||||
|
||||
|
||||
</sect1>
|
||||
|
||||
@@ -27,7 +27,9 @@
|
||||
<note>
|
||||
<para>
|
||||
If using <application>systemd</application>, ensure you have <varname>RemoveIPC</varname> set to <literal>off</literal>.
|
||||
See the <ulink url="https://wiki.postgresql.org/wiki/Systemd">systemd</ulink>
|
||||
See the <ulink url="https://www.postgresql.org/docs/current/index.html">PostgreSQL documentation</ulink> section
|
||||
<ulink url="https://www.postgresql.org/docs/current/kernel-resources.html#SYSTEMD-REMOVEIPC">systemd RemoveIPC</ulink>
|
||||
and also the <ulink url="https://wiki.postgresql.org/wiki/Systemd">systemd</ulink>
|
||||
entry in the <ulink url="https://wiki.postgresql.org/wiki/Main_Page">PostgreSQL wiki</ulink> for details.
|
||||
</para>
|
||||
</note>
|
||||
|
||||
@@ -262,7 +262,7 @@ conninfo='host=node1 user=repmgr dbname=repmgr connect_timeout=2'</programlistin
|
||||
|
||||
<indexterm>
|
||||
<primary>repmgr.conf</primary>
|
||||
<secondary>ostgreSQL major version upgrades</secondary>
|
||||
<secondary>PostgreSQL major version upgrades</secondary>
|
||||
</indexterm>
|
||||
|
||||
<para>
|
||||
|
||||
@@ -95,7 +95,8 @@
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The following parameters are provided for a subset of event notifications:
|
||||
The following parameters are provided for a subset of event notifications; their meaning may
|
||||
change according to context:
|
||||
</para>
|
||||
|
||||
<variablelist>
|
||||
@@ -108,6 +109,9 @@
|
||||
<para>
|
||||
node ID of the demoted primary (<xref linkend="repmgr-standby-switchover"/> only)
|
||||
</para>
|
||||
<para>
|
||||
node ID of the former primary (<literal>repmgrd_failover_promote</literal> only)
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
@@ -133,7 +137,7 @@
|
||||
|
||||
<para>
|
||||
The values provided for <literal>%c</literal> and <literal>%a</literal>
|
||||
will probably contain spaces, so should always be quoted.
|
||||
may contain spaces, so should always be quoted.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
|
||||
@@ -93,7 +93,7 @@
|
||||
<table id="repmgr-compatibility-matrix">
|
||||
<title>&repmgr; compatibility matrix</title>
|
||||
|
||||
<tgroup cols="3">
|
||||
<tgroup cols="4">
|
||||
<thead>
|
||||
<row>
|
||||
<entry>
|
||||
@@ -112,10 +112,9 @@
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
|
||||
<row>
|
||||
<entry>
|
||||
&repmgr; 5.2
|
||||
&repmgr; 5.3
|
||||
</entry>
|
||||
<entry>
|
||||
YES
|
||||
@@ -123,6 +122,21 @@
|
||||
<entry>
|
||||
<link linkend="release-current">&repmgrversion;</link> (&releasedate;)
|
||||
</entry>
|
||||
<entry>
|
||||
9.4, 9.5, 9.6, 10, 11, 12, 13, 14
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>
|
||||
&repmgr; 5.2
|
||||
</entry>
|
||||
<entry>
|
||||
NO
|
||||
</entry>
|
||||
<entry>
|
||||
<link linkend="release-5.2.1">5.2.1</link> (2020-12-07)
|
||||
</entry>
|
||||
<entry>
|
||||
9.4, 9.5, 9.6, 10, 11, 12, 13
|
||||
</entry>
|
||||
|
||||
@@ -178,18 +178,18 @@ deb-src https://apt.postgresql.org/pub/repos/apt/ stretch-pgdg main</programlist
|
||||
|
||||
<para>
|
||||
The source for &repmgr; is maintained at
|
||||
<ulink url="https://github.com/2ndQuadrant/repmgr">https://github.com/2ndQuadrant/repmgr</ulink>.
|
||||
<ulink url="https://github.com/EnterpriseDB/repmgr">https://github.com/EnterpriseDB/repmgr</ulink>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
There are also tags for each <ulink url="https://github.com/2ndQuadrant/repmgr/releases">&repmgr; release</ulink>, e.g.
|
||||
<literal><ulink url="https://github.com/2ndQuadrant/repmgr/releases/tag/v4.4.0">v4.4.0</ulink></literal>.
|
||||
There are also tags for each <ulink url="https://github.com/EnterpriseDB/repmgr/releases">&repmgr; release</ulink>, e.g.
|
||||
<literal><ulink url="https://github.com/EnterpriseDB/repmgr/releases/tag/v4.4.0">v4.4.0</ulink></literal>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Clone the source code using <application>git</application>:
|
||||
<programlisting>
|
||||
git clone https://github.com/2ndQuadrant/repmgr</programlisting>
|
||||
git clone https://github.com/EnterpriseDB/repmgr</programlisting>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
|
||||
@@ -3,16 +3,16 @@
|
||||
<date>2017</date>
|
||||
|
||||
<copyright>
|
||||
<year>2010-2020</year>
|
||||
<holder>2ndQuadrant, Ltd.</holder>
|
||||
<year>2010-2021</year>
|
||||
<holder>EnterpriseDB Corporation</holder>
|
||||
</copyright>
|
||||
|
||||
<legalnotice id="legalnotice">
|
||||
<title>Legal Notice</title>
|
||||
|
||||
<para>
|
||||
<productname>repmgr</productname> is Copyright © 2010-2020
|
||||
by 2ndQuadrant, Ltd. All rights reserved.
|
||||
<productname>repmgr</productname> is Copyright © 2010-2021
|
||||
by EnterpriseDB Corporation All rights reserved.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
|
||||
@@ -284,7 +284,7 @@
|
||||
|
||||
<tip>
|
||||
<simpara>
|
||||
For Debian-based distributions we recommend explictly setting
|
||||
For Debian-based distributions we recommend explicitly setting
|
||||
<option>pg_bindir</option> to the directory where <command>pg_ctl</command> and other binaries
|
||||
not in the standard path are located. For PostgreSQL 9.6 this would be <filename>/usr/lib/postgresql/9.6/bin/</filename>.
|
||||
</simpara>
|
||||
@@ -302,7 +302,7 @@
|
||||
|
||||
<para>
|
||||
See the file
|
||||
<ulink url="https://raw.githubusercontent.com/2ndQuadrant/repmgr/master/repmgr.conf.sample">repmgr.conf.sample</ulink>
|
||||
<ulink url="https://raw.githubusercontent.com/EnterpriseDB/repmgr/master/repmgr.conf.sample">repmgr.conf.sample</ulink>
|
||||
for details of all available configuration parameters.
|
||||
</para>
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
</para>
|
||||
<para>
|
||||
By default, &repmgr; will wait for up to 15 seconds to confirm that &repmgrd;
|
||||
started. This behaviour can be overridden by specifying a diffent value using the <option>--wait</option>
|
||||
started. This behaviour can be overridden by specifying a different value using the <option>--wait</option>
|
||||
option, or disabled altogether with the <option>--no-wait</option> option.
|
||||
</para>
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
<para>
|
||||
By default, &repmgr; will wait for up to 15 seconds to confirm that &repmgrd;
|
||||
stopped. This behaviour can be overridden by specifying a diffent value using the <option>--wait</option>
|
||||
stopped. This behaviour can be overridden by specifying a different value using the <option>--wait</option>
|
||||
option, or disabled altogether with the <option>--no-wait</option> option.
|
||||
</para>
|
||||
<note>
|
||||
|
||||
@@ -125,12 +125,29 @@
|
||||
is correctly configured.
|
||||
</simpara>
|
||||
</listitem>
|
||||
|
||||
|
||||
</itemizedlist>
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
|
||||
<refsect1>
|
||||
<title>repmgrd</title>
|
||||
<para>
|
||||
A separate check is available to verify whether &repmgrd; is running,
|
||||
This is not included in the general output, as this does not
|
||||
per-se constitute a check of the node's replication status.
|
||||
</para>
|
||||
<itemizedlist spacing="compact" mark="bullet">
|
||||
<listitem>
|
||||
<simpara>
|
||||
<option>--repmgrd</option>: checks whether &repmgrd; is running.
|
||||
If &repmgrd; is running but paused, status <literal>1</literal>
|
||||
(<literal>WARNING</literal>) is returned.
|
||||
</simpara>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Additional checks</title>
|
||||
<para>
|
||||
|
||||
@@ -22,6 +22,10 @@
|
||||
This can optionally use <application>pg_rewind</application> to re-integrate
|
||||
a node which has diverged from the rest of the cluster, typically a failed primary.
|
||||
</para>
|
||||
<para>
|
||||
Note that <command>repmgr node rejoin</command> can only be used to attach
|
||||
a standby to the current primary, not another standby.
|
||||
</para>
|
||||
|
||||
<tip>
|
||||
<para>
|
||||
@@ -281,6 +285,7 @@
|
||||
<programlisting>
|
||||
$ repmgr node rejoin -f /etc/repmgr.conf -d 'host=node3 dbname=repmgr user=repmgr' \
|
||||
--force-rewind --config-files=postgresql.local.conf,postgresql.conf --verbose --dry-run
|
||||
NOTICE: rejoin target is node "node3" (node ID: 3)
|
||||
INFO: replication connection to the rejoin target node was successful
|
||||
INFO: local and rejoin target system identifiers match
|
||||
DETAIL: system identifier is 6652184002263212600
|
||||
@@ -339,6 +344,7 @@
|
||||
<programlisting>
|
||||
$ repmgr node rejoin -f /etc/repmgr.conf -d 'host=node3 dbname=repmgr user=repmgr' \
|
||||
--config-files=postgresql.local.conf,postgresql.conf --verbose --force-rewind --dry-run
|
||||
NOTICE: rejoin target is node "node3" (node ID: 3)
|
||||
INFO: replication connection to the rejoin target node was successful
|
||||
INFO: local and rejoin target system identifiers match
|
||||
DETAIL: system identifier is 6652460429293670710
|
||||
@@ -449,15 +455,16 @@
|
||||
</para>
|
||||
<para>
|
||||
Currently it is not possible to resolve this situation using <application>pg_rewind</application>.
|
||||
A <ulink url="https://www.postgresql.org/message-id/flat/CABvVfJU-LDWvoz4-Yow3Ay5LZYTuPD7eSjjE4kGyNZpXC6FrVQ@mail.gmail.com">patch</ulink>
|
||||
has been submitted and will hopefully be included in a forthcoming PostgreSQL minor release.
|
||||
A <ulink url="https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=2b4f3130382fe2f8705863e4d38589d4d69cd695">patch</ulink>
|
||||
has been successfully submitted and will be included the next PostgreSQL minor release round, scheduled for
|
||||
February 2021.
|
||||
</para>
|
||||
<para>
|
||||
As a workaround, start the primary server the standby was previously attached to,
|
||||
and ensure the standby can be attached to it. If <application>pg_rewind</application> was actually executed,
|
||||
it will have copied in the <filename>.history</filename> file from the target primary server; this must
|
||||
be removed. <command>repmgr node rejoin</command> can then be used to attach the standby to the original
|
||||
primary. Ensure any changes pending on the primary have propogated to the standby. Then shut down the primary
|
||||
primary. Ensure any changes pending on the primary have propagated to the standby. Then shut down the primary
|
||||
server <emphasis>first</emphasis>, before shutting down the standby. It should then be possible to
|
||||
use <command>repmgr node rejoin</command> to attach the standby to the new primary.
|
||||
</para>
|
||||
|
||||
@@ -189,14 +189,14 @@
|
||||
</listitem>
|
||||
<listitem>
|
||||
<simpara>
|
||||
If the promotion candidate has insufficient free walsenders to accomodate the standbys which will
|
||||
If the promotion candidate has insufficient free walsenders to accommodate the standbys which will
|
||||
be attached to it, the standby will be promoted anyway.
|
||||
</simpara>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<simpara>
|
||||
If replication slots are in use but the promotion candidate has insufficient free replication slots
|
||||
to accomodate the standbys which will be attached to it, the standby will be promoted anyway.
|
||||
to accommodate the standbys which will be attached to it, the standby will be promoted anyway.
|
||||
</simpara>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
<title>repmgr &repmgrversion; Documentation</title>
|
||||
|
||||
<bookinfo>
|
||||
<corpauthor>2ndQuadrant Ltd</corpauthor>
|
||||
<corpauthor>EnterpriseDB Corporation</corpauthor>
|
||||
<productname>repmgr</productname>
|
||||
<productnumber>&repmgrversion;</productnumber>
|
||||
&legal;
|
||||
@@ -26,7 +26,7 @@
|
||||
<abstract>
|
||||
<para>
|
||||
This is the official documentation of &repmgr; &repmgrversion; for
|
||||
use with PostgreSQL 9.4 - PostgreSQL 13.
|
||||
use with PostgreSQL 9.4 - PostgreSQL 14.
|
||||
</para>
|
||||
<para>
|
||||
&repmgr; is being continually developed and we strongly recommend using the
|
||||
@@ -38,20 +38,20 @@
|
||||
|
||||
<para>
|
||||
&repmgr; is developed by
|
||||
<ulink url="https://2ndquadrant.com">2ndQuadrant</ulink>
|
||||
<ulink url="https://2ndquadrant.com">2ndQuadrant (EDB)</ulink>
|
||||
along with contributions from other individuals and organisations.
|
||||
Contributions from the community are appreciated and welcome - get
|
||||
in touch via <ulink url="https://github.com/2ndQuadrant/repmgr">github</ulink>
|
||||
in touch via <ulink url="https://github.com/EnterpriseDB/repmgr">github</ulink>
|
||||
or <ulink url="https://groups.google.com/group/repmgr">the mailing list/forum</ulink>.
|
||||
Multiple 2ndQuadrant customers contribute funding
|
||||
Multiple 2ndQuadrant (EDB) customers contribute funding
|
||||
to make repmgr development possible.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
&repmgr; is fully supported by 2ndQuadrant's
|
||||
&repmgr; is fully supported by 2ndQuadrant (EDB)'s
|
||||
<ulink url="https://www.2ndquadrant.com/en/support/support-postgresql/">24/7 Production Support</ulink>.
|
||||
2ndQuadrant, a Major Sponsor of the PostgreSQL project, continues to develop and maintain &repmgr;.
|
||||
Other organisations as well as individual developers are welcome to participate in the efforts.
|
||||
EnterpriseDB Corporation, a Major Sponsor of the PostgreSQL project, continues to maintain &repmgr;.
|
||||
We welcome participation from other organisations and individual developers.
|
||||
</para>
|
||||
</abstract>
|
||||
|
||||
|
||||
@@ -586,7 +586,7 @@ INFO: node 3 received notification to rerun promotion candidate election
|
||||
<sect2 id="repmgrd-primary-child-disconnection-caveats">
|
||||
<title>Standby disconnections monitoring caveats</title>
|
||||
<para>
|
||||
The follwing caveats should be considered if you are intending to use this functionality.
|
||||
The following caveats should be considered if you are intending to use this functionality.
|
||||
</para>
|
||||
<para>
|
||||
<itemizedlist mark="bullet">
|
||||
|
||||
@@ -89,6 +89,10 @@
|
||||
<literal>query</literal> - determines server availability
|
||||
by executing an SQL statement on the node via the existing connection
|
||||
</simpara>
|
||||
<simpara>
|
||||
The query is a minimal throwaway query - <command>SELECT 1</command> -
|
||||
which is used to determine that the server can accept queries.
|
||||
</simpara>
|
||||
</listitem>
|
||||
|
||||
</itemizedlist>
|
||||
@@ -152,7 +156,7 @@
|
||||
</variablelist>
|
||||
|
||||
<para>
|
||||
See also <filename><ulink url="https://raw.githubusercontent.com/2ndQuadrant/repmgr/master/repmgr.conf.sample">repmgr.conf.sample</ulink></filename> for an annotated sample configuration file.
|
||||
See also <filename><ulink url="https://raw.githubusercontent.com/EnterpriseDB/repmgr/master/repmgr.conf.sample">repmgr.conf.sample</ulink></filename> for an annotated sample configuration file.
|
||||
</para>
|
||||
|
||||
<sect2 id="repmgrd-automatic-failover-configuration">
|
||||
@@ -329,7 +333,7 @@
|
||||
<title>Optional configuration for automatic failover</title>
|
||||
|
||||
<para>
|
||||
The following configuraton options can be use to fine-tune automatic failover:
|
||||
The following configuraton options can be used to fine-tune automatic failover:
|
||||
</para>
|
||||
<variablelist>
|
||||
|
||||
@@ -481,6 +485,32 @@
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
|
||||
<term><option>repmgrd_exit_on_inactive_node</option></term>
|
||||
<listitem>
|
||||
<indexterm>
|
||||
<primary>repmgrd_exit_on_inactive_node</primary>
|
||||
</indexterm>
|
||||
<para>
|
||||
This parameter is available in &repmgr; 5.3 and later.
|
||||
</para>
|
||||
<para>
|
||||
If a node was marked as inactive but is running, and this option is set to
|
||||
<literal>true</literal>, &repmgrd; will abort on startup.
|
||||
</para>
|
||||
<para>
|
||||
By default, <option>repmgrd_exit_on_inactive_node</option> is set
|
||||
to <literal>false</literal>, in which case &repmgrd; will set the
|
||||
node record to active on startup.
|
||||
</para>
|
||||
<para>
|
||||
Setting this parameter to <literal>true</literal> causes &repmgrd;
|
||||
to behave in the same way it did in &repmgr; 5.2 and earlier.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
|
||||
<para>
|
||||
@@ -539,7 +569,7 @@
|
||||
</indexterm>
|
||||
<para>
|
||||
For further details and a reference implementation, see the separate document
|
||||
<ulink url="https://github.com/2ndQuadrant/repmgr/blob/master/doc/repmgrd-node-fencing.md">Fencing a failed master node with repmgrd and PgBouncer</ulink>.
|
||||
<ulink url="https://github.com/EnterpriseDB/repmgr/blob/master/doc/repmgrd-node-fencing.md">Fencing a failed master node with repmgrd and PgBouncer</ulink>.
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
@@ -969,7 +999,7 @@ repmgrd_service_stop_command='sudo systemctl repmgr12 stop'
|
||||
</para>
|
||||
<para>
|
||||
If none of the above apply, &repmgrd; will create a PID file
|
||||
in the operating system's temporary directory (as setermined by the environment variable
|
||||
in the operating system's temporary directory (as determined by the environment variable
|
||||
<varname>TMPDIR</varname>, or if that is not set, will use <filename>/tmp</filename>).
|
||||
</para>
|
||||
<para>
|
||||
@@ -1049,6 +1079,29 @@ REPMGRD_OPTS="--daemonize=false"
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="repmgrd-daemon-monitoring">
|
||||
<title>repmgrd daemon monitoring</title>
|
||||
<indexterm>
|
||||
<primary>repmgrd</primary>
|
||||
<secondary>monitoring</secondary>
|
||||
</indexterm>
|
||||
<indexterm>
|
||||
<primary>monitoring</primary>
|
||||
<secondary>repmgrd</secondary>
|
||||
</indexterm>
|
||||
|
||||
<para>
|
||||
The command <command><link linkend="repmgr-service-status">repmgr service status</link></command>
|
||||
provides an overview of the &repmgrd; daemon status (including pause status)
|
||||
on all nodes in the cluster.
|
||||
</para>
|
||||
<para>
|
||||
From &repmgr; 5.3, <command><link linkend="repmgr-node-check">repmgr node check --repmgrd</link></command>
|
||||
can be used to check the status of &repmgrd; (including pause status)
|
||||
on the local node.
|
||||
</para>
|
||||
</sect2>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="repmgrd-connection-settings">
|
||||
|
||||
@@ -120,16 +120,19 @@
|
||||
</important>
|
||||
|
||||
<note>
|
||||
<simpara>
|
||||
<para>
|
||||
On <literal>systemd</literal> systems we strongly recommend using the appropriate
|
||||
<command>systemctl</command> commands (typically run via <command>sudo</command>) to ensure
|
||||
<literal>systemd</literal> is informed about the status of the PostgreSQL service.
|
||||
</simpara>
|
||||
<simpara>
|
||||
</para>
|
||||
<para>
|
||||
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>
|
||||
</para>
|
||||
<para>
|
||||
See the <xref linkend="configuration-file-service-commands"/> documentation section for further details.
|
||||
</para>
|
||||
</note>
|
||||
|
||||
<para>
|
||||
|
||||
@@ -482,7 +482,7 @@ ALTER EXTENSION repmgr UPDATE</programlisting>
|
||||
<simpara>
|
||||
If you don't care about any data from the existing &repmgr; installation,
|
||||
(e.g. the contents of the <structname>events</structname> and <structname>monitoring</structname>
|
||||
tables), the follwing steps can be skipped; proceed to <xref linkend="upgrade-reregister-nodes"/>.
|
||||
tables), the following steps can be skipped; proceed to <xref linkend="upgrade-reregister-nodes"/>.
|
||||
</simpara>
|
||||
</tip>
|
||||
|
||||
@@ -497,10 +497,10 @@ ALTER EXTENSION repmgr UPDATE</programlisting>
|
||||
<itemizedlist spacing="compact" mark="bullet">
|
||||
<listitem>
|
||||
<simpara>
|
||||
<ulink url="https://raw.githubusercontent.com/2ndQuadrant/repmgr/REL3_3_STABLE/sql/repmgr3.0_repmgr3.1.sql">repmgr3.0_repmgr3.1.sql</ulink></simpara>
|
||||
<ulink url="https://raw.githubusercontent.com/EnterpriseDB/repmgr/REL3_3_STABLE/sql/repmgr3.0_repmgr3.1.sql">repmgr3.0_repmgr3.1.sql</ulink></simpara>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<simpara><ulink url="https://raw.githubusercontent.com/2ndQuadrant/repmgr/REL3_3_STABLE/sql/repmgr3.1.1_repmgr3.1.2.sql">repmgr3.1.1_repmgr3.1.2.sql</ulink></simpara>
|
||||
<simpara><ulink url="https://raw.githubusercontent.com/EnterpriseDB/repmgr/REL3_3_STABLE/sql/repmgr3.1.1_repmgr3.1.2.sql">repmgr3.1.1_repmgr3.1.2.sql</ulink></simpara>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* errcode.h
|
||||
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
||||
*
|
||||
* 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
|
||||
|
||||
2
log.c
2
log.c
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* log.c - Logging methods
|
||||
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
||||
*
|
||||
* 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
|
||||
|
||||
2
log.h
2
log.h
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* log.h
|
||||
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
||||
*
|
||||
* 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
|
||||
|
||||
@@ -1,17 +1,10 @@
|
||||
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
|
||||
\echo Use "CREATE EXTENSION repmgr" to load this file. \quit
|
||||
\echo Use "ALTER EXTENSION repmgr UPDATE" to load this file. \quit
|
||||
|
||||
CREATE FUNCTION set_upstream_last_seen()
|
||||
RETURNS VOID
|
||||
AS 'MODULE_PATHNAME', 'set_upstream_last_seen'
|
||||
LANGUAGE C STRICT;
|
||||
-- This script is intentionally empty and exists to skip the CREATE FUNCTION
|
||||
-- commands contained in the 4.2--4.3 and 4.3--4.4 extension upgrade scripts,
|
||||
-- which reference C functions which no longer exist in 5.3 and later.
|
||||
--
|
||||
-- These functions will be explicitly created in the 5.2--5.3 extension
|
||||
-- upgrade step with the correct C function references.
|
||||
|
||||
CREATE FUNCTION get_upstream_last_seen()
|
||||
RETURNS INT
|
||||
AS 'MODULE_PATHNAME', 'get_upstream_last_seen'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION get_wal_receiver_pid()
|
||||
RETURNS INT
|
||||
AS 'MODULE_PATHNAME', 'get_wal_receiver_pid'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
@@ -1,19 +1,9 @@
|
||||
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
|
||||
\echo Use "CREATE EXTENSION repmgr" to load this file. \quit
|
||||
\echo Use "ALTER EXTENSION repmgr UPDATE" to load this file. \quit
|
||||
|
||||
DROP FUNCTION set_upstream_last_seen();
|
||||
|
||||
CREATE FUNCTION set_upstream_last_seen(INT)
|
||||
RETURNS VOID
|
||||
AS 'MODULE_PATHNAME', 'set_upstream_last_seen'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION get_upstream_node_id()
|
||||
RETURNS INT
|
||||
AS 'MODULE_PATHNAME', 'get_upstream_node_id'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION set_upstream_node_id(INT)
|
||||
RETURNS VOID
|
||||
AS 'MODULE_PATHNAME', 'set_upstream_node_id'
|
||||
LANGUAGE C STRICT;
|
||||
-- This script is intentionally empty and exists to skip the CREATE FUNCTION
|
||||
-- commands contained in the 4.3--4.4 extension upgrade script, which reference
|
||||
-- C functions which no longer exist in 5.3 and later.
|
||||
--
|
||||
-- These functions will be explicitly created in the 5.2--5.3 extension
|
||||
-- upgrade step with the correct C function references.
|
||||
|
||||
64
repmgr--5.2--5.3.sql
Normal file
64
repmgr--5.2--5.3.sql
Normal file
@@ -0,0 +1,64 @@
|
||||
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
|
||||
\echo Use "CREATE EXTENSION repmgr" to load this file. \quit
|
||||
|
||||
CREATE OR REPLACE FUNCTION set_local_node_id(INT)
|
||||
RETURNS VOID
|
||||
AS 'MODULE_PATHNAME', 'repmgr_set_local_node_id'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE OR REPLACE FUNCTION repmgr.get_local_node_id()
|
||||
RETURNS INT
|
||||
AS 'MODULE_PATHNAME', 'repmgr_get_local_node_id'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE OR REPLACE FUNCTION standby_set_last_updated()
|
||||
RETURNS TIMESTAMP WITH TIME ZONE
|
||||
AS 'MODULE_PATHNAME', 'repmgr_standby_set_last_updated'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE OR REPLACE FUNCTION standby_get_last_updated()
|
||||
RETURNS TIMESTAMP WITH TIME ZONE
|
||||
AS 'MODULE_PATHNAME', 'repmgr_standby_get_last_updated'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE OR REPLACE FUNCTION set_upstream_last_seen(INT)
|
||||
RETURNS VOID
|
||||
AS 'MODULE_PATHNAME', 'repmgr_set_upstream_last_seen'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE OR REPLACE FUNCTION get_upstream_last_seen()
|
||||
RETURNS INT
|
||||
AS 'MODULE_PATHNAME', 'repmgr_get_upstream_last_seen'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE OR REPLACE FUNCTION get_upstream_node_id()
|
||||
RETURNS INT
|
||||
AS 'MODULE_PATHNAME', 'repmgr_get_upstream_node_id'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE OR REPLACE FUNCTION set_upstream_node_id(INT)
|
||||
RETURNS VOID
|
||||
AS 'MODULE_PATHNAME', 'repmgr_set_upstream_node_id'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
/* failover functions */
|
||||
|
||||
CREATE OR REPLACE FUNCTION notify_follow_primary(INT)
|
||||
RETURNS VOID
|
||||
AS 'MODULE_PATHNAME', 'repmgr_notify_follow_primary'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE OR REPLACE FUNCTION get_new_primary()
|
||||
RETURNS INT
|
||||
AS 'MODULE_PATHNAME', 'repmgr_get_new_primary'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE OR REPLACE FUNCTION reset_voting_status()
|
||||
RETURNS VOID
|
||||
AS 'MODULE_PATHNAME', 'repmgr_reset_voting_status'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE OR REPLACE FUNCTION get_wal_receiver_pid()
|
||||
RETURNS INT
|
||||
AS 'MODULE_PATHNAME', 'repmgr_get_wal_receiver_pid'
|
||||
LANGUAGE C STRICT;
|
||||
192
repmgr--5.3.sql
Normal file
192
repmgr--5.3.sql
Normal file
@@ -0,0 +1,192 @@
|
||||
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
|
||||
\echo Use "CREATE EXTENSION repmgr" to load this file. \quit
|
||||
|
||||
CREATE TABLE repmgr.nodes (
|
||||
node_id INTEGER PRIMARY KEY,
|
||||
upstream_node_id INTEGER NULL REFERENCES nodes (node_id) DEFERRABLE,
|
||||
active BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
node_name TEXT NOT NULL,
|
||||
type TEXT NOT NULL CHECK (type IN('primary','standby','witness','bdr')),
|
||||
location TEXT NOT NULL DEFAULT 'default',
|
||||
priority INT NOT NULL DEFAULT 100,
|
||||
conninfo TEXT NOT NULL,
|
||||
repluser VARCHAR(63) NOT NULL,
|
||||
slot_name TEXT NULL,
|
||||
config_file TEXT NOT NULL
|
||||
);
|
||||
|
||||
SELECT pg_catalog.pg_extension_config_dump('repmgr.nodes', '');
|
||||
|
||||
CREATE TABLE repmgr.events (
|
||||
node_id INTEGER NOT NULL,
|
||||
event TEXT NOT NULL,
|
||||
successful BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
event_timestamp TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
details TEXT NULL
|
||||
);
|
||||
|
||||
SELECT pg_catalog.pg_extension_config_dump('repmgr.events', '');
|
||||
|
||||
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 PG_LSN NOT NULL,
|
||||
last_wal_standby_location PG_LSN,
|
||||
replication_lag BIGINT NOT NULL,
|
||||
apply_lag BIGINT NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX idx_monitoring_history_time
|
||||
ON repmgr.monitoring_history (last_monitor_time, standby_node_id);
|
||||
|
||||
SELECT pg_catalog.pg_extension_config_dump('repmgr.monitoring_history', '');
|
||||
|
||||
CREATE VIEW repmgr.show_nodes AS
|
||||
SELECT n.node_id,
|
||||
n.node_name,
|
||||
n.active,
|
||||
n.upstream_node_id,
|
||||
un.node_name AS upstream_node_name,
|
||||
n.type,
|
||||
n.priority,
|
||||
n.conninfo
|
||||
FROM repmgr.nodes n
|
||||
LEFT JOIN repmgr.nodes un
|
||||
ON un.node_id = n.upstream_node_id;
|
||||
|
||||
CREATE TABLE repmgr.voting_term (
|
||||
term INT NOT NULL
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX voting_term_restrict
|
||||
ON repmgr.voting_term ((TRUE));
|
||||
|
||||
CREATE RULE voting_term_delete AS
|
||||
ON DELETE TO repmgr.voting_term
|
||||
DO INSTEAD NOTHING;
|
||||
|
||||
|
||||
/* ================= */
|
||||
/* repmgrd functions */
|
||||
/* ================= */
|
||||
|
||||
/* monitoring functions */
|
||||
|
||||
CREATE FUNCTION set_local_node_id(INT)
|
||||
RETURNS VOID
|
||||
AS 'MODULE_PATHNAME', 'repmgr_set_local_node_id'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION get_local_node_id()
|
||||
RETURNS INT
|
||||
AS 'MODULE_PATHNAME', 'repmgr_get_local_node_id'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION standby_set_last_updated()
|
||||
RETURNS TIMESTAMP WITH TIME ZONE
|
||||
AS 'MODULE_PATHNAME', 'repmgr_standby_set_last_updated'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION standby_get_last_updated()
|
||||
RETURNS TIMESTAMP WITH TIME ZONE
|
||||
AS 'MODULE_PATHNAME', 'repmgr_standby_get_last_updated'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION set_upstream_last_seen(INT)
|
||||
RETURNS VOID
|
||||
AS 'MODULE_PATHNAME', 'repmgr_set_upstream_last_seen'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION get_upstream_last_seen()
|
||||
RETURNS INT
|
||||
AS 'MODULE_PATHNAME', 'repmgr_get_upstream_last_seen'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION get_upstream_node_id()
|
||||
RETURNS INT
|
||||
AS 'MODULE_PATHNAME', 'repmgr_get_upstream_node_id'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION set_upstream_node_id(INT)
|
||||
RETURNS VOID
|
||||
AS 'MODULE_PATHNAME', 'repmgr_set_upstream_node_id'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
/* failover functions */
|
||||
|
||||
CREATE FUNCTION notify_follow_primary(INT)
|
||||
RETURNS VOID
|
||||
AS 'MODULE_PATHNAME', 'repmgr_notify_follow_primary'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION get_new_primary()
|
||||
RETURNS INT
|
||||
AS 'MODULE_PATHNAME', 'repmgr_get_new_primary'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION reset_voting_status()
|
||||
RETURNS VOID
|
||||
AS 'MODULE_PATHNAME', 'repmgr_reset_voting_status'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION get_repmgrd_pid()
|
||||
RETURNS INT
|
||||
AS 'MODULE_PATHNAME', 'get_repmgrd_pid'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION get_repmgrd_pidfile()
|
||||
RETURNS TEXT
|
||||
AS 'MODULE_PATHNAME', 'get_repmgrd_pidfile'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION set_repmgrd_pid(INT, TEXT)
|
||||
RETURNS VOID
|
||||
AS 'MODULE_PATHNAME', 'set_repmgrd_pid'
|
||||
LANGUAGE C CALLED ON NULL INPUT;
|
||||
|
||||
CREATE FUNCTION repmgrd_is_running()
|
||||
RETURNS BOOL
|
||||
AS 'MODULE_PATHNAME', 'repmgrd_is_running'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION repmgrd_pause(BOOL)
|
||||
RETURNS VOID
|
||||
AS 'MODULE_PATHNAME', 'repmgrd_pause'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION repmgrd_is_paused()
|
||||
RETURNS BOOL
|
||||
AS 'MODULE_PATHNAME', 'repmgrd_is_paused'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION get_wal_receiver_pid()
|
||||
RETURNS INT
|
||||
AS 'MODULE_PATHNAME', 'repmgr_get_wal_receiver_pid'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
|
||||
|
||||
|
||||
/* views */
|
||||
|
||||
CREATE VIEW repmgr.replication_status AS
|
||||
SELECT m.primary_node_id, m.standby_node_id, n.node_name AS standby_name,
|
||||
n.type AS node_type, n.active, last_monitor_time,
|
||||
CASE WHEN n.type='standby' THEN m.last_wal_primary_location ELSE NULL END AS last_wal_primary_location,
|
||||
m.last_wal_standby_location,
|
||||
CASE WHEN n.type='standby' THEN pg_catalog.pg_size_pretty(m.replication_lag) ELSE NULL END AS replication_lag,
|
||||
CASE WHEN n.type='standby' THEN
|
||||
CASE WHEN replication_lag > 0 THEN age(now(), m.last_apply_time) ELSE '0'::INTERVAL END
|
||||
ELSE NULL
|
||||
END AS replication_time_lag,
|
||||
CASE WHEN n.type='standby' THEN pg_catalog.pg_size_pretty(m.apply_lag) ELSE NULL END AS apply_lag,
|
||||
AGE(NOW(), CASE WHEN pg_catalog.pg_is_in_recovery() THEN repmgr.standby_get_last_updated() ELSE m.last_monitor_time END) AS communication_time_lag
|
||||
FROM repmgr.monitoring_history m
|
||||
JOIN repmgr.nodes n ON m.standby_node_id = n.node_id
|
||||
WHERE (m.standby_node_id, m.last_monitor_time) IN (
|
||||
SELECT m1.standby_node_id, MAX(m1.last_monitor_time)
|
||||
FROM repmgr.monitoring_history m1 GROUP BY 1
|
||||
);
|
||||
|
||||
245
repmgr--unpackaged--5.3.sql
Normal file
245
repmgr--unpackaged--5.3.sql
Normal file
@@ -0,0 +1,245 @@
|
||||
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
|
||||
\echo Use "CREATE EXTENSION repmgr" to load this file. \quit
|
||||
|
||||
-- extract the current schema name
|
||||
-- NOTE: this assumes there will be only one schema matching 'repmgr_%';
|
||||
-- user is responsible for ensuring this is the case
|
||||
|
||||
CREATE TEMPORARY TABLE repmgr_old_schema (schema_name TEXT);
|
||||
INSERT INTO repmgr_old_schema (schema_name)
|
||||
SELECT nspname AS schema_name
|
||||
FROM pg_catalog.pg_namespace
|
||||
WHERE nspname LIKE 'repmgr_%'
|
||||
LIMIT 1;
|
||||
|
||||
-- move old objects into new schema
|
||||
DO $repmgr$
|
||||
DECLARE
|
||||
old_schema TEXT;
|
||||
BEGIN
|
||||
SELECT schema_name FROM repmgr_old_schema
|
||||
INTO old_schema;
|
||||
EXECUTE format('ALTER TABLE %I.repl_nodes SET SCHEMA repmgr', old_schema);
|
||||
EXECUTE format('ALTER TABLE %I.repl_events SET SCHEMA repmgr', old_schema);
|
||||
EXECUTE format('ALTER TABLE %I.repl_monitor SET SCHEMA repmgr', old_schema);
|
||||
EXECUTE format('DROP VIEW IF EXISTS %I.repl_show_nodes', old_schema);
|
||||
EXECUTE format('DROP VIEW IF EXISTS %I.repl_status', old_schema);
|
||||
END$repmgr$;
|
||||
|
||||
-- convert "repmgr_$cluster.repl_nodes" to "repmgr.nodes"
|
||||
CREATE TABLE repmgr.nodes (
|
||||
node_id INTEGER PRIMARY KEY,
|
||||
upstream_node_id INTEGER NULL REFERENCES repmgr.nodes (node_id) DEFERRABLE,
|
||||
active BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
node_name TEXT NOT NULL,
|
||||
type TEXT NOT NULL CHECK (type IN('primary','standby','witness','bdr')),
|
||||
location TEXT NOT NULL DEFAULT 'default',
|
||||
priority INT NOT NULL DEFAULT 100,
|
||||
conninfo TEXT NOT NULL,
|
||||
repluser VARCHAR(63) NOT NULL,
|
||||
slot_name TEXT NULL,
|
||||
config_file TEXT NOT NULL
|
||||
);
|
||||
|
||||
INSERT INTO repmgr.nodes
|
||||
(node_id, upstream_node_id, active, node_name, type, location, priority, conninfo, repluser, slot_name, config_file)
|
||||
SELECT id, upstream_node_id, active, name,
|
||||
CASE WHEN type = 'master' THEN 'primary' ELSE type END,
|
||||
'default', priority, conninfo, 'unknown', slot_name, 'unknown'
|
||||
FROM repmgr.repl_nodes
|
||||
ORDER BY id;
|
||||
|
||||
|
||||
-- convert "repmgr_$cluster.repl_event" to "event"
|
||||
|
||||
CREATE TABLE repmgr.events (
|
||||
node_id INTEGER NOT NULL,
|
||||
event TEXT NOT NULL,
|
||||
successful BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
event_timestamp TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
details TEXT NULL
|
||||
);
|
||||
|
||||
INSERT INTO repmgr.events
|
||||
(node_id, event, successful, event_timestamp, details)
|
||||
SELECT node_id, event, successful, event_timestamp, details
|
||||
FROM repmgr.repl_events;
|
||||
|
||||
-- create new table "repmgr.voting_term"
|
||||
CREATE TABLE repmgr.voting_term (
|
||||
term INT NOT NULL
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX voting_term_restrict
|
||||
ON repmgr.voting_term ((TRUE));
|
||||
|
||||
CREATE RULE voting_term_delete AS
|
||||
ON DELETE TO repmgr.voting_term
|
||||
DO INSTEAD NOTHING;
|
||||
|
||||
INSERT INTO repmgr.voting_term (term) VALUES (1);
|
||||
|
||||
-- convert "repmgr_$cluster.repl_monitor" to "monitoring_history"
|
||||
|
||||
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 PG_LSN NOT NULL,
|
||||
last_wal_standby_location PG_LSN,
|
||||
replication_lag BIGINT NOT NULL,
|
||||
apply_lag BIGINT NOT NULL
|
||||
);
|
||||
|
||||
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::pg_lsn, last_wal_standby_location::pg_lsn, replication_lag, apply_lag
|
||||
FROM repmgr.repl_monitor;
|
||||
|
||||
CREATE INDEX idx_monitoring_history_time
|
||||
ON repmgr.monitoring_history (last_monitor_time, standby_node_id);
|
||||
|
||||
CREATE VIEW repmgr.show_nodes AS
|
||||
SELECT n.node_id,
|
||||
n.node_name,
|
||||
n.active,
|
||||
n.upstream_node_id,
|
||||
un.node_name AS upstream_node_name,
|
||||
n.type,
|
||||
n.priority,
|
||||
n.conninfo
|
||||
FROM repmgr.nodes n
|
||||
LEFT JOIN repmgr.nodes un
|
||||
ON un.node_id = n.upstream_node_id;
|
||||
|
||||
|
||||
/* ================= */
|
||||
/* repmgrd functions */
|
||||
/* ================= */
|
||||
|
||||
/* monitoring functions */
|
||||
|
||||
CREATE FUNCTION set_local_node_id(INT)
|
||||
RETURNS VOID
|
||||
AS 'MODULE_PATHNAME', 'repmgr_set_local_node_id'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION get_local_node_id()
|
||||
RETURNS INT
|
||||
AS 'MODULE_PATHNAME', 'repmgr_get_local_node_id'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION standby_set_last_updated()
|
||||
RETURNS TIMESTAMP WITH TIME ZONE
|
||||
AS 'MODULE_PATHNAME', 'repmgr_standby_set_last_updated'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION standby_get_last_updated()
|
||||
RETURNS TIMESTAMP WITH TIME ZONE
|
||||
AS 'MODULE_PATHNAME', 'repmgr_standby_get_last_updated'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION set_upstream_last_seen(INT)
|
||||
RETURNS VOID
|
||||
AS 'MODULE_PATHNAME', 'repmgr_set_upstream_last_seen'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION get_upstream_last_seen()
|
||||
RETURNS INT
|
||||
AS 'MODULE_PATHNAME', 'repmgr_get_upstream_last_seen'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION get_upstream_node_id()
|
||||
RETURNS INT
|
||||
AS 'MODULE_PATHNAME', 'repmgr_get_upstream_node_id'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION set_upstream_node_id(INT)
|
||||
RETURNS VOID
|
||||
AS 'MODULE_PATHNAME', 'repmgr_set_upstream_node_id'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
/* failover functions */
|
||||
|
||||
CREATE FUNCTION notify_follow_primary(INT)
|
||||
RETURNS VOID
|
||||
AS 'MODULE_PATHNAME', 'repmgr_notify_follow_primary'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION get_new_primary()
|
||||
RETURNS INT
|
||||
AS 'MODULE_PATHNAME', 'repmgr_get_new_primary'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION reset_voting_status()
|
||||
RETURNS VOID
|
||||
AS 'MODULE_PATHNAME', 'repmgr_reset_voting_status'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION get_repmgrd_pid()
|
||||
RETURNS INT
|
||||
AS 'MODULE_PATHNAME', 'get_repmgrd_pid'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION get_repmgrd_pidfile()
|
||||
RETURNS TEXT
|
||||
AS 'MODULE_PATHNAME', 'get_repmgrd_pidfile'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION set_repmgrd_pid(INT, TEXT)
|
||||
RETURNS VOID
|
||||
AS 'MODULE_PATHNAME', 'set_repmgrd_pid'
|
||||
LANGUAGE C CALLED ON NULL INPUT;
|
||||
|
||||
CREATE FUNCTION repmgrd_is_running()
|
||||
RETURNS BOOL
|
||||
AS 'MODULE_PATHNAME', 'repmgrd_is_running'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION repmgrd_pause(BOOL)
|
||||
RETURNS VOID
|
||||
AS 'MODULE_PATHNAME', 'repmgrd_pause'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION repmgrd_is_paused()
|
||||
RETURNS BOOL
|
||||
AS 'MODULE_PATHNAME', 'repmgrd_is_paused'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION get_wal_receiver_pid()
|
||||
RETURNS INT
|
||||
AS 'MODULE_PATHNAME', 'repmgr_get_wal_receiver_pid'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
|
||||
/* views */
|
||||
|
||||
CREATE VIEW repmgr.replication_status AS
|
||||
SELECT m.primary_node_id, m.standby_node_id, n.node_name AS standby_name,
|
||||
n.type AS node_type, n.active, last_monitor_time,
|
||||
CASE WHEN n.type='standby' THEN m.last_wal_primary_location ELSE NULL END AS last_wal_primary_location,
|
||||
m.last_wal_standby_location,
|
||||
CASE WHEN n.type='standby' THEN pg_catalog.pg_size_pretty(m.replication_lag) ELSE NULL END AS replication_lag,
|
||||
CASE WHEN n.type='standby' THEN
|
||||
CASE WHEN replication_lag > 0 THEN age(now(), m.last_apply_time) ELSE '0'::INTERVAL END
|
||||
ELSE NULL
|
||||
END AS replication_time_lag,
|
||||
CASE WHEN n.type='standby' THEN pg_catalog.pg_size_pretty(m.apply_lag) ELSE NULL END AS apply_lag,
|
||||
AGE(NOW(), CASE WHEN pg_catalog.pg_is_in_recovery() THEN repmgr.standby_get_last_updated() ELSE m.last_monitor_time END) AS communication_time_lag
|
||||
FROM repmgr.monitoring_history m
|
||||
JOIN repmgr.nodes n ON m.standby_node_id = n.node_id
|
||||
WHERE (m.standby_node_id, m.last_monitor_time) IN (
|
||||
SELECT m1.standby_node_id, MAX(m1.last_monitor_time)
|
||||
FROM repmgr.monitoring_history m1 GROUP BY 1
|
||||
);
|
||||
|
||||
|
||||
|
||||
/* drop old tables */
|
||||
DROP TABLE repmgr.repl_nodes;
|
||||
DROP TABLE repmgr.repl_monitor;
|
||||
DROP TABLE repmgr.repl_events;
|
||||
|
||||
-- remove temporary table
|
||||
DROP TABLE repmgr_old_schema;
|
||||
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Implements cluster information actions for the repmgr command line utility
|
||||
*
|
||||
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
||||
*
|
||||
* 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* repmgr-action-cluster.h
|
||||
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
||||
*
|
||||
* 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
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* repmgr-action-daemon.c
|
||||
*
|
||||
* Implements repmgrd actions for the repmgr command line utility
|
||||
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
||||
*
|
||||
* 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* repmgr-action-daemon.h
|
||||
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
||||
*
|
||||
* 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
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Implements actions available for any kind of node
|
||||
*
|
||||
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
||||
*
|
||||
* 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
|
||||
@@ -35,6 +35,7 @@
|
||||
static bool copy_file(const char *src_file, const char *dest_file);
|
||||
static void format_archive_dir(PQExpBufferData *archive_dir);
|
||||
static t_server_action parse_server_action(const char *action);
|
||||
static const char *output_repmgrd_status(CheckStatus status);
|
||||
|
||||
static void exit_optformat_error(const char *error, int errcode);
|
||||
|
||||
@@ -52,9 +53,11 @@ static CheckStatus do_node_check_role(PGconn *conn, OutputMode mode, t_node_info
|
||||
static CheckStatus do_node_check_slots(PGconn *conn, OutputMode mode, t_node_info *node_info, CheckStatusList *list_output);
|
||||
static CheckStatus do_node_check_missing_slots(PGconn *conn, OutputMode mode, t_node_info *node_info, CheckStatusList *list_output);
|
||||
static CheckStatus do_node_check_data_directory(PGconn *conn, OutputMode mode, t_node_info *node_info, CheckStatusList *list_output);
|
||||
static CheckStatus do_node_check_repmgrd(PGconn *conn, OutputMode mode, t_node_info *node_info, CheckStatusList *list_output);
|
||||
static CheckStatus do_node_check_replication_config_owner(PGconn *conn, OutputMode mode, t_node_info *node_info, CheckStatusList *list_output);
|
||||
static CheckStatus do_node_check_db_connection(PGconn *conn, OutputMode mode);
|
||||
|
||||
|
||||
/*
|
||||
* NODE STATUS
|
||||
*
|
||||
@@ -941,6 +944,16 @@ do_node_check(void)
|
||||
exit(return_code);
|
||||
}
|
||||
|
||||
if (runtime_options.repmgrd == true)
|
||||
{
|
||||
return_code = do_node_check_repmgrd(conn,
|
||||
runtime_options.output_mode,
|
||||
&node_info,
|
||||
NULL);
|
||||
PQfinish(conn);
|
||||
exit(return_code);
|
||||
}
|
||||
|
||||
if (runtime_options.replication_config_owner == true)
|
||||
{
|
||||
return_code = do_node_check_replication_config_owner(conn,
|
||||
@@ -2024,7 +2037,6 @@ do_node_check_missing_slots(PGconn *conn, OutputMode mode, t_node_info *node_inf
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
CheckStatus
|
||||
do_node_check_data_directory(PGconn *conn, OutputMode mode, t_node_info *node_info, CheckStatusList *list_output)
|
||||
{
|
||||
@@ -2159,6 +2171,53 @@ do_node_check_data_directory(PGconn *conn, OutputMode mode, t_node_info *node_in
|
||||
return status;
|
||||
}
|
||||
|
||||
CheckStatus
|
||||
do_node_check_repmgrd(PGconn *conn, OutputMode mode, t_node_info *node_info, CheckStatusList *list_output)
|
||||
{
|
||||
CheckStatus status = CHECK_STATUS_OK;
|
||||
|
||||
if (mode == OM_CSV && list_output == NULL)
|
||||
{
|
||||
log_error(_("--csv output not provided with --repmgrd option"));
|
||||
PQfinish(conn);
|
||||
exit(ERR_BAD_CONFIG);
|
||||
}
|
||||
|
||||
status = get_repmgrd_status(conn);
|
||||
switch (mode)
|
||||
{
|
||||
case OM_OPTFORMAT:
|
||||
printf("--repmgrd=%s\n",
|
||||
output_check_status(status));
|
||||
break;
|
||||
case OM_NAGIOS:
|
||||
printf("REPMGRD %s: %s\n",
|
||||
output_check_status(status),
|
||||
output_repmgrd_status(status));
|
||||
|
||||
break;
|
||||
case OM_CSV:
|
||||
case OM_TEXT:
|
||||
if (list_output != NULL)
|
||||
{
|
||||
check_status_list_set(list_output,
|
||||
"repmgrd",
|
||||
status,
|
||||
output_repmgrd_status(status));
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("%s (%s)\n",
|
||||
output_check_status(status),
|
||||
output_repmgrd_status(status));
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is not included in the general list output
|
||||
*/
|
||||
@@ -2612,6 +2671,13 @@ do_node_rejoin(void)
|
||||
exit(ERR_BAD_CONFIG);
|
||||
}
|
||||
|
||||
/*
|
||||
* Emit a notice about the identity of the rejoin target
|
||||
*/
|
||||
log_notice(_("rejoin target is node \"%s\" (ID: %i)"),
|
||||
primary_node_record.node_name,
|
||||
primary_node_record.node_id);
|
||||
|
||||
/* connect to registered primary and check it's not in recovery */
|
||||
primary_conn = establish_db_connection(primary_node_record.conninfo, false);
|
||||
|
||||
@@ -2813,7 +2879,8 @@ do_node_rejoin(void)
|
||||
log_notice(_("temporarily removing \"standby.signal\""));
|
||||
log_detail(_("this is required so pg_rewind can fix the unclean shutdown"));
|
||||
|
||||
make_standby_signal_path(standby_signal_file_path);
|
||||
make_standby_signal_path(config_file_options.data_directory,
|
||||
standby_signal_file_path);
|
||||
|
||||
if (unlink(standby_signal_file_path) < 0 && errno != ENOENT)
|
||||
{
|
||||
@@ -2838,7 +2905,7 @@ do_node_rejoin(void)
|
||||
* of whether the pg_rewind operation failed.
|
||||
*/
|
||||
log_notice(_("recreating \"standby.signal\""));
|
||||
write_standby_signal();
|
||||
write_standby_signal(config_file_options.data_directory);
|
||||
}
|
||||
|
||||
if (ret == false)
|
||||
@@ -3562,6 +3629,25 @@ copy_file(const char *src_file, const char *dest_file)
|
||||
}
|
||||
|
||||
|
||||
static const char *
|
||||
output_repmgrd_status(CheckStatus status)
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case CHECK_STATUS_OK:
|
||||
return "repmgrd running";
|
||||
case CHECK_STATUS_WARNING:
|
||||
return "repmgrd running but paused";
|
||||
case CHECK_STATUS_CRITICAL:
|
||||
return "repmgrd not running";
|
||||
case CHECK_STATUS_UNKNOWN:
|
||||
return "repmgrd status unknown";
|
||||
}
|
||||
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
do_node_help(void)
|
||||
{
|
||||
@@ -3599,11 +3685,12 @@ do_node_help(void)
|
||||
printf(_(" Following options check an individual status:\n"));
|
||||
printf(_(" --archive-ready number of WAL files ready for archiving\n"));
|
||||
printf(_(" --downstream whether all downstream nodes are connected\n"));
|
||||
printf(_(" --uptream whether the node is connected to its upstream\n"));
|
||||
printf(_(" --upstream whether the node is connected to its upstream\n"));
|
||||
printf(_(" --replication-lag replication lag in seconds (standbys only)\n"));
|
||||
printf(_(" --role check node has expected role\n"));
|
||||
printf(_(" --slots check for inactive replication slots\n"));
|
||||
printf(_(" --missing-slots check for missing replication slots\n"));
|
||||
printf(_(" --repmgrd check if repmgrd is running\n"));
|
||||
printf(_(" --data-directory-config check repmgr's data directory configuration\n"));
|
||||
|
||||
puts("");
|
||||
@@ -3617,7 +3704,7 @@ do_node_help(void)
|
||||
printf(_(" --dry-run check that the prerequisites are met for rejoining the node\n" \
|
||||
" (including usability of \"pg_rewind\" if requested)\n"));
|
||||
printf(_(" --force-rewind[=VALUE] execute \"pg_rewind\" if necessary\n"));
|
||||
printf(_(" (9.3 and 9.4 - provide full \"pg_rewind\" path)\n"));
|
||||
printf(_(" (PostgreSQL 9.4 - provide full \"pg_rewind\" path)\n"));
|
||||
|
||||
printf(_(" --config-files comma-separated list of configuration files to retain\n" \
|
||||
" after executing \"pg_rewind\"\n"));
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* repmgr-action-node.h
|
||||
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
||||
*
|
||||
* 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
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Implements primary actions for the repmgr command line utility
|
||||
*
|
||||
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
||||
*
|
||||
* 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* repmgr-action-primary.h
|
||||
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
||||
*
|
||||
* 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
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* repmgr-action-service.c
|
||||
*
|
||||
* Implements repmgrd actions for the repmgr command line utility
|
||||
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
||||
*
|
||||
* 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* repmgr-action-service.h
|
||||
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
||||
*
|
||||
* 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
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Implements standby actions for the repmgr command line utility
|
||||
*
|
||||
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
||||
*
|
||||
* 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
|
||||
@@ -20,6 +20,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "repmgr.h"
|
||||
#include "dirutil.h"
|
||||
@@ -173,21 +174,6 @@ do_standby_clone(void)
|
||||
|
||||
initialize_conninfo_params(&recovery_conninfo, false);
|
||||
|
||||
/*
|
||||
* --replication-conf-only provided - we'll handle that separately
|
||||
*/
|
||||
if (runtime_options.replication_conf_only == true)
|
||||
{
|
||||
return _do_create_replication_conf();
|
||||
}
|
||||
|
||||
/*
|
||||
* conninfo params for the actual upstream node (which might be different
|
||||
* to the node we're cloning from) to write to recovery.conf
|
||||
*/
|
||||
|
||||
mode = get_standby_clone_mode();
|
||||
|
||||
/*
|
||||
* Copy the provided data directory; if a configuration file was provided,
|
||||
* use the (mandatory) value from that; if -D/--pgdata was provided, use
|
||||
@@ -215,6 +201,19 @@ do_standby_clone(void)
|
||||
exit(ERR_BAD_CONFIG);
|
||||
}
|
||||
|
||||
/*
|
||||
* --replication-conf-only provided - we'll handle that separately
|
||||
*/
|
||||
if (runtime_options.replication_conf_only == true)
|
||||
{
|
||||
return _do_create_replication_conf();
|
||||
}
|
||||
|
||||
/*
|
||||
* conninfo params for the actual upstream node (which might be different
|
||||
* to the node we're cloning from) to write to recovery.conf
|
||||
*/
|
||||
mode = get_standby_clone_mode();
|
||||
|
||||
if (mode == barman)
|
||||
{
|
||||
@@ -670,6 +669,15 @@ do_standby_clone(void)
|
||||
log_hint(_("consider using the -c/--fast-checkpoint option"));
|
||||
}
|
||||
|
||||
if (mode == pg_basebackup)
|
||||
{
|
||||
/*
|
||||
* In --dry-run mode, this will just output the pg_basebackup command which
|
||||
* would be executed.
|
||||
*/
|
||||
run_basebackup(&local_node_record);
|
||||
}
|
||||
|
||||
PQfinish(source_conn);
|
||||
|
||||
log_info(_("all prerequisites for \"standby clone\" are met"));
|
||||
@@ -1300,6 +1308,64 @@ _do_create_replication_conf(void)
|
||||
PQExpBufferData msg;
|
||||
t_replication_slot slot_info = T_REPLICATION_SLOT_INITIALIZER;
|
||||
|
||||
/*
|
||||
* Check the node record has slot_name set; if not we'll need to
|
||||
* update it.
|
||||
*/
|
||||
if (local_node_record.slot_name[0] == '\0')
|
||||
{
|
||||
PGconn *primary_conn = NULL;
|
||||
|
||||
create_slot_name(local_node_record.slot_name, local_node_record.node_id);
|
||||
|
||||
/* Check we can connect to the primary so we can update the record */
|
||||
|
||||
if (get_recovery_type(upstream_conn) == RECTYPE_PRIMARY)
|
||||
{
|
||||
primary_conn = upstream_conn;
|
||||
}
|
||||
else
|
||||
{
|
||||
primary_conn = establish_primary_db_connection(upstream_conn, false);
|
||||
|
||||
if (primary_conn == NULL)
|
||||
{
|
||||
log_error(_("unable to connect to primary to update slot name for node \"%s\" (ID: %i)"),
|
||||
local_node_record.node_name,
|
||||
local_node_record.node_id);
|
||||
PQfinish(upstream_conn);
|
||||
termPQExpBuffer(&msg);
|
||||
exit(ERR_BAD_CONFIG);
|
||||
}
|
||||
}
|
||||
|
||||
if (runtime_options.dry_run == true)
|
||||
{
|
||||
log_info(_("would set \"slot_name\" for node \"%s\" (ID: %i) to \"%s\""),
|
||||
local_node_record.node_name,
|
||||
local_node_record.node_id,
|
||||
local_node_record.slot_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
bool success = update_node_record_slot_name(primary_conn,
|
||||
local_node_record.node_id,
|
||||
local_node_record.slot_name);
|
||||
|
||||
if (primary_conn != upstream_conn)
|
||||
PQfinish(primary_conn);
|
||||
|
||||
if (success == false)
|
||||
{
|
||||
log_error(_("unable to update slot name for node \"%s\" (ID: %i)"),
|
||||
local_node_record.node_name,
|
||||
local_node_record.node_id);
|
||||
PQfinish(upstream_conn);
|
||||
exit(ERR_BAD_CONFIG);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
record_status = get_slot_record(upstream_conn, local_node_record.slot_name, &slot_info);
|
||||
|
||||
/* check if replication slot exists*/
|
||||
@@ -1480,7 +1546,7 @@ _do_create_replication_conf(void)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (write_standby_signal() == false)
|
||||
if (write_standby_signal(local_data_directory) == false)
|
||||
{
|
||||
log_error(_("unable to write \"standby.signal\" file"));
|
||||
}
|
||||
@@ -1932,7 +1998,7 @@ do_standby_register(void)
|
||||
/*
|
||||
* If --upstream-node-id not provided, we're defaulting to the primary as
|
||||
* upstream node. If local node is available, double-check that it's attached
|
||||
* to the primary, in case --upstream-node-id was an accidental ommission.
|
||||
* to the primary, in case --upstream-node-id was an accidental omission.
|
||||
*
|
||||
* Currently we'll only do this for newly registered nodes.
|
||||
*/
|
||||
@@ -1941,7 +2007,7 @@ do_standby_register(void)
|
||||
/* only do this if record does not exist */
|
||||
if (record_status != RECORD_FOUND)
|
||||
{
|
||||
log_warning(_("--upstream-node-id not supplied, assuming upstream node is primary (node ID %i)"),
|
||||
log_warning(_("--upstream-node-id not supplied, assuming upstream node is primary (node ID: %i)"),
|
||||
primary_node_id);
|
||||
|
||||
/* check our standby is connected */
|
||||
@@ -3395,7 +3461,7 @@ do_standby_follow_internal(PGconn *primary_conn, PGconn *follow_target_conn, t_n
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* In the unlikley event that fails, we'll fall back to a restart */
|
||||
/* In the unlikely event that fails, we'll fall back to a restart */
|
||||
log_warning(_("unable to reload server configuration"));
|
||||
}
|
||||
|
||||
@@ -3586,8 +3652,9 @@ do_standby_switchover(void)
|
||||
PQExpBufferData remote_command_str;
|
||||
PQExpBufferData command_output;
|
||||
PQExpBufferData node_rejoin_options;
|
||||
PQExpBufferData errmsg;
|
||||
PQExpBufferData logmsg;
|
||||
PQExpBufferData detailmsg;
|
||||
PQExpBufferData event_details;
|
||||
|
||||
int r,
|
||||
i;
|
||||
@@ -3604,6 +3671,9 @@ do_standby_switchover(void)
|
||||
/* store list of configuration files on the demotion candidate */
|
||||
KeyValueList remote_config_files = {NULL, NULL};
|
||||
|
||||
/* temporary log file for "repmgr node rejoin" on the demotion candidate */
|
||||
char node_rejoin_log[MAXPGPATH] = "";
|
||||
|
||||
NodeInfoList sibling_nodes = T_NODE_INFO_LIST_INITIALIZER;
|
||||
SiblingNodeStats sibling_nodes_stats = T_SIBLING_NODES_STATS_INITIALIZER;
|
||||
|
||||
@@ -3626,7 +3696,7 @@ do_standby_switchover(void)
|
||||
* SANITY CHECKS
|
||||
*
|
||||
* We'll be doing a bunch of operations on the remote server (primary to
|
||||
* be demoted) - careful checks needed before proceding.
|
||||
* be demoted) - careful checks needed before proceeding.
|
||||
*/
|
||||
|
||||
local_conn = establish_db_connection(config_file_options.conninfo, true);
|
||||
@@ -3746,24 +3816,24 @@ do_standby_switchover(void)
|
||||
* the demotion candidate as the rejoin will fail if we are unable to to write to that.
|
||||
*/
|
||||
|
||||
initPQExpBuffer(&errmsg);
|
||||
initPQExpBuffer(&logmsg);
|
||||
initPQExpBuffer(&detailmsg);
|
||||
|
||||
if (check_replication_config_owner(PQserverVersion(local_conn),
|
||||
config_file_options.data_directory,
|
||||
&errmsg, &detailmsg) == false)
|
||||
&logmsg, &detailmsg) == false)
|
||||
{
|
||||
log_error("%s", errmsg.data);
|
||||
log_error("%s", logmsg.data);
|
||||
log_detail("%s", detailmsg.data);
|
||||
|
||||
termPQExpBuffer(&errmsg);
|
||||
termPQExpBuffer(&logmsg);
|
||||
termPQExpBuffer(&detailmsg);
|
||||
|
||||
PQfinish(local_conn);
|
||||
exit(ERR_BAD_CONFIG);
|
||||
}
|
||||
|
||||
termPQExpBuffer(&errmsg);
|
||||
termPQExpBuffer(&logmsg);
|
||||
termPQExpBuffer(&detailmsg);
|
||||
|
||||
/* check remote server connection and retrieve its record */
|
||||
@@ -4108,7 +4178,7 @@ do_standby_switchover(void)
|
||||
|
||||
if (command_success == false || command_output.data[0] == '0')
|
||||
{
|
||||
log_error(_("expected configuration file not found on the demotion candiate \"%s\" (ID: %i)"),
|
||||
log_error(_("expected configuration file not found on the demotion candidate \"%s\" (ID: %i)"),
|
||||
remote_node_record.node_name,
|
||||
remote_node_record.node_id);
|
||||
log_detail(_("registered configuration file is \"%s\""),
|
||||
@@ -4208,7 +4278,7 @@ do_standby_switchover(void)
|
||||
else if (remote_error == REMOTE_ERROR_CONNINFO_PARSE)
|
||||
{
|
||||
/* highly unlikely */
|
||||
log_detail(_("an error was encountered when parsing the \"conninfo\" parameter in \"rempgr.conf\" on node \"%s\" (ID: %i)"),
|
||||
log_detail(_("an error was encountered when parsing the \"conninfo\" parameter in \"repmgr.conf\" on node \"%s\" (ID: %i)"),
|
||||
remote_node_record.node_name,
|
||||
remote_node_record.node_id);
|
||||
}
|
||||
@@ -4711,6 +4781,7 @@ do_standby_switchover(void)
|
||||
|
||||
repmgrd_info = (RepmgrdInfo **) pg_malloc0(sizeof(RepmgrdInfo *) * all_nodes.node_count);
|
||||
|
||||
log_notice(_("attempting to pause repmgrd on %i nodes"), all_nodes.node_count);
|
||||
for (cell = all_nodes.head; cell; cell = cell->next)
|
||||
{
|
||||
repmgrd_info[i] = pg_malloc0(sizeof(RepmgrdInfo));
|
||||
@@ -4739,7 +4810,7 @@ do_standby_switchover(void)
|
||||
unreachable_node_count++;
|
||||
|
||||
item_list_append_format(&repmgrd_connection_errors,
|
||||
_("unable to connect to node \"%s\" (ID %i):\n%s"),
|
||||
_("unable to connect to node \"%s\" (ID: %i):\n%s"),
|
||||
cell->node_info->node_name,
|
||||
cell->node_info->node_id,
|
||||
PQerrorMessage(cell->node_info->conn));
|
||||
@@ -4770,8 +4841,9 @@ do_standby_switchover(void)
|
||||
|
||||
initPQExpBuffer(&msg);
|
||||
appendPQExpBuffer(&msg,
|
||||
_("unable to connect to %i node(s), unable to pause all repmgrd instances"),
|
||||
unreachable_node_count);
|
||||
_("unable to connect to %i of %i node(s), unable to pause all repmgrd instances"),
|
||||
unreachable_node_count,
|
||||
all_nodes.node_count);
|
||||
|
||||
initPQExpBuffer(&detail);
|
||||
|
||||
@@ -4822,7 +4894,7 @@ do_standby_switchover(void)
|
||||
*/
|
||||
if (repmgrd_info[i]->pg_running == false)
|
||||
{
|
||||
log_warning(_("node \"%s\" (ID %i) unreachable, unable to pause repmgrd"),
|
||||
log_warning(_("node \"%s\" (ID: %i) unreachable, unable to pause repmgrd"),
|
||||
cell->node_info->node_name,
|
||||
cell->node_info->node_id);
|
||||
i++;
|
||||
@@ -4835,7 +4907,7 @@ do_standby_switchover(void)
|
||||
*/
|
||||
if (repmgrd_info[i]->running == false)
|
||||
{
|
||||
log_warning(_("repmgrd not running on node \"%s\" (ID %i)"),
|
||||
log_notice(_("repmgrd not running on node \"%s\" (ID: %i), not pausing"),
|
||||
cell->node_info->node_name,
|
||||
cell->node_info->node_id);
|
||||
i++;
|
||||
@@ -4856,14 +4928,14 @@ do_standby_switchover(void)
|
||||
|
||||
if (runtime_options.dry_run == true)
|
||||
{
|
||||
log_info(_("would pause repmgrd on node \"%s\" (ID %i)"),
|
||||
log_info(_("would pause repmgrd on node \"%s\" (ID: %i)"),
|
||||
cell->node_info->node_name,
|
||||
cell->node_info->node_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* XXX check result */
|
||||
log_debug("pausing repmgrd on node \"%s\" (ID %i)",
|
||||
log_debug("pausing repmgrd on node \"%s\" (ID: %i)",
|
||||
cell->node_info->node_name,
|
||||
cell->node_info->node_id);
|
||||
|
||||
@@ -5163,6 +5235,18 @@ do_standby_switchover(void)
|
||||
format_lsn(replication_info.last_wal_receive_lsn),
|
||||
format_lsn(remote_last_checkpoint_lsn));
|
||||
|
||||
/*
|
||||
* optionally add a delay before promoting the standby; this is mainly
|
||||
* useful for testing (e.g. for reappearance of the original primary) and
|
||||
* is not documented.
|
||||
*/
|
||||
if (config_file_options.promote_delay > 0)
|
||||
{
|
||||
log_debug("sleeping %i seconds before promoting standby",
|
||||
config_file_options.promote_delay);
|
||||
sleep(config_file_options.promote_delay);
|
||||
}
|
||||
|
||||
/*
|
||||
* Promote standby (local node).
|
||||
*
|
||||
@@ -5288,6 +5372,21 @@ do_standby_switchover(void)
|
||||
pfree(conninfo_normalized);
|
||||
}
|
||||
|
||||
/* */
|
||||
snprintf(node_rejoin_log, MAXPGPATH,
|
||||
#if defined(__i386__) || defined(__i386)
|
||||
"/tmp/node-rejoin.%u.log",
|
||||
(unsigned)time(NULL)
|
||||
#else
|
||||
"/tmp/node-rejoin.%lu.log",
|
||||
(unsigned long)time(NULL)
|
||||
#endif
|
||||
);
|
||||
|
||||
appendPQExpBuffer(&remote_command_str,
|
||||
" > %s 2>&1 && echo \"1\" || echo \"0\"",
|
||||
node_rejoin_log);
|
||||
|
||||
termPQExpBuffer(&node_rejoin_options);
|
||||
|
||||
log_debug("executing:\n %s", remote_command_str.data);
|
||||
@@ -5301,78 +5400,161 @@ do_standby_switchover(void)
|
||||
|
||||
termPQExpBuffer(&remote_command_str);
|
||||
|
||||
/* TODO: verify this node's record was updated correctly */
|
||||
initPQExpBuffer(&logmsg);
|
||||
initPQExpBuffer(&detailmsg);
|
||||
|
||||
/* This is failure to execute the ssh command */
|
||||
if (command_success == false)
|
||||
{
|
||||
log_error(_("rejoin failed with error code %i"), r);
|
||||
switchover_success = false;
|
||||
|
||||
appendPQExpBuffer(&logmsg,
|
||||
_("unable to execute \"repmgr node rejoin\" on demotion candidate \"%s\" (ID: %i)"),
|
||||
remote_node_record.node_name,
|
||||
remote_node_record.node_id);
|
||||
appendPQExpBufferStr(&detailmsg,
|
||||
command_output.data);
|
||||
|
||||
create_event_notification_extended(local_conn,
|
||||
&config_file_options,
|
||||
config_file_options.node_id,
|
||||
"standby_switchover",
|
||||
false,
|
||||
command_output.data,
|
||||
&event_info);
|
||||
}
|
||||
else
|
||||
{
|
||||
PQExpBufferData event_details;
|
||||
standy_join_status join_success = check_standby_join(local_conn,
|
||||
&local_node_record,
|
||||
&remote_node_record);
|
||||
standy_join_status join_success = JOIN_UNKNOWN;
|
||||
|
||||
initPQExpBuffer(&event_details);
|
||||
|
||||
switch (join_success) {
|
||||
case JOIN_FAIL_NO_PING:
|
||||
appendPQExpBuffer(&event_details,
|
||||
_("node \"%s\" (ID: %i) promoted to primary, but demote node \"%s\" (ID: %i) did not beome available"),
|
||||
config_file_options.node_name,
|
||||
config_file_options.node_id,
|
||||
remote_node_record.node_name,
|
||||
remote_node_record.node_id);
|
||||
switchover_success = false;
|
||||
|
||||
break;
|
||||
case JOIN_FAIL_NO_REPLICATION:
|
||||
appendPQExpBuffer(&event_details,
|
||||
_("node \"%s\" (ID: %i) promoted to primary, but demote node \"%s\" (ID: %i) did not connect to the new primary"),
|
||||
config_file_options.node_name,
|
||||
config_file_options.node_id,
|
||||
remote_node_record.node_name,
|
||||
remote_node_record.node_id);
|
||||
switchover_success = false;
|
||||
break;
|
||||
case JOIN_SUCCESS:
|
||||
appendPQExpBuffer(&event_details,
|
||||
_("node \"%s\" (ID: %i) promoted to primary, node \"%s\" (ID: %i) demoted to standby"),
|
||||
config_file_options.node_name,
|
||||
config_file_options.node_id,
|
||||
remote_node_record.node_name,
|
||||
remote_node_record.node_id);
|
||||
}
|
||||
|
||||
create_event_notification_extended(local_conn,
|
||||
&config_file_options,
|
||||
config_file_options.node_id,
|
||||
"standby_switchover",
|
||||
switchover_success,
|
||||
event_details.data,
|
||||
&event_info);
|
||||
if (switchover_success == true)
|
||||
/* "rempgr node rejoin" failed on the demotion candidate */
|
||||
if (command_output.data[0] == '0')
|
||||
{
|
||||
log_notice("%s", event_details.data);
|
||||
appendPQExpBuffer(&logmsg,
|
||||
_("execution of \"repmgr node rejoin\" on demotion candidate \"%s\" (ID: %i) failed"),
|
||||
remote_node_record.node_name,
|
||||
remote_node_record.node_id);
|
||||
|
||||
/*
|
||||
* Speculatively check if the demotion candidate has been restarted, e.g. by
|
||||
* an external watchdog process which isn't aware a switchover is happening.
|
||||
* This falls into the category "thing outside of our control which shouldn't
|
||||
* happen, but if it does, make it easier to find out what happened".
|
||||
*/
|
||||
remote_conn = establish_db_connection(remote_node_record.conninfo, false);
|
||||
|
||||
if (PQstatus(remote_conn) == CONNECTION_OK)
|
||||
{
|
||||
if (get_recovery_type(remote_conn) == RECTYPE_PRIMARY)
|
||||
{
|
||||
appendPQExpBuffer(&detailmsg,
|
||||
_("PostgreSQL instance on demotion candidate \"%s\" (ID: %i) is running as a primary\n"),
|
||||
remote_node_record.node_name,
|
||||
remote_node_record.node_id);
|
||||
log_warning("%s", detailmsg.data);
|
||||
}
|
||||
}
|
||||
PQfinish(remote_conn);
|
||||
|
||||
appendPQExpBuffer(&detailmsg,
|
||||
"check log file \"%s\" on \"%s\" for details",
|
||||
node_rejoin_log,
|
||||
remote_node_record.node_name);
|
||||
|
||||
switchover_success = false;
|
||||
join_success = JOIN_COMMAND_FAIL;
|
||||
}
|
||||
else
|
||||
{
|
||||
log_error("%s", event_details.data);
|
||||
join_success = check_standby_join(local_conn,
|
||||
&local_node_record,
|
||||
&remote_node_record);
|
||||
|
||||
|
||||
|
||||
switch (join_success) {
|
||||
case JOIN_FAIL_NO_PING:
|
||||
appendPQExpBuffer(&logmsg,
|
||||
_("node \"%s\" (ID: %i) promoted to primary, but demotion candidate \"%s\" (ID: %i) did not become available"),
|
||||
config_file_options.node_name,
|
||||
config_file_options.node_id,
|
||||
remote_node_record.node_name,
|
||||
remote_node_record.node_id);
|
||||
|
||||
switchover_success = false;
|
||||
|
||||
break;
|
||||
case JOIN_FAIL_NO_REPLICATION:
|
||||
appendPQExpBuffer(&logmsg,
|
||||
_("node \"%s\" (ID: %i) promoted to primary, but demotion candidate \"%s\" (ID: %i) did not connect to the new primary"),
|
||||
config_file_options.node_name,
|
||||
config_file_options.node_id,
|
||||
remote_node_record.node_name,
|
||||
remote_node_record.node_id);
|
||||
switchover_success = false;
|
||||
break;
|
||||
case JOIN_SUCCESS:
|
||||
appendPQExpBuffer(&logmsg,
|
||||
_("node \"%s\" (ID: %i) promoted to primary, node \"%s\" (ID: %i) demoted to standby"),
|
||||
config_file_options.node_name,
|
||||
config_file_options.node_id,
|
||||
remote_node_record.node_name,
|
||||
remote_node_record.node_id);
|
||||
break;
|
||||
/* check_standby_join() does not return this */
|
||||
case JOIN_COMMAND_FAIL:
|
||||
break;
|
||||
/* should never happen*/
|
||||
case JOIN_UNKNOWN:
|
||||
appendPQExpBuffer(&logmsg,
|
||||
"unable to determine success of node rejoin action for demotion candidate \"%s\" (ID: %i)",
|
||||
remote_node_record.node_name,
|
||||
remote_node_record.node_id);
|
||||
switchover_success = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (switchover_success == false)
|
||||
{
|
||||
appendPQExpBuffer(&detailmsg,
|
||||
"check the PostgreSQL log file on demotion candidate \"%s\" (ID: %i)",
|
||||
remote_node_record.node_name,
|
||||
remote_node_record.node_id);
|
||||
}
|
||||
}
|
||||
termPQExpBuffer(&event_details);
|
||||
}
|
||||
|
||||
if (switchover_success == true)
|
||||
{
|
||||
/* TODO: verify demotion candidates's node record was updated correctly */
|
||||
|
||||
log_notice("%s", logmsg.data);
|
||||
}
|
||||
else
|
||||
{
|
||||
log_error("%s", logmsg.data);
|
||||
}
|
||||
|
||||
initPQExpBuffer(&event_details);
|
||||
|
||||
appendPQExpBufferStr(&event_details, logmsg.data);
|
||||
|
||||
if (detailmsg.data[0] != '\0')
|
||||
{
|
||||
log_detail("%s", detailmsg.data);
|
||||
appendPQExpBuffer(&event_details, "\n%s",
|
||||
detailmsg.data);
|
||||
}
|
||||
|
||||
|
||||
create_event_notification_extended(local_conn,
|
||||
&config_file_options,
|
||||
config_file_options.node_id,
|
||||
"standby_switchover",
|
||||
switchover_success,
|
||||
event_details.data,
|
||||
&event_info);
|
||||
|
||||
termPQExpBuffer(&event_details);
|
||||
termPQExpBuffer(&logmsg);
|
||||
termPQExpBuffer(&detailmsg);
|
||||
termPQExpBuffer(&command_output);
|
||||
|
||||
|
||||
/*
|
||||
* If --siblings-follow specified, attempt to make them follow the new
|
||||
* primary
|
||||
@@ -5485,7 +5667,7 @@ do_standby_switchover(void)
|
||||
|
||||
if (repmgrd_info[i]->paused == true && runtime_options.repmgrd_force_unpause == false)
|
||||
{
|
||||
log_debug("repmgrd on node \"%s\" (ID %i) paused before switchover, --repmgrd-force-unpause not provided, not unpausing",
|
||||
log_debug("repmgrd on node \"%s\" (ID: %i) paused before switchover, --repmgrd-force-unpause not provided, not unpausing",
|
||||
cell->node_info->node_name,
|
||||
cell->node_info->node_id);
|
||||
|
||||
@@ -5493,7 +5675,7 @@ do_standby_switchover(void)
|
||||
continue;
|
||||
}
|
||||
|
||||
log_debug("unpausing repmgrd on node \"%s\" (ID %i)",
|
||||
log_debug("unpausing repmgrd on node \"%s\" (ID: %i)",
|
||||
cell->node_info->node_name,
|
||||
cell->node_info->node_id);
|
||||
|
||||
@@ -5504,7 +5686,7 @@ do_standby_switchover(void)
|
||||
if (repmgrd_pause(cell->node_info->conn, false) == false)
|
||||
{
|
||||
item_list_append_format(&repmgrd_unpause_errors,
|
||||
_("unable to unpause node \"%s\" (ID %i)"),
|
||||
_("unable to unpause node \"%s\" (ID: %i)"),
|
||||
cell->node_info->node_name,
|
||||
cell->node_info->node_id);
|
||||
error_node_count++;
|
||||
@@ -5513,7 +5695,7 @@ do_standby_switchover(void)
|
||||
else
|
||||
{
|
||||
item_list_append_format(&repmgrd_unpause_errors,
|
||||
_("unable to connect to node \"%s\" (ID %i):\n%s"),
|
||||
_("unable to connect to node \"%s\" (ID: %i):\n%s"),
|
||||
cell->node_info->node_name,
|
||||
cell->node_info->node_id,
|
||||
PQerrorMessage(cell->node_info->conn));
|
||||
@@ -6797,6 +6979,13 @@ run_basebackup(t_node_info *node_record)
|
||||
|
||||
termPQExpBuffer(¶ms);
|
||||
|
||||
if (runtime_options.dry_run == true)
|
||||
{
|
||||
log_info(_("would execute:\n %s"), script.data);
|
||||
termPQExpBuffer(&script);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
log_info(_("executing:\n %s"), script.data);
|
||||
|
||||
/*
|
||||
@@ -7530,7 +7719,7 @@ stop_backup:
|
||||
if (record_status == RECORD_FOUND)
|
||||
{
|
||||
log_verbose(LOG_INFO,
|
||||
_("replication slot \"%s\" aleady exists on upstream node %i"),
|
||||
_("replication slot \"%s\" already exists on upstream node %i"),
|
||||
local_node_record->slot_name,
|
||||
upstream_node_id);
|
||||
}
|
||||
@@ -7960,9 +8149,9 @@ create_recovery_file(t_node_info *node_record, t_conninfo_param_list *primary_co
|
||||
free(escaped);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Caller requests the generated file to be written into a buffer
|
||||
*/
|
||||
if (as_file == false)
|
||||
{
|
||||
/* create file in buffer */
|
||||
@@ -7982,20 +8171,17 @@ create_recovery_file(t_node_info *node_record, t_conninfo_param_list *primary_co
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* PostgreSQL 12 and later: modify postgresql.auto.conf
|
||||
*
|
||||
*/
|
||||
if (server_version_num >= 120000)
|
||||
{
|
||||
|
||||
if (modify_auto_conf(dest, &recovery_config) == false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (write_standby_signal() == false)
|
||||
if (write_standby_signal(dest) == false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -8988,7 +9174,7 @@ do_standby_help(void)
|
||||
printf(_(" --dry-run perform checks etc. but don't actually execute switchover\n"));
|
||||
printf(_(" -F, --force ignore warnings and continue anyway\n"));
|
||||
printf(_(" --force-rewind[=VALUE] use \"pg_rewind\" to reintegrate the old primary if necessary\n"));
|
||||
printf(_(" (9.3 and 9.4 - provide \"pg_rewind\" path)\n"));
|
||||
printf(_(" (PostgreSQL 9.4 - provide \"pg_rewind\" path)\n"));
|
||||
|
||||
printf(_(" -R, --remote-user=USERNAME database server username for SSH operations (default: \"%s\")\n"), runtime_options.username);
|
||||
printf(_(" -S, --superuser=USERNAME superuser to use, if repmgr user is not superuser\n"));
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* repmgr-action-standby.h
|
||||
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
||||
*
|
||||
* 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
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Implements witness actions for the repmgr command line utility
|
||||
*
|
||||
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
||||
*
|
||||
* 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* repmgr-action-witness.h
|
||||
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
||||
*
|
||||
* 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* repmgr-client-global.h
|
||||
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
||||
*
|
||||
* 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
|
||||
@@ -120,6 +120,7 @@ typedef struct
|
||||
bool missing_slots;
|
||||
bool has_passfile;
|
||||
bool replication_connection;
|
||||
bool repmgrd;
|
||||
bool data_directory_config;
|
||||
bool replication_config_owner;
|
||||
bool db_connection;
|
||||
@@ -175,7 +176,7 @@ typedef struct
|
||||
/* "node status" options */ \
|
||||
false, \
|
||||
/* "node check" options */ \
|
||||
false, false, false, false, false, false, false, false, false, false, false, false, \
|
||||
false, false, false, false, false, false, false, false, false, false, false, false, false, \
|
||||
/* "node rejoin" options */ \
|
||||
"", \
|
||||
/* "node service" options */ \
|
||||
@@ -219,7 +220,9 @@ typedef enum
|
||||
|
||||
typedef enum
|
||||
{
|
||||
JOIN_UNKNOWN = -1,
|
||||
JOIN_SUCCESS,
|
||||
JOIN_COMMAND_FAIL,
|
||||
JOIN_FAIL_NO_PING,
|
||||
JOIN_FAIL_NO_REPLICATION
|
||||
} standy_join_status;
|
||||
@@ -282,8 +285,8 @@ extern void get_node_config_directory(char *config_dir_buf);
|
||||
extern void get_node_data_directory(char *data_dir_buf);
|
||||
extern void init_node_record(t_node_info *node_record);
|
||||
extern bool can_use_pg_rewind(PGconn *conn, const char *data_directory, PQExpBufferData *reason);
|
||||
extern void make_standby_signal_path(char *buf);
|
||||
extern bool write_standby_signal(void);
|
||||
extern void make_standby_signal_path(const char *data_dir, char *buf);
|
||||
extern bool write_standby_signal(const char *data_dir);
|
||||
|
||||
extern bool create_replication_slot(PGconn *conn, char *slot_name, t_node_info *upstream_node_record, PQExpBufferData *error_msg);
|
||||
extern bool drop_replication_slot_if_exists(PGconn *conn, int node_id, char *slot_name);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* repmgr-client.c - Command interpreter for the repmgr package
|
||||
*
|
||||
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
||||
*
|
||||
* This module is a command-line utility to easily setup a cluster of
|
||||
* hot standby servers for an HA environment
|
||||
@@ -51,6 +51,7 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <pwd.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <signal.h>
|
||||
@@ -122,7 +123,7 @@ main(int argc, char **argv)
|
||||
/*
|
||||
* Tell the logger we're a command-line program - this will ensure any
|
||||
* output logged before the logger is initialized will be formatted
|
||||
* correctly. Can be overriden with "--log-to-file".
|
||||
* correctly. Can be overridden with "--log-to-file".
|
||||
*/
|
||||
logger_output_mode = OM_COMMAND_LINE;
|
||||
|
||||
@@ -549,6 +550,10 @@ main(int argc, char **argv)
|
||||
runtime_options.data_directory_config = true;
|
||||
break;
|
||||
|
||||
case OPT_REPMGRD:
|
||||
runtime_options.repmgrd = true;
|
||||
break;
|
||||
|
||||
case OPT_REPLICATION_CONFIG_OWNER:
|
||||
runtime_options.replication_config_owner = true;
|
||||
break;
|
||||
@@ -2735,7 +2740,7 @@ do_help(void)
|
||||
*
|
||||
* Note:
|
||||
* This is one of two places where superuser rights are required.
|
||||
* We should also consider possible scenarious where a non-superuser
|
||||
* We should also consider possible scenarios where a non-superuser
|
||||
* has sufficient privileges to install the extension.
|
||||
*/
|
||||
|
||||
@@ -2770,7 +2775,7 @@ create_repmgr_extension(PGconn *conn)
|
||||
log_detail(_("version %s is installed but newer version %s is available"),
|
||||
extversions.installed_version,
|
||||
extversions.default_version);
|
||||
log_hint(_("update the installed extension version by executing \"ALTER EXTENSION repmgr UPDATE\""));
|
||||
log_hint(_("update the installed extension version by executing \"ALTER EXTENSION repmgr UPDATE\" in the repmgr database"));
|
||||
return false;
|
||||
|
||||
case REPMGR_INSTALLED:
|
||||
@@ -2936,7 +2941,7 @@ check_server_version(PGconn *conn, char *server_type, bool exit_on_error, char *
|
||||
* PostgreSQL from a particular PostgreSQL release onwards (e.g. 4.4 with PostgreSQL
|
||||
* 12 and later due to recovery.conf removal), set MAX_UNSUPPORTED_VERSION and
|
||||
* MAX_UNSUPPORTED_VERSION_NUM in "repmgr.h" to define the first PostgreSQL
|
||||
* version which can't be suppored.
|
||||
* version which can't be supported.
|
||||
*/
|
||||
#ifdef MAX_UNSUPPORTED_VERSION_NUM
|
||||
if (conn_server_version_num >= MAX_UNSUPPORTED_VERSION_NUM)
|
||||
@@ -3661,11 +3666,11 @@ can_use_pg_rewind(PGconn *conn, const char *data_directory, PQExpBufferData *rea
|
||||
|
||||
|
||||
void
|
||||
make_standby_signal_path(char *buf)
|
||||
make_standby_signal_path(const char *data_dir, char *buf)
|
||||
{
|
||||
snprintf(buf, MAXPGPATH,
|
||||
"%s/%s",
|
||||
config_file_options.data_directory,
|
||||
data_dir,
|
||||
STANDBY_SIGNAL_FILE);
|
||||
}
|
||||
|
||||
@@ -3673,13 +3678,15 @@ make_standby_signal_path(char *buf)
|
||||
* create standby.signal (PostgreSQL 12 and later)
|
||||
*/
|
||||
bool
|
||||
write_standby_signal(void)
|
||||
write_standby_signal(const char *data_dir)
|
||||
{
|
||||
char standby_signal_file_path[MAXPGPATH] = "";
|
||||
FILE *file;
|
||||
mode_t um;
|
||||
|
||||
make_standby_signal_path(standby_signal_file_path);
|
||||
Assert(data_dir != NULL);
|
||||
|
||||
make_standby_signal_path(data_dir, standby_signal_file_path);
|
||||
|
||||
/* Set umask to 0600 */
|
||||
um = umask((~(S_IRUSR | S_IWUSR)) & (S_IRWXG | S_IRWXO));
|
||||
@@ -4086,7 +4093,7 @@ check_standby_join(PGconn *upstream_conn, t_node_info *upstream_node_record, t_n
|
||||
|
||||
if (node_attached == NODE_NOT_ATTACHED)
|
||||
{
|
||||
log_detail(_("node \"%s\" (ID: %i) is currrently attached to its upstream node in state \"%s\""),
|
||||
log_detail(_("node \"%s\" (ID: %i) is currently attached to its upstream node in state \"%s\""),
|
||||
upstream_node_record->node_name,
|
||||
standby_node_record->node_id,
|
||||
node_state);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* repmgr-client.h
|
||||
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
||||
*
|
||||
* 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
|
||||
@@ -100,6 +100,7 @@
|
||||
#define OPT_DB_CONNECTION 1047
|
||||
#define OPT_VERIFY_BACKUP 1048
|
||||
#define OPT_RECOVERY_MIN_APPLY_DELAY 1049
|
||||
#define OPT_REPMGRD 1050
|
||||
|
||||
/* These options are for internal use only */
|
||||
#define OPT_CONFIG_ARCHIVE_DIR 2001
|
||||
@@ -193,6 +194,7 @@ static struct option long_options[] =
|
||||
{"role", no_argument, NULL, OPT_ROLE},
|
||||
{"slots", no_argument, NULL, OPT_SLOTS},
|
||||
{"missing-slots", no_argument, NULL, OPT_MISSING_SLOTS},
|
||||
{"repmgrd", no_argument, NULL, OPT_REPMGRD},
|
||||
{"has-passfile", no_argument, NULL, OPT_HAS_PASSFILE},
|
||||
{"replication-connection", no_argument, NULL, OPT_REPL_CONN},
|
||||
{"data-directory-config", no_argument, NULL, OPT_DATA_DIRECTORY_CONFIG},
|
||||
|
||||
87
repmgr.c
87
repmgr.c
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* repmgr.c - repmgr extension
|
||||
*
|
||||
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
||||
*
|
||||
* This is the actual extension code; see repmgr-client.c for the code which
|
||||
* generates the repmgr binary
|
||||
@@ -88,59 +88,24 @@ void _PG_fini(void);
|
||||
|
||||
static void repmgr_shmem_startup(void);
|
||||
|
||||
Datum set_local_node_id(PG_FUNCTION_ARGS);
|
||||
PG_FUNCTION_INFO_V1(set_local_node_id);
|
||||
|
||||
Datum get_local_node_id(PG_FUNCTION_ARGS);
|
||||
PG_FUNCTION_INFO_V1(get_local_node_id);
|
||||
|
||||
Datum standby_set_last_updated(PG_FUNCTION_ARGS);
|
||||
PG_FUNCTION_INFO_V1(standby_set_last_updated);
|
||||
|
||||
Datum standby_get_last_updated(PG_FUNCTION_ARGS);
|
||||
PG_FUNCTION_INFO_V1(standby_get_last_updated);
|
||||
|
||||
Datum set_upstream_last_seen(PG_FUNCTION_ARGS);
|
||||
PG_FUNCTION_INFO_V1(set_upstream_last_seen);
|
||||
|
||||
Datum get_upstream_last_seen(PG_FUNCTION_ARGS);
|
||||
PG_FUNCTION_INFO_V1(get_upstream_last_seen);
|
||||
|
||||
Datum get_upstream_node_id(PG_FUNCTION_ARGS);
|
||||
PG_FUNCTION_INFO_V1(get_upstream_node_id);
|
||||
|
||||
Datum set_upstream_node_id(PG_FUNCTION_ARGS);
|
||||
PG_FUNCTION_INFO_V1(set_upstream_node_id);
|
||||
|
||||
Datum notify_follow_primary(PG_FUNCTION_ARGS);
|
||||
PG_FUNCTION_INFO_V1(notify_follow_primary);
|
||||
|
||||
Datum get_new_primary(PG_FUNCTION_ARGS);
|
||||
PG_FUNCTION_INFO_V1(get_new_primary);
|
||||
|
||||
Datum reset_voting_status(PG_FUNCTION_ARGS);
|
||||
PG_FUNCTION_INFO_V1(reset_voting_status);
|
||||
|
||||
Datum set_repmgrd_pid(PG_FUNCTION_ARGS);
|
||||
PG_FUNCTION_INFO_V1(repmgr_set_local_node_id);
|
||||
PG_FUNCTION_INFO_V1(repmgr_get_local_node_id);
|
||||
PG_FUNCTION_INFO_V1(repmgr_standby_set_last_updated);
|
||||
PG_FUNCTION_INFO_V1(repmgr_standby_get_last_updated);
|
||||
PG_FUNCTION_INFO_V1(repmgr_set_upstream_last_seen);
|
||||
PG_FUNCTION_INFO_V1(repmgr_get_upstream_last_seen);
|
||||
PG_FUNCTION_INFO_V1(repmgr_get_upstream_node_id);
|
||||
PG_FUNCTION_INFO_V1(repmgr_set_upstream_node_id);
|
||||
PG_FUNCTION_INFO_V1(repmgr_notify_follow_primary);
|
||||
PG_FUNCTION_INFO_V1(repmgr_get_new_primary);
|
||||
PG_FUNCTION_INFO_V1(repmgr_reset_voting_status);
|
||||
PG_FUNCTION_INFO_V1(set_repmgrd_pid);
|
||||
|
||||
Datum get_repmgrd_pid(PG_FUNCTION_ARGS);
|
||||
PG_FUNCTION_INFO_V1(get_repmgrd_pid);
|
||||
|
||||
Datum get_repmgrd_pidfile(PG_FUNCTION_ARGS);
|
||||
PG_FUNCTION_INFO_V1(get_repmgrd_pidfile);
|
||||
|
||||
Datum repmgrd_is_running(PG_FUNCTION_ARGS);
|
||||
PG_FUNCTION_INFO_V1(repmgrd_is_running);
|
||||
|
||||
Datum repmgrd_pause(PG_FUNCTION_ARGS);
|
||||
PG_FUNCTION_INFO_V1(repmgrd_pause);
|
||||
|
||||
Datum repmgrd_is_paused(PG_FUNCTION_ARGS);
|
||||
PG_FUNCTION_INFO_V1(repmgrd_is_paused);
|
||||
|
||||
Datum get_wal_receiver_pid(PG_FUNCTION_ARGS);
|
||||
PG_FUNCTION_INFO_V1(get_wal_receiver_pid);
|
||||
PG_FUNCTION_INFO_V1(repmgr_get_wal_receiver_pid);
|
||||
|
||||
|
||||
/*
|
||||
@@ -194,7 +159,7 @@ repmgr_shmem_startup(void)
|
||||
shared_state = NULL;
|
||||
|
||||
/*
|
||||
* Create or attach to the shared memory state, including hash table
|
||||
* Create or attach to the shared memory state
|
||||
*/
|
||||
LWLockAcquire(AddinShmemInitLock, LW_EXCLUSIVE);
|
||||
|
||||
@@ -233,7 +198,7 @@ repmgr_shmem_startup(void)
|
||||
/* ==================== */
|
||||
|
||||
Datum
|
||||
set_local_node_id(PG_FUNCTION_ARGS)
|
||||
repmgr_set_local_node_id(PG_FUNCTION_ARGS)
|
||||
{
|
||||
int local_node_id = UNKNOWN_NODE_ID;
|
||||
int stored_node_id = UNKNOWN_NODE_ID;
|
||||
@@ -303,7 +268,7 @@ set_local_node_id(PG_FUNCTION_ARGS)
|
||||
|
||||
|
||||
Datum
|
||||
get_local_node_id(PG_FUNCTION_ARGS)
|
||||
repmgr_get_local_node_id(PG_FUNCTION_ARGS)
|
||||
{
|
||||
int local_node_id = UNKNOWN_NODE_ID;
|
||||
|
||||
@@ -320,7 +285,7 @@ get_local_node_id(PG_FUNCTION_ARGS)
|
||||
|
||||
/* update and return last updated with current timestamp */
|
||||
Datum
|
||||
standby_set_last_updated(PG_FUNCTION_ARGS)
|
||||
repmgr_standby_set_last_updated(PG_FUNCTION_ARGS)
|
||||
{
|
||||
TimestampTz last_updated = GetCurrentTimestamp();
|
||||
|
||||
@@ -337,7 +302,7 @@ standby_set_last_updated(PG_FUNCTION_ARGS)
|
||||
|
||||
/* get last updated timestamp */
|
||||
Datum
|
||||
standby_get_last_updated(PG_FUNCTION_ARGS)
|
||||
repmgr_standby_get_last_updated(PG_FUNCTION_ARGS)
|
||||
{
|
||||
TimestampTz last_updated;
|
||||
|
||||
@@ -354,7 +319,7 @@ standby_get_last_updated(PG_FUNCTION_ARGS)
|
||||
|
||||
|
||||
Datum
|
||||
set_upstream_last_seen(PG_FUNCTION_ARGS)
|
||||
repmgr_set_upstream_last_seen(PG_FUNCTION_ARGS)
|
||||
{
|
||||
int upstream_node_id = UNKNOWN_NODE_ID;
|
||||
|
||||
@@ -377,7 +342,7 @@ set_upstream_last_seen(PG_FUNCTION_ARGS)
|
||||
|
||||
|
||||
Datum
|
||||
get_upstream_last_seen(PG_FUNCTION_ARGS)
|
||||
repmgr_get_upstream_last_seen(PG_FUNCTION_ARGS)
|
||||
{
|
||||
long secs;
|
||||
int microsecs;
|
||||
@@ -411,7 +376,7 @@ get_upstream_last_seen(PG_FUNCTION_ARGS)
|
||||
|
||||
|
||||
Datum
|
||||
get_upstream_node_id(PG_FUNCTION_ARGS)
|
||||
repmgr_get_upstream_node_id(PG_FUNCTION_ARGS)
|
||||
{
|
||||
int upstream_node_id = UNKNOWN_NODE_ID;
|
||||
|
||||
@@ -426,7 +391,7 @@ get_upstream_node_id(PG_FUNCTION_ARGS)
|
||||
}
|
||||
|
||||
Datum
|
||||
set_upstream_node_id(PG_FUNCTION_ARGS)
|
||||
repmgr_set_upstream_node_id(PG_FUNCTION_ARGS)
|
||||
{
|
||||
int upstream_node_id = UNKNOWN_NODE_ID;
|
||||
int local_node_id = UNKNOWN_NODE_ID;
|
||||
@@ -462,7 +427,7 @@ set_upstream_node_id(PG_FUNCTION_ARGS)
|
||||
|
||||
|
||||
Datum
|
||||
notify_follow_primary(PG_FUNCTION_ARGS)
|
||||
repmgr_notify_follow_primary(PG_FUNCTION_ARGS)
|
||||
{
|
||||
int primary_node_id = UNKNOWN_NODE_ID;
|
||||
|
||||
@@ -505,7 +470,7 @@ notify_follow_primary(PG_FUNCTION_ARGS)
|
||||
|
||||
|
||||
Datum
|
||||
get_new_primary(PG_FUNCTION_ARGS)
|
||||
repmgr_get_new_primary(PG_FUNCTION_ARGS)
|
||||
{
|
||||
int new_primary_node_id = UNKNOWN_NODE_ID;
|
||||
|
||||
@@ -527,7 +492,7 @@ get_new_primary(PG_FUNCTION_ARGS)
|
||||
|
||||
|
||||
Datum
|
||||
reset_voting_status(PG_FUNCTION_ARGS)
|
||||
repmgr_reset_voting_status(PG_FUNCTION_ARGS)
|
||||
{
|
||||
if (!shared_state)
|
||||
PG_RETURN_NULL();
|
||||
@@ -735,7 +700,7 @@ repmgrd_is_paused(PG_FUNCTION_ARGS)
|
||||
|
||||
|
||||
Datum
|
||||
get_wal_receiver_pid(PG_FUNCTION_ARGS)
|
||||
repmgr_get_wal_receiver_pid(PG_FUNCTION_ARGS)
|
||||
{
|
||||
int wal_receiver_pid;
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
#replication_user='repmgr' # User to make replication connections with, if not set
|
||||
# defaults to the user defined in "conninfo".
|
||||
# defaults to the user defined in "conninfo".
|
||||
|
||||
#replication_type='physical' # Must "physical" (the default).
|
||||
|
||||
@@ -238,7 +238,7 @@ ssh_options='-q -o ConnectTimeout=10' # Options to append to "ssh"
|
||||
|
||||
#primary_follow_timeout=60 # The max length of time (in seconds) to wait
|
||||
# for the new primary to become available
|
||||
#standby_follow_timeout=15 # The max length of time (in seconds) to wait
|
||||
#standby_follow_timeout=30 # The max length of time (in seconds) to wait
|
||||
# for the standby to connect to the primary
|
||||
#standby_follow_restart=false # Restart the standby instead of sending a SIGHUP
|
||||
# (only for PostgreSQL 13 and later)
|
||||
@@ -301,7 +301,7 @@ ssh_options='-q -o ConnectTimeout=10' # Options to append to "ssh"
|
||||
|
||||
#connection_check_type=ping # How to check availability of the upstream node; valid options:
|
||||
# 'ping': use PQping() to check if the node is accepting connections
|
||||
# 'connection': execute a throwaway query on the current connection
|
||||
# 'connection': attempt to make a new connection to the node
|
||||
# 'query': execute an SQL statement on the node via the existing connection
|
||||
#reconnect_attempts=6 # Number of attempts which will be made to reconnect to an unreachable
|
||||
# primary (or other upstream node)
|
||||
@@ -314,7 +314,7 @@ ssh_options='-q -o ConnectTimeout=10' # Options to append to "ssh"
|
||||
#follow_command='' # command repmgrd executes when instructing a standby to follow a new primary;
|
||||
# use something like:
|
||||
#
|
||||
# repmgr standby follow -f /etc/repmgr.conf -W --upstream-node-id=%n
|
||||
# repmgr standby follow -f /etc/repmgr.conf --upstream-node-id=%n
|
||||
#
|
||||
#primary_notification_timeout=60 # Interval (in seconds) which repmgrd on a standby
|
||||
# will wait for a notification from the new primary,
|
||||
@@ -323,7 +323,7 @@ ssh_options='-q -o ConnectTimeout=10' # Options to append to "ssh"
|
||||
# for the the local node to restart and become ready to accept connections after
|
||||
# executing "follow_command" (defaults to the value set in "standby_reconnect_timeout")
|
||||
|
||||
#monitoring_history=no # Whether to write monitoring data to the "montoring_history" table
|
||||
#monitoring_history=no # Whether to write monitoring data to the "monitoring_history" table
|
||||
#monitor_interval_secs=2 # Interval (in seconds) at which to write monitoring data
|
||||
#degraded_monitoring_timeout=-1 # Interval (in seconds) after which repmgrd will terminate if the
|
||||
# server(s) being monitored are no longer available. -1 (default)
|
||||
@@ -337,6 +337,7 @@ ssh_options='-q -o ConnectTimeout=10' # Options to append to "ssh"
|
||||
# "--no-pid-file" will force PID file creation to be skipped.
|
||||
# Note: there is normally no need to set this, particularly if
|
||||
# repmgr was installed from packages.
|
||||
#repmgrd_exit_on_inactive_node=false # If "true", and the node record is marked as "inactive", abort repmgrd startup
|
||||
#standby_disconnect_on_failover=false # If "true", in a failover situation wait for all standbys to
|
||||
# disconnect their WAL receivers before electing a new primary
|
||||
# (PostgreSQL 9.5 and later only; repmgr user must be a superuser for this)
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
# repmgr extension
|
||||
comment = 'Replication manager for PostgreSQL'
|
||||
default_version = '5.2'
|
||||
default_version = '5.3'
|
||||
module_pathname = '$libdir/repmgr'
|
||||
relocatable = false
|
||||
schema = repmgr
|
||||
|
||||
|
||||
|
||||
3
repmgr.h
3
repmgr.h
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* repmgr.h
|
||||
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
||||
*
|
||||
* 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
|
||||
@@ -135,6 +135,7 @@
|
||||
#define DEFAULT_ASYNC_QUERY_TIMEOUT 60 /* seconds */
|
||||
#define DEFAULT_PRIMARY_NOTIFICATION_TIMEOUT 60 /* seconds */
|
||||
#define DEFAULT_REPMGRD_STANDBY_STARTUP_TIMEOUT -1 /*seconds */
|
||||
#define DEFAULT_REPMGRD_EXIT_ON_INACTIVE_NODE false,
|
||||
#define DEFAULT_STANDBY_DISCONNECT_ON_FAILOVER false
|
||||
#define DEFAULT_SIBLING_NODES_DISCONNECT_TIMEOUT 30 /* seconds */
|
||||
#define DEFAULT_CONNECTION_CHECK_TYPE CHECK_PING
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#define REPMGR_VERSION_DATE ""
|
||||
#define REPMGR_VERSION "5.2.1"
|
||||
#define REPMGR_VERSION_NUM 50201
|
||||
#define REPMGR_RELEASE_DATE "2020-12-07"
|
||||
#define REPMGR_VERSION "5.3.1"
|
||||
#define REPMGR_VERSION_NUM 50301
|
||||
#define REPMGR_EXTENSION_VERSION "5.3"
|
||||
#define REPMGR_EXTENSION_NUM 50300
|
||||
#define REPMGR_RELEASE_DATE "2022-02-15"
|
||||
#define PG_ACTUAL_VERSION_NUM
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* repmgrd-physical.c - physical (streaming) replication functionality for repmgrd
|
||||
*
|
||||
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
||||
*
|
||||
* 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
|
||||
@@ -169,45 +169,126 @@ handle_sigint_physical(SIGNAL_ARGS)
|
||||
/* perform some sanity checks on the node's configuration */
|
||||
|
||||
void
|
||||
do_physical_node_check(void)
|
||||
do_physical_node_check(PGconn *conn)
|
||||
{
|
||||
/*
|
||||
* Check if node record is active - if not, and `failover=automatic`, the
|
||||
* node won't be considered as a promotion candidate; this often happens
|
||||
* when a failed primary is recloned and the node was not re-registered,
|
||||
* giving the impression failover capability is there when it's not. In
|
||||
* this case abort with an error and a hint about registering.
|
||||
* If node record is "inactive"; if not, attempt to set it to "active".
|
||||
*
|
||||
* If `failover=manual`, repmgrd can continue to passively monitor the
|
||||
* node, but we should nevertheless issue a warning and the same hint.
|
||||
* Usually it will have become inactive due to e.g. a standby being shut down
|
||||
* while repmgrd was running in an unpaused state. In this case it's
|
||||
* perfectly reasonable to automatically mark the node as "active".
|
||||
*/
|
||||
|
||||
if (local_node_info.active == false)
|
||||
{
|
||||
char *hint = "Check that \"repmgr (primary|standby) register\" was executed for this node";
|
||||
RecoveryType recovery_type = get_recovery_type(conn);
|
||||
|
||||
switch (config_file_options.failover)
|
||||
/*
|
||||
* If the local node's recovery status is incompatible with its registered
|
||||
* status, e.g. registered as primary but running as a standby, refuse to start.
|
||||
*
|
||||
* This typically happens when a failed primary is recloned but the node was not
|
||||
* re-registered, leaving the cluster in a potentially ambiguous state. In
|
||||
* this case it would not be possible or desirable to attempt to set the
|
||||
* node to active; the user should ensure the cluster is in the correct state.
|
||||
*/
|
||||
if (recovery_type != RECTYPE_UNKNOWN && local_node_info.type != UNKNOWN)
|
||||
{
|
||||
/* "failover" is an enum, all values should be covered here */
|
||||
bool require_reregister = false;
|
||||
PQExpBufferData event_details;
|
||||
initPQExpBuffer(&event_details);
|
||||
|
||||
case FAILOVER_AUTOMATIC:
|
||||
log_error(_("this node is marked as inactive and cannot be used as a failover target"));
|
||||
if (recovery_type == RECTYPE_STANDBY && local_node_info.type != STANDBY)
|
||||
{
|
||||
appendPQExpBuffer(&event_details,
|
||||
_("node is registered as a %s but running as a standby"),
|
||||
get_node_type_string(local_node_info.type));
|
||||
|
||||
require_reregister = true;
|
||||
}
|
||||
else if (recovery_type == RECTYPE_PRIMARY && local_node_info.type == STANDBY)
|
||||
{
|
||||
log_error(_("node is registered as a standby but running as a %s"), get_node_type_string(local_node_info.type));
|
||||
require_reregister = true;
|
||||
}
|
||||
|
||||
if (require_reregister == true)
|
||||
{
|
||||
log_error("%s", event_details.data);
|
||||
log_hint(_("%s"), hint);
|
||||
|
||||
create_event_notification(NULL,
|
||||
&config_file_options,
|
||||
config_file_options.node_id,
|
||||
"repmgrd_shutdown",
|
||||
"repmgrd_start",
|
||||
false,
|
||||
"node is inactive and cannot be used as a failover target");
|
||||
event_details.data);
|
||||
|
||||
termPQExpBuffer(&event_details);
|
||||
terminate(ERR_BAD_CONFIG);
|
||||
break;
|
||||
}
|
||||
|
||||
case FAILOVER_MANUAL:
|
||||
log_warning(_("this node is marked as inactive and will be passively monitored only"));
|
||||
log_hint(_("%s"), hint);
|
||||
break;
|
||||
termPQExpBuffer(&event_details);
|
||||
}
|
||||
|
||||
/*
|
||||
* Attempt to set node record active (unless explicitly configured not to)
|
||||
*/
|
||||
log_notice(_("setting node record for node \"%s\" (ID: %i) to \"active\""),
|
||||
local_node_info.node_name,
|
||||
local_node_info.node_id);
|
||||
|
||||
if (config_file_options.repmgrd_exit_on_inactive_node == false)
|
||||
{
|
||||
PGconn *primary_conn = get_primary_connection(conn, NULL, NULL);
|
||||
bool success = true;
|
||||
|
||||
if (PQstatus(primary_conn) != CONNECTION_OK)
|
||||
{
|
||||
log_error(_("unable to connect to the primary node to activate the node record"));
|
||||
success = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
success = update_node_record_set_active(primary_conn, local_node_info.node_id, true);
|
||||
PQfinish(primary_conn);
|
||||
}
|
||||
|
||||
if (success == true)
|
||||
{
|
||||
local_node_info.active = true;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Corner-case where it was not possible to set the node to "active"
|
||||
*/
|
||||
if (local_node_info.active == false)
|
||||
{
|
||||
switch (config_file_options.failover)
|
||||
{
|
||||
/* "failover" is an enum, all values should be covered here */
|
||||
|
||||
case FAILOVER_AUTOMATIC:
|
||||
log_error(_("this node is marked as inactive and cannot be used as a failover target"));
|
||||
log_hint(_("%s"), hint);
|
||||
|
||||
create_event_notification(NULL,
|
||||
&config_file_options,
|
||||
config_file_options.node_id,
|
||||
"repmgrd_start",
|
||||
false,
|
||||
"node is inactive and cannot be used as a failover target");
|
||||
|
||||
terminate(ERR_BAD_CONFIG);
|
||||
break;
|
||||
|
||||
case FAILOVER_MANUAL:
|
||||
log_warning(_("this node is marked as inactive and will be passively monitored only"));
|
||||
log_hint(_("%s"), hint);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -504,6 +585,7 @@ monitor_streaming_primary(void)
|
||||
|
||||
if (is_server_available(local_node_info.conninfo) == true)
|
||||
{
|
||||
close_connection(&local_conn);
|
||||
local_conn = establish_db_connection(local_node_info.conninfo, false);
|
||||
|
||||
if (PQstatus(local_conn) != CONNECTION_OK)
|
||||
@@ -737,7 +819,7 @@ check_primary_status(int degraded_monitoring_elapsed)
|
||||
/* refresh our copy of the node record from the primary */
|
||||
record_status = get_node_record(new_primary_conn, config_file_options.node_id, &local_node_info);
|
||||
|
||||
/* this is unlikley to happen */
|
||||
/* this is unlikely to happen */
|
||||
if (record_status != RECORD_FOUND)
|
||||
{
|
||||
log_warning(_("unable to retrieve local node record from primary node %i"), primary_node_id);
|
||||
@@ -1111,7 +1193,7 @@ execute_child_nodes_disconnect_command(NodeInfoList *db_child_node_records, t_ch
|
||||
/* calculate number of connected child nodes */
|
||||
for (cell = db_child_node_records->head; cell; cell = cell->next)
|
||||
{
|
||||
/* exclude witness server from total, if necessay */
|
||||
/* exclude witness server from total, if necessary */
|
||||
if (config_file_options.child_nodes_connected_include_witness == false &&
|
||||
cell->node_info->type == WITNESS)
|
||||
continue;
|
||||
@@ -1149,7 +1231,7 @@ execute_child_nodes_disconnect_command(NodeInfoList *db_child_node_records, t_ch
|
||||
instr_time current_time = current_time_base;
|
||||
int seconds_since_detached;
|
||||
|
||||
/* exclude witness server from calculatin if neccessary */
|
||||
/* exclude witness server from calculation, if requested */
|
||||
if (config_file_options.child_nodes_connected_include_witness == false &&
|
||||
child_node_rec->type == WITNESS)
|
||||
continue;
|
||||
@@ -1732,7 +1814,10 @@ monitor_streaming_standby(void)
|
||||
if (upstream_check_result == true)
|
||||
{
|
||||
if (config_file_options.connection_check_type != CHECK_QUERY)
|
||||
{
|
||||
close_connection(&upstream_conn);
|
||||
upstream_conn = establish_db_connection(upstream_node_info.conninfo, false);
|
||||
}
|
||||
|
||||
if (PQstatus(upstream_conn) == CONNECTION_OK)
|
||||
{
|
||||
@@ -1813,6 +1898,7 @@ monitor_streaming_standby(void)
|
||||
int former_upstream_node_id = local_node_info.upstream_node_id;
|
||||
NodeInfoList sibling_nodes = T_NODE_INFO_LIST_INITIALIZER;
|
||||
PQExpBufferData event_details;
|
||||
t_event_info event_info = T_EVENT_INFO_INITIALIZER;
|
||||
|
||||
update_node_record_set_primary(local_conn, local_node_info.node_id);
|
||||
record_status = get_node_record(local_conn, local_node_info.node_id, &local_node_info);
|
||||
@@ -1825,12 +1911,16 @@ monitor_streaming_standby(void)
|
||||
initPQExpBuffer(&event_details);
|
||||
appendPQExpBufferStr(&event_details,
|
||||
_("promotion command failed but promotion completed successfully"));
|
||||
create_event_notification(local_conn,
|
||||
&config_file_options,
|
||||
local_node_info.node_id,
|
||||
"repmgrd_failover_promote",
|
||||
true,
|
||||
event_details.data);
|
||||
|
||||
event_info.node_id = former_upstream_node_id;
|
||||
|
||||
create_event_notification_extended(local_conn,
|
||||
&config_file_options,
|
||||
local_node_info.node_id,
|
||||
"repmgrd_failover_promote",
|
||||
true,
|
||||
event_details.data,
|
||||
&event_info);
|
||||
|
||||
termPQExpBuffer(&event_details);
|
||||
|
||||
@@ -2460,8 +2550,10 @@ monitor_streaming_witness(void)
|
||||
if (check_upstream_connection(&primary_conn, upstream_node_info.conninfo, NULL) == true)
|
||||
{
|
||||
if (config_file_options.connection_check_type != CHECK_QUERY)
|
||||
{
|
||||
close_connection(&primary_conn);
|
||||
primary_conn = establish_db_connection(upstream_node_info.conninfo, false);
|
||||
|
||||
}
|
||||
if (PQstatus(primary_conn) == CONNECTION_OK)
|
||||
{
|
||||
PQExpBufferData event_details;
|
||||
@@ -2975,7 +3067,6 @@ do_primary_failover(void)
|
||||
|
||||
t_node_info new_primary = T_NODE_INFO_INITIALIZER;
|
||||
RecordStatus record_status = RECORD_NOT_FOUND;
|
||||
PGconn *new_primary_conn;
|
||||
|
||||
record_status = get_node_record(local_conn, new_primary_id, &new_primary);
|
||||
|
||||
@@ -2987,6 +3078,7 @@ do_primary_failover(void)
|
||||
else
|
||||
{
|
||||
PQExpBufferData event_details;
|
||||
PGconn *new_primary_conn;
|
||||
|
||||
initPQExpBuffer(&event_details);
|
||||
appendPQExpBuffer(&event_details,
|
||||
@@ -3007,7 +3099,6 @@ do_primary_failover(void)
|
||||
event_details.data);
|
||||
close_connection(&new_primary_conn);
|
||||
termPQExpBuffer(&event_details);
|
||||
|
||||
}
|
||||
failover_state = FAILOVER_STATE_REQUIRES_MANUAL_FAILOVER;
|
||||
}
|
||||
@@ -3254,7 +3345,7 @@ update_monitoring_history(void)
|
||||
*
|
||||
* Attach cascaded standby to another node, currently the primary.
|
||||
*
|
||||
* Note that in contrast to a primary failover, where one of the downstrean
|
||||
* Note that in contrast to a primary failover, where one of the downstream
|
||||
* standby nodes will become a primary, a cascaded standby failover (where the
|
||||
* upstream standby has gone away) is "just" a case of attaching the standby to
|
||||
* another node.
|
||||
@@ -3674,6 +3765,7 @@ promote_self(void)
|
||||
|
||||
{
|
||||
PQExpBufferData event_details;
|
||||
t_event_info event_info = T_EVENT_INFO_INITIALIZER;
|
||||
|
||||
/* update own internal node record */
|
||||
record_status = get_node_record(local_conn, local_node_info.node_id, &local_node_info);
|
||||
@@ -3690,13 +3782,16 @@ promote_self(void)
|
||||
failed_primary.node_name,
|
||||
failed_primary.node_id);
|
||||
|
||||
event_info.node_id = failed_primary.node_id;
|
||||
|
||||
/* local_conn is now the primary connection */
|
||||
create_event_notification(local_conn,
|
||||
&config_file_options,
|
||||
local_node_info.node_id,
|
||||
"repmgrd_failover_promote",
|
||||
true,
|
||||
event_details.data);
|
||||
create_event_notification_extended(local_conn,
|
||||
&config_file_options,
|
||||
local_node_info.node_id,
|
||||
"repmgrd_failover_promote",
|
||||
true,
|
||||
event_details.data,
|
||||
&event_info);
|
||||
|
||||
termPQExpBuffer(&event_details);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* repmgrd-physical.h
|
||||
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
||||
*
|
||||
* 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
|
||||
@@ -19,7 +19,7 @@
|
||||
#ifndef _REPMGRD_PHYSICAL_H_
|
||||
#define _REPMGRD_PHYSICAL_H_
|
||||
|
||||
void do_physical_node_check(void);
|
||||
void do_physical_node_check(PGconn *conn);
|
||||
|
||||
void monitor_streaming_primary(void);
|
||||
void monitor_streaming_standby(void);
|
||||
|
||||
26
repmgrd.c
26
repmgrd.c
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* repmgrd.c - Replication manager daemon
|
||||
*
|
||||
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
||||
*
|
||||
* 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
|
||||
@@ -131,7 +131,7 @@ main(int argc, char **argv)
|
||||
|
||||
memset(pid_file, 0, MAXPGPATH);
|
||||
|
||||
while ((c = getopt_long(argc, argv, "?Vf:L:vdp:m", long_options, &optindex)) != -1)
|
||||
while ((c = getopt_long(argc, argv, "?Vf:L:vdp:sm", long_options, &optindex)) != -1)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
@@ -249,7 +249,7 @@ main(int argc, char **argv)
|
||||
/*
|
||||
* Parse the configuration file, if provided (if no configuration file was
|
||||
* provided, an attempt will be made to find one in one of the default
|
||||
* locations). If no conifguration file is available, or it can't be parsed
|
||||
* locations). If no configuration file is available, or it can't be parsed
|
||||
* parse_config() will abort anyway, with an appropriate message.
|
||||
*/
|
||||
load_config(config_file, verbose, false, argv[0]);
|
||||
@@ -307,7 +307,7 @@ main(int argc, char **argv)
|
||||
}
|
||||
|
||||
|
||||
/* Some configuration file items can be overriden by command line options */
|
||||
/* Some configuration file items can be overridden by command line options */
|
||||
|
||||
/*
|
||||
* Command-line parameter -L/--log-level overrides any setting in config
|
||||
@@ -396,13 +396,14 @@ main(int argc, char **argv)
|
||||
* extension is the latest available according to "pg_available_extensions" -
|
||||
* - does our (major) version match that?
|
||||
*/
|
||||
log_verbose(LOG_DEBUG, "binary version: %i; extension version: %i",
|
||||
REPMGR_VERSION_NUM, extversions.installed_version_num);
|
||||
if ((REPMGR_VERSION_NUM/100) < (extversions.installed_version_num / 100))
|
||||
log_verbose(LOG_DEBUG, "expected extension version: %i; extension version: %i",
|
||||
REPMGR_EXTENSION_NUM, extversions.installed_version_num);
|
||||
if ((REPMGR_EXTENSION_NUM/100) < (extversions.installed_version_num / 100))
|
||||
{
|
||||
log_error(_("this \"repmgr\" version is older than the installed \"repmgr\" extension version"));
|
||||
log_detail(_("\"repmgr\" version %s is installed but extension is version %s"),
|
||||
log_detail(_("\"repmgr\" version %s providing extension version %s is installed but extension is version %s"),
|
||||
REPMGR_VERSION,
|
||||
REPMGR_EXTENSION_VERSION,
|
||||
extversions.installed_version);
|
||||
log_hint(_("update the repmgr binaries to match the installed extension version"));
|
||||
|
||||
@@ -410,13 +411,14 @@ main(int argc, char **argv)
|
||||
exit(ERR_BAD_CONFIG);
|
||||
}
|
||||
|
||||
if ((REPMGR_VERSION_NUM/100) > (extversions.installed_version_num / 100))
|
||||
if ((REPMGR_EXTENSION_NUM/100) > (extversions.installed_version_num / 100))
|
||||
{
|
||||
log_error(_("this \"repmgr\" version is newer than the installed \"repmgr\" extension version"));
|
||||
log_detail(_("\"repmgr\" version %s is installed but extension is version %s"),
|
||||
log_detail(_("\"repmgr\" version %s providing extension version %s is installed but extension is version %s"),
|
||||
REPMGR_VERSION,
|
||||
REPMGR_EXTENSION_VERSION,
|
||||
extversions.installed_version);
|
||||
log_hint(_("update the installed extension version by executing \"ALTER EXTENSION repmgr UPDATE\""));
|
||||
log_hint(_("update the installed extension version by executing \"ALTER EXTENSION repmgr UPDATE\" in the repmgr database"));
|
||||
|
||||
close_connection(&local_conn);
|
||||
exit(ERR_BAD_CONFIG);
|
||||
@@ -510,7 +512,7 @@ main(int argc, char **argv)
|
||||
log_debug("node id is %i, upstream node id is %i",
|
||||
local_node_info.node_id,
|
||||
local_node_info.upstream_node_id);
|
||||
do_physical_node_check();
|
||||
do_physical_node_check(local_conn);
|
||||
}
|
||||
|
||||
if (daemonize == true)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* repmgrd.h
|
||||
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* strutil.c
|
||||
*
|
||||
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
||||
*
|
||||
* 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
|
||||
@@ -369,7 +369,6 @@ check_status_list_free(CheckStatusList *list)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const char *
|
||||
output_check_status(CheckStatus status)
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* strutil.h
|
||||
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
||||
*
|
||||
* 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
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Functions which need to be executed on the local system.
|
||||
*
|
||||
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
||||
*
|
||||
* 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* sysutils.h
|
||||
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
||||
*
|
||||
* 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
|
||||
|
||||
Reference in New Issue
Block a user