mirror of
https://github.com/EnterpriseDB/repmgr.git
synced 2026-03-23 15:16:29 +00:00
Compare commits
4 Commits
REL5_2_STA
...
v5.1.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
374f19675d | ||
|
|
ce88f3ec43 | ||
|
|
5acdd69add | ||
|
|
71e23107e7 |
@@ -2,7 +2,7 @@ License and Contributions
|
|||||||
=========================
|
=========================
|
||||||
|
|
||||||
`repmgr` is licensed under the GPL v3. All of its code and documentation is
|
`repmgr` is licensed under the GPL v3. All of its code and documentation is
|
||||||
Copyright 2010-2021, EnterpriseDB Corporation. See the files COPYRIGHT and LICENSE for
|
Copyright 2010-2020, 2ndQuadrant Limited. See the files COPYRIGHT and LICENSE for
|
||||||
details.
|
details.
|
||||||
|
|
||||||
The development of repmgr has primarily been sponsored by 2ndQuadrant customers.
|
The development of repmgr has primarily been sponsored by 2ndQuadrant customers.
|
||||||
@@ -12,10 +12,10 @@ which has received funding from the European Union's Seventh Framework Programme
|
|||||||
(FP7/2007-2013) under grant agreement 258862.
|
(FP7/2007-2013) under grant agreement 258862.
|
||||||
|
|
||||||
Contributions to `repmgr` are welcome, and will be listed in the file `CREDITS`.
|
Contributions to `repmgr` are welcome, and will be listed in the file `CREDITS`.
|
||||||
EnterpriseDB Corporation requires that any contributions provide a copyright
|
2ndQuadrant Limited requires that any contributions provide a copyright
|
||||||
assignment and a disclaimer of any work-for-hire ownership claims from the
|
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
|
employer of the developer. This lets us make sure that all of the repmgr
|
||||||
distribution remains free code. Please contact info@enterprise.com for a
|
distribution remains free code. Please contact info@2ndQuadrant.com for a
|
||||||
copy of the relevant Copyright Assignment Form.
|
copy of the relevant Copyright Assignment Form.
|
||||||
|
|
||||||
Code style
|
Code style
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
Copyright (c) 2010-2021, EnterpriseDB Corporation
|
Copyright (c) 2010-2020, 2ndQuadrant Limited
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
|||||||
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:
|
The repmgr 3.x FAQ can be found here:
|
||||||
|
|
||||||
https://github.com/EnterpriseDB/repmgr/blob/REL3_3_STABLE/FAQ.md
|
https://github.com/2ndQuadrant/repmgr/blob/REL3_3_STABLE/FAQ.md
|
||||||
|
|
||||||
Note that repmgr 3.x is no longer supported.
|
Note that repmgr 3.x is no longer supported.
|
||||||
|
|||||||
47
HISTORY
47
HISTORY
@@ -1,46 +1,3 @@
|
|||||||
5.2.2. 2021-??-??
|
|
||||||
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)
|
|
||||||
standby clone: add option --recovery-min-apply-delay (Ian)
|
|
||||||
standby clone: fix data directory permissions handling for
|
|
||||||
PostgreSQL 11 and later (Ian)
|
|
||||||
repmgrd: prevent termination when local node not available and
|
|
||||||
standby_disconnect_on_failover; GitHub #675 (Ian)
|
|
||||||
repmgrd: ensure reconnect_interval" is correctly handled;
|
|
||||||
GitHub #673 (Ian)
|
|
||||||
|
|
||||||
5.2.0 2020-10-22
|
|
||||||
general: add support for PostgreSQL 13 (Ian)
|
|
||||||
general: remove support for PostgreSQL 9.3 (Ian)
|
|
||||||
config: add support for file inclusion directives (Ian)
|
|
||||||
repmgr: "primary unregister --force" will unregister an active primary
|
|
||||||
with no registered standby nodes (Ian)
|
|
||||||
repmgr: add option --verify-backup to "standby clone" (Ian)
|
|
||||||
repmgr: "standby clone" honours --waldir option if set in
|
|
||||||
"pg_basebackup_options" (Ian)
|
|
||||||
repmgr: add option --db-connection to "node check" (Ian)
|
|
||||||
repmgr: report database connection error if the --optformat option was
|
|
||||||
provided to "node check" (Ian)
|
|
||||||
repmgr: improve "node rejoin" checks (Ian)
|
|
||||||
repmgr: enable "node rejoin" to join a target with a lower timeline (Ian)
|
|
||||||
repmgr: support pg_rewind's automatic crash recovery in Pg13 and later (Ian)
|
|
||||||
repmgr: improve output formatting for cluster matrix/crosscheck (Ian)
|
|
||||||
repmgr: improve database connection failure error checking on the
|
|
||||||
demotion candidate during "standby switchover" (Ian)
|
|
||||||
repmgr: make repmgr metadata tables dumpable (Ian)
|
|
||||||
repmgr: fix issue with tablespace mapping when cloning from Barman;
|
|
||||||
GitHub #650 (Ian)
|
|
||||||
repmgr: improve handling of pg_control read errors (Ian)
|
|
||||||
repmgrd: add additional optional parameters to "failover_validation command"
|
|
||||||
(spaskalev; GitHub #651)
|
|
||||||
repmgrd: ensure primary connection is reset if same as upstream;
|
|
||||||
GitHub #633 (Ian)
|
|
||||||
|
|
||||||
5.1.0 2020-04-13
|
5.1.0 2020-04-13
|
||||||
repmgr: remove BDR 2.x support
|
repmgr: remove BDR 2.x support
|
||||||
repmgr: don't query upstream's data directory (Ian)
|
repmgr: don't query upstream's data directory (Ian)
|
||||||
@@ -48,11 +5,11 @@
|
|||||||
repmgr: ensure postgresql.auto.conf is created with correct permissions (Ian)
|
repmgr: ensure postgresql.auto.conf is created with correct permissions (Ian)
|
||||||
repmgr: minimize requirement to check upstream data directory location
|
repmgr: minimize requirement to check upstream data directory location
|
||||||
during "standby clone" (Ian)
|
during "standby clone" (Ian)
|
||||||
repmgr: warn about missing pg_rewind prerequisites when executing
|
repmgr: warn about missing pg_rewind prerequisites when excuting
|
||||||
"standby clone" (Ian)
|
"standby clone" (Ian)
|
||||||
repmgr: add --upstream option to "node check"
|
repmgr: add --upstream option to "node check"
|
||||||
repmgr: report error code on follow/rejoin failure due to non-available
|
repmgr: report error code on follow/rejoin failure due to non-available
|
||||||
0 replication slot (Ian)
|
replication slot (Ian)
|
||||||
repmgr: ensure "node rejoin" checks for available replication slots (Ian)
|
repmgr: ensure "node rejoin" checks for available replication slots (Ian)
|
||||||
repmgr: improve "standby switchover" completion checks (Ian)
|
repmgr: improve "standby switchover" completion checks (Ian)
|
||||||
repmgr: add replication configuration file ownership check to
|
repmgr: add replication configuration file ownership check to
|
||||||
|
|||||||
16
Makefile.in
16
Makefile.in
@@ -12,7 +12,6 @@ EXTENSION = repmgr
|
|||||||
DATA = \
|
DATA = \
|
||||||
repmgr--unpackaged--4.0.sql \
|
repmgr--unpackaged--4.0.sql \
|
||||||
repmgr--unpackaged--5.1.sql \
|
repmgr--unpackaged--5.1.sql \
|
||||||
repmgr--unpackaged--5.2.sql \
|
|
||||||
repmgr--4.0.sql \
|
repmgr--4.0.sql \
|
||||||
repmgr--4.0--4.1.sql \
|
repmgr--4.0--4.1.sql \
|
||||||
repmgr--4.1.sql \
|
repmgr--4.1.sql \
|
||||||
@@ -25,9 +24,7 @@ DATA = \
|
|||||||
repmgr--4.4--5.0.sql \
|
repmgr--4.4--5.0.sql \
|
||||||
repmgr--5.0.sql \
|
repmgr--5.0.sql \
|
||||||
repmgr--5.0--5.1.sql \
|
repmgr--5.0--5.1.sql \
|
||||||
repmgr--5.1.sql \
|
repmgr--5.1.sql
|
||||||
repmgr--5.1--5.2.sql \
|
|
||||||
repmgr--5.2.sql
|
|
||||||
|
|
||||||
REGRESS = repmgr_extension
|
REGRESS = repmgr_extension
|
||||||
|
|
||||||
@@ -60,11 +57,8 @@ $(info Building against PostgreSQL $(MAJORVERSION))
|
|||||||
REPMGR_CLIENT_OBJS = repmgr-client.o \
|
REPMGR_CLIENT_OBJS = repmgr-client.o \
|
||||||
repmgr-action-primary.o repmgr-action-standby.o repmgr-action-witness.o \
|
repmgr-action-primary.o repmgr-action-standby.o repmgr-action-witness.o \
|
||||||
repmgr-action-cluster.o repmgr-action-node.o repmgr-action-service.o repmgr-action-daemon.o \
|
repmgr-action-cluster.o repmgr-action-node.o repmgr-action-service.o repmgr-action-daemon.o \
|
||||||
configdata.o configfile.o configfile-scan.o log.o strutil.o controldata.o dirutil.o compat.o \
|
configfile.o configfile-scan.o log.o strutil.o controldata.o dirutil.o compat.o dbutils.o sysutils.o
|
||||||
dbutils.o sysutils.o
|
REPMGRD_OBJS = repmgrd.o repmgrd-physical.o configfile.o configfile-scan.o log.o dbutils.o strutil.o controldata.o compat.o sysutils.o
|
||||||
REPMGRD_OBJS = repmgrd.o repmgrd-physical.o configdata.o configfile.o configfile-scan.o log.o \
|
|
||||||
dbutils.o strutil.o controldata.o compat.o sysutils.o
|
|
||||||
|
|
||||||
DATE=$(shell date "+%Y-%m-%d")
|
DATE=$(shell date "+%Y-%m-%d")
|
||||||
|
|
||||||
repmgr_version.h: repmgr_version.h.in
|
repmgr_version.h: repmgr_version.h.in
|
||||||
@@ -76,10 +70,10 @@ configfile-scan.c: configfile-scan.l
|
|||||||
$(REPMGR_CLIENT_OBJS): repmgr-client.h repmgr_version.h
|
$(REPMGR_CLIENT_OBJS): repmgr-client.h repmgr_version.h
|
||||||
|
|
||||||
repmgr: $(REPMGR_CLIENT_OBJS)
|
repmgr: $(REPMGR_CLIENT_OBJS)
|
||||||
$(CC) $(CFLAGS) $(REPMGR_CLIENT_OBJS) $(libpq_pgport) $(LDFLAGS) $(LDFLAGS_EX) -o $@$(X)
|
$(CC) $(CFLAGS) $(REPMGR_CLIENT_OBJS) $(libpq_pgport) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
|
||||||
|
|
||||||
repmgrd: $(REPMGRD_OBJS)
|
repmgrd: $(REPMGRD_OBJS)
|
||||||
$(CC) $(CFLAGS) $(REPMGRD_OBJS) $(libpq_pgport) $(LDFLAGS) $(LDFLAGS_EX) -o $@$(X)
|
$(CC) $(CFLAGS) $(REPMGRD_OBJS) $(libpq_pgport) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
|
||||||
|
|
||||||
$(REPMGR_CLIENT_OBJS): $(HEADERS)
|
$(REPMGR_CLIENT_OBJS): $(HEADERS)
|
||||||
$(REPMGRD_OBJS): $(HEADERS)
|
$(REPMGRD_OBJS): $(HEADERS)
|
||||||
|
|||||||
34
README.md
34
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
|
replication, and perform administrative tasks such as failover or switchover
|
||||||
operations.
|
operations.
|
||||||
|
|
||||||
The most recent `repmgr` version (5.2.1) supports all PostgreSQL versions from
|
PostgreSQL 12, 11, 10, 9.6 and 9.5 are fully supported.
|
||||||
9.5 to 13. PostgreSQL 9.4 is also supported, with some restrictions.
|
PostgreSQL 9.4 and 9.3 are supported, with some restrictions.
|
||||||
|
|
||||||
`repmgr` is distributed under the GNU GPL 3 and maintained by EnterpriseDB.
|
`repmgr` is distributed under the GNU GPL 3 and maintained by 2ndQuadrant.
|
||||||
|
|
||||||
Documentation
|
Documentation
|
||||||
-------------
|
-------------
|
||||||
@@ -21,11 +21,10 @@ The full `repmgr` documentation is available here:
|
|||||||
|
|
||||||
The old `README` file for `repmgr` 3.x is available here:
|
The old `README` file for `repmgr` 3.x is available here:
|
||||||
|
|
||||||
> https://github.com/EnterpriseDB/repmgr/blob/REL3_3_STABLE/README.md
|
> https://github.com/2ndQuadrant/repmgr/blob/REL3_3_STABLE/README.md
|
||||||
|
|
||||||
Note that the `repmgr` 3.x series is no longer supported and contains known bugs;
|
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)
|
please upgrade to the current `repmgr` version as soon as possible.
|
||||||
as soon as possible.
|
|
||||||
|
|
||||||
Versions
|
Versions
|
||||||
--------
|
--------
|
||||||
@@ -55,11 +54,11 @@ Directories
|
|||||||
Support and Assistance
|
Support and Assistance
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
EnterpriseDB provides 24x7 production support for `repmgr`, including
|
2ndQuadrant provides 24x7 production support for `repmgr`, including
|
||||||
configuration assistance, installation verification and training for
|
configuration assistance, installation verification and training for
|
||||||
running a robust replication cluster. For further details see:
|
running a robust replication cluster. For further details see:
|
||||||
|
|
||||||
* [EDB Support Services](https://www.enterprisedb.com/support/postgresql-support-overview-get-the-most-out-of-postgresql)
|
* https://2ndquadrant.com/en/support/
|
||||||
|
|
||||||
There is a mailing list/forum to discuss contributions or issues:
|
There is a mailing list/forum to discuss contributions or issues:
|
||||||
|
|
||||||
@@ -69,12 +68,23 @@ The IRC channel #repmgr is registered with freenode.
|
|||||||
|
|
||||||
Please report bugs and other issues to:
|
Please report bugs and other issues to:
|
||||||
|
|
||||||
* https://github.com/EnterpriseDB/repmgr
|
* https://github.com/2ndQuadrant/repmgr
|
||||||
|
|
||||||
|
See
|
||||||
|
|
||||||
Further information is available at https://repmgr.org/
|
Further information is available at https://repmgr.org/
|
||||||
|
|
||||||
We'd love to hear from you about how you use repmgr. Case studies and
|
We'd love to hear from you about how you use repmgr. Case studies and
|
||||||
news are always welcome.
|
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
|
||||||
|
|
||||||
Thanks from the repmgr core team.
|
Thanks from the repmgr core team.
|
||||||
|
|
||||||
@@ -90,3 +100,7 @@ Further reading
|
|||||||
* [repmgr documentation](https://repmgr.org/docs/current/index.html)
|
* [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 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 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/)
|
||||||
|
* https://blog.2ndquadrant.com/repmgr-3-2-is-here-barman-support-brand-new-high-availability-features/
|
||||||
|
* https://blog.2ndquadrant.com/improvements-in-repmgr-3-1-4/
|
||||||
|
* https://blog.2ndquadrant.com/managing-useful-clusters-repmgr/
|
||||||
|
* https://blog.2ndquadrant.com/easier_postgresql_90_clusters/
|
||||||
|
|||||||
4
TODO.md
4
TODO.md
@@ -1,7 +1,7 @@
|
|||||||
TODO
|
TODO
|
||||||
====
|
====
|
||||||
|
|
||||||
This file contains a list of improvements which are desirable and/or have
|
This file contains a list of improvements which are desireable and/or have
|
||||||
been requested, and which we aim to address/implement when time and resources
|
been requested, and which we aim to address/implement when time and resources
|
||||||
permit.
|
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
|
We'll need to implement some way of notifying each repmgrd to suspend automatic
|
||||||
failover until further notice.
|
failover until further notice.
|
||||||
|
|
||||||
Requested in GitHub #410 ( https://github.com/EnterpriseDB/repmgr/issues/410 )
|
Requested in GitHub #410 ( https://github.com/2ndQuadrant/repmgr/issues/410 )
|
||||||
|
|||||||
2
compat.c
2
compat.c
@@ -6,7 +6,7 @@
|
|||||||
* supported PostgreSQL versions. They're unlikely to change but
|
* supported PostgreSQL versions. They're unlikely to change but
|
||||||
* it would be worth keeping an eye on them for any fixes/improvements.
|
* it would be worth keeping an eye on them for any fixes/improvements.
|
||||||
*
|
*
|
||||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||||
*
|
*
|
||||||
* Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
|
|||||||
2
compat.h
2
compat.h
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* compat.h
|
* compat.h
|
||||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||||
*
|
*
|
||||||
* Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
|
|||||||
936
configdata.c
936
configdata.c
@@ -1,936 +0,0 @@
|
|||||||
/*
|
|
||||||
* configdata.c - contains structs with parsed configuration data
|
|
||||||
*
|
|
||||||
* 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
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "repmgr.h"
|
|
||||||
#include "configfile.h"
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Parsed configuration settings are stored here
|
|
||||||
*/
|
|
||||||
t_configuration_options config_file_options;
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Configuration settings are defined here
|
|
||||||
*/
|
|
||||||
|
|
||||||
struct ConfigFileSetting config_file_settings[] =
|
|
||||||
{
|
|
||||||
|
|
||||||
/* ================
|
|
||||||
* node information
|
|
||||||
* ================
|
|
||||||
*/
|
|
||||||
/* node_id */
|
|
||||||
{
|
|
||||||
"node_id",
|
|
||||||
CONFIG_INT,
|
|
||||||
{ .intptr = &config_file_options.node_id },
|
|
||||||
{ .intdefault = UNKNOWN_NODE_ID },
|
|
||||||
{ .intminval = MIN_NODE_ID },
|
|
||||||
{},
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
/* node_name */
|
|
||||||
{
|
|
||||||
"node_name",
|
|
||||||
CONFIG_STRING,
|
|
||||||
{ .strptr = config_file_options.node_name },
|
|
||||||
{ .strdefault = "" },
|
|
||||||
{},
|
|
||||||
{ .strmaxlen = sizeof(config_file_options.node_name) },
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
/* conninfo */
|
|
||||||
{
|
|
||||||
"conninfo",
|
|
||||||
CONFIG_STRING,
|
|
||||||
{ .strptr = config_file_options.conninfo },
|
|
||||||
{ .strdefault = "" },
|
|
||||||
{},
|
|
||||||
{ .strmaxlen = sizeof(config_file_options.conninfo) },
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
/* replication_user */
|
|
||||||
{
|
|
||||||
"replication_user",
|
|
||||||
CONFIG_STRING,
|
|
||||||
{ .strptr = config_file_options.replication_user },
|
|
||||||
{ .strdefault = "" },
|
|
||||||
{},
|
|
||||||
{ .strmaxlen = sizeof(config_file_options.replication_user) },
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
/* data_directory */
|
|
||||||
{
|
|
||||||
"data_directory",
|
|
||||||
CONFIG_STRING,
|
|
||||||
{ .strptr = config_file_options.data_directory },
|
|
||||||
{ .strdefault = "" },
|
|
||||||
{},
|
|
||||||
{ .strmaxlen = sizeof(config_file_options.data_directory) },
|
|
||||||
{ .postprocess_func = &repmgr_canonicalize_path }
|
|
||||||
},
|
|
||||||
/* config_directory */
|
|
||||||
{
|
|
||||||
"config_directory",
|
|
||||||
CONFIG_STRING,
|
|
||||||
{ .strptr = config_file_options.config_directory },
|
|
||||||
{ .strdefault = "" },
|
|
||||||
{},
|
|
||||||
{ .strmaxlen = sizeof(config_file_options.config_directory) },
|
|
||||||
{ .postprocess_func = &repmgr_canonicalize_path }
|
|
||||||
},
|
|
||||||
/* pg_bindir */
|
|
||||||
{
|
|
||||||
"pg_bindir",
|
|
||||||
CONFIG_STRING,
|
|
||||||
{ .strptr = config_file_options.pg_bindir },
|
|
||||||
{ .strdefault = "" },
|
|
||||||
{},
|
|
||||||
{ .strmaxlen = sizeof(config_file_options.pg_bindir) },
|
|
||||||
{ .postprocess_func = &repmgr_canonicalize_path }
|
|
||||||
},
|
|
||||||
/* repmgr_bindir */
|
|
||||||
{
|
|
||||||
"repmgr_bindir",
|
|
||||||
CONFIG_STRING,
|
|
||||||
{ .strptr = config_file_options.repmgr_bindir },
|
|
||||||
{ .strdefault = "" },
|
|
||||||
{},
|
|
||||||
{ .strmaxlen = sizeof(config_file_options.repmgr_bindir) },
|
|
||||||
{ .postprocess_func = &repmgr_canonicalize_path }
|
|
||||||
},
|
|
||||||
/* replication_type */
|
|
||||||
{
|
|
||||||
"replication_type",
|
|
||||||
CONFIG_REPLICATION_TYPE,
|
|
||||||
{ .replicationtypeptr = &config_file_options.replication_type },
|
|
||||||
{ .replicationtypedefault = DEFAULT_REPLICATION_TYPE },
|
|
||||||
{},
|
|
||||||
{},
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
|
|
||||||
/* ================
|
|
||||||
* logging settings
|
|
||||||
* ================
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* log_level
|
|
||||||
* NOTE: the default for "log_level" is set in log.c and does not need
|
|
||||||
* to be initialised here
|
|
||||||
*/
|
|
||||||
{
|
|
||||||
"log_level",
|
|
||||||
CONFIG_STRING,
|
|
||||||
{ .strptr = config_file_options.log_level },
|
|
||||||
{ .strdefault = "" },
|
|
||||||
{},
|
|
||||||
{ .strmaxlen = sizeof(config_file_options.log_level) },
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
/* log_facility */
|
|
||||||
{
|
|
||||||
"log_facility",
|
|
||||||
CONFIG_STRING,
|
|
||||||
{ .strptr = config_file_options.log_facility },
|
|
||||||
{ .strdefault = "" },
|
|
||||||
{},
|
|
||||||
{ .strmaxlen = sizeof(config_file_options.log_facility) },
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
/* log_file */
|
|
||||||
{
|
|
||||||
"log_file",
|
|
||||||
CONFIG_STRING,
|
|
||||||
{ .strptr = config_file_options.log_file },
|
|
||||||
{ .strdefault = "" },
|
|
||||||
{},
|
|
||||||
{ .strmaxlen = sizeof(config_file_options.log_file) },
|
|
||||||
{ .postprocess_func = &repmgr_canonicalize_path }
|
|
||||||
},
|
|
||||||
/* log_status_interval */
|
|
||||||
{
|
|
||||||
"log_status_interval",
|
|
||||||
CONFIG_INT,
|
|
||||||
{ .intptr = &config_file_options.log_status_interval },
|
|
||||||
{ .intdefault = DEFAULT_LOG_STATUS_INTERVAL, },
|
|
||||||
{ .intminval = 0 },
|
|
||||||
{},
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
/* ======================
|
|
||||||
* standby clone settings
|
|
||||||
* ======================
|
|
||||||
*/
|
|
||||||
/* use_replication_slots */
|
|
||||||
{
|
|
||||||
"use_replication_slots",
|
|
||||||
CONFIG_BOOL,
|
|
||||||
{ .boolptr = &config_file_options.use_replication_slots },
|
|
||||||
{ .booldefault = DEFAULT_USE_REPLICATION_SLOTS },
|
|
||||||
{},
|
|
||||||
{},
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
/* pg_basebackup_options */
|
|
||||||
{
|
|
||||||
"pg_basebackup_options",
|
|
||||||
CONFIG_STRING,
|
|
||||||
{ .strptr = config_file_options.pg_basebackup_options },
|
|
||||||
{ .strdefault = "" },
|
|
||||||
{},
|
|
||||||
{ .strmaxlen = sizeof(config_file_options.pg_basebackup_options) },
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
/* restore_command */
|
|
||||||
{
|
|
||||||
"restore_command",
|
|
||||||
CONFIG_STRING,
|
|
||||||
{ .strptr = config_file_options.restore_command },
|
|
||||||
{ .strdefault = "" },
|
|
||||||
{},
|
|
||||||
{ .strmaxlen = sizeof(config_file_options.restore_command) },
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
/* tablespace_mapping */
|
|
||||||
{
|
|
||||||
"tablespace_mapping",
|
|
||||||
CONFIG_TABLESPACE_MAPPING,
|
|
||||||
{ .tablespacemappingptr = &config_file_options.tablespace_mapping },
|
|
||||||
{},
|
|
||||||
{},
|
|
||||||
{},
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
/* recovery_min_apply_delay */
|
|
||||||
{
|
|
||||||
"recovery_min_apply_delay",
|
|
||||||
CONFIG_STRING,
|
|
||||||
{ .strptr = config_file_options.recovery_min_apply_delay },
|
|
||||||
{ .strdefault = "" },
|
|
||||||
{},
|
|
||||||
{ .strmaxlen = sizeof(config_file_options.recovery_min_apply_delay) },
|
|
||||||
{
|
|
||||||
.process_func = &parse_time_unit_parameter,
|
|
||||||
.providedptr = &config_file_options.recovery_min_apply_delay_provided
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/* archive_cleanup_command */
|
|
||||||
{
|
|
||||||
"archive_cleanup_command",
|
|
||||||
CONFIG_STRING,
|
|
||||||
{ .strptr = config_file_options.archive_cleanup_command },
|
|
||||||
{ .strdefault = "" },
|
|
||||||
{},
|
|
||||||
{ .strmaxlen = sizeof(config_file_options.archive_cleanup_command) },
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
|
|
||||||
/* use_primary_conninfo_password */
|
|
||||||
{
|
|
||||||
"use_primary_conninfo_password",
|
|
||||||
CONFIG_BOOL,
|
|
||||||
{ .boolptr = &config_file_options.use_primary_conninfo_password },
|
|
||||||
{ .booldefault = DEFAULT_USE_PRIMARY_CONNINFO_PASSWORD },
|
|
||||||
{},
|
|
||||||
{},
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
/* passfile */
|
|
||||||
{
|
|
||||||
"passfile",
|
|
||||||
CONFIG_STRING,
|
|
||||||
{ .strptr = config_file_options.passfile },
|
|
||||||
{ .strdefault = "" },
|
|
||||||
{},
|
|
||||||
{ .strmaxlen = sizeof(config_file_options.passfile) },
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
|
|
||||||
/* ======================
|
|
||||||
* standby clone settings
|
|
||||||
* ======================
|
|
||||||
*/
|
|
||||||
/* promote_check_timeout */
|
|
||||||
{
|
|
||||||
"promote_check_timeout",
|
|
||||||
CONFIG_INT,
|
|
||||||
{ .intptr = &config_file_options.promote_check_timeout },
|
|
||||||
{ .intdefault = DEFAULT_PROMOTE_CHECK_TIMEOUT },
|
|
||||||
{ .intminval = 1 },
|
|
||||||
{},
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
/* promote_check_interval */
|
|
||||||
{
|
|
||||||
"promote_check_interval",
|
|
||||||
CONFIG_INT,
|
|
||||||
{ .intptr = &config_file_options.promote_check_interval },
|
|
||||||
{ .intdefault = DEFAULT_PROMOTE_CHECK_INTERVAL },
|
|
||||||
{ .intminval = 1 },
|
|
||||||
{},
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
|
|
||||||
/* =======================
|
|
||||||
* standby follow settings
|
|
||||||
* =======================
|
|
||||||
*/
|
|
||||||
/* primary_follow_timeout */
|
|
||||||
{
|
|
||||||
"primary_follow_timeout",
|
|
||||||
CONFIG_INT,
|
|
||||||
{ .intptr = &config_file_options.primary_follow_timeout },
|
|
||||||
{ .intdefault = DEFAULT_PRIMARY_FOLLOW_TIMEOUT, },
|
|
||||||
{ .intminval = 1 },
|
|
||||||
{},
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
/* standby_follow_timeout */
|
|
||||||
{
|
|
||||||
"standby_follow_timeout",
|
|
||||||
CONFIG_INT,
|
|
||||||
{ .intptr = &config_file_options.standby_follow_timeout },
|
|
||||||
{ .intdefault = DEFAULT_STANDBY_FOLLOW_TIMEOUT },
|
|
||||||
{ .intminval = 1 },
|
|
||||||
{},
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
/* standby_follow_restart */
|
|
||||||
{
|
|
||||||
"standby_follow_restart",
|
|
||||||
CONFIG_BOOL,
|
|
||||||
{ .boolptr = &config_file_options.standby_follow_restart },
|
|
||||||
{ .booldefault = DEFAULT_STANDBY_FOLLOW_RESTART },
|
|
||||||
{},
|
|
||||||
{},
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
|
|
||||||
/* ===========================
|
|
||||||
* standby switchover settings
|
|
||||||
* ===========================
|
|
||||||
*/
|
|
||||||
/* shutdown_check_timeout */
|
|
||||||
{
|
|
||||||
"shutdown_check_timeout",
|
|
||||||
CONFIG_INT,
|
|
||||||
{ .intptr = &config_file_options.shutdown_check_timeout },
|
|
||||||
{ .intdefault = DEFAULT_SHUTDOWN_CHECK_TIMEOUT },
|
|
||||||
{ .intminval = 1 },
|
|
||||||
{},
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
/* standby_reconnect_timeout */
|
|
||||||
{
|
|
||||||
"standby_reconnect_timeout",
|
|
||||||
CONFIG_INT,
|
|
||||||
{ .intptr = &config_file_options.standby_reconnect_timeout },
|
|
||||||
{ .intdefault = DEFAULT_STANDBY_RECONNECT_TIMEOUT },
|
|
||||||
{ .intminval = 1 },
|
|
||||||
{},
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
/* wal_receive_check_timeout */
|
|
||||||
{
|
|
||||||
"wal_receive_check_timeout",
|
|
||||||
CONFIG_INT,
|
|
||||||
{ .intptr = &config_file_options.wal_receive_check_timeout },
|
|
||||||
{ .intdefault = DEFAULT_WAL_RECEIVE_CHECK_TIMEOUT },
|
|
||||||
{ .intminval = 1 },
|
|
||||||
{},
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
|
|
||||||
/* ====================
|
|
||||||
* node rejoin settings
|
|
||||||
* ====================
|
|
||||||
*/
|
|
||||||
/* node_rejoin_timeout */
|
|
||||||
{
|
|
||||||
"node_rejoin_timeout",
|
|
||||||
CONFIG_INT,
|
|
||||||
{ .intptr = &config_file_options.node_rejoin_timeout },
|
|
||||||
{ .intdefault = DEFAULT_NODE_REJOIN_TIMEOUT },
|
|
||||||
{ .intminval = 1 },
|
|
||||||
{},
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
/* ===================
|
|
||||||
* node check settings
|
|
||||||
* ===================
|
|
||||||
*/
|
|
||||||
/* archive_ready_warning */
|
|
||||||
{
|
|
||||||
"archive_ready_warning",
|
|
||||||
CONFIG_INT,
|
|
||||||
{ .intptr = &config_file_options.archive_ready_warning },
|
|
||||||
{ .intdefault = DEFAULT_ARCHIVE_READY_WARNING },
|
|
||||||
{ .intminval = 1 },
|
|
||||||
{},
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
/* archive_ready_critical */
|
|
||||||
{
|
|
||||||
"archive_ready_critical",
|
|
||||||
CONFIG_INT,
|
|
||||||
{ .intptr = &config_file_options.archive_ready_critical },
|
|
||||||
{ .intdefault = DEFAULT_ARCHIVE_READY_CRITICAL },
|
|
||||||
{ .intminval = 1 },
|
|
||||||
{},
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
/* replication_lag_warning */
|
|
||||||
{
|
|
||||||
"replication_lag_warning",
|
|
||||||
CONFIG_INT,
|
|
||||||
{ .intptr = &config_file_options.replication_lag_warning },
|
|
||||||
{ .intdefault = DEFAULT_REPLICATION_LAG_WARNING },
|
|
||||||
{ .intminval = 1 },
|
|
||||||
{},
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
/* replication_lag_critical */
|
|
||||||
{
|
|
||||||
"replication_lag_critical",
|
|
||||||
CONFIG_INT,
|
|
||||||
{ .intptr = &config_file_options.replication_lag_critical },
|
|
||||||
{ .intdefault = DEFAULT_REPLICATION_LAG_CRITICAL },
|
|
||||||
{ .intminval = 1 },
|
|
||||||
{},
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
|
|
||||||
/* ================
|
|
||||||
* witness settings
|
|
||||||
* ================
|
|
||||||
*/
|
|
||||||
/* witness_sync_interval */
|
|
||||||
{
|
|
||||||
"witness_sync_interval",
|
|
||||||
CONFIG_INT,
|
|
||||||
{ .intptr = &config_file_options.witness_sync_interval },
|
|
||||||
{ .intdefault = DEFAULT_WITNESS_SYNC_INTERVAL },
|
|
||||||
{ .intminval = 1 },
|
|
||||||
{},
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
|
|
||||||
/* ================
|
|
||||||
* repmgrd settings
|
|
||||||
* ================
|
|
||||||
*/
|
|
||||||
/* failover */
|
|
||||||
{
|
|
||||||
"failover",
|
|
||||||
CONFIG_FAILOVER_MODE,
|
|
||||||
{ .failovermodeptr = &config_file_options.failover },
|
|
||||||
{ .failovermodedefault = FAILOVER_MANUAL },
|
|
||||||
{},
|
|
||||||
{},
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
/* location */
|
|
||||||
{
|
|
||||||
"location",
|
|
||||||
CONFIG_STRING,
|
|
||||||
{ .strptr = config_file_options.location },
|
|
||||||
{ .strdefault = DEFAULT_LOCATION },
|
|
||||||
{},
|
|
||||||
{ .strmaxlen = sizeof(config_file_options.location) },
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
/* priority */
|
|
||||||
{
|
|
||||||
"priority",
|
|
||||||
CONFIG_INT,
|
|
||||||
{ .intptr = &config_file_options.priority },
|
|
||||||
{ .intdefault = DEFAULT_PRIORITY, },
|
|
||||||
{ .intminval = 0 },
|
|
||||||
{},
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
/* promote_command */
|
|
||||||
{
|
|
||||||
"promote_command",
|
|
||||||
CONFIG_STRING,
|
|
||||||
{ .strptr = config_file_options.promote_command },
|
|
||||||
{ .strdefault = "" },
|
|
||||||
{},
|
|
||||||
{ .strmaxlen = sizeof(config_file_options.promote_command) },
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
/* follow_command */
|
|
||||||
{
|
|
||||||
"follow_command",
|
|
||||||
CONFIG_STRING,
|
|
||||||
{ .strptr = config_file_options.follow_command },
|
|
||||||
{ .strdefault = "" },
|
|
||||||
{},
|
|
||||||
{ .strmaxlen = sizeof(config_file_options.follow_command) },
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
/* monitor_interval_secs */
|
|
||||||
{
|
|
||||||
"monitor_interval_secs",
|
|
||||||
CONFIG_INT,
|
|
||||||
{ .intptr = &config_file_options.monitor_interval_secs },
|
|
||||||
{ .intdefault = DEFAULT_MONITORING_INTERVAL },
|
|
||||||
{ .intminval = 1 },
|
|
||||||
{},
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
/* reconnect_attempts */
|
|
||||||
{
|
|
||||||
"reconnect_attempts",
|
|
||||||
CONFIG_INT,
|
|
||||||
{ .intptr = &config_file_options.reconnect_attempts },
|
|
||||||
{ .intdefault = DEFAULT_RECONNECTION_ATTEMPTS },
|
|
||||||
{ .intminval = 0 },
|
|
||||||
{},
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
/* reconnect_interval */
|
|
||||||
{
|
|
||||||
"reconnect_interval",
|
|
||||||
CONFIG_INT,
|
|
||||||
{ .intptr = &config_file_options.reconnect_interval },
|
|
||||||
{ .intdefault = DEFAULT_RECONNECTION_INTERVAL },
|
|
||||||
{ .intminval = 0 },
|
|
||||||
{},
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
|
|
||||||
/* monitoring_history */
|
|
||||||
{
|
|
||||||
"monitoring_history",
|
|
||||||
CONFIG_BOOL,
|
|
||||||
{ .boolptr = &config_file_options.monitoring_history },
|
|
||||||
{ .booldefault = DEFAULT_MONITORING_HISTORY },
|
|
||||||
{},
|
|
||||||
{},
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
/* degraded_monitoring_timeout */
|
|
||||||
{
|
|
||||||
"degraded_monitoring_timeout",
|
|
||||||
CONFIG_INT,
|
|
||||||
{ .intptr = &config_file_options.degraded_monitoring_timeout },
|
|
||||||
{ .intdefault = DEFAULT_DEGRADED_MONITORING_TIMEOUT },
|
|
||||||
{ .intminval = -1 },
|
|
||||||
{},
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
/* async_query_timeout */
|
|
||||||
{
|
|
||||||
"async_query_timeout",
|
|
||||||
CONFIG_INT,
|
|
||||||
{ .intptr = &config_file_options.async_query_timeout },
|
|
||||||
{ .intdefault = DEFAULT_ASYNC_QUERY_TIMEOUT },
|
|
||||||
{ .intminval = 0 },
|
|
||||||
{},
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
/* primary_notification_timeout */
|
|
||||||
{
|
|
||||||
"primary_notification_timeout",
|
|
||||||
CONFIG_INT,
|
|
||||||
{ .intptr = &config_file_options.primary_notification_timeout },
|
|
||||||
{ .intdefault = DEFAULT_PRIMARY_NOTIFICATION_TIMEOUT },
|
|
||||||
{ .intminval = 0 },
|
|
||||||
{},
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
/* repmgrd_standby_startup_timeout */
|
|
||||||
{
|
|
||||||
"repmgrd_standby_startup_timeout",
|
|
||||||
CONFIG_INT,
|
|
||||||
{ .intptr = &config_file_options.repmgrd_standby_startup_timeout },
|
|
||||||
{ .intdefault = DEFAULT_REPMGRD_STANDBY_STARTUP_TIMEOUT },
|
|
||||||
{ .intminval = 0 },
|
|
||||||
{},
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
/* repmgrd_pid_file */
|
|
||||||
{
|
|
||||||
"repmgrd_pid_file",
|
|
||||||
CONFIG_STRING,
|
|
||||||
{ .strptr = config_file_options.repmgrd_pid_file },
|
|
||||||
{ .strdefault = "" },
|
|
||||||
{},
|
|
||||||
{ .strmaxlen = sizeof(config_file_options.repmgrd_pid_file) },
|
|
||||||
{ .postprocess_func = &repmgr_canonicalize_path }
|
|
||||||
},
|
|
||||||
/* standby_disconnect_on_failover */
|
|
||||||
{
|
|
||||||
"standby_disconnect_on_failover",
|
|
||||||
CONFIG_BOOL,
|
|
||||||
{ .boolptr = &config_file_options.standby_disconnect_on_failover },
|
|
||||||
{ .booldefault = DEFAULT_STANDBY_DISCONNECT_ON_FAILOVER },
|
|
||||||
{},
|
|
||||||
{},
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
/* sibling_nodes_disconnect_timeout */
|
|
||||||
{
|
|
||||||
"sibling_nodes_disconnect_timeout",
|
|
||||||
CONFIG_INT,
|
|
||||||
{ .intptr = &config_file_options.sibling_nodes_disconnect_timeout },
|
|
||||||
{ .intdefault = DEFAULT_SIBLING_NODES_DISCONNECT_TIMEOUT },
|
|
||||||
{ .intminval = 0 },
|
|
||||||
{},
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
/* connection_check_type */
|
|
||||||
{
|
|
||||||
"connection_check_type",
|
|
||||||
CONFIG_CONNECTION_CHECK_TYPE,
|
|
||||||
{ .checktypeptr = &config_file_options.connection_check_type },
|
|
||||||
{ .checktypedefault = DEFAULT_CONNECTION_CHECK_TYPE },
|
|
||||||
{},
|
|
||||||
{},
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
/* primary_visibility_consensus */
|
|
||||||
{
|
|
||||||
"primary_visibility_consensus",
|
|
||||||
CONFIG_BOOL,
|
|
||||||
{ .boolptr = &config_file_options.primary_visibility_consensus },
|
|
||||||
{ .booldefault = DEFAULT_PRIMARY_VISIBILITY_CONSENSUS },
|
|
||||||
{},
|
|
||||||
{},
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
/* always_promote */
|
|
||||||
{
|
|
||||||
"always_promote",
|
|
||||||
CONFIG_BOOL,
|
|
||||||
{ .boolptr = &config_file_options.always_promote },
|
|
||||||
{ .booldefault = DEFAULT_ALWAYS_PROMOTE },
|
|
||||||
{},
|
|
||||||
{},
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
/* failover_validation_command */
|
|
||||||
{
|
|
||||||
"failover_validation_command",
|
|
||||||
CONFIG_STRING,
|
|
||||||
{ .strptr = config_file_options.failover_validation_command },
|
|
||||||
{ .strdefault = "" },
|
|
||||||
{},
|
|
||||||
{ .strmaxlen = sizeof(config_file_options.failover_validation_command) },
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
/* election_rerun_interval */
|
|
||||||
{
|
|
||||||
"election_rerun_interval",
|
|
||||||
CONFIG_INT,
|
|
||||||
{ .intptr = &config_file_options.election_rerun_interval },
|
|
||||||
{ .intdefault = DEFAULT_ELECTION_RERUN_INTERVAL },
|
|
||||||
{ .intminval = 1 },
|
|
||||||
{},
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
/* child_nodes_check_interval */
|
|
||||||
{
|
|
||||||
"child_nodes_check_interval",
|
|
||||||
CONFIG_INT,
|
|
||||||
{ .intptr = &config_file_options.child_nodes_check_interval },
|
|
||||||
{ .intdefault = DEFAULT_CHILD_NODES_CHECK_INTERVAL },
|
|
||||||
{ .intminval = 1 },
|
|
||||||
{},
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
/* child_nodes_disconnect_min_count */
|
|
||||||
{
|
|
||||||
"child_nodes_disconnect_min_count",
|
|
||||||
CONFIG_INT,
|
|
||||||
{ .intptr = &config_file_options.child_nodes_disconnect_min_count },
|
|
||||||
{ .intdefault = DEFAULT_CHILD_NODES_DISCONNECT_MIN_COUNT },
|
|
||||||
{ .intminval = -1 },
|
|
||||||
{},
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
/* child_nodes_connected_min_count */
|
|
||||||
{
|
|
||||||
"child_nodes_connected_min_count",
|
|
||||||
CONFIG_INT,
|
|
||||||
{ .intptr = &config_file_options.child_nodes_connected_min_count },
|
|
||||||
{ .intdefault = DEFAULT_CHILD_NODES_CONNECTED_MIN_COUNT},
|
|
||||||
{ .intminval = -1 },
|
|
||||||
{},
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
/* child_nodes_connected_include_witness */
|
|
||||||
{
|
|
||||||
"child_nodes_connected_include_witness",
|
|
||||||
CONFIG_BOOL,
|
|
||||||
{ .boolptr = &config_file_options.child_nodes_connected_include_witness },
|
|
||||||
{ .booldefault = DEFAULT_CHILD_NODES_CONNECTED_INCLUDE_WITNESS },
|
|
||||||
{},
|
|
||||||
{},
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
/* child_nodes_disconnect_timeout */
|
|
||||||
{
|
|
||||||
"child_nodes_disconnect_timeout",
|
|
||||||
CONFIG_INT,
|
|
||||||
{ .intptr = &config_file_options.child_nodes_disconnect_timeout },
|
|
||||||
{ .intdefault = DEFAULT_CHILD_NODES_DISCONNECT_TIMEOUT },
|
|
||||||
{ .intminval = 0 },
|
|
||||||
{},
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
/* child_nodes_disconnect_command */
|
|
||||||
{
|
|
||||||
"child_nodes_disconnect_command",
|
|
||||||
CONFIG_STRING,
|
|
||||||
{ .strptr = config_file_options.child_nodes_disconnect_command },
|
|
||||||
{ .strdefault = "" },
|
|
||||||
{},
|
|
||||||
{ .strmaxlen = sizeof(config_file_options.child_nodes_disconnect_command) },
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
/* ================
|
|
||||||
* service settings
|
|
||||||
* ================
|
|
||||||
*/
|
|
||||||
/* pg_ctl_options */
|
|
||||||
{
|
|
||||||
"pg_ctl_options",
|
|
||||||
CONFIG_STRING,
|
|
||||||
{ .strptr = config_file_options.pg_ctl_options },
|
|
||||||
{ .strdefault = "" },
|
|
||||||
{},
|
|
||||||
{ .strmaxlen = sizeof(config_file_options.pg_ctl_options) },
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
/* service_start_command */
|
|
||||||
{
|
|
||||||
"service_start_command",
|
|
||||||
CONFIG_STRING,
|
|
||||||
{ .strptr = config_file_options.service_start_command },
|
|
||||||
{ .strdefault = "" },
|
|
||||||
{},
|
|
||||||
{ .strmaxlen = sizeof(config_file_options.service_start_command) },
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
/* service_stop_command */
|
|
||||||
{
|
|
||||||
"service_stop_command",
|
|
||||||
CONFIG_STRING,
|
|
||||||
{ .strptr = config_file_options.service_stop_command },
|
|
||||||
{ .strdefault = "" },
|
|
||||||
{},
|
|
||||||
{ .strmaxlen = sizeof(config_file_options.service_stop_command) },
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
/* service_restart_command */
|
|
||||||
{
|
|
||||||
"service_restart_command",
|
|
||||||
CONFIG_STRING,
|
|
||||||
{ .strptr = config_file_options.service_restart_command },
|
|
||||||
{ .strdefault = "" },
|
|
||||||
{},
|
|
||||||
{ .strmaxlen = sizeof(config_file_options.service_restart_command) },
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
/* service_reload_command */
|
|
||||||
{
|
|
||||||
"service_reload_command",
|
|
||||||
CONFIG_STRING,
|
|
||||||
{ .strptr = config_file_options.service_reload_command },
|
|
||||||
{ .strdefault = "" },
|
|
||||||
{},
|
|
||||||
{ .strmaxlen = sizeof(config_file_options.service_reload_command) },
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
/* service_promote_command */
|
|
||||||
{
|
|
||||||
"service_promote_command",
|
|
||||||
CONFIG_STRING,
|
|
||||||
{ .strptr = config_file_options.service_promote_command },
|
|
||||||
{ .strdefault = "" },
|
|
||||||
{},
|
|
||||||
{ .strmaxlen = sizeof(config_file_options.service_promote_command) },
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
|
|
||||||
/* ========================
|
|
||||||
* repmgrd service settings
|
|
||||||
* ========================
|
|
||||||
*/
|
|
||||||
/* repmgrd_service_start_command */
|
|
||||||
{
|
|
||||||
"repmgrd_service_start_command",
|
|
||||||
CONFIG_STRING,
|
|
||||||
{ .strptr = config_file_options.repmgrd_service_start_command },
|
|
||||||
{ .strdefault = "" },
|
|
||||||
{},
|
|
||||||
{ .strmaxlen = sizeof(config_file_options.repmgrd_service_start_command) },
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
/* repmgrd_service_stop_command */
|
|
||||||
{
|
|
||||||
"repmgrd_service_stop_command",
|
|
||||||
CONFIG_STRING,
|
|
||||||
{ .strptr = config_file_options.repmgrd_service_stop_command },
|
|
||||||
{ .strdefault = "" },
|
|
||||||
{},
|
|
||||||
{ .strmaxlen = sizeof(config_file_options.repmgrd_service_stop_command) },
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
/* ===========================
|
|
||||||
* event notification settings
|
|
||||||
* ===========================
|
|
||||||
*/
|
|
||||||
/* event_notification_command */
|
|
||||||
{
|
|
||||||
"event_notification_command",
|
|
||||||
CONFIG_STRING,
|
|
||||||
{ .strptr = config_file_options.event_notification_command },
|
|
||||||
{ .strdefault = "" },
|
|
||||||
{},
|
|
||||||
{ .strmaxlen = sizeof(config_file_options.event_notification_command) },
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"event_notifications",
|
|
||||||
CONFIG_EVENT_NOTIFICATION_LIST,
|
|
||||||
{ .notificationlistptr = &config_file_options.event_notifications },
|
|
||||||
{},
|
|
||||||
{},
|
|
||||||
{},
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
/* ===============
|
|
||||||
* barman settings
|
|
||||||
* ===============
|
|
||||||
*/
|
|
||||||
/* barman_host */
|
|
||||||
{
|
|
||||||
"barman_host",
|
|
||||||
CONFIG_STRING,
|
|
||||||
{ .strptr = config_file_options.barman_host },
|
|
||||||
{ .strdefault = "" },
|
|
||||||
{},
|
|
||||||
{ .strmaxlen = sizeof(config_file_options.barman_host) },
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
/* barman_server */
|
|
||||||
{
|
|
||||||
"barman_server",
|
|
||||||
CONFIG_STRING,
|
|
||||||
{ .strptr = config_file_options.barman_server },
|
|
||||||
{ .strdefault = "" },
|
|
||||||
{},
|
|
||||||
{ .strmaxlen = sizeof(config_file_options.barman_server) },
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
/* barman_config */
|
|
||||||
{
|
|
||||||
"barman_config",
|
|
||||||
CONFIG_STRING,
|
|
||||||
{ .strptr = config_file_options.barman_config },
|
|
||||||
{ .strdefault = "" },
|
|
||||||
{},
|
|
||||||
{ .strmaxlen = sizeof(config_file_options.barman_config) },
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
/* ==================
|
|
||||||
* rsync/ssh settings
|
|
||||||
* ==================
|
|
||||||
*/
|
|
||||||
/* rsync_options */
|
|
||||||
{
|
|
||||||
"rsync_options",
|
|
||||||
CONFIG_STRING,
|
|
||||||
{ .strptr = config_file_options.rsync_options },
|
|
||||||
{ .strdefault = "" },
|
|
||||||
{},
|
|
||||||
{ .strmaxlen = sizeof(config_file_options.rsync_options) },
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
/* ssh_options */
|
|
||||||
{
|
|
||||||
"ssh_options",
|
|
||||||
CONFIG_STRING,
|
|
||||||
{ .strptr = config_file_options.ssh_options },
|
|
||||||
{ .strdefault = DEFAULT_SSH_OPTIONS },
|
|
||||||
{},
|
|
||||||
{ .strmaxlen = sizeof(config_file_options.ssh_options) },
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
/* ==================================
|
|
||||||
* undocumented experimental settings
|
|
||||||
* ==================================
|
|
||||||
*/
|
|
||||||
/* reconnect_loop_sync */
|
|
||||||
{
|
|
||||||
"reconnect_loop_sync",
|
|
||||||
CONFIG_BOOL,
|
|
||||||
{ .boolptr = &config_file_options.reconnect_loop_sync },
|
|
||||||
{ .booldefault = false },
|
|
||||||
{},
|
|
||||||
{},
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
/* ==========================
|
|
||||||
* undocumented test settings
|
|
||||||
* ==========================
|
|
||||||
*/
|
|
||||||
/* promote_delay */
|
|
||||||
{
|
|
||||||
"promote_delay",
|
|
||||||
CONFIG_INT,
|
|
||||||
{ .intptr = &config_file_options.promote_delay },
|
|
||||||
{ .intdefault = 0 },
|
|
||||||
{ .intminval = 1 },
|
|
||||||
{},
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
/* failover_delay */
|
|
||||||
{
|
|
||||||
"failover_delay",
|
|
||||||
CONFIG_INT,
|
|
||||||
{ .intptr = &config_file_options.failover_delay },
|
|
||||||
{ .intdefault = 0 },
|
|
||||||
{ .intminval = 1 },
|
|
||||||
{},
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"connection_check_query",
|
|
||||||
CONFIG_STRING,
|
|
||||||
{ .strptr = config_file_options.connection_check_query },
|
|
||||||
{ .strdefault = "SELECT 1" },
|
|
||||||
{},
|
|
||||||
{ .strmaxlen = sizeof(config_file_options.connection_check_query) },
|
|
||||||
{}
|
|
||||||
},
|
|
||||||
/* End-of-list marker */
|
|
||||||
{
|
|
||||||
NULL, CONFIG_INT, {}, {}, {}, {}, {}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
@@ -5,8 +5,6 @@
|
|||||||
%{
|
%{
|
||||||
|
|
||||||
#include <setjmp.h>
|
#include <setjmp.h>
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <dirent.h>
|
|
||||||
|
|
||||||
#include "repmgr.h"
|
#include "repmgr.h"
|
||||||
#include "configfile.h"
|
#include "configfile.h"
|
||||||
@@ -40,13 +38,7 @@ static sigjmp_buf *CONF_flex_fatal_jmp;
|
|||||||
static char *CONF_scanstr(const char *s);
|
static char *CONF_scanstr(const char *s);
|
||||||
static int CONF_flex_fatal(const char *msg);
|
static int CONF_flex_fatal(const char *msg);
|
||||||
|
|
||||||
static bool ProcessConfigFile(const char *base_dir, const char *config_file, const char *calling_file, bool strict, int depth, KeyValueList *contents, ItemList *error_list, ItemList *warning_list);
|
static bool ProcessConfigFile(FILE *fp, const char *config_file, KeyValueList *contents, t_configuration_options *options, ItemList *error_list, ItemList *warning_list);
|
||||||
|
|
||||||
static bool ProcessConfigFp(FILE *fp, const char *config_file, const char *calling_file, int depth, const char *base_dir, KeyValueList *contents, ItemList *error_list, ItemList *warning_list);
|
|
||||||
|
|
||||||
static bool ProcessConfigDirectory(const char *base_dir, const char *includedir, const char *calling_file, int depth, KeyValueList *contents, ItemList *error_list, ItemList *warning_list);
|
|
||||||
|
|
||||||
static char *AbsoluteConfigLocation(const char *base_dir, const char *location, const char *calling_file);
|
|
||||||
|
|
||||||
%}
|
%}
|
||||||
|
|
||||||
@@ -98,91 +90,20 @@ STRING \'([^'\\\n]|\\.|\'\')*\'
|
|||||||
|
|
||||||
%%
|
%%
|
||||||
|
|
||||||
|
|
||||||
extern bool
|
extern bool
|
||||||
ProcessRepmgrConfigFile(const char *config_file, const char *base_dir, ItemList *error_list, ItemList *warning_list)
|
ProcessRepmgrConfigFile(FILE *fp, const char *config_file, t_configuration_options *options, ItemList *error_list, ItemList *warning_list)
|
||||||
{
|
{
|
||||||
return ProcessConfigFile(base_dir, config_file, NULL, true, 0, NULL, error_list, warning_list);
|
return ProcessConfigFile(fp, config_file, NULL, options, error_list, warning_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
extern bool
|
extern bool
|
||||||
ProcessPostgresConfigFile(const char *config_file, const char *base_dir, bool strict, KeyValueList *contents, ItemList *error_list, ItemList *warning_list)
|
ProcessPostgresConfigFile(FILE *fp, const char *config_file, KeyValueList *contents, ItemList *error_list, ItemList *warning_list)
|
||||||
{
|
{
|
||||||
return ProcessConfigFile(base_dir, config_file, NULL, strict, 0, contents, error_list, warning_list);
|
return ProcessConfigFile(fp, config_file, contents, NULL, error_list, warning_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
ProcessConfigFile(const char *base_dir, const char *config_file, const char *calling_file, bool strict, int depth, KeyValueList *contents, ItemList *error_list, ItemList *warning_list)
|
ProcessConfigFile(FILE *fp, const char *config_file, KeyValueList *contents, t_configuration_options *options, ItemList *error_list, ItemList *warning_list)
|
||||||
{
|
|
||||||
char *abs_path;
|
|
||||||
bool success = true;
|
|
||||||
FILE *fp;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Reject file name that is all-blank (including empty), as that leads to
|
|
||||||
* confusion --- we'd try to read the containing directory as a file.
|
|
||||||
*/
|
|
||||||
if (strspn(config_file, " \t\r\n") == strlen(config_file))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Reject too-deep include nesting depth. This is just a safety check to
|
|
||||||
* avoid dumping core due to stack overflow if an include file loops back
|
|
||||||
* to itself. The maximum nesting depth is pretty arbitrary.
|
|
||||||
*/
|
|
||||||
if (depth > 10)
|
|
||||||
{
|
|
||||||
item_list_append_format(error_list,
|
|
||||||
_("could not open configuration file \"%s\": maximum nesting depth exceeded"),
|
|
||||||
config_file);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
abs_path = AbsoluteConfigLocation(base_dir, config_file, calling_file);
|
|
||||||
|
|
||||||
/* Reject direct recursion */
|
|
||||||
if (calling_file && strcmp(abs_path, calling_file) == 0)
|
|
||||||
{
|
|
||||||
item_list_append_format(error_list,
|
|
||||||
_("configuration file recursion in \"%s\""),
|
|
||||||
calling_file);
|
|
||||||
pfree(abs_path);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
fp = fopen(abs_path, "r");
|
|
||||||
if (!fp)
|
|
||||||
{
|
|
||||||
if (strict == false)
|
|
||||||
{
|
|
||||||
item_list_append_format(error_list,
|
|
||||||
"skipping configuration file \"%s\"",
|
|
||||||
abs_path);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
item_list_append_format(error_list,
|
|
||||||
"could not open configuration file \"%s\": %s",
|
|
||||||
abs_path,
|
|
||||||
strerror(errno));
|
|
||||||
success = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
success = ProcessConfigFp(fp, abs_path, calling_file, depth + 1, base_dir, contents, error_list, warning_list);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(abs_path);
|
|
||||||
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
ProcessConfigFp(FILE *fp, const char *config_file, const char *calling_file, int depth, const char *base_dir, KeyValueList *contents, ItemList *error_list, ItemList *warning_list)
|
|
||||||
{
|
{
|
||||||
volatile bool OK = true;
|
volatile bool OK = true;
|
||||||
volatile YY_BUFFER_STATE lex_buffer = NULL;
|
volatile YY_BUFFER_STATE lex_buffer = NULL;
|
||||||
@@ -258,62 +179,22 @@ ProcessConfigFp(FILE *fp, const char *config_file, const char *calling_file, int
|
|||||||
ConfigFileLineno++;
|
ConfigFileLineno++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Handle include files */
|
/* OK, process the option name and value */
|
||||||
if (base_dir != NULL && strcasecmp(opt_name, "include_dir") == 0)
|
if (contents != NULL)
|
||||||
{
|
{
|
||||||
/*
|
key_value_list_replace_or_set(contents,
|
||||||
* An include_dir directive isn't a variable and should be
|
opt_name,
|
||||||
* processed immediately.
|
opt_value);
|
||||||
*/
|
|
||||||
if (!ProcessConfigDirectory(base_dir, opt_value, config_file,
|
|
||||||
depth + 1, contents,
|
|
||||||
error_list, warning_list))
|
|
||||||
OK = false;
|
|
||||||
yy_switch_to_buffer(lex_buffer);
|
|
||||||
pfree(opt_name);
|
|
||||||
pfree(opt_value);
|
|
||||||
}
|
|
||||||
else if (base_dir != NULL && strcasecmp(opt_name, "include_if_exists") == 0)
|
|
||||||
{
|
|
||||||
if (!ProcessConfigFile(base_dir, opt_value, config_file,
|
|
||||||
false, depth + 1, contents,
|
|
||||||
error_list, warning_list))
|
|
||||||
OK = false;
|
|
||||||
|
|
||||||
yy_switch_to_buffer(lex_buffer);
|
|
||||||
pfree(opt_name);
|
|
||||||
pfree(opt_value);
|
|
||||||
}
|
|
||||||
else if (base_dir != NULL && strcasecmp(opt_name, "include") == 0)
|
|
||||||
{
|
|
||||||
if (!ProcessConfigFile(base_dir, opt_value, config_file,
|
|
||||||
true, depth + 1, contents,
|
|
||||||
error_list, warning_list))
|
|
||||||
OK = false;
|
|
||||||
|
|
||||||
yy_switch_to_buffer(lex_buffer);
|
|
||||||
pfree(opt_name);
|
|
||||||
pfree(opt_value);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* OK, process the option name and value */
|
|
||||||
if (contents != NULL)
|
|
||||||
{
|
|
||||||
key_value_list_replace_or_set(contents,
|
|
||||||
opt_name,
|
|
||||||
opt_value);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
parse_configuration_item(error_list,
|
|
||||||
warning_list,
|
|
||||||
opt_name,
|
|
||||||
opt_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options != NULL)
|
||||||
|
{
|
||||||
|
parse_configuration_item(options,
|
||||||
|
error_list,
|
||||||
|
warning_list,
|
||||||
|
opt_name,
|
||||||
|
opt_value);
|
||||||
|
}
|
||||||
|
|
||||||
/* break out of loop if read EOF, else loop for next line */
|
/* break out of loop if read EOF, else loop for next line */
|
||||||
if (token == 0)
|
if (token == 0)
|
||||||
@@ -372,132 +253,6 @@ cleanup:
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Read and parse all config files in a subdirectory in alphabetical order
|
|
||||||
*
|
|
||||||
* includedir is the absolute or relative path to the subdirectory to scan.
|
|
||||||
*
|
|
||||||
* See ProcessConfigFp for further details.
|
|
||||||
*/
|
|
||||||
static bool
|
|
||||||
ProcessConfigDirectory(const char *base_dir, const char *includedir, const char *calling_file, int depth, KeyValueList *contents, ItemList *error_list, ItemList *warning_list)
|
|
||||||
{
|
|
||||||
char *directory;
|
|
||||||
DIR *d;
|
|
||||||
struct dirent *de;
|
|
||||||
char **filenames;
|
|
||||||
int num_filenames;
|
|
||||||
int size_filenames;
|
|
||||||
bool status;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Reject directory name that is all-blank (including empty), as that
|
|
||||||
* leads to confusion --- we'd read the containing directory, typically
|
|
||||||
* resulting in recursive inclusion of the same file(s).
|
|
||||||
*/
|
|
||||||
if (strspn(includedir, " \t\r\n") == strlen(includedir))
|
|
||||||
{
|
|
||||||
item_list_append_format(error_list,
|
|
||||||
_("empty configuration directory name: \"%s\""),
|
|
||||||
includedir);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
directory = AbsoluteConfigLocation(base_dir, includedir, calling_file);
|
|
||||||
d = opendir(directory);
|
|
||||||
if (d == NULL)
|
|
||||||
{
|
|
||||||
item_list_append_format(error_list,
|
|
||||||
_("could not open configuration directory \"%s\": %s"),
|
|
||||||
directory,
|
|
||||||
strerror(errno));
|
|
||||||
status = false;
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Read the directory and put the filenames in an array, so we can sort
|
|
||||||
* them prior to processing the contents.
|
|
||||||
*/
|
|
||||||
size_filenames = 32;
|
|
||||||
filenames = (char **) palloc(size_filenames * sizeof(char *));
|
|
||||||
num_filenames = 0;
|
|
||||||
|
|
||||||
while ((de = readdir(d)) != NULL)
|
|
||||||
{
|
|
||||||
struct stat st;
|
|
||||||
char filename[MAXPGPATH];
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Only parse files with names ending in ".conf". Explicitly reject
|
|
||||||
* files starting with ".". This excludes things like "." and "..",
|
|
||||||
* as well as typical hidden files, backup files, and editor debris.
|
|
||||||
*/
|
|
||||||
if (strlen(de->d_name) < 6)
|
|
||||||
continue;
|
|
||||||
if (de->d_name[0] == '.')
|
|
||||||
continue;
|
|
||||||
if (strcmp(de->d_name + strlen(de->d_name) - 5, ".conf") != 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
join_path_components(filename, directory, de->d_name);
|
|
||||||
canonicalize_path(filename);
|
|
||||||
if (stat(filename, &st) == 0)
|
|
||||||
{
|
|
||||||
if (!S_ISDIR(st.st_mode))
|
|
||||||
{
|
|
||||||
/* Add file to array, increasing its size in blocks of 32 */
|
|
||||||
if (num_filenames >= size_filenames)
|
|
||||||
{
|
|
||||||
size_filenames += 32;
|
|
||||||
filenames = (char **) repalloc(filenames,
|
|
||||||
size_filenames * sizeof(char *));
|
|
||||||
}
|
|
||||||
filenames[num_filenames] = pstrdup(filename);
|
|
||||||
num_filenames++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* stat does not care about permissions, so the most likely reason
|
|
||||||
* a file can't be accessed now is if it was removed between the
|
|
||||||
* directory listing and now.
|
|
||||||
*/
|
|
||||||
item_list_append_format(error_list,
|
|
||||||
_("could not stat file \"%s\": %s"),
|
|
||||||
filename, strerror(errno));
|
|
||||||
status = false;
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (num_filenames > 0)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
qsort(filenames, num_filenames, sizeof(char *), pg_qsort_strcmp);
|
|
||||||
for (i = 0; i < num_filenames; i++)
|
|
||||||
{
|
|
||||||
if (!ProcessConfigFile(base_dir, filenames[i], calling_file,
|
|
||||||
true, depth, contents,
|
|
||||||
error_list, warning_list))
|
|
||||||
{
|
|
||||||
status = false;
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
status = true;
|
|
||||||
|
|
||||||
|
|
||||||
cleanup:
|
|
||||||
if (d)
|
|
||||||
closedir(d);
|
|
||||||
pfree(directory);
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* scanstr
|
* scanstr
|
||||||
@@ -593,39 +348,6 @@ CONF_scanstr(const char *s)
|
|||||||
return newStr;
|
return newStr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Given a configuration file or directory location that may be a relative
|
|
||||||
* path, return an absolute one. We consider the location to be relative to
|
|
||||||
* the directory holding the calling file, or to DataDir if no calling file.
|
|
||||||
*/
|
|
||||||
static char *
|
|
||||||
AbsoluteConfigLocation(const char *base_dir, const char *location, const char *calling_file)
|
|
||||||
{
|
|
||||||
char abs_path[MAXPGPATH];
|
|
||||||
|
|
||||||
if (is_absolute_path(location))
|
|
||||||
return strdup(location);
|
|
||||||
|
|
||||||
if (calling_file != NULL)
|
|
||||||
{
|
|
||||||
strlcpy(abs_path, calling_file, sizeof(abs_path));
|
|
||||||
get_parent_directory(abs_path);
|
|
||||||
join_path_components(abs_path, abs_path, location);
|
|
||||||
canonicalize_path(abs_path);
|
|
||||||
}
|
|
||||||
else if (base_dir != NULL)
|
|
||||||
{
|
|
||||||
join_path_components(abs_path, base_dir, location);
|
|
||||||
canonicalize_path(abs_path);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
strlcpy(abs_path, location, sizeof(abs_path));
|
|
||||||
}
|
|
||||||
|
|
||||||
return strdup(abs_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Flex fatal errors bring us here. Stash the error message and jump back to
|
* Flex fatal errors bring us here. Stash the error message and jump back to
|
||||||
|
|||||||
1694
configfile.c
1694
configfile.c
File diff suppressed because it is too large
Load Diff
161
configfile.h
161
configfile.h
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* configfile.h
|
* configfile.h
|
||||||
*
|
*
|
||||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
@@ -29,7 +29,7 @@
|
|||||||
#define TARGET_TIMELINE_LATEST 0
|
#define TARGET_TIMELINE_LATEST 0
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is defined in src/include/utils.h, however it's not practical
|
* This is defined src/include/utils.h, however it's not practical
|
||||||
* to include that from a frontend application.
|
* to include that from a frontend application.
|
||||||
*/
|
*/
|
||||||
#define PG_AUTOCONF_FILENAME "postgresql.auto.conf"
|
#define PG_AUTOCONF_FILENAME "postgresql.auto.conf"
|
||||||
@@ -50,11 +50,6 @@ typedef enum
|
|||||||
CHECK_CONNECTION
|
CHECK_CONNECTION
|
||||||
} ConnectionCheckType;
|
} ConnectionCheckType;
|
||||||
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
REPLICATION_TYPE_PHYSICAL
|
|
||||||
} ReplicationType;
|
|
||||||
|
|
||||||
typedef struct EventNotificationListCell
|
typedef struct EventNotificationListCell
|
||||||
{
|
{
|
||||||
struct EventNotificationListCell *next;
|
struct EventNotificationListCell *next;
|
||||||
@@ -83,58 +78,6 @@ typedef struct TablespaceList
|
|||||||
} TablespaceList;
|
} TablespaceList;
|
||||||
|
|
||||||
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
CONFIG_BOOL,
|
|
||||||
CONFIG_INT,
|
|
||||||
CONFIG_STRING,
|
|
||||||
CONFIG_FAILOVER_MODE,
|
|
||||||
CONFIG_CONNECTION_CHECK_TYPE,
|
|
||||||
CONFIG_EVENT_NOTIFICATION_LIST,
|
|
||||||
CONFIG_TABLESPACE_MAPPING,
|
|
||||||
CONFIG_REPLICATION_TYPE
|
|
||||||
} ConfigItemType;
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct ConfigFileSetting
|
|
||||||
{
|
|
||||||
const char *name;
|
|
||||||
ConfigItemType type;
|
|
||||||
union
|
|
||||||
{
|
|
||||||
int *intptr;
|
|
||||||
char *strptr;
|
|
||||||
bool *boolptr;
|
|
||||||
failover_mode_opt *failovermodeptr;
|
|
||||||
ConnectionCheckType *checktypeptr;
|
|
||||||
EventNotificationList *notificationlistptr;
|
|
||||||
TablespaceList *tablespacemappingptr;
|
|
||||||
ReplicationType *replicationtypeptr;
|
|
||||||
} val;
|
|
||||||
union {
|
|
||||||
int intdefault;
|
|
||||||
const char *strdefault;
|
|
||||||
bool booldefault;
|
|
||||||
failover_mode_opt failovermodedefault;
|
|
||||||
ConnectionCheckType checktypedefault;
|
|
||||||
ReplicationType replicationtypedefault;
|
|
||||||
} defval;
|
|
||||||
union {
|
|
||||||
int intminval;
|
|
||||||
} minval;
|
|
||||||
union {
|
|
||||||
int strmaxlen;
|
|
||||||
} maxval;
|
|
||||||
struct {
|
|
||||||
void (*process_func)(const char *, const char *, char *, ItemList *errors);
|
|
||||||
void (*postprocess_func)(const char *, const char *, char *, ItemList *errors);
|
|
||||||
bool *providedptr;
|
|
||||||
} process;
|
|
||||||
} ConfigFileSetting;
|
|
||||||
|
|
||||||
/* Declare the main configfile structure for client applications */
|
|
||||||
extern ConfigFileSetting config_file_settings[];
|
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
/* node information */
|
/* node information */
|
||||||
@@ -146,7 +89,7 @@ typedef struct
|
|||||||
char config_directory[MAXPGPATH];
|
char config_directory[MAXPGPATH];
|
||||||
char pg_bindir[MAXPGPATH];
|
char pg_bindir[MAXPGPATH];
|
||||||
char repmgr_bindir[MAXPGPATH];
|
char repmgr_bindir[MAXPGPATH];
|
||||||
ReplicationType replication_type;
|
int replication_type;
|
||||||
|
|
||||||
/* log settings */
|
/* log settings */
|
||||||
char log_level[MAXLEN];
|
char log_level[MAXLEN];
|
||||||
@@ -172,7 +115,6 @@ typedef struct
|
|||||||
/* standby follow settings */
|
/* standby follow settings */
|
||||||
int primary_follow_timeout;
|
int primary_follow_timeout;
|
||||||
int standby_follow_timeout;
|
int standby_follow_timeout;
|
||||||
bool standby_follow_restart;
|
|
||||||
|
|
||||||
/* standby switchover settings */
|
/* standby switchover settings */
|
||||||
int shutdown_check_timeout;
|
int shutdown_check_timeout;
|
||||||
@@ -210,7 +152,6 @@ typedef struct
|
|||||||
int sibling_nodes_disconnect_timeout;
|
int sibling_nodes_disconnect_timeout;
|
||||||
ConnectionCheckType connection_check_type;
|
ConnectionCheckType connection_check_type;
|
||||||
bool primary_visibility_consensus;
|
bool primary_visibility_consensus;
|
||||||
bool always_promote;
|
|
||||||
char failover_validation_command[MAXPGPATH];
|
char failover_validation_command[MAXPGPATH];
|
||||||
int election_rerun_interval;
|
int election_rerun_interval;
|
||||||
int child_nodes_check_interval;
|
int child_nodes_check_interval;
|
||||||
@@ -246,35 +187,77 @@ typedef struct
|
|||||||
char rsync_options[MAXLEN];
|
char rsync_options[MAXLEN];
|
||||||
char ssh_options[MAXLEN];
|
char ssh_options[MAXLEN];
|
||||||
|
|
||||||
/*
|
/* undocumented test settings */
|
||||||
* undocumented settings
|
|
||||||
*
|
|
||||||
* These settings are for testing or experimental features
|
|
||||||
* and may be changed without notice.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* experimental settings */
|
|
||||||
bool reconnect_loop_sync;
|
|
||||||
|
|
||||||
/* test settings */
|
|
||||||
int promote_delay;
|
int promote_delay;
|
||||||
int failover_delay;
|
|
||||||
char connection_check_query[MAXLEN];
|
|
||||||
} t_configuration_options;
|
} t_configuration_options;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The following will initialize the structure with a minimal set of options;
|
||||||
|
* actual defaults are set in parse_config() before parsing the configuration file
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define T_CONFIGURATION_OPTIONS_INITIALIZER { \
|
||||||
|
/* node information */ \
|
||||||
|
UNKNOWN_NODE_ID, "", "", "", "", "", "", "", REPLICATION_TYPE_PHYSICAL, \
|
||||||
|
/* log settings */ \
|
||||||
|
"", "", "", DEFAULT_LOG_STATUS_INTERVAL, \
|
||||||
|
/* standby clone settings */ \
|
||||||
|
false, "", "", { NULL, NULL }, "", false, "", false, "", \
|
||||||
|
/* standby promote settings */ \
|
||||||
|
DEFAULT_PROMOTE_CHECK_TIMEOUT, DEFAULT_PROMOTE_CHECK_INTERVAL, \
|
||||||
|
/* standby follow settings */ \
|
||||||
|
DEFAULT_PRIMARY_FOLLOW_TIMEOUT, \
|
||||||
|
DEFAULT_STANDBY_FOLLOW_TIMEOUT, \
|
||||||
|
/* standby switchover settings */ \
|
||||||
|
DEFAULT_SHUTDOWN_CHECK_TIMEOUT, \
|
||||||
|
DEFAULT_STANDBY_RECONNECT_TIMEOUT, \
|
||||||
|
DEFAULT_WAL_RECEIVE_CHECK_TIMEOUT, \
|
||||||
|
/* node rejoin settings */ \
|
||||||
|
DEFAULT_NODE_REJOIN_TIMEOUT, \
|
||||||
|
/* node check settings */ \
|
||||||
|
DEFAULT_ARCHIVE_READY_WARNING, DEFAULT_ARCHIVE_READY_CRITICAL, \
|
||||||
|
DEFAULT_REPLICATION_LAG_WARNING, DEFAULT_REPLICATION_LAG_CRITICAL, \
|
||||||
|
/* witness settings */ \
|
||||||
|
DEFAULT_WITNESS_SYNC_INTERVAL, \
|
||||||
|
/* repmgrd settings */ \
|
||||||
|
FAILOVER_MANUAL, DEFAULT_LOCATION, DEFAULT_PRIORITY, "", "", \
|
||||||
|
DEFAULT_MONITORING_INTERVAL, \
|
||||||
|
DEFAULT_RECONNECTION_ATTEMPTS, \
|
||||||
|
DEFAULT_RECONNECTION_INTERVAL, \
|
||||||
|
false, -1, \
|
||||||
|
DEFAULT_ASYNC_QUERY_TIMEOUT, \
|
||||||
|
DEFAULT_PRIMARY_NOTIFICATION_TIMEOUT, \
|
||||||
|
-1, "", false, DEFAULT_SIBLING_NODES_DISCONNECT_TIMEOUT, \
|
||||||
|
CHECK_PING, true, "", DEFAULT_ELECTION_RERUN_INTERVAL, \
|
||||||
|
DEFAULT_CHILD_NODES_CHECK_INTERVAL, \
|
||||||
|
DEFAULT_CHILD_NODES_DISCONNECT_MIN_COUNT, \
|
||||||
|
DEFAULT_CHILD_NODES_CONNECTED_MIN_COUNT, \
|
||||||
|
DEFAULT_CHILD_NODES_CONNECTED_INCLUDE_WITNESS, \
|
||||||
|
DEFAULT_CHILD_NODES_DISCONNECT_TIMEOUT, "", \
|
||||||
|
/* service settings */ \
|
||||||
|
"", "", "", "", "", "", \
|
||||||
|
/* repmgrd service settings */ \
|
||||||
|
"", "", \
|
||||||
|
/* event notification settings */ \
|
||||||
|
"", "", { NULL, NULL }, \
|
||||||
|
/* barman settings */ \
|
||||||
|
"", "", "", \
|
||||||
|
/* rsync/ssh settings */ \
|
||||||
|
"", "", \
|
||||||
|
/* undocumented test settings */ \
|
||||||
|
0 \
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Declare the main configfile structure for client applications */
|
|
||||||
extern t_configuration_options config_file_options;
|
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
char slot[MAXLEN];
|
char slot[MAXLEN];
|
||||||
char wal_method[MAXLEN];
|
char wal_method[MAXLEN];
|
||||||
char waldir[MAXPGPATH];
|
|
||||||
bool no_slot; /* from PostgreSQL 10 */
|
bool no_slot; /* from PostgreSQL 10 */
|
||||||
} t_basebackup_options;
|
} t_basebackup_options;
|
||||||
|
|
||||||
#define T_BASEBACKUP_OPTIONS_INITIALIZER { "", "", "", false }
|
#define T_BASEBACKUP_OPTIONS_INITIALIZER { "", "", false }
|
||||||
|
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
@@ -331,11 +314,10 @@ typedef struct
|
|||||||
void set_progname(const char *argv0);
|
void set_progname(const char *argv0);
|
||||||
const char *progname(void);
|
const char *progname(void);
|
||||||
|
|
||||||
void load_config(const char *config_file, bool verbose, bool terse, char *argv0);
|
void load_config(const char *config_file, bool verbose, bool terse, t_configuration_options *options, char *argv0);
|
||||||
bool reload_config(t_server_type server_type);
|
bool reload_config(t_configuration_options *orig_options, t_server_type server_type);
|
||||||
void dump_config(void);
|
|
||||||
|
|
||||||
void parse_configuration_item(ItemList *error_list, ItemList *warning_list, const char *name, const char *value);
|
void parse_configuration_item(t_configuration_options *options, ItemList *error_list, ItemList *warning_list, const char *name, const char *value);
|
||||||
|
|
||||||
bool parse_recovery_conf(const char *data_dir, t_recovery_conf *conf);
|
bool parse_recovery_conf(const char *data_dir, t_recovery_conf *conf);
|
||||||
|
|
||||||
@@ -348,9 +330,6 @@ int repmgr_atoi(const char *s,
|
|||||||
ItemList *error_list,
|
ItemList *error_list,
|
||||||
int minval);
|
int minval);
|
||||||
|
|
||||||
void parse_time_unit_parameter(const char *name, const char *value, char *dest, ItemList *errors);
|
|
||||||
void repmgr_canonicalize_path(const char *name, const char *value, char *config_item, ItemList *errors);
|
|
||||||
|
|
||||||
bool parse_pg_basebackup_options(const char *pg_basebackup_options,
|
bool parse_pg_basebackup_options(const char *pg_basebackup_options,
|
||||||
t_basebackup_options *backup_options,
|
t_basebackup_options *backup_options,
|
||||||
int server_version_num,
|
int server_version_num,
|
||||||
@@ -358,21 +337,17 @@ bool parse_pg_basebackup_options(const char *pg_basebackup_options,
|
|||||||
|
|
||||||
int parse_output_to_argv(const char *string, char ***argv_array);
|
int parse_output_to_argv(const char *string, char ***argv_array);
|
||||||
void free_parsed_argv(char ***argv_array);
|
void free_parsed_argv(char ***argv_array);
|
||||||
const char *format_failover_mode(failover_mode_opt failover);
|
|
||||||
|
|
||||||
/* called by repmgr-client and repmgrd */
|
/* called by repmgr-client and repmgrd */
|
||||||
void exit_with_cli_errors(ItemList *error_list, const char *repmgr_command);
|
void exit_with_cli_errors(ItemList *error_list, const char *repmgr_command);
|
||||||
|
|
||||||
void print_item_list(ItemList *item_list);
|
void print_item_list(ItemList *item_list);
|
||||||
const char *print_replication_type(ReplicationType type);
|
|
||||||
const char *print_connection_check_type(ConnectionCheckType type);
|
const char *print_connection_check_type(ConnectionCheckType type);
|
||||||
char *print_event_notification_list(EventNotificationList *list);
|
|
||||||
char *print_tablespace_mapping(TablespaceList *tablespacemappingptr);
|
|
||||||
|
|
||||||
extern bool modify_auto_conf(const char *data_dir, KeyValueList *items);
|
extern bool modify_auto_conf(const char *data_dir, KeyValueList *items);
|
||||||
|
|
||||||
extern bool ProcessRepmgrConfigFile(const char *config_file, const char *base_dir, ItemList *error_list, ItemList *warning_list);
|
extern bool ProcessRepmgrConfigFile(FILE *fp, const char *config_file, t_configuration_options *options, ItemList *error_list, ItemList *warning_list);
|
||||||
|
|
||||||
extern bool ProcessPostgresConfigFile(const char *config_file, const char *base_dir, bool strict, KeyValueList *contents, ItemList *error_list, ItemList *warning_list);
|
extern bool ProcessPostgresConfigFile(FILE *fp, const char *config_file, KeyValueList *contents, ItemList *error_list, ItemList *warning_list);
|
||||||
|
|
||||||
#endif /* _REPMGR_CONFIGFILE_H_ */
|
#endif /* _REPMGR_CONFIGFILE_H_ */
|
||||||
|
|||||||
24
configure
vendored
24
configure
vendored
@@ -1,6 +1,6 @@
|
|||||||
#! /bin/sh
|
#! /bin/sh
|
||||||
# Guess values for system-dependent variables and create Makefiles.
|
# Guess values for system-dependent variables and create Makefiles.
|
||||||
# Generated by GNU Autoconf 2.69 for repmgr 5.2.1.
|
# Generated by GNU Autoconf 2.69 for repmgr 5.1.0.
|
||||||
#
|
#
|
||||||
# Report bugs to <repmgr@googlegroups.com>.
|
# Report bugs to <repmgr@googlegroups.com>.
|
||||||
#
|
#
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
# This configure script is free software; the Free Software Foundation
|
# This configure script is free software; the Free Software Foundation
|
||||||
# gives unlimited permission to copy, distribute and modify it.
|
# gives unlimited permission to copy, distribute and modify it.
|
||||||
#
|
#
|
||||||
# Copyright (c) 2010-2021, EnterpriseDB Corporation
|
# Copyright (c) 2010-2020, 2ndQuadrant Ltd.
|
||||||
## -------------------- ##
|
## -------------------- ##
|
||||||
## M4sh Initialization. ##
|
## M4sh Initialization. ##
|
||||||
## -------------------- ##
|
## -------------------- ##
|
||||||
@@ -582,8 +582,8 @@ MAKEFLAGS=
|
|||||||
# Identity of this package.
|
# Identity of this package.
|
||||||
PACKAGE_NAME='repmgr'
|
PACKAGE_NAME='repmgr'
|
||||||
PACKAGE_TARNAME='repmgr'
|
PACKAGE_TARNAME='repmgr'
|
||||||
PACKAGE_VERSION='5.2.1'
|
PACKAGE_VERSION='5.1.0'
|
||||||
PACKAGE_STRING='repmgr 5.2.1'
|
PACKAGE_STRING='repmgr 5.1.0'
|
||||||
PACKAGE_BUGREPORT='repmgr@googlegroups.com'
|
PACKAGE_BUGREPORT='repmgr@googlegroups.com'
|
||||||
PACKAGE_URL='https://repmgr.org/'
|
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.
|
# Omit some internal or obsolete options to make the list less imposing.
|
||||||
# This message is too long to be a string in the A/UX 3.1 sh.
|
# This message is too long to be a string in the A/UX 3.1 sh.
|
||||||
cat <<_ACEOF
|
cat <<_ACEOF
|
||||||
\`configure' configures repmgr 5.2.1 to adapt to many kinds of systems.
|
\`configure' configures repmgr 5.1.0 to adapt to many kinds of systems.
|
||||||
|
|
||||||
Usage: $0 [OPTION]... [VAR=VALUE]...
|
Usage: $0 [OPTION]... [VAR=VALUE]...
|
||||||
|
|
||||||
@@ -1242,7 +1242,7 @@ fi
|
|||||||
|
|
||||||
if test -n "$ac_init_help"; then
|
if test -n "$ac_init_help"; then
|
||||||
case $ac_init_help in
|
case $ac_init_help in
|
||||||
short | recursive ) echo "Configuration of repmgr 5.2.1:";;
|
short | recursive ) echo "Configuration of repmgr 5.1.0:";;
|
||||||
esac
|
esac
|
||||||
cat <<\_ACEOF
|
cat <<\_ACEOF
|
||||||
|
|
||||||
@@ -1316,14 +1316,14 @@ fi
|
|||||||
test -n "$ac_init_help" && exit $ac_status
|
test -n "$ac_init_help" && exit $ac_status
|
||||||
if $ac_init_version; then
|
if $ac_init_version; then
|
||||||
cat <<\_ACEOF
|
cat <<\_ACEOF
|
||||||
repmgr configure 5.2.1
|
repmgr configure 5.1.0
|
||||||
generated by GNU Autoconf 2.69
|
generated by GNU Autoconf 2.69
|
||||||
|
|
||||||
Copyright (C) 2012 Free Software Foundation, Inc.
|
Copyright (C) 2012 Free Software Foundation, Inc.
|
||||||
This configure script is free software; the Free Software Foundation
|
This configure script is free software; the Free Software Foundation
|
||||||
gives unlimited permission to copy, distribute and modify it.
|
gives unlimited permission to copy, distribute and modify it.
|
||||||
|
|
||||||
Copyright (c) 2010-2021, EnterpriseDB Corporation
|
Copyright (c) 2010-2020, 2ndQuadrant Ltd.
|
||||||
_ACEOF
|
_ACEOF
|
||||||
exit
|
exit
|
||||||
fi
|
fi
|
||||||
@@ -1335,7 +1335,7 @@ cat >config.log <<_ACEOF
|
|||||||
This file contains any messages produced by compilers while
|
This file contains any messages produced by compilers while
|
||||||
running configure, to aid debugging if configure makes a mistake.
|
running configure, to aid debugging if configure makes a mistake.
|
||||||
|
|
||||||
It was created by repmgr $as_me 5.2.1, which was
|
It was created by repmgr $as_me 5.1.0, which was
|
||||||
generated by GNU Autoconf 2.69. Invocation command line was
|
generated by GNU Autoconf 2.69. Invocation command line was
|
||||||
|
|
||||||
$ $0 $@
|
$ $0 $@
|
||||||
@@ -1824,7 +1824,7 @@ if test "$major_version_num" -lt '10'; then
|
|||||||
version_num_int=$(echo "$version_num"|
|
version_num_int=$(echo "$version_num"|
|
||||||
$SED -e 's/^\([0-9]*\)\.\([0-9]*\)$/\1\2/')
|
$SED -e 's/^\([0-9]*\)\.\([0-9]*\)$/\1\2/')
|
||||||
|
|
||||||
if test "$version_num_int" -lt '94'; then
|
if test "$version_num_int" -lt '93'; then
|
||||||
as_fn_error $? "repmgr is not compatible with detected PostgreSQL version: $version_num" "$LINENO" 5
|
as_fn_error $? "repmgr is not compatible with detected PostgreSQL version: $version_num" "$LINENO" 5
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
@@ -2487,7 +2487,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
|
|||||||
# report actual input values of CONFIG_FILES etc. instead of their
|
# report actual input values of CONFIG_FILES etc. instead of their
|
||||||
# values after options handling.
|
# values after options handling.
|
||||||
ac_log="
|
ac_log="
|
||||||
This file was extended by repmgr $as_me 5.2.1, which was
|
This file was extended by repmgr $as_me 5.1.0, which was
|
||||||
generated by GNU Autoconf 2.69. Invocation command line was
|
generated by GNU Autoconf 2.69. Invocation command line was
|
||||||
|
|
||||||
CONFIG_FILES = $CONFIG_FILES
|
CONFIG_FILES = $CONFIG_FILES
|
||||||
@@ -2550,7 +2550,7 @@ _ACEOF
|
|||||||
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
||||||
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
|
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
|
||||||
ac_cs_version="\\
|
ac_cs_version="\\
|
||||||
repmgr config.status 5.2.1
|
repmgr config.status 5.1.0
|
||||||
configured by $0, generated by GNU Autoconf 2.69,
|
configured by $0, generated by GNU Autoconf 2.69,
|
||||||
with options \\"\$ac_cs_config\\"
|
with options \\"\$ac_cs_config\\"
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
AC_INIT([repmgr], [5.2.1], [repmgr@googlegroups.com], [repmgr], [https://repmgr.org/])
|
AC_INIT([repmgr], [5.1.0], [repmgr@googlegroups.com], [repmgr], [https://repmgr.org/])
|
||||||
|
|
||||||
AC_COPYRIGHT([Copyright (c) 2010-2021, EnterpriseDB Corporation])
|
AC_COPYRIGHT([Copyright (c) 2010-2020, 2ndQuadrant Ltd.])
|
||||||
|
|
||||||
AC_CONFIG_HEADER(config.h)
|
AC_CONFIG_HEADER(config.h)
|
||||||
|
|
||||||
@@ -32,7 +32,7 @@ if test "$major_version_num" -lt '10'; then
|
|||||||
version_num_int=$(echo "$version_num"|
|
version_num_int=$(echo "$version_num"|
|
||||||
$SED -e 's/^\([[0-9]]*\)\.\([[0-9]]*\)$/\1\2/')
|
$SED -e 's/^\([[0-9]]*\)\.\([[0-9]]*\)$/\1\2/')
|
||||||
|
|
||||||
if test "$version_num_int" -lt '94'; then
|
if test "$version_num_int" -lt '93'; then
|
||||||
AC_MSG_ERROR([repmgr is not compatible with detected PostgreSQL version: $version_num])
|
AC_MSG_ERROR([repmgr is not compatible with detected PostgreSQL version: $version_num])
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -2,11 +2,11 @@
|
|||||||
* controldata.c - functions for reading the pg_control file
|
* controldata.c - functions for reading the pg_control file
|
||||||
*
|
*
|
||||||
* The functions provided here enable repmgr to read a pg_control file
|
* The functions provided here enable repmgr to read a pg_control file
|
||||||
* in a version-independent way, even if the PostgreSQL instance is not
|
* in a version-indepent way, even if the PostgreSQL instance is not
|
||||||
* running. For that reason we can't use on the pg_control_*() functions
|
* running. For that reason we can't use on the pg_control_*() functions
|
||||||
* provided in PostgreSQL 9.6 and later.
|
* provided in PostgreSQL 9.6 and later.
|
||||||
*
|
*
|
||||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||||
*
|
*
|
||||||
* Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
@@ -90,9 +90,7 @@ get_system_identifier(const char *data_directory)
|
|||||||
uint64 system_identifier = UNKNOWN_SYSTEM_IDENTIFIER;
|
uint64 system_identifier = UNKNOWN_SYSTEM_IDENTIFIER;
|
||||||
|
|
||||||
control_file_info = get_controlfile(data_directory);
|
control_file_info = get_controlfile(data_directory);
|
||||||
|
system_identifier = control_file_info->system_identifier;
|
||||||
if (control_file_info->control_file_processed == true)
|
|
||||||
system_identifier = control_file_info->system_identifier;
|
|
||||||
|
|
||||||
pfree(control_file_info);
|
pfree(control_file_info);
|
||||||
|
|
||||||
@@ -100,21 +98,19 @@ get_system_identifier(const char *data_directory)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
DBState
|
||||||
get_db_state(const char *data_directory, DBState *state)
|
get_db_state(const char *data_directory)
|
||||||
{
|
{
|
||||||
ControlFileInfo *control_file_info = NULL;
|
ControlFileInfo *control_file_info = NULL;
|
||||||
bool control_file_processed;
|
DBState state;
|
||||||
|
|
||||||
control_file_info = get_controlfile(data_directory);
|
control_file_info = get_controlfile(data_directory);
|
||||||
control_file_processed = control_file_info->control_file_processed;
|
|
||||||
|
|
||||||
if (control_file_processed == true)
|
state = control_file_info->state;
|
||||||
*state = control_file_info->state;
|
|
||||||
|
|
||||||
pfree(control_file_info);
|
pfree(control_file_info);
|
||||||
|
|
||||||
return control_file_processed;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -126,8 +122,7 @@ get_latest_checkpoint_location(const char *data_directory)
|
|||||||
|
|
||||||
control_file_info = get_controlfile(data_directory);
|
control_file_info = get_controlfile(data_directory);
|
||||||
|
|
||||||
if (control_file_info->control_file_processed == true)
|
checkPoint = control_file_info->checkPoint;
|
||||||
checkPoint = control_file_info->checkPoint;
|
|
||||||
|
|
||||||
pfree(control_file_info);
|
pfree(control_file_info);
|
||||||
|
|
||||||
@@ -139,12 +134,11 @@ int
|
|||||||
get_data_checksum_version(const char *data_directory)
|
get_data_checksum_version(const char *data_directory)
|
||||||
{
|
{
|
||||||
ControlFileInfo *control_file_info = NULL;
|
ControlFileInfo *control_file_info = NULL;
|
||||||
int data_checksum_version = UNKNOWN_DATA_CHECKSUM_VERSION;
|
int data_checksum_version = -1;
|
||||||
|
|
||||||
control_file_info = get_controlfile(data_directory);
|
control_file_info = get_controlfile(data_directory);
|
||||||
|
|
||||||
if (control_file_info->control_file_processed == true)
|
data_checksum_version = (int) control_file_info->data_checksum_version;
|
||||||
data_checksum_version = (int) control_file_info->data_checksum_version;
|
|
||||||
|
|
||||||
pfree(control_file_info);
|
pfree(control_file_info);
|
||||||
|
|
||||||
@@ -283,19 +277,8 @@ get_controlfile(const char *DataDir)
|
|||||||
return control_file_info;
|
return control_file_info;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (version_num >= 120000)
|
|
||||||
{
|
if (version_num >= 90500)
|
||||||
#if PG_ACTUAL_VERSION_NUM >= 120000
|
|
||||||
expected_size = sizeof(ControlFileData12);
|
|
||||||
ControlFileDataPtr = palloc0(expected_size);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
else if (version_num >= 110000)
|
|
||||||
{
|
|
||||||
expected_size = sizeof(ControlFileData11);
|
|
||||||
ControlFileDataPtr = palloc0(expected_size);
|
|
||||||
}
|
|
||||||
else if (version_num >= 90500)
|
|
||||||
{
|
{
|
||||||
expected_size = sizeof(ControlFileData95);
|
expected_size = sizeof(ControlFileData95);
|
||||||
ControlFileDataPtr = palloc0(expected_size);
|
ControlFileDataPtr = palloc0(expected_size);
|
||||||
@@ -305,6 +288,12 @@ get_controlfile(const char *DataDir)
|
|||||||
expected_size = sizeof(ControlFileData94);
|
expected_size = sizeof(ControlFileData94);
|
||||||
ControlFileDataPtr = palloc0(expected_size);
|
ControlFileDataPtr = palloc0(expected_size);
|
||||||
}
|
}
|
||||||
|
else if (version_num >= 90300)
|
||||||
|
{
|
||||||
|
expected_size = sizeof(ControlFileData93);
|
||||||
|
ControlFileDataPtr = palloc0(expected_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (read(fd, ControlFileDataPtr, expected_size) != expected_size)
|
if (read(fd, ControlFileDataPtr, expected_size) != expected_size)
|
||||||
{
|
{
|
||||||
@@ -333,7 +322,7 @@ get_controlfile(const char *DataDir)
|
|||||||
control_file_info->minRecoveryPointTLI = ptr->minRecoveryPointTLI;
|
control_file_info->minRecoveryPointTLI = ptr->minRecoveryPointTLI;
|
||||||
control_file_info->minRecoveryPoint = ptr->minRecoveryPoint;
|
control_file_info->minRecoveryPoint = ptr->minRecoveryPoint;
|
||||||
#else
|
#else
|
||||||
fprintf(stderr, "ERROR: please use a repmgr version built for PostgreSQL 12 or later\n");
|
fprintf(stderr, "ERROR: please use a repmgr version built for PostgreSQL 12\n");
|
||||||
exit(ERR_BAD_CONFIG);
|
exit(ERR_BAD_CONFIG);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -370,6 +359,17 @@ get_controlfile(const char *DataDir)
|
|||||||
control_file_info->minRecoveryPointTLI = ptr->minRecoveryPointTLI;
|
control_file_info->minRecoveryPointTLI = ptr->minRecoveryPointTLI;
|
||||||
control_file_info->minRecoveryPoint = ptr->minRecoveryPoint;
|
control_file_info->minRecoveryPoint = ptr->minRecoveryPoint;
|
||||||
}
|
}
|
||||||
|
else if (version_num >= 90300)
|
||||||
|
{
|
||||||
|
ControlFileData93 *ptr = (struct ControlFileData93 *)ControlFileDataPtr;
|
||||||
|
control_file_info->system_identifier = ptr->system_identifier;
|
||||||
|
control_file_info->state = ptr->state;
|
||||||
|
control_file_info->checkPoint = ptr->checkPoint;
|
||||||
|
control_file_info->data_checksum_version = ptr->data_checksum_version;
|
||||||
|
control_file_info->timeline = ptr->checkPointCopy.ThisTimeLineID;
|
||||||
|
control_file_info->minRecoveryPointTLI = ptr->minRecoveryPointTLI;
|
||||||
|
control_file_info->minRecoveryPoint = ptr->minRecoveryPoint;
|
||||||
|
}
|
||||||
|
|
||||||
pfree(ControlFileDataPtr);
|
pfree(ControlFileDataPtr);
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* controldata.h
|
* controldata.h
|
||||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||||
*
|
*
|
||||||
* Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
@@ -31,7 +31,9 @@ typedef struct
|
|||||||
} ControlFileInfo;
|
} ControlFileInfo;
|
||||||
|
|
||||||
|
|
||||||
typedef struct CheckPoint94
|
|
||||||
|
/* Same for 9.3, 9.4 */
|
||||||
|
typedef struct CheckPoint93
|
||||||
{
|
{
|
||||||
XLogRecPtr redo; /* next RecPtr available when we began to
|
XLogRecPtr redo; /* next RecPtr available when we began to
|
||||||
* create CheckPoint (i.e. REDO start point) */
|
* create CheckPoint (i.e. REDO start point) */
|
||||||
@@ -51,7 +53,7 @@ typedef struct CheckPoint94
|
|||||||
pg_time_t time; /* time stamp of checkpoint */
|
pg_time_t time; /* time stamp of checkpoint */
|
||||||
|
|
||||||
TransactionId oldestActiveXid;
|
TransactionId oldestActiveXid;
|
||||||
} CheckPoint94;
|
} CheckPoint93;
|
||||||
|
|
||||||
|
|
||||||
/* Same for 9.5, 9.6, 10, 11 */
|
/* Same for 9.5, 9.6, 10, 11 */
|
||||||
@@ -126,6 +128,65 @@ typedef struct CheckPoint12
|
|||||||
} CheckPoint12;
|
} CheckPoint12;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
typedef struct ControlFileData93
|
||||||
|
{
|
||||||
|
uint64 system_identifier;
|
||||||
|
|
||||||
|
uint32 pg_control_version; /* PG_CONTROL_VERSION */
|
||||||
|
uint32 catalog_version_no; /* see catversion.h */
|
||||||
|
|
||||||
|
DBState state; /* see enum above */
|
||||||
|
pg_time_t time; /* time stamp of last pg_control update */
|
||||||
|
XLogRecPtr checkPoint; /* last check point record ptr */
|
||||||
|
XLogRecPtr prevCheckPoint; /* previous check point record ptr */
|
||||||
|
|
||||||
|
CheckPoint93 checkPointCopy; /* copy of last check point record */
|
||||||
|
|
||||||
|
XLogRecPtr unloggedLSN; /* current fake LSN value, for unlogged rels */
|
||||||
|
|
||||||
|
XLogRecPtr minRecoveryPoint;
|
||||||
|
TimeLineID minRecoveryPointTLI;
|
||||||
|
XLogRecPtr backupStartPoint;
|
||||||
|
XLogRecPtr backupEndPoint;
|
||||||
|
bool backupEndRequired;
|
||||||
|
|
||||||
|
int wal_level;
|
||||||
|
int MaxConnections;
|
||||||
|
int max_prepared_xacts;
|
||||||
|
int max_locks_per_xact;
|
||||||
|
|
||||||
|
uint32 maxAlign; /* alignment requirement for tuples */
|
||||||
|
double floatFormat; /* constant 1234567.0 */
|
||||||
|
|
||||||
|
uint32 blcksz; /* data block size for this DB */
|
||||||
|
uint32 relseg_size; /* blocks per segment of large relation */
|
||||||
|
|
||||||
|
uint32 xlog_blcksz; /* block size within WAL files */
|
||||||
|
uint32 xlog_seg_size; /* size of each WAL segment */
|
||||||
|
|
||||||
|
uint32 nameDataLen; /* catalog name field width */
|
||||||
|
uint32 indexMaxKeys; /* max number of columns in an index */
|
||||||
|
|
||||||
|
uint32 toast_max_chunk_size; /* chunk size in TOAST tables */
|
||||||
|
|
||||||
|
/* flag indicating internal format of timestamp, interval, time */
|
||||||
|
bool enableIntTimes; /* int64 storage enabled? */
|
||||||
|
|
||||||
|
/* flags indicating pass-by-value status of various types */
|
||||||
|
bool float4ByVal; /* float4 pass-by-value? */
|
||||||
|
bool float8ByVal; /* float8, int8, etc pass-by-value? */
|
||||||
|
|
||||||
|
/* Are data pages protected by checksums? Zero if no checksum version */
|
||||||
|
uint32 data_checksum_version;
|
||||||
|
|
||||||
|
} ControlFileData93;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Following field added since 9.3:
|
||||||
|
*
|
||||||
|
* int max_worker_processes;
|
||||||
|
*/
|
||||||
|
|
||||||
typedef struct ControlFileData94
|
typedef struct ControlFileData94
|
||||||
{
|
{
|
||||||
@@ -139,7 +200,7 @@ typedef struct ControlFileData94
|
|||||||
XLogRecPtr checkPoint; /* last check point record ptr */
|
XLogRecPtr checkPoint; /* last check point record ptr */
|
||||||
XLogRecPtr prevCheckPoint; /* previous check point record ptr */
|
XLogRecPtr prevCheckPoint; /* previous check point record ptr */
|
||||||
|
|
||||||
CheckPoint94 checkPointCopy; /* copy of last check point record */
|
CheckPoint93 checkPointCopy; /* copy of last check point record */
|
||||||
|
|
||||||
XLogRecPtr unloggedLSN; /* current fake LSN value, for unlogged rels */
|
XLogRecPtr unloggedLSN; /* current fake LSN value, for unlogged rels */
|
||||||
|
|
||||||
@@ -377,7 +438,7 @@ typedef struct ControlFileData12
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern int get_pg_version(const char *data_directory, char *version_string);
|
extern int get_pg_version(const char *data_directory, char *version_string);
|
||||||
extern bool get_db_state(const char *data_directory, DBState *state);
|
extern DBState get_db_state(const char *data_directory);
|
||||||
extern const char *describe_db_state(DBState state);
|
extern const char *describe_db_state(DBState state);
|
||||||
extern int get_data_checksum_version(const char *data_directory);
|
extern int get_data_checksum_version(const char *data_directory);
|
||||||
extern uint64 get_system_identifier(const char *data_directory);
|
extern uint64 get_system_identifier(const char *data_directory);
|
||||||
|
|||||||
306
dbutils.c
306
dbutils.c
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* dbutils.c - Database connection/management functions
|
* dbutils.c - Database connection/management functions
|
||||||
*
|
*
|
||||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
@@ -153,9 +153,6 @@ _establish_db_connection(const char *conninfo, const bool exit_on_error, const b
|
|||||||
if (param_get(&conninfo_params, "replication") != NULL)
|
if (param_get(&conninfo_params, "replication") != NULL)
|
||||||
is_replication_connection = true;
|
is_replication_connection = true;
|
||||||
|
|
||||||
/* use a secure search_path */
|
|
||||||
param_set(&conninfo_params, "options", "-csearch_path=");
|
|
||||||
|
|
||||||
connection_string = param_list_to_string(&conninfo_params);
|
connection_string = param_list_to_string(&conninfo_params);
|
||||||
|
|
||||||
log_debug(_("connecting to: \"%s\""), connection_string);
|
log_debug(_("connecting to: \"%s\""), connection_string);
|
||||||
@@ -306,9 +303,6 @@ establish_db_connection_by_params(t_conninfo_param_list *param_list,
|
|||||||
param_set_ine(param_list, "connect_timeout", "2");
|
param_set_ine(param_list, "connect_timeout", "2");
|
||||||
param_set_ine(param_list, "fallback_application_name", "repmgr");
|
param_set_ine(param_list, "fallback_application_name", "repmgr");
|
||||||
|
|
||||||
/* use a secure search_path */
|
|
||||||
param_set(param_list, "options", "-csearch_path=");
|
|
||||||
|
|
||||||
/* Connect to the database using the provided parameters */
|
/* Connect to the database using the provided parameters */
|
||||||
conn = PQconnectdbParams((const char **) param_list->keywords, (const char **) param_list->values, true);
|
conn = PQconnectdbParams((const char **) param_list->keywords, (const char **) param_list->values, true);
|
||||||
|
|
||||||
@@ -711,37 +705,10 @@ param_get(t_conninfo_param_list *param_list, const char *param)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Validate a conninfo string by attempting to parse it.
|
|
||||||
*
|
|
||||||
* "errmsg": passed to PQconninfoParse(), may be NULL
|
|
||||||
*
|
|
||||||
* NOTE: PQconninfoParse() verifies the string format and checks for
|
|
||||||
* valid options but does not sanity check values.
|
|
||||||
*/
|
|
||||||
|
|
||||||
bool
|
|
||||||
validate_conninfo_string(const char *conninfo_str, char **errmsg)
|
|
||||||
{
|
|
||||||
PQconninfoOption *connOptions = NULL;
|
|
||||||
|
|
||||||
connOptions = PQconninfoParse(conninfo_str, errmsg);
|
|
||||||
|
|
||||||
if (connOptions == NULL)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
PQconninfoFree(connOptions);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Parse a conninfo string into a t_conninfo_param_list
|
* Parse a conninfo string into a t_conninfo_param_list
|
||||||
*
|
*
|
||||||
* See conn_to_param_list() to do the same for a PGconn.
|
* See conn_to_param_list() to do the same for a PGconn
|
||||||
*
|
|
||||||
* "errmsg": passed to PQconninfoParse(), may be NULL
|
|
||||||
*
|
*
|
||||||
* "ignore_local_params": ignores those parameters specific
|
* "ignore_local_params": ignores those parameters specific
|
||||||
* to a local installation, i.e. when parsing an upstream
|
* to a local installation, i.e. when parsing an upstream
|
||||||
@@ -762,7 +729,8 @@ parse_conninfo_string(const char *conninfo_str, t_conninfo_param_list *param_lis
|
|||||||
for (option = connOptions; option && option->keyword; option++)
|
for (option = connOptions; option && option->keyword; option++)
|
||||||
{
|
{
|
||||||
/* Ignore non-set or blank parameter values */
|
/* Ignore non-set or blank parameter values */
|
||||||
if (option->val == NULL || option->val[0] == '\0')
|
if ((option->val == NULL) ||
|
||||||
|
(option->val != NULL && option->val[0] == '\0'))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Ignore settings specific to the upstream node */
|
/* Ignore settings specific to the upstream node */
|
||||||
@@ -807,7 +775,8 @@ conn_to_param_list(PGconn *conn, t_conninfo_param_list *param_list)
|
|||||||
for (option = connOptions; option && option->keyword; option++)
|
for (option = connOptions; option && option->keyword; option++)
|
||||||
{
|
{
|
||||||
/* Ignore non-set or blank parameter values */
|
/* Ignore non-set or blank parameter values */
|
||||||
if (option->val == NULL || option->val[0] == '\0')
|
if ((option->val == NULL) ||
|
||||||
|
(option->val != NULL && option->val[0] == '\0'))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Ignore "password" */
|
/* Ignore "password" */
|
||||||
@@ -1257,7 +1226,7 @@ bool
|
|||||||
pg_reload_conf(PGconn *conn)
|
pg_reload_conf(PGconn *conn)
|
||||||
{
|
{
|
||||||
PGresult *res = NULL;
|
PGresult *res = NULL;
|
||||||
bool success = true;
|
bool success = false;
|
||||||
|
|
||||||
res = PQexec(conn, "SELECT pg_catalog.pg_reload_conf()");
|
res = PQexec(conn, "SELECT pg_catalog.pg_reload_conf()");
|
||||||
|
|
||||||
@@ -1674,12 +1643,7 @@ identify_system(PGconn *repl_conn, t_system_identification *identification)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(__i386__) || defined(__i386)
|
|
||||||
identification->system_identifier = atoll(PQgetvalue(res, 0, 0));
|
|
||||||
#else
|
|
||||||
identification->system_identifier = atol(PQgetvalue(res, 0, 0));
|
identification->system_identifier = atol(PQgetvalue(res, 0, 0));
|
||||||
#endif
|
|
||||||
|
|
||||||
identification->timeline = atoi(PQgetvalue(res, 0, 1));
|
identification->timeline = atoi(PQgetvalue(res, 0, 1));
|
||||||
identification->xlogpos = parse_lsn(PQgetvalue(res, 0, 2));
|
identification->xlogpos = parse_lsn(PQgetvalue(res, 0, 2));
|
||||||
|
|
||||||
@@ -1716,11 +1680,7 @@ system_identifier(PGconn *conn)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
#if defined(__i386__) || defined(__i386)
|
|
||||||
system_identifier = atoll(PQgetvalue(res, 0, 0));
|
|
||||||
#else
|
|
||||||
system_identifier = atol(PQgetvalue(res, 0, 0));
|
system_identifier = atol(PQgetvalue(res, 0, 0));
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PQclear(res);
|
PQclear(res);
|
||||||
@@ -1839,7 +1799,7 @@ can_execute_pg_promote(PGconn *conn)
|
|||||||
bool has_pg_promote= false;
|
bool has_pg_promote= false;
|
||||||
|
|
||||||
/* pg_promote() available from PostgreSQL 12 */
|
/* pg_promote() available from PostgreSQL 12 */
|
||||||
if (PQserverVersion(conn) < 120000)
|
if(PQserverVersion(conn) < 120000)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
initPQExpBuffer(&query);
|
initPQExpBuffer(&query);
|
||||||
@@ -1867,59 +1827,48 @@ can_execute_pg_promote(PGconn *conn)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Determine if the user associated with the current connection is
|
|
||||||
* a member of the "pg_monitor" default role, or optionally one
|
|
||||||
* of its three constituent "subroles".
|
|
||||||
*/
|
|
||||||
bool
|
bool
|
||||||
connection_has_pg_monitor_role(PGconn *conn, const char *subrole)
|
connection_has_pg_settings(PGconn *conn)
|
||||||
{
|
{
|
||||||
PQExpBufferData query;
|
bool has_pg_settings = false;
|
||||||
PGresult *res;
|
|
||||||
bool has_pg_monitor_role = false;
|
|
||||||
|
|
||||||
/* superusers can read anything, no role check needed */
|
/* superusers can always read pg_settings */
|
||||||
if (is_superuser_connection(conn, NULL) == true)
|
if (is_superuser_connection(conn, NULL) == true)
|
||||||
return true;
|
|
||||||
|
|
||||||
/* pg_monitor and associated "subroles" introduced in PostgreSQL 10 */
|
|
||||||
if (PQserverVersion(conn) < 100000)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
initPQExpBuffer(&query);
|
|
||||||
appendPQExpBufferStr(&query,
|
|
||||||
" SELECT CASE "
|
|
||||||
" WHEN pg_catalog.pg_has_role('pg_monitor','MEMBER') "
|
|
||||||
" THEN TRUE ");
|
|
||||||
|
|
||||||
if (subrole != NULL)
|
|
||||||
{
|
{
|
||||||
appendPQExpBuffer(&query,
|
has_pg_settings = true;
|
||||||
" WHEN pg_catalog.pg_has_role('%s','MEMBER') "
|
}
|
||||||
" THEN TRUE ",
|
/* from PostgreSQL 10, a non-superuser may have been granted access */
|
||||||
subrole);
|
else if(PQserverVersion(conn) >= 100000)
|
||||||
|
{
|
||||||
|
PQExpBufferData query;
|
||||||
|
PGresult *res;
|
||||||
|
|
||||||
|
initPQExpBuffer(&query);
|
||||||
|
appendPQExpBufferStr(&query,
|
||||||
|
" SELECT CASE "
|
||||||
|
" WHEN pg_catalog.pg_has_role('pg_monitor','MEMBER') "
|
||||||
|
" THEN TRUE "
|
||||||
|
" WHEN pg_catalog.pg_has_role('pg_read_all_settings','MEMBER') "
|
||||||
|
" THEN TRUE "
|
||||||
|
" ELSE FALSE "
|
||||||
|
" END AS has_pg_settings");
|
||||||
|
|
||||||
|
res = PQexec(conn, query.data);
|
||||||
|
|
||||||
|
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
||||||
|
{
|
||||||
|
log_db_error(conn, query.data,
|
||||||
|
_("connection_has_pg_settings(): unable to query user roles"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
has_pg_settings = atobool(PQgetvalue(res, 0, 0));
|
||||||
|
}
|
||||||
|
termPQExpBuffer(&query);
|
||||||
|
PQclear(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
appendPQExpBufferStr(&query,
|
return has_pg_settings;
|
||||||
" ELSE FALSE "
|
|
||||||
" END AS has_pg_monitor");
|
|
||||||
|
|
||||||
res = PQexec(conn, query.data);
|
|
||||||
|
|
||||||
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
|
||||||
{
|
|
||||||
log_db_error(conn, query.data,
|
|
||||||
_("connection_has_pg_monitor_role(): unable to query user roles"));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
has_pg_monitor_role = atobool(PQgetvalue(res, 0, 0));
|
|
||||||
}
|
|
||||||
termPQExpBuffer(&query);
|
|
||||||
PQclear(res);
|
|
||||||
|
|
||||||
return has_pg_monitor_role;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -2548,10 +2497,7 @@ resume_wal_replay(PGconn *conn)
|
|||||||
/* Node record functions */
|
/* Node record functions */
|
||||||
/* ===================== */
|
/* ===================== */
|
||||||
|
|
||||||
/*
|
|
||||||
* Note: init_defaults may only be false when the caller is refreshing a previously
|
|
||||||
* populated record.
|
|
||||||
*/
|
|
||||||
static RecordStatus
|
static RecordStatus
|
||||||
_get_node_record(PGconn *conn, char *sqlquery, t_node_info *node_info, bool init_defaults)
|
_get_node_record(PGconn *conn, char *sqlquery, t_node_info *node_info, bool init_defaults)
|
||||||
{
|
{
|
||||||
@@ -2582,10 +2528,6 @@ _get_node_record(PGconn *conn, char *sqlquery, t_node_info *node_info, bool init
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Note: init_defaults may only be false when the caller is refreshing a previously
|
|
||||||
* populated record.
|
|
||||||
*/
|
|
||||||
static void
|
static void
|
||||||
_populate_node_record(PGresult *res, t_node_info *node_info, int row, bool init_defaults)
|
_populate_node_record(PGresult *res, t_node_info *node_info, int row, bool init_defaults)
|
||||||
{
|
{
|
||||||
@@ -2916,37 +2858,6 @@ get_all_node_records(PGconn *conn, NodeInfoList *node_list)
|
|||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
|
||||||
get_all_nodes_count(PGconn *conn, int *count)
|
|
||||||
{
|
|
||||||
PQExpBufferData query;
|
|
||||||
PGresult *res = NULL;
|
|
||||||
bool success = true;
|
|
||||||
initPQExpBuffer(&query);
|
|
||||||
|
|
||||||
appendPQExpBufferStr(&query,
|
|
||||||
" SELECT count(*) "
|
|
||||||
" FROM repmgr.nodes n ");
|
|
||||||
|
|
||||||
log_verbose(LOG_DEBUG, "get_all_nodes_count():\n%s", query.data);
|
|
||||||
|
|
||||||
res = PQexec(conn, query.data);
|
|
||||||
|
|
||||||
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
|
||||||
{
|
|
||||||
log_db_error(conn, query.data, _("get_all_nodes_count(): unable to execute query"));
|
|
||||||
success = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
*count = atoi(PQgetvalue(res, 0, 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
PQclear(res);
|
|
||||||
termPQExpBuffer(&query);
|
|
||||||
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
get_downstream_node_records(PGconn *conn, int node_id, NodeInfoList *node_list)
|
get_downstream_node_records(PGconn *conn, int node_id, NodeInfoList *node_list)
|
||||||
@@ -3040,7 +2951,7 @@ get_child_nodes(PGconn *conn, int node_id, NodeInfoList *node_list)
|
|||||||
" WHERE n.upstream_node_id = %i ",
|
" WHERE n.upstream_node_id = %i ",
|
||||||
node_id);
|
node_id);
|
||||||
|
|
||||||
log_verbose(LOG_DEBUG, "get_child_nodes():\n%s", query.data);
|
log_verbose(LOG_DEBUG, "get_active_sibling_node_records():\n%s", query.data);
|
||||||
|
|
||||||
res = PQexec(conn, query.data);
|
res = PQexec(conn, query.data);
|
||||||
|
|
||||||
@@ -3603,21 +3514,11 @@ witness_copy_node_records(PGconn *primary_conn, PGconn *witness_conn)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (get_all_node_records(primary_conn, &nodes) == false)
|
get_all_node_records(primary_conn, &nodes);
|
||||||
{
|
|
||||||
rollback_transaction(witness_conn);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (cell = nodes.head; cell; cell = cell->next)
|
for (cell = nodes.head; cell; cell = cell->next)
|
||||||
{
|
{
|
||||||
if (create_node_record(witness_conn, NULL, cell->node_info) == false)
|
create_node_record(witness_conn, NULL, cell->node_info);
|
||||||
{
|
|
||||||
rollback_transaction(witness_conn);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* and done */
|
/* and done */
|
||||||
@@ -4827,7 +4728,7 @@ cancel_query(PGconn *conn, int timeout)
|
|||||||
* Wait until current query finishes, ignoring any results.
|
* Wait until current query finishes, ignoring any results.
|
||||||
* Usually this will be an async query or query cancellation.
|
* Usually this will be an async query or query cancellation.
|
||||||
*
|
*
|
||||||
* Returns 1 for success; 0 if any error occurred; -1 if timeout reached.
|
* Returns 1 for success; 0 if any error ocurred; -1 if timeout reached.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
wait_connection_availability(PGconn *conn, int timeout)
|
wait_connection_availability(PGconn *conn, int timeout)
|
||||||
@@ -5578,9 +5479,21 @@ get_replication_info(PGconn *conn, t_server_type node_type, ReplInfo *replicatio
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
if (PQserverVersion(conn) >= 90400)
|
||||||
|
{
|
||||||
|
appendPQExpBufferStr(&query,
|
||||||
|
" COALESCE(pg_catalog.pg_last_xlog_receive_location(), '0/0'::PG_LSN) AS last_wal_receive_lsn, "
|
||||||
|
" COALESCE(pg_catalog.pg_last_xlog_replay_location(), '0/0'::PG_LSN) AS last_wal_replay_lsn, ");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* 9.3 does not have "pg_lsn" datatype */
|
||||||
|
appendPQExpBufferStr(&query,
|
||||||
|
" COALESCE(pg_catalog.pg_last_xlog_receive_location(), '0/0') AS last_wal_receive_lsn, "
|
||||||
|
" COALESCE(pg_catalog.pg_last_xlog_replay_location(), '0/0') AS last_wal_replay_lsn, ");
|
||||||
|
}
|
||||||
|
|
||||||
appendPQExpBufferStr(&query,
|
appendPQExpBufferStr(&query,
|
||||||
" COALESCE(pg_catalog.pg_last_xlog_receive_location(), '0/0'::PG_LSN) AS last_wal_receive_lsn, "
|
|
||||||
" COALESCE(pg_catalog.pg_last_xlog_replay_location(), '0/0'::PG_LSN) AS last_wal_replay_lsn, "
|
|
||||||
" CASE WHEN pg_catalog.pg_is_in_recovery() IS FALSE "
|
" CASE WHEN pg_catalog.pg_is_in_recovery() IS FALSE "
|
||||||
" THEN FALSE "
|
" THEN FALSE "
|
||||||
" ELSE pg_catalog.pg_is_xlog_replay_paused() "
|
" ELSE pg_catalog.pg_is_xlog_replay_paused() "
|
||||||
@@ -5751,11 +5664,28 @@ get_node_replication_stats(PGconn *conn, t_node_info *node_info)
|
|||||||
|
|
||||||
appendPQExpBufferStr(&query,
|
appendPQExpBufferStr(&query,
|
||||||
" SELECT pg_catalog.current_setting('max_wal_senders')::INT AS max_wal_senders, "
|
" SELECT pg_catalog.current_setting('max_wal_senders')::INT AS max_wal_senders, "
|
||||||
" (SELECT pg_catalog.count(*) FROM pg_catalog.pg_stat_replication) AS attached_wal_receivers, "
|
" (SELECT pg_catalog.count(*) FROM pg_catalog.pg_stat_replication) AS attached_wal_receivers, ");
|
||||||
" current_setting('max_replication_slots')::INT AS max_replication_slots, "
|
|
||||||
" (SELECT pg_catalog.count(*) FROM pg_catalog.pg_replication_slots WHERE slot_type='physical') AS total_replication_slots, "
|
/* no replication slots in PostgreSQL 9.3 */
|
||||||
" (SELECT pg_catalog.count(*) FROM pg_catalog.pg_replication_slots WHERE active IS TRUE AND slot_type='physical') AS active_replication_slots, "
|
if (PQserverVersion(conn) < 90400)
|
||||||
" (SELECT pg_catalog.count(*) FROM pg_catalog.pg_replication_slots WHERE active IS FALSE AND slot_type='physical') AS inactive_replication_slots, "
|
{
|
||||||
|
appendPQExpBufferStr(&query,
|
||||||
|
" 0 AS max_replication_slots, "
|
||||||
|
" 0 AS total_replication_slots, "
|
||||||
|
" 0 AS active_replication_slots, "
|
||||||
|
" 0 AS inactive_replication_slots, ");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
appendPQExpBufferStr(&query,
|
||||||
|
" current_setting('max_replication_slots')::INT AS max_replication_slots, "
|
||||||
|
" (SELECT pg_catalog.count(*) FROM pg_catalog.pg_replication_slots WHERE slot_type='physical') AS total_replication_slots, "
|
||||||
|
" (SELECT pg_catalog.count(*) FROM pg_catalog.pg_replication_slots WHERE active IS TRUE AND slot_type='physical') AS active_replication_slots, "
|
||||||
|
" (SELECT pg_catalog.count(*) FROM pg_catalog.pg_replication_slots WHERE active IS FALSE AND slot_type='physical') AS inactive_replication_slots, ");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
appendPQExpBufferStr(&query,
|
||||||
" pg_catalog.pg_is_in_recovery() AS in_recovery");
|
" pg_catalog.pg_is_in_recovery() AS in_recovery");
|
||||||
|
|
||||||
log_verbose(LOG_DEBUG, "get_node_replication_stats():\n%s", query.data);
|
log_verbose(LOG_DEBUG, "get_node_replication_stats():\n%s", query.data);
|
||||||
@@ -5790,15 +5720,16 @@ get_node_replication_stats(PGconn *conn, t_node_info *node_info)
|
|||||||
|
|
||||||
|
|
||||||
NodeAttached
|
NodeAttached
|
||||||
is_downstream_node_attached(PGconn *conn, char *node_name, char **node_state)
|
is_downstream_node_attached(PGconn *conn, char *node_name)
|
||||||
{
|
{
|
||||||
PQExpBufferData query;
|
PQExpBufferData query;
|
||||||
PGresult *res = NULL;
|
PGresult *res = NULL;
|
||||||
|
int c = 0;
|
||||||
|
|
||||||
initPQExpBuffer(&query);
|
initPQExpBuffer(&query);
|
||||||
|
|
||||||
appendPQExpBuffer(&query,
|
appendPQExpBuffer(&query,
|
||||||
" SELECT pid, state "
|
" SELECT pg_catalog.count(*) "
|
||||||
" FROM pg_catalog.pg_stat_replication "
|
" FROM pg_catalog.pg_stat_replication "
|
||||||
" WHERE application_name = '%s'",
|
" WHERE application_name = '%s'",
|
||||||
node_name);
|
node_name);
|
||||||
@@ -5817,68 +5748,31 @@ is_downstream_node_attached(PGconn *conn, char *node_name, char **node_state)
|
|||||||
return NODE_ATTACHED_UNKNOWN;
|
return NODE_ATTACHED_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
termPQExpBuffer(&query);
|
if (PQntuples(res) != 1)
|
||||||
|
|
||||||
/*
|
|
||||||
* If there's more than one entry in pg_stat_application, there's no
|
|
||||||
* way we can reliably determine which one belongs to the node we're
|
|
||||||
* checking, so there's nothing more we can do.
|
|
||||||
*/
|
|
||||||
if (PQntuples(res) > 1)
|
|
||||||
{
|
{
|
||||||
log_error(_("multiple entries with \"application_name\" set to \"%s\" found in \"pg_stat_replication\""),
|
log_verbose(LOG_WARNING, _("unexpected number of tuples (%i) returned"), PQntuples(res));
|
||||||
node_name);
|
|
||||||
log_hint(_("verify that a unique node name is configured for each node"));
|
|
||||||
|
|
||||||
|
termPQExpBuffer(&query);
|
||||||
PQclear(res);
|
PQclear(res);
|
||||||
|
|
||||||
return NODE_ATTACHED_UNKNOWN;
|
return NODE_ATTACHED_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PQntuples(res) == 0)
|
c = atoi(PQgetvalue(res, 0, 0));
|
||||||
{
|
|
||||||
log_warning(_("node \"%s\" not found in \"pg_stat_replication\""), node_name);
|
|
||||||
|
|
||||||
PQclear(res);
|
termPQExpBuffer(&query);
|
||||||
|
PQclear(res);
|
||||||
|
|
||||||
|
if (c == 0)
|
||||||
|
{
|
||||||
|
log_verbose(LOG_WARNING, _("node \"%s\" not found in \"pg_stat_replication\""), node_name);
|
||||||
|
|
||||||
return NODE_DETACHED;
|
return NODE_DETACHED;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
if (c > 1)
|
||||||
* If the connection is not a superuser or member of pg_read_all_stats, we
|
log_verbose(LOG_WARNING, _("multiple entries with \"application_name\" set to \"%s\" found in \"pg_stat_replication\""),
|
||||||
* won't be able to retrieve the "state" column, so we'll assume
|
node_name);
|
||||||
* the node is attached.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (connection_has_pg_monitor_role(conn, "pg_read_all_stats"))
|
|
||||||
{
|
|
||||||
const char *state = PQgetvalue(res, 0, 1);
|
|
||||||
|
|
||||||
if (node_state != NULL)
|
|
||||||
{
|
|
||||||
int state_len = strlen(state);
|
|
||||||
*node_state = palloc0(state_len + 1);
|
|
||||||
strncpy(*node_state, state, state_len);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strcmp(state, "streaming") != 0)
|
|
||||||
{
|
|
||||||
log_warning(_("node \"%s\" attached in state \"%s\""),
|
|
||||||
node_name,
|
|
||||||
state);
|
|
||||||
|
|
||||||
PQclear(res);
|
|
||||||
|
|
||||||
return NODE_NOT_ATTACHED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (node_state != NULL)
|
|
||||||
{
|
|
||||||
*node_state = palloc0(1);
|
|
||||||
*node_state[0] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
PQclear(res);
|
|
||||||
|
|
||||||
return NODE_ATTACHED;
|
return NODE_ATTACHED;
|
||||||
}
|
}
|
||||||
|
|||||||
17
dbutils.h
17
dbutils.h
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* dbutils.h
|
* dbutils.h
|
||||||
*
|
*
|
||||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -119,14 +119,9 @@ typedef enum
|
|||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
/* unable to query "pg_stat_replication" or other error */
|
|
||||||
NODE_ATTACHED_UNKNOWN = -1,
|
NODE_ATTACHED_UNKNOWN = -1,
|
||||||
/* node has record in "pg_stat_replication" and state is not "streaming" */
|
NODE_DETACHED,
|
||||||
NODE_ATTACHED,
|
NODE_ATTACHED
|
||||||
/* node has record in "pg_stat_replication" but state is not "streaming" */
|
|
||||||
NODE_NOT_ATTACHED,
|
|
||||||
/* node has no record in "pg_stat_replication" */
|
|
||||||
NODE_DETACHED
|
|
||||||
} NodeAttached;
|
} NodeAttached;
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
@@ -418,7 +413,6 @@ void conn_to_param_list(PGconn *conn, t_conninfo_param_list *param_list);
|
|||||||
void param_set(t_conninfo_param_list *param_list, const char *param, const char *value);
|
void param_set(t_conninfo_param_list *param_list, const char *param, const char *value);
|
||||||
void param_set_ine(t_conninfo_param_list *param_list, const char *param, const char *value);
|
void param_set_ine(t_conninfo_param_list *param_list, const char *param, const char *value);
|
||||||
char *param_get(t_conninfo_param_list *param_list, const char *param);
|
char *param_get(t_conninfo_param_list *param_list, const char *param);
|
||||||
bool validate_conninfo_string(const char *conninfo_str, char **errmsg);
|
|
||||||
bool parse_conninfo_string(const char *conninfo_str, t_conninfo_param_list *param_list, char **errmsg, bool ignore_local_params);
|
bool parse_conninfo_string(const char *conninfo_str, t_conninfo_param_list *param_list, char **errmsg, bool ignore_local_params);
|
||||||
char *param_list_to_string(t_conninfo_param_list *param_list);
|
char *param_list_to_string(t_conninfo_param_list *param_list);
|
||||||
char *normalize_conninfo_string(const char *conninfo_str);
|
char *normalize_conninfo_string(const char *conninfo_str);
|
||||||
@@ -453,7 +447,7 @@ TimeLineHistoryEntry *get_timeline_history(PGconn *repl_conn, TimeLineID tli);
|
|||||||
|
|
||||||
/* user/role information functions */
|
/* user/role information functions */
|
||||||
bool can_execute_pg_promote(PGconn *conn);
|
bool can_execute_pg_promote(PGconn *conn);
|
||||||
bool connection_has_pg_monitor_role(PGconn *conn, const char *subrole);
|
bool connection_has_pg_settings(PGconn *conn);
|
||||||
bool is_replication_role(PGconn *conn, char *rolname);
|
bool is_replication_role(PGconn *conn, char *rolname);
|
||||||
bool is_superuser_connection(PGconn *conn, t_connection_user *userinfo);
|
bool is_superuser_connection(PGconn *conn, t_connection_user *userinfo);
|
||||||
|
|
||||||
@@ -496,7 +490,6 @@ bool get_local_node_record(PGconn *conn, int node_id, t_node_info *node_info);
|
|||||||
bool get_primary_node_record(PGconn *conn, t_node_info *node_info);
|
bool get_primary_node_record(PGconn *conn, t_node_info *node_info);
|
||||||
|
|
||||||
bool get_all_node_records(PGconn *conn, NodeInfoList *node_list);
|
bool get_all_node_records(PGconn *conn, NodeInfoList *node_list);
|
||||||
bool get_all_nodes_count(PGconn *conn, int *count);
|
|
||||||
void get_downstream_node_records(PGconn *conn, int node_id, NodeInfoList *nodes);
|
void get_downstream_node_records(PGconn *conn, int node_id, NodeInfoList *nodes);
|
||||||
void get_active_sibling_node_records(PGconn *conn, int node_id, int upstream_node_id, NodeInfoList *node_list);
|
void get_active_sibling_node_records(PGconn *conn, int node_id, int upstream_node_id, NodeInfoList *node_list);
|
||||||
bool get_child_nodes(PGconn *conn, int node_id, NodeInfoList *node_list);
|
bool get_child_nodes(PGconn *conn, int node_id, NodeInfoList *node_list);
|
||||||
@@ -596,7 +589,7 @@ bool get_replication_info(PGconn *conn, t_server_type node_type, ReplInfo *repl
|
|||||||
int get_replication_lag_seconds(PGconn *conn);
|
int get_replication_lag_seconds(PGconn *conn);
|
||||||
TimeLineID get_node_timeline(PGconn *conn, char *timeline_id_str);
|
TimeLineID get_node_timeline(PGconn *conn, char *timeline_id_str);
|
||||||
void get_node_replication_stats(PGconn *conn, t_node_info *node_info);
|
void get_node_replication_stats(PGconn *conn, t_node_info *node_info);
|
||||||
NodeAttached is_downstream_node_attached(PGconn *conn, char *node_name, char **node_state);
|
NodeAttached is_downstream_node_attached(PGconn *conn, char *node_name);
|
||||||
void set_upstream_last_seen(PGconn *conn, int upstream_node_id);
|
void set_upstream_last_seen(PGconn *conn, int upstream_node_id);
|
||||||
int get_upstream_last_seen(PGconn *conn, t_server_type node_type);
|
int get_upstream_last_seen(PGconn *conn, t_server_type node_type);
|
||||||
|
|
||||||
|
|||||||
76
dirutil.c
76
dirutil.c
@@ -3,7 +3,7 @@
|
|||||||
* dirmod.c
|
* dirmod.c
|
||||||
* directory handling functions
|
* directory handling functions
|
||||||
*
|
*
|
||||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -109,56 +109,9 @@ create_dir(const char *path)
|
|||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
set_dir_permissions(const char *path, int server_version_num)
|
set_dir_permissions(const char *path)
|
||||||
{
|
{
|
||||||
struct stat stat_buf;
|
return (chmod(path, 0700) != 0) ? false : true;
|
||||||
bool no_group_access =
|
|
||||||
(server_version_num != UNKNOWN_SERVER_VERSION_NUM) &&
|
|
||||||
(server_version_num < 110000);
|
|
||||||
/*
|
|
||||||
* At this point the path should exist, so this check is very
|
|
||||||
* much just-in-case.
|
|
||||||
*/
|
|
||||||
if (stat(path, &stat_buf) != 0)
|
|
||||||
{
|
|
||||||
if (errno == ENOENT)
|
|
||||||
{
|
|
||||||
log_warning(_("directory \"%s\" does not exist"), path);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
log_warning(_("could not read permissions of directory \"%s\""),
|
|
||||||
path);
|
|
||||||
log_detail("%s", strerror(errno));
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If mode is not 0700 or 0750, attempt to change.
|
|
||||||
*/
|
|
||||||
if ((no_group_access == true && (stat_buf.st_mode & (S_IRWXG | S_IRWXO)))
|
|
||||||
|| (no_group_access == false && (stat_buf.st_mode & (S_IWGRP | S_IRWXO))))
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Currently we default to 0700.
|
|
||||||
* There is no facility to override this directly,
|
|
||||||
* but the user can manually create the directory with
|
|
||||||
* the desired permissions.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (chmod(path, 0700) != 0) {
|
|
||||||
log_error(_("unable to change permissions of directory \"%s\""), path);
|
|
||||||
log_detail("%s", strerror(errno));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Leave as-is */
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -205,7 +158,7 @@ mkdir_p(char *path, mode_t omode)
|
|||||||
/*
|
/*
|
||||||
* POSIX 1003.2: For each dir operand that does not name an
|
* POSIX 1003.2: For each dir operand that does not name an
|
||||||
* existing directory, effects equivalent to those caused by the
|
* existing directory, effects equivalent to those caused by the
|
||||||
* following command shall occur:
|
* following command shall occcur:
|
||||||
*
|
*
|
||||||
* mkdir -p -m $(umask -S),u+wx $(dirname dir) && mkdir [-m mode]
|
* mkdir -p -m $(umask -S),u+wx $(dirname dir) && mkdir [-m mode]
|
||||||
* dir
|
* dir
|
||||||
@@ -289,7 +242,7 @@ is_pg_running(const char *path)
|
|||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* No PID file - PostgreSQL shouldn't be running. From 9.3 (the
|
* No PID file - PostgreSQL shouldn't be running. From 9.3 (the
|
||||||
* earliest version we care about) removal of the PID file will
|
* earliesty version we care about) removal of the PID file will
|
||||||
* cause the postmaster to shut down, so it's highly unlikely
|
* cause the postmaster to shut down, so it's highly unlikely
|
||||||
* that PostgreSQL will still be running.
|
* that PostgreSQL will still be running.
|
||||||
*/
|
*/
|
||||||
@@ -350,7 +303,7 @@ create_pg_dir(const char *path, bool force)
|
|||||||
switch (check_dir(path))
|
switch (check_dir(path))
|
||||||
{
|
{
|
||||||
case DIR_NOENT:
|
case DIR_NOENT:
|
||||||
/* Directory does not exist, attempt to create it. */
|
/* directory does not exist, attempt to create it */
|
||||||
log_info(_("creating directory \"%s\"..."), path);
|
log_info(_("creating directory \"%s\"..."), path);
|
||||||
|
|
||||||
if (!create_dir(path))
|
if (!create_dir(path))
|
||||||
@@ -361,23 +314,14 @@ create_pg_dir(const char *path, bool force)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case DIR_EMPTY:
|
case DIR_EMPTY:
|
||||||
/*
|
/* exists but empty, fix permissions and use it */
|
||||||
* Directory exists but empty, fix permissions and use it.
|
|
||||||
*
|
|
||||||
* Note that at this point the caller might not know the server
|
|
||||||
* version number, so in this case "set_dir_permissions()" will
|
|
||||||
* accept 0750 as a valid setting. As this is invalid in Pg10 and
|
|
||||||
* earlier, the caller should call "set_dir_permissions()" again
|
|
||||||
* when it has the number.
|
|
||||||
*
|
|
||||||
* We need to do the permissions check here in any case to catch
|
|
||||||
* fatal permissions early.
|
|
||||||
*/
|
|
||||||
log_info(_("checking and correcting permissions on existing directory \"%s\""),
|
log_info(_("checking and correcting permissions on existing directory \"%s\""),
|
||||||
path);
|
path);
|
||||||
|
|
||||||
if (!set_dir_permissions(path, UNKNOWN_SERVER_VERSION_NUM))
|
if (!set_dir_permissions(path))
|
||||||
{
|
{
|
||||||
|
log_error(_("unable to change permissions of directory \"%s\""), path);
|
||||||
|
log_detail("%s", strerror(errno));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* dirutil.h
|
* dirutil.h
|
||||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -35,7 +35,7 @@ typedef enum
|
|||||||
} PgDirState;
|
} PgDirState;
|
||||||
|
|
||||||
extern int mkdir_p(char *path, mode_t omode);
|
extern int mkdir_p(char *path, mode_t omode);
|
||||||
extern bool set_dir_permissions(const char *path, int server_version_num);
|
extern bool set_dir_permissions(const char *path);
|
||||||
|
|
||||||
extern DataDirState check_dir(const char *path);
|
extern DataDirState check_dir(const char *path);
|
||||||
extern bool create_dir(const char *path);
|
extern bool create_dir(const char *path);
|
||||||
|
|||||||
@@ -95,8 +95,6 @@ clean:
|
|||||||
rm -f repmgr.html
|
rm -f repmgr.html
|
||||||
rm -f repmgr-A4.pdf
|
rm -f repmgr-A4.pdf
|
||||||
rm -f repmgr-US.pdf
|
rm -f repmgr-US.pdf
|
||||||
rm -f *.fo
|
|
||||||
rm -f html/*
|
|
||||||
|
|
||||||
maintainer-clean:
|
maintainer-clean:
|
||||||
rm -rf html
|
rm -rf html
|
||||||
|
|||||||
@@ -22,9 +22,6 @@
|
|||||||
&repmgr; 5 is fundamentally the same code base as &repmgr; 4, but provides
|
&repmgr; 5 is fundamentally the same code base as &repmgr; 4, but provides
|
||||||
support for the revised replication configuration mechanism in PostgreSQL 12.
|
support for the revised replication configuration mechanism in PostgreSQL 12.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
|
||||||
Support for PostgreSQL 9.3 is no longer available from &repmgr; 5.2.
|
|
||||||
</para>
|
|
||||||
</note>
|
</note>
|
||||||
<para>
|
<para>
|
||||||
&repmgr; 3.x builds on the improved replication facilities added
|
&repmgr; 3.x builds on the improved replication facilities added
|
||||||
@@ -62,7 +59,7 @@
|
|||||||
|
|
||||||
<tip>
|
<tip>
|
||||||
<para>
|
<para>
|
||||||
Our recommended configuration is to configure
|
2ndQuadrant's recommended configuration is to configure
|
||||||
<ulink url="https://www.pgbarman.org/">Barman</ulink> as a fallback
|
<ulink url="https://www.pgbarman.org/">Barman</ulink> as a fallback
|
||||||
source of WAL files, rather than maintain replication slots for
|
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>.
|
each standby. See also: <link linkend="cloning-from-barman-restore-command">Using Barman as a WAL file source</link>.
|
||||||
@@ -127,7 +124,7 @@
|
|||||||
filesystem layouts.
|
filesystem layouts.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
Either use PostgreSQL packages provided by the community or EnterpriseDB; if this
|
Either use PostgreSQL packages provided by the community or 2ndQuadrant; if this
|
||||||
is not possible, contact your vendor for assistance.
|
is not possible, contact your vendor for assistance.
|
||||||
</para>
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
@@ -170,7 +167,7 @@
|
|||||||
<para>
|
<para>
|
||||||
If different "minor" &repmgr; versions (e.g. 4.1.1 and 4.1.6) are installed,
|
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
|
&repmgr; will function, but we strongly recommend always running the same version
|
||||||
to ensure there are no unexpected surprises, e.g. a newer version behaving slightly
|
to ensure there are no unexpected suprises, e.g. a newer version behaving slightly
|
||||||
differently to the older version.
|
differently to the older version.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
@@ -212,11 +209,11 @@
|
|||||||
</para>
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
<sect2 id="faq-third-party-packages" xreflabel="Compatibility with third party vendor packages">
|
<sect2 id="faq-third-party-packages" xreflabel="Compatability with third party vendor packages">
|
||||||
<title>Are &repmgr; packages compatible with <literal>$third_party_vendor</literal>'s packages?</title>
|
<title>Are &repmgr; packages compatible with <literal>$third_party_vendor</literal>'s packages?</title>
|
||||||
<para>
|
<para>
|
||||||
&repmgr; packages provided by EnterpriseDB are compatible with the community-provided PostgreSQL
|
&repmgr; packages provided by 2ndQuadrant are compatible with the community-provided PostgreSQL
|
||||||
packages and specified software provided by EnterpriseDB.
|
packages and any software provided by 2ndQuadrant.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
A number of other vendors provide their own versions of PostgreSQL packages, often with different
|
A number of other vendors provide their own versions of PostgreSQL packages, often with different
|
||||||
@@ -311,7 +308,7 @@
|
|||||||
</para>
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
<sect2 id="faq-repmgr-shared-preload-libraries-no-repmgrd" xreflabel="shared_preload_libraries without repmgrd">
|
<sect2 id="faq-repmgr-shared-preload-libaries-no-repmgrd" xreflabel="shared_preload_libraries without repmgrd">
|
||||||
<title>Do I need to include <literal>shared_preload_libraries = 'repmgr'</literal>
|
<title>Do I need to include <literal>shared_preload_libraries = 'repmgr'</literal>
|
||||||
in <filename>postgresql.conf</filename> if I'm not using &repmgrd;?</title>
|
in <filename>postgresql.conf</filename> if I'm not using &repmgrd;?</title>
|
||||||
<para>
|
<para>
|
||||||
@@ -350,9 +347,6 @@
|
|||||||
and earlier) with the absolute path to the WAL directory in <varname>pg_basebackup_options</varname>.
|
and earlier) with the absolute path to the WAL directory in <varname>pg_basebackup_options</varname>.
|
||||||
For more details see <xref linkend="cloning-advanced-pg-basebackup-options"/>.
|
For more details see <xref linkend="cloning-advanced-pg-basebackup-options"/>.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
|
||||||
In &repmgr; 5.2 and later, this setting will also be honoured when cloning from Barman.
|
|
||||||
</para>
|
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
<sect2 id="faq-repmgr-events-no-fkey" xreflabel="No foreign key on node_id in repmgr.events">
|
<sect2 id="faq-repmgr-events-no-fkey" xreflabel="No foreign key on node_id in repmgr.events">
|
||||||
@@ -379,22 +373,6 @@
|
|||||||
</para>
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
<sect2 id="faq-repmgr-exclude-metadata-from-dump" xreflabel="Excluding repmgr metadata from pg_dump output">
|
|
||||||
<title>How can I exclude &repmgr; metadata from <application>pg_dump</application> output?</title>
|
|
||||||
<para>
|
|
||||||
Beginning with &repmgr; 5.2, the metadata tables associated with the &repmgr; extension
|
|
||||||
(<literal>repmgr.nodes</literal>, <literal>repmgr.events</literal> and <literal>repmgr.monitoring_history</literal>)
|
|
||||||
have been marked as dumpable as they contain configuration and user-generated data.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
To exclude these from <application>pg_dump</application> output, add the flag <option>--exclude-schema=repmgr</option>.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
To exclude individual &repmgr; metadata tables from <application>pg_dump</application> output, add the flag
|
|
||||||
e.g. <option>--exclude-table=repmgr.monitoring_history</option>. This flag can be provided multiple times
|
|
||||||
to exclude individual tables,
|
|
||||||
</para>
|
|
||||||
</sect2>
|
|
||||||
|
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
@@ -459,7 +437,7 @@
|
|||||||
</title>
|
</title>
|
||||||
<para>
|
<para>
|
||||||
<varname>promote_command</varname> or <varname>follow_command</varname> can be user-defined scripts,
|
<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 executing &repmgr;. Always provide the full
|
so &repmgr; will not apply <option>pg_bindir</option> even if excuting &repmgr;. Always provide the full
|
||||||
path; see <xref linkend="repmgrd-automatic-failover-configuration"/> for more details.
|
path; see <xref linkend="repmgrd-automatic-failover-configuration"/> for more details.
|
||||||
</para>
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
@@ -479,7 +457,7 @@
|
|||||||
is out-of-date, which may lead to incorrect failover behaviour.
|
is out-of-date, which may lead to incorrect failover behaviour.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
The onus is therefore on the administrator to manually set the cluster to a stable, healthy state before
|
The onus is therefore on the adminstrator to manually set the cluster to a stable, healthy state before
|
||||||
starting &repmgrd;.
|
starting &repmgrd;.
|
||||||
</para>
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|||||||
@@ -52,7 +52,8 @@
|
|||||||
<para>
|
<para>
|
||||||
&repmgr; packages are available from the public 2ndQuadrant repository, and also the
|
&repmgr; packages are available from the public 2ndQuadrant repository, and also the
|
||||||
PostgreSQL community repository. The 2ndQuadrant repository is updated immediately
|
PostgreSQL community repository. The 2ndQuadrant repository is updated immediately
|
||||||
after each &repmgr; release.
|
after each
|
||||||
|
&repmgr; release.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<table id="centos-2ndquadrant-repository">
|
<table id="centos-2ndquadrant-repository">
|
||||||
@@ -397,7 +398,7 @@
|
|||||||
</indexterm>
|
</indexterm>
|
||||||
<indexterm>
|
<indexterm>
|
||||||
<primary>packages</primary>
|
<primary>packages</primary>
|
||||||
<secondary>snapshots</secondary>
|
<secondary>snaphots</secondary>
|
||||||
</indexterm>
|
</indexterm>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
@@ -438,7 +439,7 @@ curl https://dl.2ndquadrant.com/default/snapshot/get/9.6/rpm | sudo bash</progra
|
|||||||
The package name will be formatted like this:
|
The package name will be formatted like this:
|
||||||
<programlisting>
|
<programlisting>
|
||||||
repmgr96-4.1.1-0.0git320.g5113ab0.1.el7.x86_64.rpm</programlisting>
|
repmgr96-4.1.1-0.0git320.g5113ab0.1.el7.x86_64.rpm</programlisting>
|
||||||
containing the snapshot build number (here: <literal>320</literal>) and the hash
|
containg 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>).
|
of the <application>git</application> commit it was built from (here: <literal>g5113ab0</literal>).
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
@@ -470,7 +471,7 @@ repmgr96-4.1.1-0.0git320.g5113ab0.1.el7.x86_64.rpm</programlisting>
|
|||||||
<title>Debian/Ubuntu</title>
|
<title>Debian/Ubuntu</title>
|
||||||
<para>
|
<para>
|
||||||
An archive of old packages (<literal>3.3.2</literal> and later) for Debian/Ubuntu-based systems is available here:
|
An archive of old packages (<literal>3.3.2</literal> and later) for Debian/Ubuntu-based systems is available here:
|
||||||
<ulink url="https://apt-archive.postgresql.org/">https://apt-archive.postgresql.org/</ulink>
|
<ulink url="http://atalia.postgresql.org/morgue/r/repmgr/">http://atalia.postgresql.org/morgue/r/repmgr/</ulink>
|
||||||
</para>
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
|
|||||||
@@ -16,327 +16,8 @@
|
|||||||
</para>
|
</para>
|
||||||
|
|
||||||
<!-- remember to update the release date in ../repmgr_version.h.in -->
|
<!-- remember to update the release date in ../repmgr_version.h.in -->
|
||||||
<sect1 id="release-5.2.2">
|
|
||||||
<title id="release-current">Release 5.2.2</title>
|
|
||||||
<para><emphasis>??? ? ???, 2021</emphasis></para>
|
|
||||||
<para>
|
|
||||||
&repmgr; 5.2.2 is a minor release.
|
|
||||||
</para>
|
|
||||||
<sect2>
|
|
||||||
<title>Bug fixes</title>
|
|
||||||
<para>
|
|
||||||
|
|
||||||
<itemizedlist>
|
<sect1 id="release-5.1-0">
|
||||||
<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>
|
|
||||||
<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>
|
|
||||||
&repmgrd;: ensure short option <option>-s</option> is accepted.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
</itemizedlist>
|
|
||||||
</para>
|
|
||||||
</sect2>
|
|
||||||
</sect1>
|
|
||||||
|
|
||||||
<sect1 id="release-5.2.1">
|
|
||||||
<title>Release 5.2.1</title>
|
|
||||||
<para><emphasis>Mon 7 December, 2020</emphasis></para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
&repmgr; 5.2.1 is a minor release.
|
|
||||||
</para>
|
|
||||||
<sect2>
|
|
||||||
<title>Improvements</title>
|
|
||||||
<para>
|
|
||||||
<itemizedlist>
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
<link linkend="repmgr-standby-clone">repmgr standby clone</link>:
|
|
||||||
option <option>--recovery-min-apply-delay</option> added, overriding any
|
|
||||||
setting present in <filename>repmgr.conf</filename>.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
</itemizedlist>
|
|
||||||
</para>
|
|
||||||
</sect2>
|
|
||||||
|
|
||||||
<sect2>
|
|
||||||
<title>Bug fixes</title>
|
|
||||||
<para>
|
|
||||||
|
|
||||||
<itemizedlist>
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
Configuration: fix parsing of <option>replication_type</option> configuration parameter. GitHub #672.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
<link linkend="repmgr-standby-clone">repmgr standby clone</link>:
|
|
||||||
handle case where <filename>postgresql.auto.conf</filename> is absent on the
|
|
||||||
source node.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
<link linkend="repmgr-standby-clone">repmgr standby clone</link>:
|
|
||||||
in PostgreSQL 11 and later, an existing data directory's permissions
|
|
||||||
will not be changed to <option>0700</option> if they are already set to
|
|
||||||
<option>0750</option>.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
&repmgrd;: prevent termination when local node not available and
|
|
||||||
<option>standby_disconnect_on_failover</option> is set. GitHub #675.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
&repmgrd;: ensure <option>reconnect_interval</option> is correctly handled.
|
|
||||||
GitHub #673.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
<command>repmgr witness --help</command>: fix <command>witness unregister</command>
|
|
||||||
description. GitHub #676.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
</itemizedlist>
|
|
||||||
</para>
|
|
||||||
</sect2>
|
|
||||||
</sect1>
|
|
||||||
|
|
||||||
|
|
||||||
<sect1 id="release-5.2.0">
|
|
||||||
<title>Release 5.2.0</title>
|
|
||||||
<para><emphasis>Thu 22 October, 2020</emphasis></para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
&repmgr; 5.2.0 is a major release.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
This release provides support for <ulink url="https://www.postgresql.org/docs/13/release-13.html">PostgreSQL 13</ulink>, released in September 2020.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
This release removes support for PostgreSQL 9.3, which was
|
|
||||||
<ulink url="https://www.postgresql.org/docs/9.3/release-9-3-25.html">designated EOL in November 2018</ulink>.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<sect2>
|
|
||||||
<title>General improvements</title>
|
|
||||||
<para>
|
|
||||||
<itemizedlist>
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
Configuration: support <command>include</command>, <command>include_dir</command> and
|
|
||||||
<command>include_if_exists</command> directives (see <xref linkend="configuration-file-include-directives"/>).
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
<link linkend="repmgr-standby-switchover"><command>repmgr standby switchover</command></link>:
|
|
||||||
Improve sanity check failure log output from the demotion candidate.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
If database connection configuration is not consistent across all nodes, it's
|
|
||||||
possible remote &repmgr; invocations (e.g. during switchover, from the promotion candidate
|
|
||||||
to the demotion candidate) will not be able to connect to the database. This will
|
|
||||||
now be explicitly reported as a database connection failure, rather than as a failure
|
|
||||||
of the respective sanity check.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
<link linkend="repmgr-cluster-crosscheck">repmgr cluster crosscheck</link> /
|
|
||||||
<link linkend="repmgr-cluster-matrix">repmgr cluster matrix</link>:
|
|
||||||
improve text mode output format, in particular so that node identifiers of arbitrary length are
|
|
||||||
displayed correctly.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
<link linkend="repmgr-primary-unregister">repmgr primary unregister</link>:
|
|
||||||
the <option>--force</option> can be provided to unregister an active primary node, provided
|
|
||||||
it has no registered standby nodes.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
<link linkend="repmgr-standby-clone">repmgr standby clone</link>: new option
|
|
||||||
<option>--verify-backup</option> to run PostgreSQL's
|
|
||||||
<ulink url="https://www.postgresql.org/docs/13/app-pgverifybackup.html">pg_verifybackup</ulink>
|
|
||||||
utility after cloning a standby to verify the integrity of the copied data
|
|
||||||
(PostgreSQL 13 and later).
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
<link linkend="repmgr-standby-clone">repmgr standby clone</link>:
|
|
||||||
when cloning from Barman, setting <option>--waldir</option>
|
|
||||||
(PostgreSQL 9.6 and earlier: <option>--xlogdir</option>) in
|
|
||||||
<option>pg_basebackup_options</option> will cause &repmgr; to create
|
|
||||||
a WAL directory outside of the main data directory and symlink
|
|
||||||
it from there, in the same way as would happen when cloning
|
|
||||||
using <application>pg_basebackup</application>.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
<link linkend="repmgr-standby-follow">repmgr standby follow</link>:
|
|
||||||
In PostgreSQL 13 and later, a standby no longer requires a restart to
|
|
||||||
follow a new upstream node.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
The old behaviour (always restarting the standby to follow a new node)
|
|
||||||
can be restored by setting the configuration file parameter
|
|
||||||
<varname>standby_follow_restart</varname> to <literal>true</literal>.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
<link linkend="repmgr-node-rejoin">repmgr node rejoin</link>:
|
|
||||||
enable a node to attach to a target node even the target node
|
|
||||||
has a lower timeline (PostgreSQL 9.6 and later).
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
<link linkend="repmgr-node-rejoin">repmgr node rejoin</link>:
|
|
||||||
in PostgreSQL 13 and later, support <application>pg_rewind</application>'s
|
|
||||||
ability to automatically run crash recovery on a PostgreSQL instance
|
|
||||||
which was not shut down cleanly.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
<link linkend="repmgr-node-check">repmgr node check</link>:
|
|
||||||
option <option>--db-connection</option> added to check if &repmgr;
|
|
||||||
can connect to the database on the local node.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
<link linkend="repmgr-node-check">repmgr node check</link>:
|
|
||||||
report database connection error if the <option>--optformat</option> was provided.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
Improve handling of pg_control read errors.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
It is now possible to dump the contents of &repmgr; metadata tables with
|
|
||||||
<application>pg_dump</application>.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
</itemizedlist>
|
|
||||||
</para>
|
|
||||||
</sect2>
|
|
||||||
<sect2>
|
|
||||||
<title>repmgrd enhancements</title>
|
|
||||||
<para>
|
|
||||||
<itemizedlist>
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
Following additional parameters can be provided to <varname>failover_validation_command</varname>:
|
|
||||||
<itemizedlist spacing="compact" mark="bullet">
|
|
||||||
<listitem>
|
|
||||||
<simpara><literal>%n</literal>: node ID</simpara>
|
|
||||||
</listitem>
|
|
||||||
<listitem>
|
|
||||||
<simpara><literal>%a</literal>: node name</simpara>
|
|
||||||
</listitem>
|
|
||||||
<listitem>
|
|
||||||
<simpara><literal>%v</literal>: number of visible nodes</simpara>
|
|
||||||
</listitem>
|
|
||||||
<listitem>
|
|
||||||
<simpara><literal>%u</literal>: number of shared upstream nodes</simpara>
|
|
||||||
</listitem>
|
|
||||||
<listitem>
|
|
||||||
<simpara><literal>%t</literal>: total number of nodes</simpara>
|
|
||||||
</listitem>
|
|
||||||
</itemizedlist>
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
Configuration option <varname>always_promote</varname> (default: <literal>false</literal>)
|
|
||||||
to control whether a node should be promoted if the &repmgr; metadata is not up-to-date
|
|
||||||
on that node.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
</itemizedlist>
|
|
||||||
</para>
|
|
||||||
</sect2>
|
|
||||||
|
|
||||||
<sect2>
|
|
||||||
<title>Bug fixes</title>
|
|
||||||
<para>
|
|
||||||
<itemizedlist>
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
<link linkend="repmgr-standby-clone">repmgr standby clone</link>:
|
|
||||||
fix issue with cloning from Barman where the tablespace mapping file was
|
|
||||||
not flushed to disk before attempting to retrieve files from Barman. GitHub #650.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
<link linkend="repmgr-node-rejoin">repmgr node rejoin</link>:
|
|
||||||
ensure that when verifying a standby node has attached to its upstream, the
|
|
||||||
node has started streaming before confirming the success of the rejoin operation.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
&repmgrd;: ensure primary connection is reset if same as upstream. GitHub #633.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
</itemizedlist>
|
|
||||||
</para>
|
|
||||||
</sect2>
|
|
||||||
|
|
||||||
</sect1>
|
|
||||||
|
|
||||||
<sect1 id="release-5.1.0">
|
|
||||||
<title>Release 5.1.0</title>
|
<title>Release 5.1.0</title>
|
||||||
<para><emphasis>Mon 13 April, 2020</emphasis></para>
|
<para><emphasis>Mon 13 April, 2020</emphasis></para>
|
||||||
|
|
||||||
@@ -530,7 +211,7 @@
|
|||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
<sect1 id="release-5.0">
|
<sect1 id="release-5.0">
|
||||||
<title>Release 5.0</title>
|
<title id="release-current">Release 5.0</title>
|
||||||
<para><emphasis>Tue 15 October, 2019</emphasis></para>
|
<para><emphasis>Tue 15 October, 2019</emphasis></para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
@@ -1240,7 +921,7 @@ REPMGRD_OPTS="--daemonize=false"</programlisting>
|
|||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
Possible values are <literal>ping</literal> (default; uses <command>PQping()</command> to
|
Possible values are <literal>ping</literal> (default; uses <command>PQping()</command> to
|
||||||
determine server availability), <literal>connection</literal> (attempts to make a new connection to
|
determine server availability), <literal>connection</literal> (attempst to make a new connection to
|
||||||
the upstream node), and <literal>query</literal> (determines server availability
|
the upstream node), and <literal>query</literal> (determines server availability
|
||||||
by executing an SQL statement on the node via the existing connection).
|
by executing an SQL statement on the node via the existing connection).
|
||||||
</para>
|
</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>.
|
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>
|
||||||
<para>
|
<para>
|
||||||
Please report bugs and other issues to: <ulink url="https://github.com/EnterpriseDB/repmgr">https://github.com/EnterpriseDB/repmgr</ulink>.
|
Please report bugs and other issues to: <ulink url="https://github.com/2ndQuadrant/repmgr">https://github.com/2ndQuadrant/repmgr</ulink>.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<important>
|
<important>
|
||||||
@@ -64,7 +64,7 @@
|
|||||||
|
|
||||||
<listitem>
|
<listitem>
|
||||||
<simpara>
|
<simpara>
|
||||||
<filename>repmgr.conf</filename> files (suitably anonymized if necessary)
|
<filename>repmpgr.conf</filename> files (suitably anonymized if necessary)
|
||||||
</simpara>
|
</simpara>
|
||||||
</listitem>
|
</listitem>
|
||||||
|
|
||||||
|
|||||||
@@ -46,7 +46,6 @@
|
|||||||
<para>
|
<para>
|
||||||
WAL management on the primary becomes much easier as there's no need
|
WAL management on the primary becomes much easier as there's no need
|
||||||
to use replication slots, and <varname>wal_keep_segments</varname>
|
to use replication slots, and <varname>wal_keep_segments</varname>
|
||||||
(PostgreSQL 13 and later: <varname>wal_keep_size</varname>)
|
|
||||||
does not need to be set.
|
does not need to be set.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
@@ -148,15 +147,6 @@ description = "Main cluster"
|
|||||||
section in <command>man 5 ssh_config</command> for more details.
|
section in <command>man 5 ssh_config</command> for more details.
|
||||||
</simpara>
|
</simpara>
|
||||||
</tip>
|
</tip>
|
||||||
<para>
|
|
||||||
If you wish to place WAL files in a location outside the main
|
|
||||||
PostgreSQL data directory, set <option>--waldir</option>
|
|
||||||
(PostgreSQL 9.6 and earlier: <option>--xlogdir</option>) in
|
|
||||||
<option>pg_basebackup_options</option> to the target directory
|
|
||||||
(must be an absolute filepath). &repmgr; will create and
|
|
||||||
symlink to this directory in exactly the same way
|
|
||||||
<application>pg_basebackup</application> would.
|
|
||||||
</para>
|
|
||||||
<para>
|
<para>
|
||||||
It's now possible to clone a standby from Barman, e.g.:
|
It's now possible to clone a standby from Barman, e.g.:
|
||||||
<programlisting>
|
<programlisting>
|
||||||
@@ -244,8 +234,7 @@ description = "Main cluster"
|
|||||||
that any standby connected to the primary using a replication slot will always
|
that any standby connected to the primary using a replication slot will always
|
||||||
be able to retrieve the required WAL files. This removes the need to manually
|
be able to retrieve the required WAL files. This removes the need to manually
|
||||||
manage WAL file retention by estimating the number of WAL files that need to
|
manage WAL file retention by estimating the number of WAL files that need to
|
||||||
be maintained on the primary using <varname>wal_keep_segments</varname>
|
be maintained on the primary using <varname>wal_keep_segments</varname>.
|
||||||
(PostgreSQL 13 and later: <varname>wal_keep_size</varname>).
|
|
||||||
Do however be aware that if a standby is disconnected, WAL will continue to
|
Do however be aware that if a standby is disconnected, WAL will continue to
|
||||||
accumulate on the primary until either the standby reconnects or the replication
|
accumulate on the primary until either the standby reconnects or the replication
|
||||||
slot is dropped.
|
slot is dropped.
|
||||||
@@ -319,7 +308,7 @@ description = "Main cluster"
|
|||||||
Cascading replication, introduced with PostgreSQL 9.2, enables a standby server
|
Cascading replication, introduced with PostgreSQL 9.2, enables a standby server
|
||||||
to replicate from another standby server rather than directly from the primary,
|
to replicate from another standby server rather than directly from the primary,
|
||||||
meaning replication changes "cascade" down through a hierarchy of servers. This
|
meaning replication changes "cascade" down through a hierarchy of servers. This
|
||||||
can be used to reduce load on the primary and minimize bandwidth usage between
|
can be used to reduce load on the primary and minimize bandwith usage between
|
||||||
sites. For more details, see the
|
sites. For more details, see the
|
||||||
<ulink url="https://www.postgresql.org/docs/current/warm-standby.html#CASCADING-REPLICATION">
|
<ulink url="https://www.postgresql.org/docs/current/warm-standby.html#CASCADING-REPLICATION">
|
||||||
PostgreSQL cascading replication documentation</ulink>.
|
PostgreSQL cascading replication documentation</ulink>.
|
||||||
@@ -391,7 +380,7 @@ description = "Main cluster"
|
|||||||
cluster, you may wish to clone a downstream standby whose upstream node
|
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
|
does not yet exist. In this case you can clone from the primary (or
|
||||||
another upstream node); provide the parameter <literal>--upstream-conninfo</literal>
|
another upstream node); provide the parameter <literal>--upstream-conninfo</literal>
|
||||||
to explicitly set the upstream's <varname>primary_conninfo</varname> string
|
to explictly set the upstream's <varname>primary_conninfo</varname> string
|
||||||
in <filename>recovery.conf</filename>.
|
in <filename>recovery.conf</filename>.
|
||||||
</simpara>
|
</simpara>
|
||||||
</tip>
|
</tip>
|
||||||
@@ -449,13 +438,6 @@ description = "Main cluster"
|
|||||||
WAL directory. Any WALs generated during the cloning process will be copied here, and
|
WAL directory. Any WALs generated during the cloning process will be copied here, and
|
||||||
a symlink will automatically be created from the main data directory.
|
a symlink will automatically be created from the main data directory.
|
||||||
</para>
|
</para>
|
||||||
<tip>
|
|
||||||
<para>
|
|
||||||
The <literal>--waldir</literal> (<literal>--xlogdir</literal>) option,
|
|
||||||
if present in <varname>pg_basebackup_options</varname>, will be honoured by &repmgr;
|
|
||||||
when cloning from Barman (&repmgr; 5.2 and later).
|
|
||||||
</para>
|
|
||||||
</tip>
|
|
||||||
<para>
|
<para>
|
||||||
See the <ulink url="https://www.postgresql.org/docs/current/app-pgbasebackup.html">PostgreSQL pg_basebackup documentation</ulink>
|
See the <ulink url="https://www.postgresql.org/docs/current/app-pgbasebackup.html">PostgreSQL pg_basebackup documentation</ulink>
|
||||||
for more details of available options.
|
for more details of available options.
|
||||||
|
|||||||
@@ -7,14 +7,6 @@
|
|||||||
<secondary>optional settings</secondary>
|
<secondary>optional settings</secondary>
|
||||||
</indexterm>
|
</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>
|
<variablelist>
|
||||||
|
|
||||||
|
|
||||||
@@ -140,50 +132,5 @@ ssh_options='-q -o ConnectTimeout=10'</programlisting>
|
|||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</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>
|
</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>
|
</sect1>
|
||||||
|
|||||||
@@ -96,9 +96,6 @@
|
|||||||
</variablelist>
|
</variablelist>
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
|
||||||
See <xref linkend="configuration-file-optional-settings"/> for further configuration options.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
|
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|||||||
@@ -27,9 +27,7 @@
|
|||||||
<note>
|
<note>
|
||||||
<para>
|
<para>
|
||||||
If using <application>systemd</application>, ensure you have <varname>RemoveIPC</varname> set to <literal>off</literal>.
|
If using <application>systemd</application>, ensure you have <varname>RemoveIPC</varname> set to <literal>off</literal>.
|
||||||
See the <ulink url="https://www.postgresql.org/docs/current/index.html">PostgreSQL documentation</ulink> section
|
See the <ulink url="https://wiki.postgresql.org/wiki/Systemd">systemd</ulink>
|
||||||
<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.
|
entry in the <ulink url="https://wiki.postgresql.org/wiki/Main_Page">PostgreSQL wiki</ulink> for details.
|
||||||
</para>
|
</para>
|
||||||
</note>
|
</note>
|
||||||
|
|||||||
@@ -80,51 +80,6 @@ conninfo='host=node1 user=repmgr dbname=repmgr connect_timeout=2'</programlistin
|
|||||||
</para>
|
</para>
|
||||||
</note>
|
</note>
|
||||||
|
|
||||||
|
|
||||||
<sect3 id="configuration-file-include-directives" xreflabel="configuration file include directives">
|
|
||||||
|
|
||||||
<title>Configuration file include directives</title>
|
|
||||||
|
|
||||||
<indexterm>
|
|
||||||
<primary>repmgr.conf</primary>
|
|
||||||
<secondary>include directives</secondary>
|
|
||||||
</indexterm>
|
|
||||||
<para>
|
|
||||||
From &repmgr; 5.2, the configuration file can contain the following include directives:
|
|
||||||
<itemizedlist spacing="compact" mark="bullet">
|
|
||||||
<listitem>
|
|
||||||
<simpara>
|
|
||||||
<option>include</option>: include the specified file,
|
|
||||||
either as an absolute path or path relative to the current file
|
|
||||||
</simpara>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<simpara>
|
|
||||||
<option>include_if_exists</option>: include the specified file.
|
|
||||||
The file is specified as an absolute path or path relative to the current file.
|
|
||||||
However, if it does not exist, an error will not be raised.
|
|
||||||
</simpara>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<simpara>
|
|
||||||
<option>include_dir</option>: include files in the specified directory
|
|
||||||
which have the <filename>.conf</filename> suffix.
|
|
||||||
The directory is specified either as an absolute path or path
|
|
||||||
relative to the current file
|
|
||||||
</simpara>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
</itemizedlist>
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
These behave in exactly the same way as the PostgreSQL configuration file processing;
|
|
||||||
see the <ulink url="https://www.postgresql.org/docs/current/config-setting.html#CONFIG-INCLUDES">PostgreSQL documentation</ulink>
|
|
||||||
for additional details.
|
|
||||||
</para>
|
|
||||||
</sect3>
|
|
||||||
|
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
|
|
||||||
@@ -227,14 +182,6 @@ conninfo='host=node1 user=repmgr dbname=repmgr connect_timeout=2'</programlistin
|
|||||||
</itemizedlist>
|
</itemizedlist>
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
|
||||||
In examples provided in this documentation, it is assumed the configuration file is located
|
|
||||||
at <filename>/etc/repmgr.conf</filename>. If &repmgr; is installed from a package, the
|
|
||||||
configuration file will probably be located at another location specified by the packager;
|
|
||||||
see appendix <xref linkend="appendix-packages"/> for configuration file locations in
|
|
||||||
different packaging systems.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Note that if a file is explicitly specified with <literal>-f/--config-file</literal>,
|
Note that if a file is explicitly specified with <literal>-f/--config-file</literal>,
|
||||||
an error will be raised if it is not found or not readable, and no attempt will be made to
|
an error will be raised if it is not found or not readable, and no attempt will be made to
|
||||||
@@ -255,61 +202,6 @@ conninfo='host=node1 user=repmgr dbname=repmgr connect_timeout=2'</programlistin
|
|||||||
<filename>/path/to/repmgr.conf</filename>).
|
<filename>/path/to/repmgr.conf</filename>).
|
||||||
</para>
|
</para>
|
||||||
</note>
|
</note>
|
||||||
</sect2>
|
|
||||||
|
|
||||||
<sect2 id="configuration-file-postgresql-major-upgrades" xreflabel="configuration file and PostgreSQL major version upgrades">
|
|
||||||
<title>Configuration file and PostgreSQL major version upgrades</title>
|
|
||||||
|
|
||||||
<indexterm>
|
|
||||||
<primary>repmgr.conf</primary>
|
|
||||||
<secondary>ostgreSQL major version upgrades</secondary>
|
|
||||||
</indexterm>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
When upgrading the PostgreSQL cluster to a new major version, <filename>repmgr.conf</filename>
|
|
||||||
will probably needed to be updated.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
Usually <option>pg_bindir</option> and <option>data_directory</option> will need to be modified,
|
|
||||||
particularly if the default package locations are used, as these usually change.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
It's also possible the location of <filename>repmgr.conf</filename> itself will change
|
|
||||||
(e.g. from <filename>/etc/repmgr/11/repmgr.conf</filename> to <filename>/etc/repmgr/12/repmgr.conf</filename>).
|
|
||||||
This is stored as part of the &repmgr; metadata and is used by &repmgr; to execute &repmgr; remotely
|
|
||||||
(e.g. during a <link linkend="performing-switchover">switchover operation</link>).
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
If the content and/or location of <filename>repmgr.conf</filename> has changed, the &repmgr; metadata
|
|
||||||
needs to be updated to reflect this. The &repmgr; metadata can be updated on each node with:
|
|
||||||
<itemizedlist spacing="compact" mark="bullet">
|
|
||||||
<listitem>
|
|
||||||
<simpara>
|
|
||||||
<link linkend="repmgr-primary-register">
|
|
||||||
<command>repmgr primary register --force -f /path/to/repmgr.conf</command>
|
|
||||||
</link>
|
|
||||||
</simpara>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<simpara>
|
|
||||||
<link linkend="repmgr-standby-register">
|
|
||||||
<command>repmgr standby register --force -f /path/to/repmgr.conf</command>
|
|
||||||
</link>
|
|
||||||
</simpara>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<simpara>
|
|
||||||
<link linkend="repmgr-witness-register">
|
|
||||||
<command>repmgr witness register --force -f /path/to/repmgr.conf -h primary_host</command>
|
|
||||||
</link>
|
|
||||||
</simpara>
|
|
||||||
</listitem>
|
|
||||||
</itemizedlist>
|
|
||||||
</para>
|
|
||||||
|
|
||||||
</sect2>
|
</sect2>
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|||||||
@@ -127,31 +127,8 @@ node2:5432:repmgr:repmgr:foo
|
|||||||
node2:5432:replication:repluser:foo
|
node2:5432:replication:repluser:foo
|
||||||
node3:5432:repmgr:repmgr:foo
|
node3:5432:repmgr:repmgr:foo
|
||||||
node3:5432:replication:repluser:foo</programlisting>
|
node3:5432:replication:repluser:foo</programlisting>
|
||||||
If you are planning to use the <option>-S</option>/<option>--superuser</option> option,
|
|
||||||
there must also be an entry enabling the superuser to connect to the &repmgr; database.
|
|
||||||
Assuming the superuser is <literal>postgres</literal>, the file would look like this:
|
|
||||||
<programlisting>
|
|
||||||
node1:5432:repmgr:repmgr:foo
|
|
||||||
node1:5432:repmgr:postgres:foo
|
|
||||||
node1:5432:replication:repluser:foo
|
|
||||||
node2:5432:repmgr:repmgr:foo
|
|
||||||
node2:5432:repmgr:postgres:foo
|
|
||||||
node2:5432:replication:repluser:foo
|
|
||||||
node3:5432:repmgr:repmgr:foo
|
|
||||||
node3:5432:repmgr:postgres:foo
|
|
||||||
node3:5432:replication:repluser:foo</programlisting>
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
The <filename>~/.pgpass</filename> file can be simplified with the use of wildcards if
|
|
||||||
there is no requirement to restrict provision of passwords to particular hosts, ports
|
|
||||||
or databases. The preceding file could then be formatted like this:
|
|
||||||
<programlisting>
|
|
||||||
*:*:*:repmgr:foo
|
|
||||||
*:*:*:postgres:foo
|
|
||||||
</programlisting>
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<note>
|
<note>
|
||||||
<para>
|
<para>
|
||||||
It's possible to specify an alternative location for the <filename>~/.pgpass</filename> file, either via
|
It's possible to specify an alternative location for the <filename>~/.pgpass</filename> file, either via
|
||||||
@@ -163,11 +140,6 @@ node3:5432:replication:repluser:foo</programlisting>
|
|||||||
location on all nodes, as when connecting to a remote node, the file referenced is the one on the
|
location on all nodes, as when connecting to a remote node, the file referenced is the one on the
|
||||||
local node.
|
local node.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
|
||||||
Additionally, you <emphasis>must</emphasis> specify the passfile location in <filename>repmgr.conf</filename>
|
|
||||||
with the <option>passfile</option> option so &repmgr; can write the correct path when creating the
|
|
||||||
<option>primary_conninfo</option> parameter for replication configuration on standbys.
|
|
||||||
</para>
|
|
||||||
</note>
|
</note>
|
||||||
|
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|||||||
@@ -270,7 +270,7 @@
|
|||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
|
|
||||||
<term><option>wal_keep_segments</option> / <option>wal_keep_size</option></term>
|
<term><option>wal_keep_segments</option></term>
|
||||||
|
|
||||||
<listitem>
|
<listitem>
|
||||||
|
|
||||||
@@ -279,36 +279,25 @@
|
|||||||
<secondary>PostgreSQL configuration</secondary>
|
<secondary>PostgreSQL configuration</secondary>
|
||||||
</indexterm>
|
</indexterm>
|
||||||
|
|
||||||
|
|
||||||
<indexterm>
|
|
||||||
<primary>wal_keep_size</primary>
|
|
||||||
<secondary>PostgreSQL configuration</secondary>
|
|
||||||
</indexterm>
|
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Normally there is no need to set <option>wal_keep_segments</option>
|
Normally there is no need to set <option>wal_keep_segments</option> (default: <literal>0</literal>), as it
|
||||||
(PostgreSQL 13 and later: <varname>wal_keep_size</varname>; default: <literal>0</literal>),
|
is <emphasis>not</emphasis> a reliable way of ensuring that all required WAL segments are available to standbys.
|
||||||
as it is <emphasis>not</emphasis> a reliable way of ensuring that all required WAL
|
Replication slots and/or an archiving solution such as Barman are recommended to ensure standbys have a reliable
|
||||||
segments are available to standbys. Replication slots and/or an archiving solution
|
|
||||||
such as Barman are recommended to ensure standbys have a reliable
|
|
||||||
source of WAL segments at all times.
|
source of WAL segments at all times.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
The only reason ever to set <option>wal_keep_segments</option> / <option>wal_keep_size</option>
|
The only reason ever to set <option>wal_keep_segments</option> is you have
|
||||||
is you have you have configured <option>pg_basebackup_options</option>
|
you have configured <option>pg_basebackup_options</option>
|
||||||
in <filename>repmgr.conf</filename> to include the setting <literal>--wal-method=fetch</literal>
|
in <filename>repmgr.conf</filename> to include the setting <literal>--wal-method=fetch</literal>
|
||||||
(PostgreSQL 9.6 and earlier: <literal>--xlog-method=fetch</literal>)
|
(PostgreSQL 9.6 and earlier: <literal>--xlog-method=fetch</literal>)
|
||||||
<emphasis>and</emphasis> you have <emphasis>not</emphasis> set <option>restore_command</option>
|
<emphasis>and</emphasis> you have <emphasis>not</emphasis> set <option>restore_command</option>
|
||||||
in <filename>repmgr.conf</filename> to fetch WAL files from a reliable source such as Barman,
|
in <filename>repmgr.conf</filename> to fetch WAL files from a reliable source such as Barman,
|
||||||
in which case you'll need to set <option>wal_keep_segments</option>
|
in which case you'll need to set <option>wal_keep_segments</option>
|
||||||
to a sufficiently high number to ensure that all WAL files required by the standby
|
to a sufficiently high number to ensure that all WAL files required by the standby
|
||||||
are retained. However we do not recommend WAL retention in this way.
|
are retained. However we do not recommend managing replication in this way.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
PostgreSQL documentation: <ulink url="https://www.postgresql.org/docs/current/runtime-config-replication.html#GUC-WAL-KEEP-SEGMENTS">wal_keep_segments</ulink>.
|
PostgreSQL documentation: <ulink url="https://www.postgresql.org/docs/current/runtime-config-replication.html#GUC-WAL-KEEP-SEGMENTS">wal_keep_segments</ulink>.
|
||||||
<!--
|
|
||||||
PostgreSQL documentation: <ulink url="https://www.postgresql.org/docs/current/runtime-config-replication.html#GUC-WAL-KEEP-SIZE">wal_keep_size</ulink>.
|
|
||||||
-->
|
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
&repmgr; &repmgrversion; is compatible with all PostgreSQL versions from 9.4. See
|
&repmgr; &repmgrversion; is compatible with all PostgreSQL versions from 9.3. See
|
||||||
section <link linkend="install-compatibility-matrix">&repmgr; compatibility matrix</link>
|
section <link linkend="install-compatibility-matrix">&repmgr; compatibility matrix</link>
|
||||||
for an overview of version compatibility.
|
for an overview of version compatibility.
|
||||||
</para>
|
</para>
|
||||||
@@ -93,7 +93,7 @@
|
|||||||
<table id="repmgr-compatibility-matrix">
|
<table id="repmgr-compatibility-matrix">
|
||||||
<title>&repmgr; compatibility matrix</title>
|
<title>&repmgr; compatibility matrix</title>
|
||||||
|
|
||||||
<tgroup cols="4">
|
<tgroup cols="3">
|
||||||
<thead>
|
<thead>
|
||||||
<row>
|
<row>
|
||||||
<entry>
|
<entry>
|
||||||
@@ -115,7 +115,7 @@
|
|||||||
|
|
||||||
<row>
|
<row>
|
||||||
<entry>
|
<entry>
|
||||||
&repmgr; 5.2
|
&repmgr; 5.x
|
||||||
</entry>
|
</entry>
|
||||||
<entry>
|
<entry>
|
||||||
YES
|
YES
|
||||||
@@ -123,42 +123,11 @@
|
|||||||
<entry>
|
<entry>
|
||||||
<link linkend="release-current">&repmgrversion;</link> (&releasedate;)
|
<link linkend="release-current">&repmgrversion;</link> (&releasedate;)
|
||||||
</entry>
|
</entry>
|
||||||
<entry>
|
|
||||||
9.4, 9.5, 9.6, 10, 11, 12, 13
|
|
||||||
</entry>
|
|
||||||
</row>
|
|
||||||
|
|
||||||
<row>
|
|
||||||
<entry>
|
|
||||||
&repmgr; 5.1
|
|
||||||
</entry>
|
|
||||||
<entry>
|
|
||||||
NO
|
|
||||||
</entry>
|
|
||||||
<entry>
|
|
||||||
<link linkend="release-5.1.0">5.1.0</link> (2020-04-13)
|
|
||||||
</entry>
|
|
||||||
<entry>
|
<entry>
|
||||||
9.3, 9.4, 9.5, 9.6, 10, 11, 12
|
9.3, 9.4, 9.5, 9.6, 10, 11, 12
|
||||||
</entry>
|
</entry>
|
||||||
</row>
|
</row>
|
||||||
|
|
||||||
<row>
|
|
||||||
<entry>
|
|
||||||
&repmgr; 5.0
|
|
||||||
</entry>
|
|
||||||
<entry>
|
|
||||||
NO
|
|
||||||
</entry>
|
|
||||||
<entry>
|
|
||||||
<link linkend="release-5.0">5.0</link> (2019-10-15)
|
|
||||||
</entry>
|
|
||||||
<entry>
|
|
||||||
9.3, 9.4, 9.5, 9.6, 10, 11, 12
|
|
||||||
</entry>
|
|
||||||
</row>
|
|
||||||
|
|
||||||
|
|
||||||
<row>
|
<row>
|
||||||
<entry>
|
<entry>
|
||||||
&repmgr; 4.x
|
&repmgr; 4.x
|
||||||
@@ -224,49 +193,52 @@
|
|||||||
|
|
||||||
<sect2 id="install-postgresql-93-94">
|
<sect2 id="install-postgresql-93-94">
|
||||||
|
|
||||||
<title>PostgreSQL 9.4 support</title>
|
<title>PostgreSQL 9.3 and 9.4 support</title>
|
||||||
|
|
||||||
<indexterm>
|
<indexterm>
|
||||||
<primary>PostgreSQL 9.4</primary>
|
<primary>PostgreSQL 9.3</primary>
|
||||||
<secondary>repmgr support</secondary>
|
<secondary>repmgr support</secondary>
|
||||||
</indexterm>
|
</indexterm>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Note that some &repmgr; functionality is not available in PostgreSQL 9.4:
|
Note that some &repmgr; functionality is not available in PostgreSQL 9.3 and PostgreSQL 9.4:
|
||||||
</para>
|
</para>
|
||||||
<itemizedlist spacing="compact" mark="bullet">
|
<itemizedlist spacing="compact" mark="bullet">
|
||||||
|
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
In PostgreSQL 9.4, <command>pg_rewind</command> is not part of the core
|
PostgreSQL 9.3 does not support replication slots, so corresponding &repmgr; functionality
|
||||||
|
is not available.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
In PostgreSQL 9.3 and PostgreSQL 9.4, <command>pg_rewind</command> is not part of the core
|
||||||
distribution. <command>pg_rewind</command> will need to be compiled separately to be able
|
distribution. <command>pg_rewind</command> will need to be compiled separately to be able
|
||||||
to use any &repmgr; functionality which takes advantage of it.
|
to use any &repmgr; functionality which takes advantage of it.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</itemizedlist>
|
</itemizedlist>
|
||||||
|
|
||||||
<warning>
|
<important>
|
||||||
<para>
|
<para>
|
||||||
PostgreSQL 9.3 has reached the end of its community support period (final release was
|
PostgreSQL 9.3 has reached the end of its community support period (final release was
|
||||||
<ulink url="https://www.postgresql.org/docs/9.3/release-9-3-25.html">9.3.25</ulink>
|
<ulink url="https://www.postgresql.org/docs/9.3/release-9-3-25.html">9.3.25</ulink>
|
||||||
in November 2018) and will no longer be updated with security or bugfixes.
|
in November 2018) and will no longer be updated with security or bugfixes.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
|
||||||
Beginning with &repmgr; 5.2, &repmgr; no longer supports PostgreSQL 9.3.
|
|
||||||
</para>
|
|
||||||
<para>
|
<para>
|
||||||
PostgreSQL 9.4 has reached the end of its community support period (final release was
|
PostgreSQL 9.4 has reached the end of its community support period (final release was
|
||||||
<ulink url="https://www.postgresql.org/docs/9.4/release-9-4-26.html">9.4.26</ulink>
|
<ulink url="https://www.postgresql.org/docs/9.4/release-9-4-26.html">9.4.26</ulink>
|
||||||
in February 2020) and will no longer be updated with security or bugfixes.
|
in February 2020) and will no longer be updated with security or bugfixes.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
We recommend that users of these versions migrate to a supported PostgreSQL version
|
We recommend that users of these versions migrate to a recent PostgreSQL version
|
||||||
as soon as possible.
|
as soon as possible.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
For further details, see the <ulink url="https://www.postgresql.org/support/versioning/">PostgreSQL Versioning Policy</ulink>.
|
For further details, see the <ulink url="https://www.postgresql.org/support/versioning/">PostgreSQL Versioning Policy</ulink>.
|
||||||
</para>
|
</para>
|
||||||
</warning>
|
</important>
|
||||||
|
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
|
|||||||
@@ -178,18 +178,18 @@ deb-src https://apt.postgresql.org/pub/repos/apt/ stretch-pgdg main</programlist
|
|||||||
|
|
||||||
<para>
|
<para>
|
||||||
The source for &repmgr; is maintained at
|
The source for &repmgr; is maintained at
|
||||||
<ulink url="https://github.com/EnterpriseDB/repmgr">https://github.com/EnterpriseDB/repmgr</ulink>.
|
<ulink url="https://github.com/2ndQuadrant/repmgr">https://github.com/2ndQuadrant/repmgr</ulink>.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
There are also tags for each <ulink url="https://github.com/EnterpriseDB/repmgr/releases">&repmgr; release</ulink>, e.g.
|
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/EnterpriseDB/repmgr/releases/tag/v4.4.0">v4.4.0</ulink></literal>.
|
<literal><ulink url="https://github.com/2ndQuadrant/repmgr/releases/tag/v4.4.0">v4.4.0</ulink></literal>.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Clone the source code using <application>git</application>:
|
Clone the source code using <application>git</application>:
|
||||||
<programlisting>
|
<programlisting>
|
||||||
git clone https://github.com/EnterpriseDB/repmgr</programlisting>
|
git clone https://github.com/2ndQuadrant/repmgr</programlisting>
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
|
|||||||
@@ -3,16 +3,16 @@
|
|||||||
<date>2017</date>
|
<date>2017</date>
|
||||||
|
|
||||||
<copyright>
|
<copyright>
|
||||||
<year>2010-2021</year>
|
<year>2010-2020</year>
|
||||||
<holder>EnterpriseDB Corporation</holder>
|
<holder>2ndQuadrant, Ltd.</holder>
|
||||||
</copyright>
|
</copyright>
|
||||||
|
|
||||||
<legalnotice id="legalnotice">
|
<legalnotice id="legalnotice">
|
||||||
<title>Legal Notice</title>
|
<title>Legal Notice</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
<productname>repmgr</productname> is Copyright © 2010-2021
|
<productname>repmgr</productname> is Copyright © 2010-2020
|
||||||
by EnterpriseDB Corporation All rights reserved.
|
by 2ndQuadrant, Ltd. All rights reserved.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
|
|||||||
@@ -284,7 +284,7 @@
|
|||||||
|
|
||||||
<tip>
|
<tip>
|
||||||
<simpara>
|
<simpara>
|
||||||
For Debian-based distributions we recommend explicitly setting
|
For Debian-based distributions we recommend explictly setting
|
||||||
<option>pg_bindir</option> to the directory where <command>pg_ctl</command> and other binaries
|
<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>.
|
not in the standard path are located. For PostgreSQL 9.6 this would be <filename>/usr/lib/postgresql/9.6/bin/</filename>.
|
||||||
</simpara>
|
</simpara>
|
||||||
@@ -302,7 +302,7 @@
|
|||||||
|
|
||||||
<para>
|
<para>
|
||||||
See the file
|
See the file
|
||||||
<ulink url="https://raw.githubusercontent.com/EnterpriseDB/repmgr/master/repmgr.conf.sample">repmgr.conf.sample</ulink>
|
<ulink url="https://raw.githubusercontent.com/2ndQuadrant/repmgr/master/repmgr.conf.sample">repmgr.conf.sample</ulink>
|
||||||
for details of all available configuration parameters.
|
for details of all available configuration parameters.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
By default, &repmgr; will wait for up to 15 seconds to confirm that &repmgrd;
|
By default, &repmgr; will wait for up to 15 seconds to confirm that &repmgrd;
|
||||||
started. This behaviour can be overridden by specifying a different value using the <option>--wait</option>
|
started. This behaviour can be overridden by specifying a diffent value using the <option>--wait</option>
|
||||||
option, or disabled altogether with the <option>--no-wait</option> option.
|
option, or disabled altogether with the <option>--no-wait</option> option.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
|
|
||||||
<para>
|
<para>
|
||||||
By default, &repmgr; will wait for up to 15 seconds to confirm that &repmgrd;
|
By default, &repmgr; will wait for up to 15 seconds to confirm that &repmgrd;
|
||||||
stopped. This behaviour can be overridden by specifying a different value using the <option>--wait</option>
|
stopped. This behaviour can be overridden by specifying a diffent value using the <option>--wait</option>
|
||||||
option, or disabled altogether with the <option>--no-wait</option> option.
|
option, or disabled altogether with the <option>--no-wait</option> option.
|
||||||
</para>
|
</para>
|
||||||
<note>
|
<note>
|
||||||
|
|||||||
@@ -131,46 +131,6 @@
|
|||||||
</para>
|
</para>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
<refsect1>
|
|
||||||
<title>Additional checks</title>
|
|
||||||
<para>
|
|
||||||
Several checks are provided for diagnostic purposes and are not
|
|
||||||
included in the general output:
|
|
||||||
<itemizedlist spacing="compact" mark="bullet">
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<simpara>
|
|
||||||
<option>--db-connection</option>: checks if &repmgr; can connect to the
|
|
||||||
database on the local node.
|
|
||||||
</simpara>
|
|
||||||
<simpara>
|
|
||||||
This option is particularly useful in combination with <command>SSH</command>, as
|
|
||||||
it can be used to troubleshoot connection issues encountered when &repmgr; is
|
|
||||||
executed remotely (e.g. during a switchover operation).
|
|
||||||
</simpara>
|
|
||||||
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<simpara>
|
|
||||||
<option>--replication-config-owner</option>: checks if the file containing replication
|
|
||||||
configuration (PostgreSQL 12 and later: <filename>postgresql.auto.conf</filename>;
|
|
||||||
PostgreSQL 11 and earlier: <filename>recovery.conf</filename>) is
|
|
||||||
owned by the same user who owns the data directory.
|
|
||||||
</simpara>
|
|
||||||
<simpara>
|
|
||||||
Incorrect ownership of these files (e.g. if they are owned by <literal>root</literal>)
|
|
||||||
will cause operations which need to update the replication configuration
|
|
||||||
(e.g. <link linkend="repmgr-standby-follow"><command>repmgr standby follow</command></link>
|
|
||||||
or <link linkend="repmgr-standby-promote"><command>repmgr standby promote</command></link>)
|
|
||||||
to fail.
|
|
||||||
</simpara>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
</itemizedlist>
|
|
||||||
</para>
|
|
||||||
</refsect1>
|
|
||||||
|
|
||||||
<refsect1>
|
<refsect1>
|
||||||
<title>Connection options</title>
|
<title>Connection options</title>
|
||||||
<para>
|
<para>
|
||||||
|
|||||||
@@ -22,10 +22,6 @@
|
|||||||
This can optionally use <application>pg_rewind</application> to re-integrate
|
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.
|
a node which has diverged from the rest of the cluster, typically a failed primary.
|
||||||
</para>
|
</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>
|
<tip>
|
||||||
<para>
|
<para>
|
||||||
@@ -47,12 +43,7 @@
|
|||||||
<programlisting>
|
<programlisting>
|
||||||
repmgr node rejoin -d '$conninfo'</programlisting>
|
repmgr node rejoin -d '$conninfo'</programlisting>
|
||||||
|
|
||||||
where <literal>$conninfo</literal> is the PostgreSQL <literal>conninfo</literal> string of the
|
where <literal>$conninfo</literal> is the conninfo string of any reachable node in the cluster.
|
||||||
<emphasis>current</emphasis> primary node (or that of any reachable node in the cluster, but
|
|
||||||
<emphasis>not</emphasis> the local node). This is so that &repmgr; can fetch up-to-date information
|
|
||||||
about the current state of the cluster.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
<filename>repmgr.conf</filename> for the stopped node *must* be supplied explicitly if not
|
<filename>repmgr.conf</filename> for the stopped node *must* be supplied explicitly if not
|
||||||
otherwise available.
|
otherwise available.
|
||||||
</para>
|
</para>
|
||||||
@@ -80,7 +71,7 @@
|
|||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
It is only necessary to provide the <application>pg_rewind</application> path
|
It is only necessary to provide the <application>pg_rewind</application> path
|
||||||
if using PostgreSQL 9.4, and <application>pg_rewind</application>
|
if using PostgreSQL 9.3 or 9.4, and <application>pg_rewind</application>
|
||||||
is not installed in the PostgreSQL <filename>bin</filename> directory.
|
is not installed in the PostgreSQL <filename>bin</filename> directory.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
@@ -216,18 +207,9 @@
|
|||||||
a standby to the current primary, not another standby.
|
a standby to the current primary, not another standby.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
The node's PostgreSQL instance must have been shut down cleanly. If this was not the
|
The node must have been shut down cleanly; if this was not the case, it will
|
||||||
case, it will need to be started up until it has reached a consistent recovery point,
|
need to be manually started (remove any existing <filename>recovery.conf</filename> file first)
|
||||||
then shut down cleanly.
|
until it has reached a consistent recovery point, then shut down cleanly.
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
In PostgreSQL 13 and later, this will be done automatically
|
|
||||||
if the <option>--force-rewind</option> is provided (even if an actual rewind
|
|
||||||
is not necessary).
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
With PostgreSQL 12 and earlier, PostgreSQL will need to
|
|
||||||
be started and shut down manually; see below for the best way to do this.
|
|
||||||
</para>
|
</para>
|
||||||
<tip>
|
<tip>
|
||||||
<para>
|
<para>
|
||||||
@@ -239,14 +221,11 @@
|
|||||||
rm -f /var/lib/pgsql/data/recovery.conf
|
rm -f /var/lib/pgsql/data/recovery.conf
|
||||||
postgres --single -D /var/lib/pgsql/data/ < /dev/null</programlisting>
|
postgres --single -D /var/lib/pgsql/data/ < /dev/null</programlisting>
|
||||||
</para>
|
</para>
|
||||||
<para>
|
|
||||||
Note that <filename>standby.signal</filename> (PostgreSQL 11 and earlier:
|
|
||||||
<filename>recovery.conf</filename>) <emphasis>must</emphasis> be removed
|
|
||||||
from the data directory for PostgreSQL to be able to start in single
|
|
||||||
user mode.
|
|
||||||
</para>
|
|
||||||
</tip>
|
</tip>
|
||||||
|
<para>
|
||||||
|
&repmgr; will attempt to verify whether the node can rejoin as-is, or whether
|
||||||
|
<command>pg_rewind</command> must be used (see following section).
|
||||||
|
</para>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
<refsect1 id="repmgr-node-rejoin-pg-rewind" xreflabel="Using pg_rewind">
|
<refsect1 id="repmgr-node-rejoin-pg-rewind" xreflabel="Using pg_rewind">
|
||||||
@@ -262,7 +241,7 @@
|
|||||||
<command>repmgr node rejoin</command> can optionally use <command>pg_rewind</command> to re-integrate a
|
<command>repmgr node rejoin</command> can optionally use <command>pg_rewind</command> to re-integrate a
|
||||||
node which has diverged from the rest of the cluster, typically a failed primary.
|
node which has diverged from the rest of the cluster, typically a failed primary.
|
||||||
<command>pg_rewind</command> is available in PostgreSQL 9.5 and later as part of the core distribution,
|
<command>pg_rewind</command> is available in PostgreSQL 9.5 and later as part of the core distribution,
|
||||||
and can be installed from external sources for PostgreSQL 9.4.
|
and can be installed from external sources for PostgreSQL 9.3 and 9.4.
|
||||||
</para>
|
</para>
|
||||||
<note>
|
<note>
|
||||||
<para>
|
<para>
|
||||||
@@ -285,7 +264,6 @@
|
|||||||
<programlisting>
|
<programlisting>
|
||||||
$ repmgr node rejoin -f /etc/repmgr.conf -d 'host=node3 dbname=repmgr user=repmgr' \
|
$ 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
|
--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: replication connection to the rejoin target node was successful
|
||||||
INFO: local and rejoin target system identifiers match
|
INFO: local and rejoin target system identifiers match
|
||||||
DETAIL: system identifier is 6652184002263212600
|
DETAIL: system identifier is 6652184002263212600
|
||||||
@@ -305,15 +283,7 @@
|
|||||||
to execute <command>pg_rewind</command> to ensure the node can be rejoined successfully.
|
to execute <command>pg_rewind</command> to ensure the node can be rejoined successfully.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<refsect2 id="repmgr-node-rejoin-pg-rewind-config-files" xreflabel="pg_rewind and configuration files">
|
<important>
|
||||||
|
|
||||||
<title><command>pg_rewind</command> and configuration file retention</title>
|
|
||||||
|
|
||||||
<indexterm>
|
|
||||||
<primary>pg_rewind</primary>
|
|
||||||
<secondary>configuration file retention</secondary>
|
|
||||||
</indexterm>
|
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Be aware that if <command>pg_rewind</command> is executed and actually performs a
|
Be aware that if <command>pg_rewind</command> is executed and actually performs a
|
||||||
rewind operation, any configuration files in the PostgreSQL data directory will be
|
rewind operation, any configuration files in the PostgreSQL data directory will be
|
||||||
@@ -321,30 +291,19 @@
|
|||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
To prevent this happening, provide a comma-separated list of files to retain
|
To prevent this happening, provide a comma-separated list of files to retain
|
||||||
using the <option>--config-file</option> command line option; the specified files
|
using the <literal>--config-file</literal> command line option; the specified files
|
||||||
will be archived in a temporary directory (whose parent directory can be specified with
|
will be archived in a temporary directory (whose parent directory can be specified with
|
||||||
<option>--config-archive-dir</option>, default: <filename>/tmp</filename>)
|
<literal>--config-archive-dir</literal>) and restored once the rewind operation is
|
||||||
and restored once the rewind operation is complete.
|
complete.
|
||||||
</para>
|
</para>
|
||||||
</refsect2>
|
</important>
|
||||||
|
|
||||||
<refsect2 id="repmgr-node-rejoin-pg-rewind-example" xreflabel="example using repmgr node rejoin and pg_rewind">
|
<para>
|
||||||
|
Example, first using <literal>--dry-run</literal>, then actually executing the
|
||||||
<title>Example using <command>repmgr node rejoin</command> and <command>pg_rewind</command></title>
|
<literal>node rejoin command</literal>.
|
||||||
|
<programlisting>
|
||||||
<indexterm>
|
|
||||||
<primary>pg_rewind</primary>
|
|
||||||
<secondary>configuration file retention</secondary>
|
|
||||||
</indexterm>
|
|
||||||
|
|
||||||
|
|
||||||
<para>
|
|
||||||
Example, first using <option>--dry-run</option>, then actually executing the
|
|
||||||
<literal>node rejoin command</literal>.
|
|
||||||
<programlisting>
|
|
||||||
$ repmgr node rejoin -f /etc/repmgr.conf -d 'host=node3 dbname=repmgr user=repmgr' \
|
$ 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
|
--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: replication connection to the rejoin target node was successful
|
||||||
INFO: local and rejoin target system identifiers match
|
INFO: local and rejoin target system identifiers match
|
||||||
DETAIL: system identifier is 6652460429293670710
|
DETAIL: system identifier is 6652460429293670710
|
||||||
@@ -358,17 +317,17 @@
|
|||||||
pg_rewind -D '/var/lib/postgresql/data' --source-server='host=node3 dbname=repmgr user=repmgr'
|
pg_rewind -D '/var/lib/postgresql/data' --source-server='host=node3 dbname=repmgr user=repmgr'
|
||||||
INFO: prerequisites for executing NODE REJOIN are met</programlisting>
|
INFO: prerequisites for executing NODE REJOIN are met</programlisting>
|
||||||
|
|
||||||
<note>
|
<note>
|
||||||
<para>
|
<para>
|
||||||
If <option>--force-rewind</option> is used with the <option>--dry-run</option> option,
|
If <option>--force-rewind</option> is used with the <option>--dry-run</option> option,
|
||||||
this checks the prerequisites for using <application>pg_rewind</application>, but is
|
this checks the prerequisites for using <application>pg_rewind</application>, but is
|
||||||
not an absolute guarantee that actually executing <application>pg_rewind</application>
|
not an absolute guarantee that actually executing <application>pg_rewind</application>
|
||||||
will succeed. See also section <xref linkend="repmgr-node-rejoin-caveats"/> below.
|
will succeed. See also section <xref linkend="repmgr-node-rejoin-caveats"/> below.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
</note>
|
</note>
|
||||||
|
|
||||||
<programlisting>
|
<programlisting>
|
||||||
$ repmgr node rejoin -f /etc/repmgr.conf -d 'host=node3 dbname=repmgr user=repmgr' \
|
$ repmgr node rejoin -f /etc/repmgr.conf -d 'host=node3 dbname=repmgr user=repmgr' \
|
||||||
--config-files=postgresql.local.conf,postgresql.conf --verbose --force-rewind
|
--config-files=postgresql.local.conf,postgresql.conf --verbose --force-rewind
|
||||||
NOTICE: pg_rewind execution required for this node to attach to rejoin target node 3
|
NOTICE: pg_rewind execution required for this node to attach to rejoin target node 3
|
||||||
@@ -380,8 +339,8 @@
|
|||||||
NOTICE: starting server using "pg_ctl -l /var/log/postgres/startup.log -w -D '/var/lib/pgsql/data' start"
|
NOTICE: starting server using "pg_ctl -l /var/log/postgres/startup.log -w -D '/var/lib/pgsql/data' start"
|
||||||
NOTICE: NODE REJOIN successful
|
NOTICE: NODE REJOIN successful
|
||||||
DETAIL: node 2 is now attached to node 3</programlisting>
|
DETAIL: node 2 is now attached to node 3</programlisting>
|
||||||
</para>
|
</para>
|
||||||
</refsect2>
|
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
<refsect1 id="repmgr-node-rejoin-caveats" xreflabel="Caveats">
|
<refsect1 id="repmgr-node-rejoin-caveats" xreflabel="Caveats">
|
||||||
@@ -410,11 +369,6 @@
|
|||||||
the current standby's PostgreSQL log will contain entries with the text
|
the current standby's PostgreSQL log will contain entries with the text
|
||||||
"<literal>record with incorrect prev-link</literal>".
|
"<literal>record with incorrect prev-link</literal>".
|
||||||
</para>
|
</para>
|
||||||
<para>
|
|
||||||
In PostgreSQL 9.5 and earlier, it is <emphasis>not</emphasis> possible to use
|
|
||||||
<application>pg_rewind</application> to attach to a target node with a lower
|
|
||||||
timeline than the local node.
|
|
||||||
</para>
|
|
||||||
<para>
|
<para>
|
||||||
We strongly recommend running <command>repmgr node rejoin</command> with the
|
We strongly recommend running <command>repmgr node rejoin</command> with the
|
||||||
<option>--dry-run</option> option first. Additionally it might be a good idea
|
<option>--dry-run</option> option first. Additionally it might be a good idea
|
||||||
@@ -424,52 +378,6 @@
|
|||||||
is running in <option>--dry-run</option> mode.
|
is running in <option>--dry-run</option> mode.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<warning>
|
|
||||||
<para>
|
|
||||||
In all current PostgreSQL versions (as of September 2020), <application>pg_rewind</application>
|
|
||||||
contains a corner-case bug which affects standbys in a very specific situation.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
This situation occurs when a standby was shut down <emphasis>before</emphasis> its
|
|
||||||
primary node, and an attempt is made to attach this standby to another primary
|
|
||||||
in the same cluster (following a "split brain" situation where the standby
|
|
||||||
was connected to the wrong primary). In this case, &repmgr; will correctly determine
|
|
||||||
that <application>pg_rewind</application> should be executed, however
|
|
||||||
<application>pg_rewind</application> incorrectly decides that no action is necessary.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
In this situation, &repmgr; will report something like:
|
|
||||||
<programlisting>
|
|
||||||
NOTICE: pg_rewind execution required for this node to attach to rejoin target node 1
|
|
||||||
DETAIL: rejoin target server's timeline 3 forked off current database system timeline 2 before current recovery point 0/7019C10</programlisting>
|
|
||||||
but when executed, <application>pg_rewind</application> will report:
|
|
||||||
<programlisting>
|
|
||||||
pg_rewind: servers diverged at WAL location 0/7015540 on timeline 2
|
|
||||||
pg_rewind: no rewind required</programlisting>
|
|
||||||
and if an attempt is made to attach the standby to the new primary, PostgreSQL logs on the standby
|
|
||||||
will contain errors like:
|
|
||||||
<programlisting>
|
|
||||||
[2020-09-07 15:01:41 UTC] LOG: 00000: replication terminated by primary server
|
|
||||||
[2020-09-07 15:01:41 UTC] DETAIL: End of WAL reached on timeline 2 at 0/7015540.
|
|
||||||
[2020-09-07 15:01:41 UTC] LOG: 00000: new timeline 3 forked off current database system timeline 2 before current recovery point 0/7019C10</programlisting>
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
Currently it is not possible to resolve this situation using <application>pg_rewind</application>.
|
|
||||||
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 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>
|
|
||||||
</warning>
|
|
||||||
|
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
<refsect1>
|
<refsect1>
|
||||||
|
|||||||
@@ -60,17 +60,6 @@
|
|||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
|
||||||
<term><option>--force</option></term>
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
Forcibly unregister the node if it is registered as an active primary,
|
|
||||||
as long as it has no registered standbys; or if it is registered as
|
|
||||||
a primary but running as a standby.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
</varlistentry>
|
|
||||||
|
|
||||||
</variablelist>
|
</variablelist>
|
||||||
|
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|||||||
@@ -104,6 +104,14 @@
|
|||||||
|
|
||||||
<itemizedlist spacing="compact" mark="bullet">
|
<itemizedlist spacing="compact" mark="bullet">
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<simpara><varname>standby_mode</varname> (always <literal>'on'</literal>)</simpara>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<simpara><varname>recovery_target_timeline</varname> (always <literal>'latest'</literal>)</simpara>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
<listitem>
|
<listitem>
|
||||||
<simpara><varname>primary_conninfo</varname></simpara>
|
<simpara><varname>primary_conninfo</varname></simpara>
|
||||||
</listitem>
|
</listitem>
|
||||||
@@ -114,21 +122,6 @@
|
|||||||
|
|
||||||
</itemizedlist>
|
</itemizedlist>
|
||||||
|
|
||||||
<para>
|
|
||||||
For PostgreSQL 11 and earlier, these parameters will also be set:
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<itemizedlist spacing="compact" mark="bullet">
|
|
||||||
<listitem>
|
|
||||||
<simpara><varname>standby_mode</varname> (always <literal>'on'</literal>)</simpara>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<simpara><varname>recovery_target_timeline</varname> (always <literal>'latest'</literal>)</simpara>
|
|
||||||
</listitem>
|
|
||||||
</itemizedlist>
|
|
||||||
|
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
The following additional parameters can be specified in <filename>repmgr.conf</filename>
|
The following additional parameters can be specified in <filename>repmgr.conf</filename>
|
||||||
for inclusion in the replication configuration:
|
for inclusion in the replication configuration:
|
||||||
@@ -182,10 +175,7 @@
|
|||||||
<programlisting>
|
<programlisting>
|
||||||
pg_basebackup_options='--wal-method=fetch'</programlisting>
|
pg_basebackup_options='--wal-method=fetch'</programlisting>
|
||||||
|
|
||||||
and ensure that <literal>wal_keep_segments</literal> (PostgreSQL 13 and later:
|
and ensure that <literal>wal_keep_segments</literal> is set to an appropriately high value.
|
||||||
<literal>wal_keep_size</literal>) is set to an appropriately high value. Note
|
|
||||||
however that this is not a particularly reliable way of ensuring sufficient
|
|
||||||
WAL is retained and is not recommended.
|
|
||||||
See the <ulink url="https://www.postgresql.org/docs/current/app-pgbasebackup.html">
|
See the <ulink url="https://www.postgresql.org/docs/current/app-pgbasebackup.html">
|
||||||
pg_basebackup</ulink> documentation for details.
|
pg_basebackup</ulink> documentation for details.
|
||||||
</para>
|
</para>
|
||||||
@@ -198,25 +188,6 @@
|
|||||||
</note>
|
</note>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
<refsect1 id="repmgr-standby-clone-wal-directory">
|
|
||||||
|
|
||||||
<title>Placing WAL files into a different directory</title>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
To ensure that WAL files are placed in a directory outside of the main data
|
|
||||||
directory (e.g. to keep them on a separate disk for performance reasons),
|
|
||||||
specify the location with <option>--waldir</option>
|
|
||||||
(PostgreSQL 9.6 and earlier: <option>--xlogdir</option>) in
|
|
||||||
the <filename>repmgr.conf</filename> parameter <option>pg_basebackup_options</option>,
|
|
||||||
e.g.:
|
|
||||||
<programlisting>
|
|
||||||
pg_basebackup_options='--waldir=/path/to/wal-directory'</programlisting>
|
|
||||||
This setting will also be honored by &repmgr; when cloning from Barman
|
|
||||||
(&repmgr; 5.2 and later).
|
|
||||||
</para>
|
|
||||||
|
|
||||||
</refsect1>
|
|
||||||
|
|
||||||
<!-- don't rename this id as it may be used in external links -->
|
<!-- don't rename this id as it may be used in external links -->
|
||||||
<refsect1 id="repmgr-standby-create-recovery-conf">
|
<refsect1 id="repmgr-standby-create-recovery-conf">
|
||||||
|
|
||||||
@@ -260,29 +231,16 @@ pg_basebackup_options='--waldir=/path/to/wal-directory'</programlisting>
|
|||||||
upstream node if required.
|
upstream node if required.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
The upstream node must be running so the correct replication configuration can be obtained.
|
Note that the upstream node must be running. In PostgreSQL 11 and earlier, an existing
|
||||||
</para>
|
<filename>recovery.conf</filename> will not be overwritten unless the
|
||||||
<para>
|
|
||||||
If the standby is running, the replication configuration will not be written unless the
|
|
||||||
<option>-F/--force</option> option is provided.
|
<option>-F/--force</option> option is provided.
|
||||||
</para>
|
</para>
|
||||||
<tip>
|
|
||||||
<para>
|
|
||||||
Execute <command>repmgr standby clone --replication-conf-only --dry-run</command>
|
|
||||||
to check the prerequisites for creating the recovery configuration,
|
|
||||||
and display the configuration changes which would be made without actually
|
|
||||||
making any changes.
|
|
||||||
</para>
|
|
||||||
</tip>
|
|
||||||
<para>
|
<para>
|
||||||
In PostgreSQL 13 and later, the PostgreSQL configuration must be reloaded for replication
|
Execute <command>repmgr standby clone --replication-conf-only --dry-run</command>
|
||||||
configuration changes to take effect.
|
to check the prerequisites for creating the recovery configuration,
|
||||||
|
and display the contents of the configuration which would be added without actually
|
||||||
|
making any changes.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
|
||||||
In PostgreSQL 12 and earlier, the PostgreSQL instance must be restarted for replication
|
|
||||||
configuration changes to take effect.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
|
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
@@ -344,25 +302,6 @@ pg_basebackup_options='--waldir=/path/to/wal-directory'</programlisting>
|
|||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
<varlistentry>
|
|
||||||
<term><option>--recovery-min-apply-delay</option></term>
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
Set PostgreSQL configuration <option>recovery_min_apply_delay</option> parameter
|
|
||||||
to the provided value.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
This overrides any <option>recovery_min_apply_delay</option> provided via
|
|
||||||
<filename>repmgr.conf</filename>.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
For more details on this parameter, see:
|
|
||||||
<ulink url="https://www.postgresql.org/docs/current/runtime-config-replication.html#GUC-RECOVERY-MIN-APPLY-DELAY">recovery_min_apply_delay</ulink>.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
</varlistentry>
|
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><option>-R, --remote-user=USERNAME</option></term>
|
<term><option>-R, --remote-user=USERNAME</option></term>
|
||||||
<listitem>
|
<listitem>
|
||||||
@@ -378,14 +317,14 @@ pg_basebackup_options='--waldir=/path/to/wal-directory'</programlisting>
|
|||||||
<para>
|
<para>
|
||||||
Create recovery configuration for a previously cloned instance.
|
Create recovery configuration for a previously cloned instance.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
|
||||||
In PostgreSQL 12 and later, the replication configuration will be
|
|
||||||
written to <filename>postgresql.auto.conf</filename>.
|
|
||||||
</para>
|
|
||||||
<para>
|
<para>
|
||||||
In PostgreSQL 11 and earlier, the replication configuration will be
|
In PostgreSQL 11 and earlier, the replication configuration will be
|
||||||
written to <filename>recovery.conf</filename>.
|
written to <filename>recovery.conf</filename>.
|
||||||
</para>
|
</para>
|
||||||
|
<para>
|
||||||
|
In PostgreSQL 12 and later, the replication configuration will be
|
||||||
|
written to <filename>postgresql.auto.conf</filename>.
|
||||||
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
@@ -431,23 +370,6 @@ pg_basebackup_options='--waldir=/path/to/wal-directory'</programlisting>
|
|||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
|
||||||
<term><option>--verify-backup</option></term>
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
<!-- update link after Pg13 release -->
|
|
||||||
Verify a cloned node using the
|
|
||||||
<ulink url="https://www.postgresql.org/docs/13/app-pgverifybackup.html">pg_verifybackup</ulink>
|
|
||||||
utility (PostgreSQL 13 and later).
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
This option can currently only be used when cloning directly from an upstream
|
|
||||||
node.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
</varlistentry>
|
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><option>--without-barman </option></term>
|
<term><option>--without-barman </option></term>
|
||||||
<listitem>
|
<listitem>
|
||||||
|
|||||||
@@ -47,15 +47,7 @@
|
|||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
In PostgreSQL 12 and earlier, this command will force a restart of PostgreSQL on the standby node.
|
This command will force a restart of PostgreSQL on the standby node.
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
In PostgreSQL 13 and later, by default this command will signal PostgreSQL to reload its
|
|
||||||
configuration, which will cause PostgreSQL to follow the new upstream without
|
|
||||||
a restart. If this behaviour is not desired for whatever reason, the configuration
|
|
||||||
file parameter <varname>standby_follow_restart</varname> can be set <literal>true</literal>
|
|
||||||
to always force a restart.
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
|
|||||||
@@ -66,10 +66,10 @@
|
|||||||
Both values can be defined in <filename>repmgr.conf</filename>.
|
Both values can be defined in <filename>repmgr.conf</filename>.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<warning>
|
<note>
|
||||||
<para>
|
<para>
|
||||||
In PostgreSQL 12 and earlier, if WAL replay is paused on the standby, and not all
|
If WAL replay is paused on the standby, and not all WAL files on the standby have been
|
||||||
WAL files on the standby have been replayed, &repmgr; will not attempt to promote it.
|
replayed, &repmgr; will not attempt to promote it.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
This is because if WAL replay is paused, PostgreSQL itself will not react to a promote command
|
This is because if WAL replay is paused, PostgreSQL itself will not react to a promote command
|
||||||
@@ -81,10 +81,7 @@
|
|||||||
Note that if the standby is in archive recovery, &repmgr; will not be able to determine
|
Note that if the standby is in archive recovery, &repmgr; will not be able to determine
|
||||||
if more WAL is pending replay, and will abort the promotion attempt if WAL replay is paused.
|
if more WAL is pending replay, and will abort the promotion attempt if WAL replay is paused.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
</note>
|
||||||
This restriction does <emphasis>not</emphasis> apply to PostgreSQL 13 and later.
|
|
||||||
</para>
|
|
||||||
</warning>
|
|
||||||
|
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
@@ -98,6 +95,7 @@
|
|||||||
NOTICE: promoting standby to primary
|
NOTICE: promoting standby to primary
|
||||||
DETAIL: promoting server "node2" (ID: 2) using "pg_ctl -l /var/log/postgres/startup.log -w -D '/var/lib/postgres/data' promote"
|
DETAIL: promoting server "node2" (ID: 2) using "pg_ctl -l /var/log/postgres/startup.log -w -D '/var/lib/postgres/data' promote"
|
||||||
server promoting
|
server promoting
|
||||||
|
DEBUG: setting node 2 as primary and marking existing primary as failed
|
||||||
NOTICE: STANDBY PROMOTE successful
|
NOTICE: STANDBY PROMOTE successful
|
||||||
DETAIL: server "node2" (ID: 2) was successfully promoted to primary</programlisting>
|
DETAIL: server "node2" (ID: 2) was successfully promoted to primary</programlisting>
|
||||||
</para>
|
</para>
|
||||||
@@ -172,42 +170,6 @@
|
|||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
|
||||||
<term><option>-F</option></term>
|
|
||||||
<term><option>--force</option></term>
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
Ignore warnings and continue anyway.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
This option is relevant in the following situations if <option>--siblings-follow</option> was specified:
|
|
||||||
<itemizedlist spacing="compact" mark="bullet">
|
|
||||||
<listitem>
|
|
||||||
<simpara>
|
|
||||||
If one or more sibling nodes was not reachable via SSH, the standby will be promoted anyway.
|
|
||||||
</simpara>
|
|
||||||
</listitem>
|
|
||||||
<listitem>
|
|
||||||
<simpara>
|
|
||||||
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 accommodate the standbys which will be attached to it, the standby will be promoted anyway.
|
|
||||||
</simpara>
|
|
||||||
</listitem>
|
|
||||||
</itemizedlist>
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
Note that if the <option>-F</option>/<option>--force</option> option is used when any of the above
|
|
||||||
situations is encountered, the onus is on the user to manually resolve any resulting issues.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
</varlistentry>
|
|
||||||
|
|
||||||
</variablelist>
|
</variablelist>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
|
|||||||
@@ -147,7 +147,7 @@
|
|||||||
<para>
|
<para>
|
||||||
Use <application>pg_rewind</application> to reintegrate the old primary if necessary
|
Use <application>pg_rewind</application> to reintegrate the old primary if necessary
|
||||||
(and the prerequisites for using <application>pg_rewind</application> are met).
|
(and the prerequisites for using <application>pg_rewind</application> are met).
|
||||||
If using PostgreSQL 9.4, and the <application>pg_rewind</application>
|
If using PostgreSQL 9.3 or 9.4, and the <application>pg_rewind</application>
|
||||||
binary is not installed in the PostgreSQL <filename>bin</filename> directory,
|
binary is not installed in the PostgreSQL <filename>bin</filename> directory,
|
||||||
provide its full path. For more details see also <xref linkend="switchover-pg-rewind"/>.
|
provide its full path. For more details see also <xref linkend="switchover-pg-rewind"/>.
|
||||||
</para>
|
</para>
|
||||||
|
|||||||
@@ -63,34 +63,6 @@
|
|||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<refsect1>
|
|
||||||
|
|
||||||
<title>Options</title>
|
|
||||||
<variablelist>
|
|
||||||
|
|
||||||
<varlistentry>
|
|
||||||
<term><option>--dry-run</option></term>
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
Check prerequisites but don't actually register the witness
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
</varlistentry>
|
|
||||||
|
|
||||||
|
|
||||||
<varlistentry>
|
|
||||||
<term><option>-F</option>/<option>--force</option></term>
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
Overwrite an existing node record
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
</varlistentry>
|
|
||||||
|
|
||||||
</variablelist>
|
|
||||||
</refsect1>
|
|
||||||
|
|
||||||
<refsect1 id="repmgr-witness-register-events">
|
<refsect1 id="repmgr-witness-register-events">
|
||||||
<title>Event notifications</title>
|
<title>Event notifications</title>
|
||||||
<para>
|
<para>
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
<title>repmgr &repmgrversion; Documentation</title>
|
<title>repmgr &repmgrversion; Documentation</title>
|
||||||
|
|
||||||
<bookinfo>
|
<bookinfo>
|
||||||
<corpauthor>EnterpriseDB Corporation</corpauthor>
|
<corpauthor>2ndQuadrant Ltd</corpauthor>
|
||||||
<productname>repmgr</productname>
|
<productname>repmgr</productname>
|
||||||
<productnumber>&repmgrversion;</productnumber>
|
<productnumber>&repmgrversion;</productnumber>
|
||||||
&legal;
|
&legal;
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
<abstract>
|
<abstract>
|
||||||
<para>
|
<para>
|
||||||
This is the official documentation of &repmgr; &repmgrversion; for
|
This is the official documentation of &repmgr; &repmgrversion; for
|
||||||
use with PostgreSQL 9.4 - PostgreSQL 13.
|
use with PostgreSQL 9.3 - PostgreSQL 12.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
&repmgr; is being continually developed and we strongly recommend using the
|
&repmgr; is being continually developed and we strongly recommend using the
|
||||||
@@ -38,20 +38,20 @@
|
|||||||
|
|
||||||
<para>
|
<para>
|
||||||
&repmgr; is developed by
|
&repmgr; is developed by
|
||||||
<ulink url="https://2ndquadrant.com">2ndQuadrant (EDB)</ulink>
|
<ulink url="https://2ndquadrant.com">2ndQuadrant</ulink>
|
||||||
along with contributions from other individuals and organisations.
|
along with contributions from other individuals and organisations.
|
||||||
Contributions from the community are appreciated and welcome - get
|
Contributions from the community are appreciated and welcome - get
|
||||||
in touch via <ulink url="https://github.com/EnterpriseDB/repmgr">github</ulink>
|
in touch via <ulink url="https://github.com/2ndQuadrant/repmgr">github</ulink>
|
||||||
or <ulink url="https://groups.google.com/group/repmgr">the mailing list/forum</ulink>.
|
or <ulink url="https://groups.google.com/group/repmgr">the mailing list/forum</ulink>.
|
||||||
Multiple 2ndQuadrant (EDB) customers contribute funding
|
Multiple 2ndQuadrant customers contribute funding
|
||||||
to make repmgr development possible.
|
to make repmgr development possible.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
&repmgr; is fully supported by 2ndQuadrant (EDB)'s
|
&repmgr; is fully supported by 2ndQuadrant's
|
||||||
<ulink url="https://www.2ndquadrant.com/en/support/support-postgresql/">24/7 Production Support</ulink>.
|
<ulink url="https://www.2ndquadrant.com/en/support/support-postgresql/">24/7 Production Support</ulink>.
|
||||||
EnterpriseDB Corporation, a Major Sponsor of the PostgreSQL project, continues to maintain &repmgr;.
|
2ndQuadrant, a Major Sponsor of the PostgreSQL project, continues to develop and maintain &repmgr;.
|
||||||
We welcome participation from other organisations and individual developers.
|
Other organisations as well as individual developers are welcome to participate in the efforts.
|
||||||
</para>
|
</para>
|
||||||
</abstract>
|
</abstract>
|
||||||
|
|
||||||
|
|||||||
@@ -331,12 +331,11 @@
|
|||||||
To use this, <option>failover_validation_command</option> in <filename>repmgr.conf</filename>
|
To use this, <option>failover_validation_command</option> in <filename>repmgr.conf</filename>
|
||||||
to a script executable by the <literal>postgres</literal> system user, e.g.:
|
to a script executable by the <literal>postgres</literal> system user, e.g.:
|
||||||
<programlisting>
|
<programlisting>
|
||||||
failover_validation_command=/path/to/script.sh %n</programlisting>
|
failover_validation_command=/path/to/script.sh %n %a</programlisting>
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
The <literal>%n</literal> parameter will be replaced with the node ID when the script is
|
The <literal>%n</literal> parameter will be replaced with the node ID, and the
|
||||||
executed. A number of other parameters are also available, see section
|
<literal>%a</literal> parameter will be replaced by the node name when the script is executed.
|
||||||
"<xref linkend="repmgrd-automatic-failover-configuration-optional"/>" for details.
|
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
This script must return an exit code of <literal>0</literal> to indicate the node should promote itself.
|
This script must return an exit code of <literal>0</literal> to indicate the node should promote itself.
|
||||||
@@ -586,7 +585,7 @@ INFO: node 3 received notification to rerun promotion candidate election
|
|||||||
<sect2 id="repmgrd-primary-child-disconnection-caveats">
|
<sect2 id="repmgrd-primary-child-disconnection-caveats">
|
||||||
<title>Standby disconnections monitoring caveats</title>
|
<title>Standby disconnections monitoring caveats</title>
|
||||||
<para>
|
<para>
|
||||||
The following caveats should be considered if you are intending to use this functionality.
|
The follwing caveats should be considered if you are intending to use this functionality.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
<itemizedlist mark="bullet">
|
<itemizedlist mark="bullet">
|
||||||
|
|||||||
@@ -15,13 +15,9 @@
|
|||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
&repmgrd; can be configured to provide failover
|
&repmgrd; can be configured to provide failover
|
||||||
capability in case the primary or upstream node becomes unreachable, and/or
|
capability in case the primary upstream node becomes unreachable, and/or
|
||||||
provide monitoring data to the &repmgr; metadatabase.
|
provide monitoring data to the &repmgr; metadatabase.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
|
||||||
From &repmgr; 4.4, when running on the primary node, &repmgrd; can also monitor
|
|
||||||
standby disconnections/reconnections (see <xref linkend="repmgrd-primary-child-disconnection"/>).
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<sect1 id="repmgrd-basic-configuration">
|
<sect1 id="repmgrd-basic-configuration">
|
||||||
<title>repmgrd configuration</title>
|
<title>repmgrd configuration</title>
|
||||||
@@ -89,10 +85,6 @@
|
|||||||
<literal>query</literal> - determines server availability
|
<literal>query</literal> - determines server availability
|
||||||
by executing an SQL statement on the node via the existing connection
|
by executing an SQL statement on the node via the existing connection
|
||||||
</simpara>
|
</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>
|
</listitem>
|
||||||
|
|
||||||
</itemizedlist>
|
</itemizedlist>
|
||||||
@@ -156,7 +148,7 @@
|
|||||||
</variablelist>
|
</variablelist>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
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.
|
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.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<sect2 id="repmgrd-automatic-failover-configuration">
|
<sect2 id="repmgrd-automatic-failover-configuration">
|
||||||
@@ -329,11 +321,11 @@
|
|||||||
|
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
<sect2 id="repmgrd-automatic-failover-configuration-optional" xreflabel="Optional configuration for automatic failover">
|
<sect2 id="repmgrd-automatic-failover-configuration-optional">
|
||||||
<title>Optional configuration for automatic failover</title>
|
<title>Optional configuration for automatic failover</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
The following configuraton options can be used to fine-tune automatic failover:
|
The following configuraton options can be use to fine-tune automatic failover:
|
||||||
</para>
|
</para>
|
||||||
<variablelist>
|
<variablelist>
|
||||||
|
|
||||||
@@ -374,8 +366,8 @@
|
|||||||
</para>
|
</para>
|
||||||
</note>
|
</note>
|
||||||
<para>
|
<para>
|
||||||
One or more of the following parameter placeholders
|
One or both of the following parameter placeholders
|
||||||
may be provided, which will be replaced by repmgrd with the appropriate
|
should be provided, which will be replaced by repmgrd with the appropriate
|
||||||
value:
|
value:
|
||||||
<itemizedlist spacing="compact" mark="bullet">
|
<itemizedlist spacing="compact" mark="bullet">
|
||||||
<listitem>
|
<listitem>
|
||||||
@@ -384,15 +376,6 @@
|
|||||||
<listitem>
|
<listitem>
|
||||||
<simpara><literal>%a</literal>: node name</simpara>
|
<simpara><literal>%a</literal>: node name</simpara>
|
||||||
</listitem>
|
</listitem>
|
||||||
<listitem>
|
|
||||||
<simpara><literal>%v</literal>: number of visible nodes</simpara>
|
|
||||||
</listitem>
|
|
||||||
<listitem>
|
|
||||||
<simpara><literal>%u</literal>: number of shared upstream nodes</simpara>
|
|
||||||
</listitem>
|
|
||||||
<listitem>
|
|
||||||
<simpara><literal>%t</literal>: total number of nodes</simpara>
|
|
||||||
</listitem>
|
|
||||||
</itemizedlist>
|
</itemizedlist>
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
@@ -423,33 +406,6 @@
|
|||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
|
||||||
<term><option>always_promote</option></term>
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<indexterm>
|
|
||||||
<primary>always_promote</primary>
|
|
||||||
</indexterm>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
Default: <literal>false</literal>.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
If <literal>true</literal>, promote the local node even if its
|
|
||||||
&repmgr; metadata is not up-to-date.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
Normally &repmgr; expects its metadata (stored in the <varname>repmgr.nodes</varname>
|
|
||||||
table) to be up-to-date so &repmgrd; can take the correct action during a failover.
|
|
||||||
However it's possible that updates made on the primary may not
|
|
||||||
have propagated to the standby (promotion candidate). In this case &repmgrd; will
|
|
||||||
default to not promoting the standby. This behaviour can be overridden by setting
|
|
||||||
<option>always_promote</option> to <literal>true</literal>.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
</varlistentry>
|
|
||||||
|
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
|
|
||||||
<term><option>standby_disconnect_on_failover</option></term>
|
<term><option>standby_disconnect_on_failover</option></term>
|
||||||
@@ -543,7 +499,7 @@
|
|||||||
</indexterm>
|
</indexterm>
|
||||||
<para>
|
<para>
|
||||||
For further details and a reference implementation, see the separate document
|
For further details and a reference implementation, see the separate document
|
||||||
<ulink url="https://github.com/EnterpriseDB/repmgr/blob/master/doc/repmgrd-node-fencing.md">Fencing a failed master node with repmgrd and PgBouncer</ulink>.
|
<ulink url="https://github.com/2ndQuadrant/repmgr/blob/master/doc/repmgrd-node-fencing.md">Fencing a failed master node with repmgrd and PgBouncer</ulink>.
|
||||||
</para>
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
@@ -627,8 +583,7 @@ repmgrd_service_stop_command='sudo systemctl repmgr12 stop'
|
|||||||
the option <option>monitor_interval_secs</option> (see above).
|
the option <option>monitor_interval_secs</option> (see above).
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
For more details on monitoring, see <xref linkend="repmgrd-monitoring"/>. For information on
|
For more details on monitoring, see <xref linkend="repmgrd-monitoring"/>.
|
||||||
monitoring standby disconnections, see <xref linkend="repmgrd-primary-child-disconnection"/>.
|
|
||||||
</para>
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
@@ -796,12 +751,6 @@ repmgrd_service_stop_command='sudo systemctl repmgr12 stop'
|
|||||||
</simpara>
|
</simpara>
|
||||||
</listitem>
|
</listitem>
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<simpara>
|
|
||||||
<varname>always_promote</varname>
|
|
||||||
</simpara>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
<listitem>
|
<listitem>
|
||||||
<simpara>
|
<simpara>
|
||||||
<varname>promote_command</varname>
|
<varname>promote_command</varname>
|
||||||
@@ -973,7 +922,7 @@ repmgrd_service_stop_command='sudo systemctl repmgr12 stop'
|
|||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
If none of the above apply, &repmgrd; will create a PID file
|
If none of the above apply, &repmgrd; will create a PID file
|
||||||
in the operating system's temporary directory (as determined by the environment variable
|
in the operating system's temporary directory (as setermined by the environment variable
|
||||||
<varname>TMPDIR</varname>, or if that is not set, will use <filename>/tmp</filename>).
|
<varname>TMPDIR</varname>, or if that is not set, will use <filename>/tmp</filename>).
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
|
|||||||
@@ -137,7 +137,7 @@ NOTICE: node 3 (node3) paused</programlisting>
|
|||||||
If the primary becomes available again (e.g. following a software upgrade), &repmgrd;
|
If the primary becomes available again (e.g. following a software upgrade), &repmgrd;
|
||||||
will automatically reconnect, e.g.:
|
will automatically reconnect, e.g.:
|
||||||
<programlisting>
|
<programlisting>
|
||||||
[2019-08-28 12:25:41] [NOTICE] reconnected to upstream node "node1" (ID: 1) after 8 seconds, resuming monitoring</programlisting>
|
[2019-08-28 12:25:41] [NOTICE] reconnected to upstream node 1 after 8 seconds, resuming monitoring</programlisting>
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
@@ -295,7 +295,7 @@ NOTICE: node 3 (node3) unpaused</programlisting>
|
|||||||
[2017-08-29 10:59:37] [HINT] use "repmgr standby promote" to manually promote this node
|
[2017-08-29 10:59:37] [HINT] use "repmgr standby promote" to manually promote this node
|
||||||
[2017-08-29 10:59:37] [INFO] node "node2" (ID: 2) monitoring upstream node "node1" (ID: 1) in degraded state (automatic failover disabled)
|
[2017-08-29 10:59:37] [INFO] node "node2" (ID: 2) monitoring upstream node "node1" (ID: 1) in degraded state (automatic failover disabled)
|
||||||
[2017-08-29 10:59:53] [INFO] node "node2" (ID: 2) monitoring upstream node "node1" (ID: 1) in degraded state (automatic failover disabled)
|
[2017-08-29 10:59:53] [INFO] node "node2" (ID: 2) monitoring upstream node "node1" (ID: 1) in degraded state (automatic failover disabled)
|
||||||
[2017-08-29 11:00:45] [NOTICE] reconnected to upstream node "node1" (ID: 1) after 68 seconds, resuming monitoring
|
[2017-08-29 11:00:45] [NOTICE] reconnected to upstream node 1 after 68 seconds, resuming monitoring
|
||||||
[2017-08-29 11:00:57] [INFO] node "node2" (ID: 2) monitoring upstream node "node1" (ID: 1) in normal state (automatic failover disabled)</programlisting>
|
[2017-08-29 11:00:57] [INFO] node "node2" (ID: 2) monitoring upstream node "node1" (ID: 1) in normal state (automatic failover disabled)</programlisting>
|
||||||
|
|
||||||
</para>
|
</para>
|
||||||
|
|||||||
@@ -120,19 +120,16 @@
|
|||||||
</important>
|
</important>
|
||||||
|
|
||||||
<note>
|
<note>
|
||||||
<para>
|
<simpara>
|
||||||
On <literal>systemd</literal> systems we strongly recommend using the appropriate
|
On <literal>systemd</literal> systems we strongly recommend using the appropriate
|
||||||
<command>systemctl</command> commands (typically run via <command>sudo</command>) to ensure
|
<command>systemctl</command> commands (typically run via <command>sudo</command>) to ensure
|
||||||
<literal>systemd</literal> is informed about the status of the PostgreSQL service.
|
<literal>systemd</literal> is informed about the status of the PostgreSQL service.
|
||||||
</para>
|
</simpara>
|
||||||
<para>
|
<simpara>
|
||||||
If using <command>sudo</command> for the <command>systemctl</command> calls, make sure the
|
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
|
<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.
|
this way, <command>repmgr</command> will fail to stop the primary.
|
||||||
</para>
|
</simpara>
|
||||||
<para>
|
|
||||||
See the <xref linkend="configuration-file-service-commands"/> documentation section for further details.
|
|
||||||
</para>
|
|
||||||
</note>
|
</note>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
@@ -247,15 +244,16 @@
|
|||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
<application>pg_rewind</application> has been part of the core PostgreSQL distribution since
|
<application>pg_rewind</application> has been part of the core PostgreSQL distribution since
|
||||||
version 9.5. Users of PostgreSQL 9.4 will need to manually install it; the source code is available here:
|
version 9.5. Users of versions 9.3 and 9.4 will need to manually install it; the source code is available here:
|
||||||
<ulink url="https://github.com/vmware/pg_rewind">https://github.com/vmware/pg_rewind</ulink>.
|
<ulink url="https://github.com/vmware/pg_rewind">https://github.com/vmware/pg_rewind</ulink>.
|
||||||
If the <application>pg_rewind</application>
|
If the <application>pg_rewind</application>
|
||||||
binary is not installed in the PostgreSQL <filename>bin</filename> directory, provide
|
binary is not installed in the PostgreSQL <filename>bin</filename> directory, provide
|
||||||
its full path on the demotion candidate with <option>--force-rewind</option>.
|
its full path on the demotion candidate with <option>--force-rewind</option>.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
Note that building the 9.4 version of <application>pg_rewind</application> requires the PostgreSQL
|
Note that building the 9.3/9.4 version of <application>pg_rewind</application> requires the PostgreSQL
|
||||||
source code.
|
source code. Also, PostgreSQL 9.3 does not provide <varname>wal_log_hints</varname>,
|
||||||
|
meaning data checksums must have been enabled when the database was initialized.
|
||||||
</para>
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
@@ -345,7 +343,7 @@
|
|||||||
<itemizedlist spacing="compact" mark="bullet">
|
<itemizedlist spacing="compact" mark="bullet">
|
||||||
<listitem>
|
<listitem>
|
||||||
<simpara>
|
<simpara>
|
||||||
If using PostgreSQL 9.4, you should ensure that the shutdown command
|
If using PostgreSQL 9.3 or 9.4, you should ensure that the shutdown command
|
||||||
is configured to use PostgreSQL's <varname>fast</varname> shutdown mode (the default in 9.5
|
is configured to use PostgreSQL's <varname>fast</varname> shutdown mode (the default in 9.5
|
||||||
and later). If relying on <command>pg_ctl</command> to perform database server operations,
|
and later). If relying on <command>pg_ctl</command> to perform database server operations,
|
||||||
you should include <literal>-m fast</literal> in <varname>pg_ctl_options</varname>
|
you should include <literal>-m fast</literal> in <varname>pg_ctl_options</varname>
|
||||||
|
|||||||
@@ -201,13 +201,9 @@ ALTER EXTENSION repmgr UPDATE</programlisting>
|
|||||||
</para>
|
</para>
|
||||||
<tip>
|
<tip>
|
||||||
<para>
|
<para>
|
||||||
If the &repmgr; upgrade requires a PostgreSQL restart, combine the &repmgr; upgrade
|
If the &repmgr; upgrade requires a PostgreSQL restart, combine the &repmgr; upgrade
|
||||||
with a PostgreSQL minor version upgrade, which will require a restart in any case.
|
with a PostgreSQL minor version upgrade, which will require a restart in any case.
|
||||||
</para>
|
New PostgreSQL minor version are usually released every couple of months.
|
||||||
<para>
|
|
||||||
New PostgreSQL minor versions are usually released every couple of months;
|
|
||||||
see the <ulink url="https://www.postgresql.org/developer/roadmap/">Roadmap</ulink>
|
|
||||||
for the current schedule.
|
|
||||||
</para>
|
</para>
|
||||||
</tip>
|
</tip>
|
||||||
</sect2>
|
</sect2>
|
||||||
@@ -312,12 +308,12 @@ ALTER EXTENSION repmgr UPDATE</programlisting>
|
|||||||
<orderedlist>
|
<orderedlist>
|
||||||
<listitem>
|
<listitem>
|
||||||
<simpara>
|
<simpara>
|
||||||
converting the <filename>repmgr.conf</filename> configuration files
|
converting the repmgr.conf configuration files
|
||||||
</simpara>
|
</simpara>
|
||||||
</listitem>
|
</listitem>
|
||||||
<listitem>
|
<listitem>
|
||||||
<simpara>
|
<simpara>
|
||||||
upgrading the repmgr schema using <command>CREATE EXTENSION</command> (PostgreSQL 12 and earlier)
|
upgrading the repmgr schema using <command>CREATE EXTENSION</command>
|
||||||
</simpara>
|
</simpara>
|
||||||
</listitem>
|
</listitem>
|
||||||
</orderedlist>
|
</orderedlist>
|
||||||
@@ -461,31 +457,22 @@ ALTER EXTENSION repmgr UPDATE</programlisting>
|
|||||||
<para>
|
<para>
|
||||||
Please note that the the conversion script will add an empty
|
Please note that the the conversion script will add an empty
|
||||||
placeholder parameter for <varname>data_directory</varname>, which
|
placeholder parameter for <varname>data_directory</varname>, which
|
||||||
is a required parameter from &repmgr; 4. This must be manually modified to contain
|
is a required parameter from &repmgr; 4.
|
||||||
the correct data directory.
|
|
||||||
</para>
|
</para>
|
||||||
</sect3>
|
</sect3>
|
||||||
</sect2>
|
</sect2>
|
||||||
<sect2>
|
<sect2>
|
||||||
<title>Upgrading the repmgr schema (PostgreSQL 12 and earlier)</title>
|
<title>Upgrading the repmgr schema</title>
|
||||||
<para>
|
<para>
|
||||||
Ensure &repmgrd; is not running, or any cron jobs which execute the
|
Ensure &repmgrd; is not running, or any cron jobs which execute the
|
||||||
<command>repmgr</command> binary.
|
<command>repmgr</command> binary.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
Install the latest &repmgr; package; any <literal>repmgr 3.x</literal> packages
|
Install <literal>repmgr 4</literal> packages; any <literal>repmgr 3.x</literal> packages
|
||||||
should be uninstalled (if not automatically uninstalled already by your packaging system).
|
should be uninstalled (if not automatically uninstalled already by your packaging system).
|
||||||
</para>
|
</para>
|
||||||
<sect3>
|
<sect3>
|
||||||
<title>Upgrading from repmgr 3.1.1 or earlier</title>
|
<title>Upgrading from repmgr 3.1.1 or earlier</title>
|
||||||
<tip>
|
|
||||||
<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 following steps can be skipped; proceed to <xref linkend="upgrade-reregister-nodes"/>.
|
|
||||||
</simpara>
|
|
||||||
</tip>
|
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
If your repmgr version is 3.1.1 or earlier, you will need to update
|
If your repmgr version is 3.1.1 or earlier, you will need to update
|
||||||
the schema to the latest version in the 3.x series (3.3.2) before
|
the schema to the latest version in the 3.x series (3.3.2) before
|
||||||
@@ -497,10 +484,10 @@ ALTER EXTENSION repmgr UPDATE</programlisting>
|
|||||||
<itemizedlist spacing="compact" mark="bullet">
|
<itemizedlist spacing="compact" mark="bullet">
|
||||||
<listitem>
|
<listitem>
|
||||||
<simpara>
|
<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>
|
<ulink url="https://raw.githubusercontent.com/2ndQuadrant/repmgr/REL3_3_STABLE/sql/repmgr3.0_repmgr3.1.sql">repmgr3.0_repmgr3.1.sql</ulink></simpara>
|
||||||
</listitem>
|
</listitem>
|
||||||
<listitem>
|
<listitem>
|
||||||
<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>
|
<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>
|
||||||
</listitem>
|
</listitem>
|
||||||
</itemizedlist>
|
</itemizedlist>
|
||||||
</para>
|
</para>
|
||||||
@@ -514,37 +501,19 @@ ALTER EXTENSION repmgr UPDATE</programlisting>
|
|||||||
<para>
|
<para>
|
||||||
In the database used by the existing &repmgr; installation, execute:
|
In the database used by the existing &repmgr; installation, execute:
|
||||||
<programlisting>
|
<programlisting>
|
||||||
CREATE EXTENSION repmgr FROM unpackaged</programlisting>
|
CREATE EXTENSION repmgr FROM unpackaged;</programlisting>
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
This will move and convert all objects from the existing schema
|
This will move and convert all objects from the existing schema
|
||||||
into the new, standard <literal>repmgr</literal> schema.
|
into the new, standard <literal>repmgr</literal> schema.
|
||||||
</para>
|
</para>
|
||||||
<note>
|
<note>
|
||||||
<simpara>There must be only one schema matching <literal>repmgr_%</literal> in the
|
<simpara>there must be only one schema matching <literal>repmgr_%</literal> in the
|
||||||
database, otherwise this step may not work.
|
database, otherwise this step may not work.
|
||||||
</simpara>
|
</simpara>
|
||||||
</note>
|
</note>
|
||||||
</sect3>
|
</sect3>
|
||||||
</sect2>
|
<sect3>
|
||||||
|
|
||||||
<sect2>
|
|
||||||
<title>Upgrading the repmgr schema (PostgreSQL 13 and later)</title>
|
|
||||||
<para>
|
|
||||||
Beginning with PostgreSQL 13, the <command>CREATE EXTENSION ... FROM unpackaged</command>
|
|
||||||
syntax is no longer available. In the unlikely event you have ended up with an
|
|
||||||
installation running PostgreSQL 13 or later and containing the legacy &repmgr;
|
|
||||||
schema, there is no convenient way of upgrading this; instead you'll just need
|
|
||||||
to re-register the nodes as detailed in <link linkend="upgrade-reregister-nodes">the following section</link>,
|
|
||||||
which will create the &repmgr; extension automatically.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
Any historical data you wish to retain (e.g. the contents of the <structname>events</structname>
|
|
||||||
and <structname>monitoring</structname> tables) will need to be exported manually.
|
|
||||||
</para>
|
|
||||||
</sect2>
|
|
||||||
<sect2 id="upgrade-reregister-nodes">
|
|
||||||
<title>Re-register each node</title>
|
<title>Re-register each node</title>
|
||||||
<para>
|
<para>
|
||||||
This is necessary to update the <literal>repmgr</literal> metadata with some additional items.
|
This is necessary to update the <literal>repmgr</literal> metadata with some additional items.
|
||||||
@@ -554,10 +523,6 @@ ALTER EXTENSION repmgr UPDATE</programlisting>
|
|||||||
<programlisting>
|
<programlisting>
|
||||||
repmgr primary register -f /etc/repmgr.conf --force</programlisting>
|
repmgr primary register -f /etc/repmgr.conf --force</programlisting>
|
||||||
</para>
|
</para>
|
||||||
<para>
|
|
||||||
If not already present (e.g. after executing <command>CREATE EXTENSION repmgr FROM unpackaged</command>),
|
|
||||||
the &repmgr; extension will be automatically created by <command>repmgr primary register</command>.
|
|
||||||
</para>
|
|
||||||
<para>
|
<para>
|
||||||
On each standby node, execute e.g.
|
On each standby node, execute e.g.
|
||||||
<programlisting>
|
<programlisting>
|
||||||
@@ -570,20 +535,18 @@ ALTER EXTENSION repmgr UPDATE</programlisting>
|
|||||||
<para>
|
<para>
|
||||||
The original <literal>repmgr_$cluster</literal> schema can be dropped at any time.
|
The original <literal>repmgr_$cluster</literal> schema can be dropped at any time.
|
||||||
</para>
|
</para>
|
||||||
|
<tip>
|
||||||
|
<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 manual <command>CREATE EXTENSION</command> step can be skipped; just re-register
|
||||||
|
each node, starting with the primary node, and the <literal>repmgr</literal> extension will be
|
||||||
|
automatically created.
|
||||||
|
</simpara>
|
||||||
|
</tip>
|
||||||
|
</sect3>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
<sect2 id="upgrade-drop-repmgr-cluster-schema">
|
|
||||||
<title>Drop the legacy repmgr schema</title>
|
|
||||||
<para>
|
|
||||||
Once the cluster has been registered with the current &repmgr; version, the legacy
|
|
||||||
<literal>repmgr_$cluster</literal> schema can be dropped at any time with:
|
|
||||||
<programlisting>
|
|
||||||
DROP SCHEMA repmgr_$cluster CASCADE</programlisting>
|
|
||||||
(substitute <literal>$cluster</literal> with the value of the <varname>clustername</varname>
|
|
||||||
variable used in &repmgr; 3.x).
|
|
||||||
</para>
|
|
||||||
</sect2>
|
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
</chapter>
|
</chapter>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* errcode.h
|
* errcode.h
|
||||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
2
log.c
2
log.c
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* log.c - Logging methods
|
* log.c - Logging methods
|
||||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
2
log.h
2
log.h
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* log.h
|
* log.h
|
||||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
|
|
||||||
\echo Use "CREATE EXTENSION repmgr" to load this file. \quit
|
|
||||||
|
|
||||||
SELECT pg_catalog.pg_extension_config_dump('repmgr.nodes', '');
|
|
||||||
SELECT pg_catalog.pg_extension_config_dump('repmgr.events', '');
|
|
||||||
SELECT pg_catalog.pg_extension_config_dump('repmgr.monitoring_history', '');
|
|
||||||
|
|
||||||
192
repmgr--5.2.sql
192
repmgr--5.2.sql
@@ -1,192 +0,0 @@
|
|||||||
-- 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', 'set_local_node_id'
|
|
||||||
LANGUAGE C STRICT;
|
|
||||||
|
|
||||||
CREATE FUNCTION get_local_node_id()
|
|
||||||
RETURNS INT
|
|
||||||
AS 'MODULE_PATHNAME', 'get_local_node_id'
|
|
||||||
LANGUAGE C STRICT;
|
|
||||||
|
|
||||||
CREATE FUNCTION standby_set_last_updated()
|
|
||||||
RETURNS TIMESTAMP WITH TIME ZONE
|
|
||||||
AS 'MODULE_PATHNAME', 'standby_set_last_updated'
|
|
||||||
LANGUAGE C STRICT;
|
|
||||||
|
|
||||||
CREATE FUNCTION standby_get_last_updated()
|
|
||||||
RETURNS TIMESTAMP WITH TIME ZONE
|
|
||||||
AS 'MODULE_PATHNAME', 'standby_get_last_updated'
|
|
||||||
LANGUAGE C STRICT;
|
|
||||||
|
|
||||||
CREATE FUNCTION set_upstream_last_seen(INT)
|
|
||||||
RETURNS VOID
|
|
||||||
AS 'MODULE_PATHNAME', 'set_upstream_last_seen'
|
|
||||||
LANGUAGE C STRICT;
|
|
||||||
|
|
||||||
CREATE FUNCTION get_upstream_last_seen()
|
|
||||||
RETURNS INT
|
|
||||||
AS 'MODULE_PATHNAME', 'get_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;
|
|
||||||
|
|
||||||
/* failover functions */
|
|
||||||
|
|
||||||
CREATE FUNCTION notify_follow_primary(INT)
|
|
||||||
RETURNS VOID
|
|
||||||
AS 'MODULE_PATHNAME', 'notify_follow_primary'
|
|
||||||
LANGUAGE C STRICT;
|
|
||||||
|
|
||||||
CREATE FUNCTION get_new_primary()
|
|
||||||
RETURNS INT
|
|
||||||
AS 'MODULE_PATHNAME', 'get_new_primary'
|
|
||||||
LANGUAGE C STRICT;
|
|
||||||
|
|
||||||
CREATE FUNCTION reset_voting_status()
|
|
||||||
RETURNS VOID
|
|
||||||
AS 'MODULE_PATHNAME', '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', '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
|
|
||||||
);
|
|
||||||
|
|
||||||
@@ -1,245 +0,0 @@
|
|||||||
-- 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', 'set_local_node_id'
|
|
||||||
LANGUAGE C STRICT;
|
|
||||||
|
|
||||||
CREATE FUNCTION get_local_node_id()
|
|
||||||
RETURNS INT
|
|
||||||
AS 'MODULE_PATHNAME', 'get_local_node_id'
|
|
||||||
LANGUAGE C STRICT;
|
|
||||||
|
|
||||||
CREATE FUNCTION standby_set_last_updated()
|
|
||||||
RETURNS TIMESTAMP WITH TIME ZONE
|
|
||||||
AS 'MODULE_PATHNAME', 'standby_set_last_updated'
|
|
||||||
LANGUAGE C STRICT;
|
|
||||||
|
|
||||||
CREATE FUNCTION standby_get_last_updated()
|
|
||||||
RETURNS TIMESTAMP WITH TIME ZONE
|
|
||||||
AS 'MODULE_PATHNAME', 'standby_get_last_updated'
|
|
||||||
LANGUAGE C STRICT;
|
|
||||||
|
|
||||||
CREATE FUNCTION set_upstream_last_seen(INT)
|
|
||||||
RETURNS VOID
|
|
||||||
AS 'MODULE_PATHNAME', 'set_upstream_last_seen'
|
|
||||||
LANGUAGE C STRICT;
|
|
||||||
|
|
||||||
CREATE FUNCTION get_upstream_last_seen()
|
|
||||||
RETURNS INT
|
|
||||||
AS 'MODULE_PATHNAME', 'get_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;
|
|
||||||
|
|
||||||
/* failover functions */
|
|
||||||
|
|
||||||
CREATE FUNCTION notify_follow_primary(INT)
|
|
||||||
RETURNS VOID
|
|
||||||
AS 'MODULE_PATHNAME', 'notify_follow_primary'
|
|
||||||
LANGUAGE C STRICT;
|
|
||||||
|
|
||||||
CREATE FUNCTION get_new_primary()
|
|
||||||
RETURNS INT
|
|
||||||
AS 'MODULE_PATHNAME', 'get_new_primary'
|
|
||||||
LANGUAGE C STRICT;
|
|
||||||
|
|
||||||
CREATE FUNCTION reset_voting_status()
|
|
||||||
RETURNS VOID
|
|
||||||
AS 'MODULE_PATHNAME', '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', '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
|
* Implements cluster information actions for the repmgr command line utility
|
||||||
*
|
*
|
||||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -55,8 +55,10 @@ typedef enum
|
|||||||
struct ColHeader headers_show[SHOW_HEADER_COUNT];
|
struct ColHeader headers_show[SHOW_HEADER_COUNT];
|
||||||
struct ColHeader headers_event[EVENT_HEADER_COUNT];
|
struct ColHeader headers_event[EVENT_HEADER_COUNT];
|
||||||
|
|
||||||
static int build_cluster_matrix(t_node_matrix_rec ***matrix_rec_dest, ItemList *warnings, int *error_code);
|
|
||||||
static int build_cluster_crosscheck(t_node_status_cube ***cube_dest, ItemList *warnings, int *error_code);
|
|
||||||
|
static int build_cluster_matrix(t_node_matrix_rec ***matrix_rec_dest, int *name_length, ItemList *warnings, int *error_code);
|
||||||
|
static int build_cluster_crosscheck(t_node_status_cube ***cube_dest, int *name_length, ItemList *warnings, int *error_code);
|
||||||
static void cube_set_node_status(t_node_status_cube **cube, int n, int node_id, int matrix_node_id, int connection_node_id, int connection_status);
|
static void cube_set_node_status(t_node_status_cube **cube, int n, int node_id, int matrix_node_id, int connection_node_id, int connection_status);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -536,6 +538,9 @@ do_cluster_crosscheck(void)
|
|||||||
{
|
{
|
||||||
int i = 0,
|
int i = 0,
|
||||||
n = 0;
|
n = 0;
|
||||||
|
char c;
|
||||||
|
const char *node_header = "Name";
|
||||||
|
int name_length = strlen(node_header);
|
||||||
|
|
||||||
t_node_status_cube **cube;
|
t_node_status_cube **cube;
|
||||||
|
|
||||||
@@ -543,7 +548,7 @@ do_cluster_crosscheck(void)
|
|||||||
int error_code = SUCCESS;
|
int error_code = SUCCESS;
|
||||||
ItemList warnings = {NULL, NULL};
|
ItemList warnings = {NULL, NULL};
|
||||||
|
|
||||||
n = build_cluster_crosscheck(&cube, &warnings, &error_code);
|
n = build_cluster_crosscheck(&cube, &name_length, &warnings, &error_code);
|
||||||
|
|
||||||
if (runtime_options.output_mode == OM_CSV)
|
if (runtime_options.output_mode == OM_CSV)
|
||||||
{
|
{
|
||||||
@@ -577,56 +582,24 @@ do_cluster_crosscheck(void)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* output header contains node name, node ID and one column for each node in the cluster */
|
printf("%*s | Id ", name_length, node_header);
|
||||||
struct ColHeader *headers_crosscheck = NULL;
|
|
||||||
|
|
||||||
int header_count = n + 2;
|
|
||||||
int header_id = 2;
|
|
||||||
|
|
||||||
headers_crosscheck = palloc0(sizeof(ColHeader) * header_count);
|
|
||||||
|
|
||||||
/* Initialize column headers */
|
|
||||||
strncpy(headers_crosscheck[0].title, _("Name"), MAXLEN);
|
|
||||||
strncpy(headers_crosscheck[1].title, _("ID"), MAXLEN);
|
|
||||||
|
|
||||||
for (i = 0; i < n; i++)
|
for (i = 0; i < n; i++)
|
||||||
{
|
printf("| %2d ", cube[i]->node_id);
|
||||||
maxlen_snprintf(headers_crosscheck[header_id].title, "%i", cube[i]->node_id);
|
printf("\n");
|
||||||
header_id++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Initialize column max values */
|
|
||||||
for (i = 0; i < header_count; i++)
|
|
||||||
{
|
|
||||||
headers_crosscheck[i].display = true;
|
|
||||||
headers_crosscheck[i].max_length = strlen(headers_crosscheck[i].title);
|
|
||||||
headers_crosscheck[i].cur_length = headers_crosscheck[i].max_length;
|
|
||||||
|
|
||||||
/* We can derive the maximum node ID length for the ID column from
|
|
||||||
* the generated matrix node ID headers
|
|
||||||
*/
|
|
||||||
if (i >= 2 && headers_crosscheck[i].max_length > headers_crosscheck[1].max_length)
|
|
||||||
headers_crosscheck[1].max_length = headers_crosscheck[i].max_length;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
for (i = 0; i < name_length; i++)
|
||||||
|
printf("-");
|
||||||
|
printf("-+----");
|
||||||
for (i = 0; i < n; i++)
|
for (i = 0; i < n; i++)
|
||||||
{
|
printf("+----");
|
||||||
if (strlen(cube[i]->node_name) > headers_crosscheck[0].max_length)
|
printf("\n");
|
||||||
{
|
|
||||||
headers_crosscheck[0].max_length = strlen(cube[i]->node_name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
print_status_header(header_count, headers_crosscheck);
|
|
||||||
|
|
||||||
for (i = 0; i < n; i++)
|
for (i = 0; i < n; i++)
|
||||||
{
|
{
|
||||||
int column_node_ix;
|
int column_node_ix;
|
||||||
|
|
||||||
printf(" %-*s | %-*i ",
|
printf("%*s | %2d ", name_length,
|
||||||
headers_crosscheck[0].max_length,
|
|
||||||
cube[i]->node_name,
|
cube[i]->node_name,
|
||||||
headers_crosscheck[1].max_length,
|
|
||||||
cube[i]->node_id);
|
cube[i]->node_id);
|
||||||
|
|
||||||
for (column_node_ix = 0; column_node_ix < n; column_node_ix++)
|
for (column_node_ix = 0; column_node_ix < n; column_node_ix++)
|
||||||
@@ -634,8 +607,6 @@ do_cluster_crosscheck(void)
|
|||||||
int max_node_status = -2;
|
int max_node_status = -2;
|
||||||
int node_ix = 0;
|
int node_ix = 0;
|
||||||
|
|
||||||
char c;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The value of entry (i,j) is equal to the maximum value of all
|
* The value of entry (i,j) is equal to the maximum value of all
|
||||||
* the (i,j,k). Indeed:
|
* the (i,j,k). Indeed:
|
||||||
@@ -675,14 +646,12 @@ do_cluster_crosscheck(void)
|
|||||||
exit(ERR_INTERNAL);
|
exit(ERR_INTERNAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("| %-*c ", headers_crosscheck[column_node_ix + 2].max_length, c);
|
printf("| %c ", c);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
pfree(headers_crosscheck);
|
|
||||||
|
|
||||||
if (warnings.head != NULL && runtime_options.terse == false)
|
if (warnings.head != NULL && runtime_options.terse == false)
|
||||||
{
|
{
|
||||||
log_warning(_("following problems detected:"));
|
log_warning(_("following problems detected:"));
|
||||||
@@ -739,13 +708,16 @@ do_cluster_matrix()
|
|||||||
j = 0,
|
j = 0,
|
||||||
n = 0;
|
n = 0;
|
||||||
|
|
||||||
|
const char *node_header = "Name";
|
||||||
|
int name_length = strlen(node_header);
|
||||||
|
|
||||||
t_node_matrix_rec **matrix_rec_list;
|
t_node_matrix_rec **matrix_rec_list;
|
||||||
|
|
||||||
bool connection_error_found = false;
|
bool connection_error_found = false;
|
||||||
int error_code = SUCCESS;
|
int error_code = SUCCESS;
|
||||||
ItemList warnings = {NULL, NULL};
|
ItemList warnings = {NULL, NULL};
|
||||||
|
|
||||||
n = build_cluster_matrix(&matrix_rec_list, &warnings, &error_code);
|
n = build_cluster_matrix(&matrix_rec_list, &name_length, &warnings, &error_code);
|
||||||
|
|
||||||
if (runtime_options.output_mode == OM_CSV)
|
if (runtime_options.output_mode == OM_CSV)
|
||||||
{
|
{
|
||||||
@@ -768,60 +740,27 @@ do_cluster_matrix()
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* output header contains node name, node ID and one column for each node in the cluster */
|
char c;
|
||||||
struct ColHeader *headers_matrix = NULL;
|
|
||||||
|
|
||||||
int header_count = n + 2;
|
printf("%*s | Id ", name_length, node_header);
|
||||||
int header_id = 2;
|
for (i = 0; i < n; i++)
|
||||||
|
printf("| %2d ", matrix_rec_list[i]->node_id);
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
headers_matrix = palloc0(sizeof(ColHeader) * header_count);
|
for (i = 0; i < name_length; i++)
|
||||||
|
printf("-");
|
||||||
/* Initialize column headers */
|
printf("-+----");
|
||||||
strncpy(headers_matrix[0].title, _("Name"), MAXLEN);
|
for (i = 0; i < n; i++)
|
||||||
strncpy(headers_matrix[1].title, _("ID"), MAXLEN);
|
printf("+----");
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
for (i = 0; i < n; i++)
|
for (i = 0; i < n; i++)
|
||||||
{
|
{
|
||||||
maxlen_snprintf(headers_matrix[header_id].title, "%i", matrix_rec_list[i]->node_id);
|
printf("%*s | %2d ", name_length,
|
||||||
header_id++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Initialize column max values */
|
|
||||||
for (i = 0; i < header_count; i++)
|
|
||||||
{
|
|
||||||
headers_matrix[i].display = true;
|
|
||||||
headers_matrix[i].max_length = strlen(headers_matrix[i].title);
|
|
||||||
headers_matrix[i].cur_length = headers_matrix[i].max_length;
|
|
||||||
|
|
||||||
/* We can derive the maximum node ID length for the ID column from
|
|
||||||
* the generated matrix node ID headers
|
|
||||||
*/
|
|
||||||
if (i >= 2 && headers_matrix[i].max_length > headers_matrix[1].max_length)
|
|
||||||
headers_matrix[1].max_length = headers_matrix[i].max_length;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
for (i = 0; i < n; i++)
|
|
||||||
{
|
|
||||||
if (strlen(matrix_rec_list[i]->node_name) > headers_matrix[0].max_length)
|
|
||||||
{
|
|
||||||
headers_matrix[0].max_length = strlen(matrix_rec_list[i]->node_name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
print_status_header(header_count, headers_matrix);
|
|
||||||
|
|
||||||
for (i = 0; i < n; i++)
|
|
||||||
{
|
|
||||||
printf(" %-*s | %-*i ",
|
|
||||||
headers_matrix[0].max_length,
|
|
||||||
matrix_rec_list[i]->node_name,
|
matrix_rec_list[i]->node_name,
|
||||||
headers_matrix[1].max_length,
|
|
||||||
matrix_rec_list[i]->node_id);
|
matrix_rec_list[i]->node_id);
|
||||||
for (j = 0; j < n; j++)
|
for (j = 0; j < n; j++)
|
||||||
{
|
{
|
||||||
char c;
|
|
||||||
|
|
||||||
switch (matrix_rec_list[i]->node_status_list[j]->node_status)
|
switch (matrix_rec_list[i]->node_status_list[j]->node_status)
|
||||||
{
|
{
|
||||||
case -2:
|
case -2:
|
||||||
@@ -839,13 +778,11 @@ do_cluster_matrix()
|
|||||||
exit(ERR_INTERNAL);
|
exit(ERR_INTERNAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("| %-*c ", headers_matrix[j + 2].max_length, c);
|
printf("| %c ", c);
|
||||||
}
|
}
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
pfree(headers_matrix);
|
|
||||||
|
|
||||||
if (warnings.head != NULL && runtime_options.terse == false)
|
if (warnings.head != NULL && runtime_options.terse == false)
|
||||||
{
|
{
|
||||||
log_warning(_("following problems detected:"));
|
log_warning(_("following problems detected:"));
|
||||||
@@ -901,7 +838,7 @@ matrix_set_node_status(t_node_matrix_rec **matrix_rec_list, int n, int node_id,
|
|||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
build_cluster_matrix(t_node_matrix_rec ***matrix_rec_dest, ItemList *warnings, int *error_code)
|
build_cluster_matrix(t_node_matrix_rec ***matrix_rec_dest, int *name_length, ItemList *warnings, int *error_code)
|
||||||
{
|
{
|
||||||
PGconn *conn = NULL;
|
PGconn *conn = NULL;
|
||||||
int i = 0,
|
int i = 0,
|
||||||
@@ -959,6 +896,7 @@ build_cluster_matrix(t_node_matrix_rec ***matrix_rec_dest, ItemList *warnings, i
|
|||||||
/* Initialise matrix structure for each node */
|
/* Initialise matrix structure for each node */
|
||||||
for (cell = nodes.head; cell; cell = cell->next)
|
for (cell = nodes.head; cell; cell = cell->next)
|
||||||
{
|
{
|
||||||
|
int name_length_cur;
|
||||||
NodeInfoListCell *cell_j;
|
NodeInfoListCell *cell_j;
|
||||||
|
|
||||||
matrix_rec_list[i] = (t_node_matrix_rec *) pg_malloc0(sizeof(t_node_matrix_rec));
|
matrix_rec_list[i] = (t_node_matrix_rec *) pg_malloc0(sizeof(t_node_matrix_rec));
|
||||||
@@ -968,6 +906,13 @@ build_cluster_matrix(t_node_matrix_rec ***matrix_rec_dest, ItemList *warnings, i
|
|||||||
cell->node_info->node_name,
|
cell->node_info->node_name,
|
||||||
sizeof(matrix_rec_list[i]->node_name));
|
sizeof(matrix_rec_list[i]->node_name));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find the maximum length of a node name
|
||||||
|
*/
|
||||||
|
name_length_cur = strlen(matrix_rec_list[i]->node_name);
|
||||||
|
if (name_length_cur > *name_length)
|
||||||
|
*name_length = name_length_cur;
|
||||||
|
|
||||||
matrix_rec_list[i]->node_status_list = (t_node_status_rec **) pg_malloc0(sizeof(t_node_status_rec) * nodes.node_count);
|
matrix_rec_list[i]->node_status_list = (t_node_status_rec **) pg_malloc0(sizeof(t_node_status_rec) * nodes.node_count);
|
||||||
|
|
||||||
j = 0;
|
j = 0;
|
||||||
@@ -1132,7 +1077,7 @@ build_cluster_matrix(t_node_matrix_rec ***matrix_rec_dest, ItemList *warnings, i
|
|||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
build_cluster_crosscheck(t_node_status_cube ***dest_cube, ItemList *warnings, int *error_code)
|
build_cluster_crosscheck(t_node_status_cube ***dest_cube, int *name_length, ItemList *warnings, int *error_code)
|
||||||
{
|
{
|
||||||
PGconn *conn = NULL;
|
PGconn *conn = NULL;
|
||||||
int h,
|
int h,
|
||||||
@@ -1181,12 +1126,20 @@ build_cluster_crosscheck(t_node_status_cube ***dest_cube, ItemList *warnings, in
|
|||||||
|
|
||||||
for (cell = nodes.head; cell; cell = cell->next)
|
for (cell = nodes.head; cell; cell = cell->next)
|
||||||
{
|
{
|
||||||
|
int name_length_cur = 0;
|
||||||
NodeInfoListCell *cell_i = NULL;
|
NodeInfoListCell *cell_i = NULL;
|
||||||
|
|
||||||
cube[h] = (t_node_status_cube *) pg_malloc(sizeof(t_node_status_cube));
|
cube[h] = (t_node_status_cube *) pg_malloc(sizeof(t_node_status_cube));
|
||||||
cube[h]->node_id = cell->node_info->node_id;
|
cube[h]->node_id = cell->node_info->node_id;
|
||||||
strncpy(cube[h]->node_name, cell->node_info->node_name, sizeof(cube[h]->node_name));
|
strncpy(cube[h]->node_name, cell->node_info->node_name, sizeof(cube[h]->node_name));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find the maximum length of a node name
|
||||||
|
*/
|
||||||
|
name_length_cur = strlen(cube[h]->node_name);
|
||||||
|
if (name_length_cur > *name_length)
|
||||||
|
*name_length = name_length_cur;
|
||||||
|
|
||||||
cube[h]->matrix_list_rec = (t_node_matrix_rec **) pg_malloc(sizeof(t_node_matrix_rec) * nodes.node_count);
|
cube[h]->matrix_list_rec = (t_node_matrix_rec **) pg_malloc(sizeof(t_node_matrix_rec) * nodes.node_count);
|
||||||
|
|
||||||
i = 0;
|
i = 0;
|
||||||
@@ -1554,5 +1507,4 @@ do_cluster_help(void)
|
|||||||
printf(_(" -k, --keep-history=VALUE retain indicated number of days of history (default: 0)\n"));
|
printf(_(" -k, --keep-history=VALUE retain indicated number of days of history (default: 0)\n"));
|
||||||
puts("");
|
puts("");
|
||||||
|
|
||||||
printf(_("%s home page: <%s>\n"), "repmgr", REPMGR_URL);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* repmgr-action-cluster.h
|
* repmgr-action-cluster.h
|
||||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
* repmgr-action-daemon.c
|
* repmgr-action-daemon.c
|
||||||
*
|
*
|
||||||
* Implements repmgrd actions for the repmgr command line utility
|
* Implements repmgrd actions for the repmgr command line utility
|
||||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -339,5 +339,4 @@ void do_daemon_help(void)
|
|||||||
|
|
||||||
puts("");
|
puts("");
|
||||||
|
|
||||||
printf(_("%s home page: <%s>\n"), "repmgr", REPMGR_URL);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* repmgr-action-daemon.h
|
* repmgr-action-daemon.h
|
||||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Implements actions available for any kind of node
|
* Implements actions available for any kind of node
|
||||||
*
|
*
|
||||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -36,8 +36,6 @@ static bool copy_file(const char *src_file, const char *dest_file);
|
|||||||
static void format_archive_dir(PQExpBufferData *archive_dir);
|
static void format_archive_dir(PQExpBufferData *archive_dir);
|
||||||
static t_server_action parse_server_action(const char *action);
|
static t_server_action parse_server_action(const char *action);
|
||||||
|
|
||||||
static void exit_optformat_error(const char *error, int errcode);
|
|
||||||
|
|
||||||
static void _do_node_service_list_actions(t_server_action action);
|
static void _do_node_service_list_actions(t_server_action action);
|
||||||
static void _do_node_status_is_shutdown_cleanly(void);
|
static void _do_node_status_is_shutdown_cleanly(void);
|
||||||
static void _do_node_archive_config(void);
|
static void _do_node_archive_config(void);
|
||||||
@@ -45,7 +43,7 @@ static void _do_node_restore_config(void);
|
|||||||
|
|
||||||
static void do_node_check_replication_connection(void);
|
static void do_node_check_replication_connection(void);
|
||||||
static CheckStatus do_node_check_archive_ready(PGconn *conn, OutputMode mode, CheckStatusList *list_output);
|
static CheckStatus do_node_check_archive_ready(PGconn *conn, OutputMode mode, CheckStatusList *list_output);
|
||||||
static CheckStatus do_node_check_downstream(PGconn *conn, OutputMode mode, t_node_info *node_info, CheckStatusList *list_output);
|
static CheckStatus do_node_check_downstream(PGconn *conn, OutputMode mode, CheckStatusList *list_output);
|
||||||
static CheckStatus do_node_check_upstream(PGconn *conn, OutputMode mode, t_node_info *node_info, CheckStatusList *list_output);
|
static CheckStatus do_node_check_upstream(PGconn *conn, OutputMode mode, t_node_info *node_info, CheckStatusList *list_output);
|
||||||
static CheckStatus do_node_check_replication_lag(PGconn *conn, OutputMode mode, t_node_info *node_info, CheckStatusList *list_output);
|
static CheckStatus do_node_check_replication_lag(PGconn *conn, OutputMode mode, t_node_info *node_info, CheckStatusList *list_output);
|
||||||
static CheckStatus do_node_check_role(PGconn *conn, OutputMode mode, t_node_info *node_info, CheckStatusList *list_output);
|
static CheckStatus do_node_check_role(PGconn *conn, OutputMode mode, t_node_info *node_info, CheckStatusList *list_output);
|
||||||
@@ -53,8 +51,6 @@ static CheckStatus do_node_check_slots(PGconn *conn, OutputMode mode, t_node_inf
|
|||||||
static CheckStatus do_node_check_missing_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_data_directory(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_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
|
* NODE STATUS
|
||||||
*
|
*
|
||||||
@@ -85,6 +81,7 @@ do_node_status(void)
|
|||||||
t_recovery_conf recovery_conf = T_RECOVERY_CONF_INITIALIZER;
|
t_recovery_conf recovery_conf = T_RECOVERY_CONF_INITIALIZER;
|
||||||
|
|
||||||
char data_dir[MAXPGPATH] = "";
|
char data_dir[MAXPGPATH] = "";
|
||||||
|
int server_version_num = UNKNOWN_SERVER_VERSION_NUM;
|
||||||
char server_version_str[MAXVERSIONSTR] = "";
|
char server_version_str[MAXVERSIONSTR] = "";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -102,7 +99,7 @@ do_node_status(void)
|
|||||||
conn = establish_db_connection(config_file_options.conninfo, true);
|
conn = establish_db_connection(config_file_options.conninfo, true);
|
||||||
strncpy(data_dir, config_file_options.data_directory, MAXPGPATH);
|
strncpy(data_dir, config_file_options.data_directory, MAXPGPATH);
|
||||||
|
|
||||||
(void)get_server_version(conn, server_version_str);
|
server_version_num = get_server_version(conn, server_version_str);
|
||||||
|
|
||||||
/* check node exists */
|
/* check node exists */
|
||||||
|
|
||||||
@@ -134,22 +131,13 @@ do_node_status(void)
|
|||||||
|
|
||||||
if (runtime_options.verbose == true)
|
if (runtime_options.verbose == true)
|
||||||
{
|
{
|
||||||
uint64 local_system_identifier = get_system_identifier(config_file_options.data_directory);
|
uint64 local_system_identifier = UNKNOWN_SYSTEM_IDENTIFIER;
|
||||||
|
|
||||||
if (local_system_identifier == UNKNOWN_SYSTEM_IDENTIFIER)
|
local_system_identifier = get_system_identifier(config_file_options.data_directory);
|
||||||
{
|
|
||||||
key_value_list_set(&node_status,
|
key_value_list_set_format(&node_status,
|
||||||
"System identifier",
|
"System identifier",
|
||||||
"unknown");
|
"%lu", local_system_identifier);
|
||||||
item_list_append_format(&warnings,
|
|
||||||
_("unable to retrieve system identifier from pg_control"));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
key_value_list_set_format(&node_status,
|
|
||||||
"System identifier",
|
|
||||||
"%lu", local_system_identifier);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
key_value_list_set(&node_status,
|
key_value_list_set(&node_status,
|
||||||
@@ -216,16 +204,7 @@ do_node_status(void)
|
|||||||
|
|
||||||
if (enabled == false && recovery_type == RECTYPE_STANDBY)
|
if (enabled == false && recovery_type == RECTYPE_STANDBY)
|
||||||
{
|
{
|
||||||
if (PQserverVersion(conn) >= 90500)
|
appendPQExpBufferStr(&archiving_status, " (on standbys \"archive_mode\" must be set to \"always\" to be effective)");
|
||||||
{
|
|
||||||
appendPQExpBufferStr(&archiving_status,
|
|
||||||
" (on standbys \"archive_mode\" must be set to \"always\" to be effective)");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
appendPQExpBufferStr(&archiving_status,
|
|
||||||
" (\"archive_mode\" has no effect on standbys)");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
key_value_list_set(&node_status,
|
key_value_list_set(&node_status,
|
||||||
@@ -315,7 +294,7 @@ do_node_status(void)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_downstream_node_attached(conn, node_cell->node_info->node_name, NULL) != NODE_ATTACHED)
|
if (is_downstream_node_attached(conn, node_cell->node_info->node_name) != NODE_ATTACHED)
|
||||||
{
|
{
|
||||||
missing_nodes_count++;
|
missing_nodes_count++;
|
||||||
item_list_append_format(&missing_nodes,
|
item_list_append_format(&missing_nodes,
|
||||||
@@ -342,7 +321,13 @@ do_node_status(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node_info.max_replication_slots == 0)
|
if (server_version_num < 90400)
|
||||||
|
{
|
||||||
|
key_value_list_set(&node_status,
|
||||||
|
"Replication slots",
|
||||||
|
"not available");
|
||||||
|
}
|
||||||
|
else if (node_info.max_replication_slots == 0)
|
||||||
{
|
{
|
||||||
key_value_list_set(&node_status,
|
key_value_list_set(&node_status,
|
||||||
"Replication slots",
|
"Replication slots",
|
||||||
@@ -647,17 +632,9 @@ _do_node_status_is_shutdown_cleanly(void)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check what pg_control says */
|
/* check what pg_controldata says */
|
||||||
|
|
||||||
if (get_db_state(config_file_options.data_directory, &db_state) == false)
|
db_state = get_db_state(config_file_options.data_directory);
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Unable to retrieve the database state from pg_control
|
|
||||||
*/
|
|
||||||
node_status = NODE_STATUS_UNKNOWN;
|
|
||||||
log_verbose(LOG_DEBUG, "unable to determine db state");
|
|
||||||
goto return_state;
|
|
||||||
}
|
|
||||||
|
|
||||||
log_verbose(LOG_DEBUG, "db state now: %s", describe_db_state(db_state));
|
log_verbose(LOG_DEBUG, "db state now: %s", describe_db_state(db_state));
|
||||||
|
|
||||||
@@ -676,23 +653,21 @@ _do_node_status_is_shutdown_cleanly(void)
|
|||||||
|
|
||||||
checkPoint = get_latest_checkpoint_location(config_file_options.data_directory);
|
checkPoint = get_latest_checkpoint_location(config_file_options.data_directory);
|
||||||
|
|
||||||
|
/* unable to read pg_control, don't know what's happening */
|
||||||
if (checkPoint == InvalidXLogRecPtr)
|
if (checkPoint == InvalidXLogRecPtr)
|
||||||
{
|
{
|
||||||
/* unable to read pg_control, don't know what's happening */
|
|
||||||
node_status = NODE_STATUS_UNKNOWN;
|
node_status = NODE_STATUS_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* if still "UNKNOWN" at this point, then the node must be cleanly shut
|
||||||
|
* down
|
||||||
|
*/
|
||||||
else if (node_status == NODE_STATUS_UNKNOWN)
|
else if (node_status == NODE_STATUS_UNKNOWN)
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
* if still "UNKNOWN" at this point, then the node must be cleanly shut
|
|
||||||
* down
|
|
||||||
*/
|
|
||||||
node_status = NODE_STATUS_DOWN;
|
node_status = NODE_STATUS_DOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return_state:
|
|
||||||
|
|
||||||
log_verbose(LOG_DEBUG, "node status determined as: %s",
|
log_verbose(LOG_DEBUG, "node status determined as: %s",
|
||||||
print_node_status(node_status));
|
print_node_status(node_status));
|
||||||
|
|
||||||
@@ -711,26 +686,6 @@ return_state:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
exit_optformat_error(const char *error, int errcode)
|
|
||||||
{
|
|
||||||
PQExpBufferData output;
|
|
||||||
|
|
||||||
Assert(runtime_options.output_mode == OM_OPTFORMAT);
|
|
||||||
|
|
||||||
initPQExpBuffer(&output);
|
|
||||||
|
|
||||||
appendPQExpBuffer(&output,
|
|
||||||
"--error=%s",
|
|
||||||
error);
|
|
||||||
|
|
||||||
printf("%s\n", output.data);
|
|
||||||
|
|
||||||
termPQExpBuffer(&output);
|
|
||||||
|
|
||||||
exit(errcode);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Configuration file required
|
* Configuration file required
|
||||||
*/
|
*/
|
||||||
@@ -747,7 +702,6 @@ do_node_check(void)
|
|||||||
CheckStatusListCell *cell = NULL;
|
CheckStatusListCell *cell = NULL;
|
||||||
|
|
||||||
bool issue_detected = false;
|
bool issue_detected = false;
|
||||||
bool exit_on_connection_error = true;
|
|
||||||
|
|
||||||
/* for internal use */
|
/* for internal use */
|
||||||
if (runtime_options.has_passfile == true)
|
if (runtime_options.has_passfile == true)
|
||||||
@@ -757,28 +711,12 @@ do_node_check(void)
|
|||||||
exit(return_code);
|
exit(return_code);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* for use by "standby switchover" */
|
|
||||||
if (runtime_options.replication_connection == true)
|
if (runtime_options.replication_connection == true)
|
||||||
{
|
{
|
||||||
do_node_check_replication_connection();
|
do_node_check_replication_connection();
|
||||||
exit(SUCCESS);
|
exit(SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (runtime_options.db_connection == true)
|
|
||||||
{
|
|
||||||
exit_on_connection_error = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If --optformat was provided, we'll assume this is a remote invocation
|
|
||||||
* and instead of exiting with an error, we'll return an error string to
|
|
||||||
* so the remote invoker will know what's happened.
|
|
||||||
*/
|
|
||||||
if (runtime_options.output_mode == OM_OPTFORMAT)
|
|
||||||
{
|
|
||||||
exit_on_connection_error = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (config_file_options.conninfo[0] != '\0')
|
if (config_file_options.conninfo[0] != '\0')
|
||||||
{
|
{
|
||||||
@@ -794,12 +732,6 @@ do_node_check(void)
|
|||||||
|
|
||||||
if (parse_success == false)
|
if (parse_success == false)
|
||||||
{
|
{
|
||||||
if (runtime_options.output_mode == OM_OPTFORMAT)
|
|
||||||
{
|
|
||||||
exit_optformat_error("CONNINFO_PARSE",
|
|
||||||
ERR_BAD_CONFIG);
|
|
||||||
}
|
|
||||||
|
|
||||||
log_error(_("unable to parse conninfo string \"%s\" for local node"),
|
log_error(_("unable to parse conninfo string \"%s\" for local node"),
|
||||||
config_file_options.conninfo);
|
config_file_options.conninfo);
|
||||||
log_detail("%s", errmsg);
|
log_detail("%s", errmsg);
|
||||||
@@ -817,36 +749,16 @@ do_node_check(void)
|
|||||||
config_file_options.conninfo,
|
config_file_options.conninfo,
|
||||||
"user",
|
"user",
|
||||||
runtime_options.superuser,
|
runtime_options.superuser,
|
||||||
exit_on_connection_error);
|
true);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
conn = establish_db_connection_by_params(&node_conninfo, exit_on_connection_error);
|
conn = establish_db_connection_by_params(&node_conninfo, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
conn = establish_db_connection_by_params(&source_conninfo, exit_on_connection_error);
|
conn = establish_db_connection_by_params(&source_conninfo, true);
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* --db-connection option provided
|
|
||||||
*/
|
|
||||||
if (runtime_options.db_connection == true)
|
|
||||||
{
|
|
||||||
return_code = do_node_check_db_connection(conn, runtime_options.output_mode);
|
|
||||||
PQfinish(conn);
|
|
||||||
exit(return_code);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If we've reached here, and the connection is invalid, then --optformat was provided
|
|
||||||
*/
|
|
||||||
if (PQstatus(conn) != CONNECTION_OK)
|
|
||||||
{
|
|
||||||
exit_optformat_error("DB_CONNECTION",
|
|
||||||
ERR_DB_CONN);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (get_node_record(conn, config_file_options.node_id, &node_info) != RECORD_FOUND)
|
if (get_node_record(conn, config_file_options.node_id, &node_info) != RECORD_FOUND)
|
||||||
@@ -885,7 +797,6 @@ do_node_check(void)
|
|||||||
{
|
{
|
||||||
return_code = do_node_check_downstream(conn,
|
return_code = do_node_check_downstream(conn,
|
||||||
runtime_options.output_mode,
|
runtime_options.output_mode,
|
||||||
&node_info,
|
|
||||||
NULL);
|
NULL);
|
||||||
PQfinish(conn);
|
PQfinish(conn);
|
||||||
exit(return_code);
|
exit(return_code);
|
||||||
@@ -977,7 +888,7 @@ do_node_check(void)
|
|||||||
if (do_node_check_upstream(conn, runtime_options.output_mode, &node_info, &status_list) != CHECK_STATUS_OK)
|
if (do_node_check_upstream(conn, runtime_options.output_mode, &node_info, &status_list) != CHECK_STATUS_OK)
|
||||||
issue_detected = true;
|
issue_detected = true;
|
||||||
|
|
||||||
if (do_node_check_downstream(conn, runtime_options.output_mode, &node_info, &status_list) != CHECK_STATUS_OK)
|
if (do_node_check_downstream(conn, runtime_options.output_mode, &status_list) != CHECK_STATUS_OK)
|
||||||
issue_detected = true;
|
issue_detected = true;
|
||||||
|
|
||||||
if (do_node_check_slots(conn, runtime_options.output_mode, &node_info, &status_list) != CHECK_STATUS_OK)
|
if (do_node_check_slots(conn, runtime_options.output_mode, &node_info, &status_list) != CHECK_STATUS_OK)
|
||||||
@@ -1075,15 +986,7 @@ do_node_check_replication_connection(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* retrieve remote node record from local database */
|
/* retrieve remote node record from local database */
|
||||||
local_conn = establish_db_connection(config_file_options.conninfo, false);
|
local_conn = establish_db_connection(config_file_options.conninfo, true);
|
||||||
|
|
||||||
if (PQstatus(local_conn) != CONNECTION_OK)
|
|
||||||
{
|
|
||||||
appendPQExpBufferStr(&output, "CONNECTION_ERROR");
|
|
||||||
printf("%s\n", output.data);
|
|
||||||
termPQExpBuffer(&output);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
record_status = get_node_record(local_conn, runtime_options.remote_node_id, &node_record);
|
record_status = get_node_record(local_conn, runtime_options.remote_node_id, &node_record);
|
||||||
PQfinish(local_conn);
|
PQfinish(local_conn);
|
||||||
@@ -1280,7 +1183,7 @@ do_node_check_archive_ready(PGconn *conn, OutputMode mode, CheckStatusList *list
|
|||||||
|
|
||||||
|
|
||||||
static CheckStatus
|
static CheckStatus
|
||||||
do_node_check_downstream(PGconn *conn, OutputMode mode, t_node_info *node_info, CheckStatusList *list_output)
|
do_node_check_downstream(PGconn *conn, OutputMode mode, CheckStatusList *list_output)
|
||||||
{
|
{
|
||||||
NodeInfoList downstream_nodes = T_NODE_INFO_LIST_INITIALIZER;
|
NodeInfoList downstream_nodes = T_NODE_INFO_LIST_INITIALIZER;
|
||||||
NodeInfoListCell *cell = NULL;
|
NodeInfoListCell *cell = NULL;
|
||||||
@@ -1314,7 +1217,7 @@ do_node_check_downstream(PGconn *conn, OutputMode mode, t_node_info *node_info,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_downstream_node_attached(conn, cell->node_info->node_name, NULL) != NODE_ATTACHED)
|
if (is_downstream_node_attached(conn, cell->node_info->node_name) != NODE_ATTACHED)
|
||||||
{
|
{
|
||||||
missing_nodes_count++;
|
missing_nodes_count++;
|
||||||
item_list_append_format(&missing_nodes,
|
item_list_append_format(&missing_nodes,
|
||||||
@@ -1331,13 +1234,7 @@ do_node_check_downstream(PGconn *conn, OutputMode mode, t_node_info *node_info,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node_info->type == WITNESS)
|
if (missing_nodes_count == 0)
|
||||||
{
|
|
||||||
/* witness is not connecting to any upstream */
|
|
||||||
appendPQExpBufferStr(&details,
|
|
||||||
_("N/A - node is a witness"));
|
|
||||||
}
|
|
||||||
else if (missing_nodes_count == 0)
|
|
||||||
{
|
{
|
||||||
if (expected_nodes_count == 0)
|
if (expected_nodes_count == 0)
|
||||||
appendPQExpBufferStr(&details,
|
appendPQExpBufferStr(&details,
|
||||||
@@ -1470,13 +1367,7 @@ do_node_check_upstream(PGconn *conn, OutputMode mode, t_node_info *node_info, Ch
|
|||||||
|
|
||||||
initPQExpBuffer(&details);
|
initPQExpBuffer(&details);
|
||||||
|
|
||||||
if (node_info->type == WITNESS)
|
if (get_node_record(conn, node_info->upstream_node_id, &upstream_node_info) != RECORD_FOUND)
|
||||||
{
|
|
||||||
/* witness is not connecting to any upstream */
|
|
||||||
appendPQExpBufferStr(&details,
|
|
||||||
_("N/A - node is a witness"));
|
|
||||||
}
|
|
||||||
else if (get_node_record(conn, node_info->upstream_node_id, &upstream_node_info) != RECORD_FOUND)
|
|
||||||
{
|
{
|
||||||
if (get_recovery_type(conn) == RECTYPE_STANDBY)
|
if (get_recovery_type(conn) == RECTYPE_STANDBY)
|
||||||
{
|
{
|
||||||
@@ -1497,7 +1388,7 @@ do_node_check_upstream(PGconn *conn, OutputMode mode, t_node_info *node_info, Ch
|
|||||||
upstream_conn = establish_db_connection(upstream_node_info.conninfo, true);
|
upstream_conn = establish_db_connection(upstream_node_info.conninfo, true);
|
||||||
|
|
||||||
/* check our node is connected */
|
/* check our node is connected */
|
||||||
if (is_downstream_node_attached(upstream_conn, config_file_options.node_name, NULL) != NODE_ATTACHED)
|
if (is_downstream_node_attached(upstream_conn, config_file_options.node_name) != NODE_ATTACHED)
|
||||||
{
|
{
|
||||||
appendPQExpBuffer(&details,
|
appendPQExpBuffer(&details,
|
||||||
_("node \"%s\" (ID: %i) is not attached to expected upstream node \"%s\" (ID: %i)"),
|
_("node \"%s\" (ID: %i) is not attached to expected upstream node \"%s\" (ID: %i)"),
|
||||||
@@ -1526,7 +1417,6 @@ do_node_check_upstream(PGconn *conn, OutputMode mode, t_node_info *node_info, Ch
|
|||||||
output_check_status(status),
|
output_check_status(status),
|
||||||
details.data);
|
details.data);
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case OM_TEXT:
|
case OM_TEXT:
|
||||||
if (list_output != NULL)
|
if (list_output != NULL)
|
||||||
{
|
{
|
||||||
@@ -1856,7 +1746,12 @@ do_node_check_slots(PGconn *conn, OutputMode mode, t_node_info *node_info, Check
|
|||||||
|
|
||||||
initPQExpBuffer(&details);
|
initPQExpBuffer(&details);
|
||||||
|
|
||||||
if (node_info->total_replication_slots == 0)
|
if (PQserverVersion(conn) < 90400)
|
||||||
|
{
|
||||||
|
appendPQExpBufferStr(&details,
|
||||||
|
_("replication slots not available for this PostgreSQL version"));
|
||||||
|
}
|
||||||
|
else if (node_info->total_replication_slots == 0)
|
||||||
{
|
{
|
||||||
appendPQExpBufferStr(&details,
|
appendPQExpBufferStr(&details,
|
||||||
_("node has no physical replication slots"));
|
_("node has no physical replication slots"));
|
||||||
@@ -1927,42 +1822,50 @@ do_node_check_missing_slots(PGconn *conn, OutputMode mode, t_node_info *node_inf
|
|||||||
|
|
||||||
initPQExpBuffer(&details);
|
initPQExpBuffer(&details);
|
||||||
|
|
||||||
get_downstream_nodes_with_missing_slot(conn,
|
if (PQserverVersion(conn) < 90400)
|
||||||
config_file_options.node_id,
|
|
||||||
&missing_slots);
|
|
||||||
|
|
||||||
if (missing_slots.node_count == 0)
|
|
||||||
{
|
{
|
||||||
appendPQExpBufferStr(&details,
|
appendPQExpBufferStr(&details,
|
||||||
_("node has no missing physical replication slots"));
|
_("replication slots not available for this PostgreSQL version"));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
NodeInfoListCell *missing_slot_cell = NULL;
|
get_downstream_nodes_with_missing_slot(conn,
|
||||||
bool first_element = true;
|
config_file_options.node_id,
|
||||||
|
&missing_slots);
|
||||||
|
|
||||||
status = CHECK_STATUS_CRITICAL;
|
if (missing_slots.node_count == 0)
|
||||||
|
|
||||||
appendPQExpBuffer(&details,
|
|
||||||
_("%i physical replication slots are missing"),
|
|
||||||
missing_slots.node_count);
|
|
||||||
|
|
||||||
if (missing_slots.node_count)
|
|
||||||
{
|
{
|
||||||
appendPQExpBufferStr(&details, ": ");
|
appendPQExpBufferStr(&details,
|
||||||
|
_("node has no missing physical replication slots"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
NodeInfoListCell *missing_slot_cell = NULL;
|
||||||
|
bool first_element = true;
|
||||||
|
|
||||||
for (missing_slot_cell = missing_slots.head; missing_slot_cell; missing_slot_cell = missing_slot_cell->next)
|
status = CHECK_STATUS_CRITICAL;
|
||||||
|
|
||||||
|
appendPQExpBuffer(&details,
|
||||||
|
_("%i physical replication slots are missing"),
|
||||||
|
missing_slots.node_count);
|
||||||
|
|
||||||
|
if (missing_slots.node_count)
|
||||||
{
|
{
|
||||||
if (first_element == true)
|
appendPQExpBufferStr(&details, ": ");
|
||||||
{
|
|
||||||
first_element = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
appendPQExpBufferStr(&details, ", ");
|
|
||||||
}
|
|
||||||
|
|
||||||
appendPQExpBufferStr(&details, missing_slot_cell->node_info->slot_name);
|
for (missing_slot_cell = missing_slots.head; missing_slot_cell; missing_slot_cell = missing_slot_cell->next)
|
||||||
|
{
|
||||||
|
if (first_element == true)
|
||||||
|
{
|
||||||
|
first_element = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
appendPQExpBufferStr(&details, ", ");
|
||||||
|
}
|
||||||
|
|
||||||
|
appendPQExpBufferStr(&details, missing_slot_cell->node_info->slot_name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2045,7 +1948,7 @@ do_node_check_data_directory(PGconn *conn, OutputMode mode, t_node_info *node_in
|
|||||||
* Check actual data directory matches that in repmgr.conf; note this requires
|
* Check actual data directory matches that in repmgr.conf; note this requires
|
||||||
* a superuser connection
|
* a superuser connection
|
||||||
*/
|
*/
|
||||||
if (connection_has_pg_monitor_role(conn, "pg_read_all_settings") == true)
|
if (connection_has_pg_settings(conn) == true)
|
||||||
{
|
{
|
||||||
/* we expect to have a database connection */
|
/* we expect to have a database connection */
|
||||||
if (get_pg_setting(conn, "data_directory", actual_data_directory) == false)
|
if (get_pg_setting(conn, "data_directory", actual_data_directory) == false)
|
||||||
@@ -2194,72 +2097,6 @@ CheckStatus do_node_check_replication_config_owner(PGconn *conn, OutputMode mode
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This is not included in the general list output
|
|
||||||
*/
|
|
||||||
static CheckStatus
|
|
||||||
do_node_check_db_connection(PGconn *conn, OutputMode mode)
|
|
||||||
{
|
|
||||||
CheckStatus status = CHECK_STATUS_OK;
|
|
||||||
PQExpBufferData details;
|
|
||||||
|
|
||||||
if (mode == OM_CSV)
|
|
||||||
{
|
|
||||||
log_error(_("--csv output not provided with --db-connection option"));
|
|
||||||
PQfinish(conn);
|
|
||||||
exit(ERR_BAD_CONFIG);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This check is for configuration diagnostics only */
|
|
||||||
if (mode == OM_NAGIOS)
|
|
||||||
{
|
|
||||||
log_error(_("--nagios output not provided with --db-connection option"));
|
|
||||||
PQfinish(conn);
|
|
||||||
exit(ERR_BAD_CONFIG);
|
|
||||||
}
|
|
||||||
|
|
||||||
initPQExpBuffer(&details);
|
|
||||||
|
|
||||||
if (PQstatus(conn) != CONNECTION_OK)
|
|
||||||
{
|
|
||||||
t_conninfo_param_list conninfo = T_CONNINFO_PARAM_LIST_INITIALIZER;
|
|
||||||
int c;
|
|
||||||
|
|
||||||
status = CHECK_STATUS_CRITICAL;
|
|
||||||
initialize_conninfo_params(&conninfo, false);
|
|
||||||
conn_to_param_list(conn, &conninfo);
|
|
||||||
|
|
||||||
appendPQExpBufferStr(&details,
|
|
||||||
"connection parameters used:");
|
|
||||||
for (c = 0; c < conninfo.size && conninfo.keywords[c] != NULL; c++)
|
|
||||||
{
|
|
||||||
if (conninfo.values[c] != NULL && conninfo.values[c][0] != '\0')
|
|
||||||
{
|
|
||||||
appendPQExpBuffer(&details,
|
|
||||||
" %s=%s",
|
|
||||||
conninfo.keywords[c], conninfo.values[c]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mode == OM_OPTFORMAT)
|
|
||||||
{
|
|
||||||
printf("--db-connection=%s\n",
|
|
||||||
output_check_status(status));
|
|
||||||
}
|
|
||||||
else if (mode == OM_TEXT)
|
|
||||||
{
|
|
||||||
printf("%s (%s)\n",
|
|
||||||
output_check_status(status),
|
|
||||||
details.data);
|
|
||||||
}
|
|
||||||
termPQExpBuffer(&details);
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
do_node_service(void)
|
do_node_service(void)
|
||||||
{
|
{
|
||||||
@@ -2494,8 +2331,6 @@ do_node_rejoin(void)
|
|||||||
DBState db_state;
|
DBState db_state;
|
||||||
PGPing status;
|
PGPing status;
|
||||||
bool is_shutdown = true;
|
bool is_shutdown = true;
|
||||||
int server_version_num = UNKNOWN_SERVER_VERSION_NUM;
|
|
||||||
bool hide_standby_signal = false;
|
|
||||||
|
|
||||||
PQExpBufferData command;
|
PQExpBufferData command;
|
||||||
PQExpBufferData command_output;
|
PQExpBufferData command_output;
|
||||||
@@ -2526,11 +2361,7 @@ do_node_rejoin(void)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (get_db_state(config_file_options.data_directory, &db_state) == false)
|
db_state = get_db_state(config_file_options.data_directory);
|
||||||
{
|
|
||||||
log_error(_("unable to determine database state from pg_control"));
|
|
||||||
exit(ERR_BAD_CONFIG);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_shutdown == false)
|
if (is_shutdown == false)
|
||||||
{
|
{
|
||||||
@@ -2540,21 +2371,6 @@ do_node_rejoin(void)
|
|||||||
exit(ERR_REJOIN_FAIL);
|
exit(ERR_REJOIN_FAIL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Server version number required to determine whether pg_rewind will run
|
|
||||||
* crash recovery (Pg 13 and later).
|
|
||||||
*/
|
|
||||||
server_version_num = get_pg_version(config_file_options.data_directory, NULL);
|
|
||||||
|
|
||||||
if (server_version_num == UNKNOWN_SERVER_VERSION_NUM)
|
|
||||||
{
|
|
||||||
/* This is very unlikely to happen */
|
|
||||||
log_error(_("unable to determine database version"));
|
|
||||||
exit(ERR_BAD_CONFIG);
|
|
||||||
}
|
|
||||||
|
|
||||||
log_verbose(LOG_DEBUG, "server version number is: %i", server_version_num);
|
|
||||||
|
|
||||||
/* check if cleanly shut down */
|
/* check if cleanly shut down */
|
||||||
if (db_state != DB_SHUTDOWNED && db_state != DB_SHUTDOWNED_IN_RECOVERY)
|
if (db_state != DB_SHUTDOWNED && db_state != DB_SHUTDOWNED_IN_RECOVERY)
|
||||||
{
|
{
|
||||||
@@ -2562,41 +2378,15 @@ do_node_rejoin(void)
|
|||||||
{
|
{
|
||||||
log_error(_("database is still shutting down"));
|
log_error(_("database is still shutting down"));
|
||||||
}
|
}
|
||||||
else if (server_version_num >= 130000 && runtime_options.force_rewind_used == true)
|
|
||||||
{
|
|
||||||
log_warning(_("database is not shut down cleanly"));
|
|
||||||
log_detail(_("--force-rewind provided, pg_rewind will automatically perform recovery"));
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If pg_rewind is executed, the first change it will make
|
|
||||||
* is to start the server in single user mode, which will fail
|
|
||||||
* in the presence of "standby.signal", so we'll "hide" it
|
|
||||||
* (actually delete and recreate).
|
|
||||||
*/
|
|
||||||
hide_standby_signal = true;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
* If the database was not shut down cleanly, it *might* rejoin correctly
|
|
||||||
* after starting up and recovering, but better to ensure the database
|
|
||||||
* can recover before trying anything else.
|
|
||||||
*/
|
|
||||||
log_error(_("database is not shut down cleanly"));
|
log_error(_("database is not shut down cleanly"));
|
||||||
|
|
||||||
if (server_version_num >= 130000)
|
if (runtime_options.force_rewind_used == true)
|
||||||
{
|
{
|
||||||
log_hint(_("provide --force-rewind to run recovery"));
|
log_detail(_("pg_rewind will not be able to run"));
|
||||||
}
|
}
|
||||||
else
|
log_hint(_("database should be restarted then shut down cleanly after crash recovery completes"));
|
||||||
{
|
|
||||||
if (runtime_options.force_rewind_used == true)
|
|
||||||
{
|
|
||||||
log_detail(_("pg_rewind will not be able to run"));
|
|
||||||
}
|
|
||||||
log_hint(_("database should be restarted then shut down cleanly after crash recovery completes"));
|
|
||||||
}
|
|
||||||
|
|
||||||
exit(ERR_REJOIN_FAIL);
|
exit(ERR_REJOIN_FAIL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2604,6 +2394,10 @@ do_node_rejoin(void)
|
|||||||
/* check provided upstream connection */
|
/* check provided upstream connection */
|
||||||
upstream_conn = establish_db_connection_by_params(&source_conninfo, true);
|
upstream_conn = establish_db_connection_by_params(&source_conninfo, true);
|
||||||
|
|
||||||
|
/* sanity checks for 9.3 */
|
||||||
|
if (PQserverVersion(upstream_conn) < 90400)
|
||||||
|
check_93_config();
|
||||||
|
|
||||||
if (get_primary_node_record(upstream_conn, &primary_node_record) == false)
|
if (get_primary_node_record(upstream_conn, &primary_node_record) == false)
|
||||||
{
|
{
|
||||||
log_error(_("unable to retrieve primary node record"));
|
log_error(_("unable to retrieve primary node record"));
|
||||||
@@ -2612,13 +2406,6 @@ do_node_rejoin(void)
|
|||||||
exit(ERR_BAD_CONFIG);
|
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 */
|
/* connect to registered primary and check it's not in recovery */
|
||||||
primary_conn = establish_db_connection(primary_node_record.conninfo, false);
|
primary_conn = establish_db_connection(primary_node_record.conninfo, false);
|
||||||
|
|
||||||
@@ -2671,7 +2458,7 @@ do_node_rejoin(void)
|
|||||||
log_hint(_("check the local node is registered with the current primary \"%s\" (ID: %i)"),
|
log_hint(_("check the local node is registered with the current primary \"%s\" (ID: %i)"),
|
||||||
primary_node_record.node_name,
|
primary_node_record.node_name,
|
||||||
primary_node_record.node_id);
|
primary_node_record.node_id);
|
||||||
|
PQfinish(upstream_conn);
|
||||||
PQfinish(primary_conn);
|
PQfinish(primary_conn);
|
||||||
exit(ERR_BAD_CONFIG);
|
exit(ERR_BAD_CONFIG);
|
||||||
}
|
}
|
||||||
@@ -2695,7 +2482,7 @@ do_node_rejoin(void)
|
|||||||
* sanity-check that it will actually be possible to stream from the new upstream
|
* sanity-check that it will actually be possible to stream from the new upstream
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
bool can_rejoin;
|
bool can_follow;
|
||||||
TimeLineID tli = get_min_recovery_end_timeline(config_file_options.data_directory);
|
TimeLineID tli = get_min_recovery_end_timeline(config_file_options.data_directory);
|
||||||
XLogRecPtr min_recovery_location = get_min_recovery_location(config_file_options.data_directory);
|
XLogRecPtr min_recovery_location = get_min_recovery_location(config_file_options.data_directory);
|
||||||
|
|
||||||
@@ -2709,13 +2496,13 @@ do_node_rejoin(void)
|
|||||||
if (tli == 0)
|
if (tli == 0)
|
||||||
tli = get_timeline(config_file_options.data_directory);
|
tli = get_timeline(config_file_options.data_directory);
|
||||||
|
|
||||||
can_rejoin = check_node_can_attach(tli,
|
can_follow = check_node_can_attach(tli,
|
||||||
min_recovery_location,
|
min_recovery_location,
|
||||||
primary_conn,
|
primary_conn,
|
||||||
&primary_node_record,
|
&primary_node_record,
|
||||||
true);
|
true);
|
||||||
|
|
||||||
if (can_rejoin == false)
|
if (can_follow == false)
|
||||||
{
|
{
|
||||||
PQfinish(primary_conn);
|
PQfinish(primary_conn);
|
||||||
exit(ERR_REJOIN_FAIL);
|
exit(ERR_REJOIN_FAIL);
|
||||||
@@ -2783,9 +2570,9 @@ do_node_rejoin(void)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
make_pg_path(&command, "pg_rewind");
|
appendPQExpBuffer(&command,
|
||||||
appendPQExpBufferStr(&command,
|
"%s -D ",
|
||||||
" -D ");
|
make_pg_path("pg_rewind"));
|
||||||
}
|
}
|
||||||
|
|
||||||
appendShellString(&command,
|
appendShellString(&command,
|
||||||
@@ -2807,30 +2594,6 @@ do_node_rejoin(void)
|
|||||||
log_detail(_("pg_rewind command is \"%s\""),
|
log_detail(_("pg_rewind command is \"%s\""),
|
||||||
command.data);
|
command.data);
|
||||||
|
|
||||||
/*
|
|
||||||
* In Pg13 and later, pg_rewind will attempt to start up a server which
|
|
||||||
* was not cleanly shut down in single user mode. This will fail if
|
|
||||||
* "standby.signal" is present. We'll remove it and restore it after
|
|
||||||
* pg_rewind runs.
|
|
||||||
*/
|
|
||||||
if (hide_standby_signal == true)
|
|
||||||
{
|
|
||||||
char standby_signal_file_path[MAXPGPATH] = "";
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
if (unlink(standby_signal_file_path) < 0 && errno != ENOENT)
|
|
||||||
{
|
|
||||||
log_error(_("unable to remove \"standby.signal\" file in data directory \"%s\""),
|
|
||||||
standby_signal_file_path);
|
|
||||||
log_detail("%s", strerror(errno));
|
|
||||||
exit(ERR_REJOIN_FAIL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
initPQExpBuffer(&command_output);
|
initPQExpBuffer(&command_output);
|
||||||
|
|
||||||
ret = local_command(command.data,
|
ret = local_command(command.data,
|
||||||
@@ -2838,19 +2601,9 @@ do_node_rejoin(void)
|
|||||||
|
|
||||||
termPQExpBuffer(&command);
|
termPQExpBuffer(&command);
|
||||||
|
|
||||||
if (hide_standby_signal == true)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Restore standby.signal if we previously removed it, regardless
|
|
||||||
* of whether the pg_rewind operation failed.
|
|
||||||
*/
|
|
||||||
log_notice(_("recreating \"standby.signal\""));
|
|
||||||
write_standby_signal();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ret == false)
|
if (ret == false)
|
||||||
{
|
{
|
||||||
log_error(_("pg_rewind execution failed"));
|
log_error(_("unable to execute pg_rewind"));
|
||||||
log_detail("%s", command_output.data);
|
log_detail("%s", command_output.data);
|
||||||
|
|
||||||
termPQExpBuffer(&command_output);
|
termPQExpBuffer(&command_output);
|
||||||
@@ -2918,7 +2671,7 @@ do_node_rejoin(void)
|
|||||||
struct stat statbuf;
|
struct stat statbuf;
|
||||||
PQExpBufferData slotdir_ent_path;
|
PQExpBufferData slotdir_ent_path;
|
||||||
|
|
||||||
if (strcmp(slotdir_ent->d_name, ".") == 0 || strcmp(slotdir_ent->d_name, "..") == 0)
|
if(strcmp(slotdir_ent->d_name, ".") == 0 || strcmp(slotdir_ent->d_name, "..") == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
initPQExpBuffer(&slotdir_ent_path);
|
initPQExpBuffer(&slotdir_ent_path);
|
||||||
@@ -3024,7 +2777,7 @@ do_node_rejoin(void)
|
|||||||
config_file_options.node_rejoin_timeout);
|
config_file_options.node_rejoin_timeout);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
log_detail(_("no active record for local node \"%s\" found in node \"%s\"'s \"pg_stat_replication\" table"),
|
log_detail(_("no record for local node \"%s\" found in node \"%s\"'s \"pg_stat_replication\" table"),
|
||||||
config_file_options.node_name,
|
config_file_options.node_name,
|
||||||
primary_node_record.node_name);
|
primary_node_record.node_name);
|
||||||
}
|
}
|
||||||
@@ -3036,7 +2789,7 @@ do_node_rejoin(void)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* -W/--no-wait provided - check once */
|
/* -W/--no-wait provided - check once */
|
||||||
NodeAttached node_attached = is_downstream_node_attached(primary_conn, config_file_options.node_name, NULL);
|
NodeAttached node_attached = is_downstream_node_attached(primary_conn, config_file_options.node_name);
|
||||||
if (node_attached == NODE_ATTACHED)
|
if (node_attached == NODE_ATTACHED)
|
||||||
success = true;
|
success = true;
|
||||||
}
|
}
|
||||||
@@ -3606,7 +3359,7 @@ do_node_help(void)
|
|||||||
printf(_(" Following options check an individual status:\n"));
|
printf(_(" Following options check an individual status:\n"));
|
||||||
printf(_(" --archive-ready number of WAL files ready for archiving\n"));
|
printf(_(" --archive-ready number of WAL files ready for archiving\n"));
|
||||||
printf(_(" --downstream whether all downstream nodes are connected\n"));
|
printf(_(" --downstream whether all downstream nodes are connected\n"));
|
||||||
printf(_(" --upstream whether the node is connected to its upstream\n"));
|
printf(_(" --uptream whether the node is connected to its upstream\n"));
|
||||||
printf(_(" --replication-lag replication lag in seconds (standbys only)\n"));
|
printf(_(" --replication-lag replication lag in seconds (standbys only)\n"));
|
||||||
printf(_(" --role check node has expected role\n"));
|
printf(_(" --role check node has expected role\n"));
|
||||||
printf(_(" --slots check for inactive replication slots\n"));
|
printf(_(" --slots check for inactive replication slots\n"));
|
||||||
@@ -3624,7 +3377,7 @@ do_node_help(void)
|
|||||||
printf(_(" --dry-run check that the prerequisites are met for rejoining the node\n" \
|
printf(_(" --dry-run check that the prerequisites are met for rejoining the node\n" \
|
||||||
" (including usability of \"pg_rewind\" if requested)\n"));
|
" (including usability of \"pg_rewind\" if requested)\n"));
|
||||||
printf(_(" --force-rewind[=VALUE] execute \"pg_rewind\" if necessary\n"));
|
printf(_(" --force-rewind[=VALUE] execute \"pg_rewind\" if necessary\n"));
|
||||||
printf(_(" (PostgreSQL 9.4 - provide full \"pg_rewind\" path)\n"));
|
printf(_(" (9.3 and 9.4 - provide full \"pg_rewind\" path)\n"));
|
||||||
|
|
||||||
printf(_(" --config-files comma-separated list of configuration files to retain\n" \
|
printf(_(" --config-files comma-separated list of configuration files to retain\n" \
|
||||||
" after executing \"pg_rewind\"\n"));
|
" after executing \"pg_rewind\"\n"));
|
||||||
@@ -3645,8 +3398,8 @@ do_node_help(void)
|
|||||||
printf(_(" --list-actions show what command would be performed for each action\n"));
|
printf(_(" --list-actions show what command would be performed for each action\n"));
|
||||||
printf(_(" --checkpoint issue a CHECKPOINT before stopping or restarting the node\n"));
|
printf(_(" --checkpoint issue a CHECKPOINT before stopping or restarting the node\n"));
|
||||||
printf(_(" -S, --superuser=USERNAME superuser to use, if repmgr user is not superuser\n"));
|
printf(_(" -S, --superuser=USERNAME superuser to use, if repmgr user is not superuser\n"));
|
||||||
|
|
||||||
puts("");
|
puts("");
|
||||||
|
|
||||||
printf(_("%s home page: <%s>\n"), "repmgr", REPMGR_URL);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* repmgr-action-node.h
|
* repmgr-action-node.h
|
||||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Implements primary actions for the repmgr command line utility
|
* Implements primary actions for the repmgr command line utility
|
||||||
*
|
*
|
||||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -454,9 +454,9 @@ do_primary_unregister(void)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* This appears to be the cluster primary - cowardly refuse to
|
* This appears to be the cluster primary - cowardly refuse to
|
||||||
* delete the record, unless --force is supplied.
|
* delete the record
|
||||||
*/
|
*/
|
||||||
if (primary_node_info.node_id == target_node_info_ptr->node_id && !runtime_options.force)
|
if (primary_node_info.node_id == target_node_info_ptr->node_id)
|
||||||
{
|
{
|
||||||
log_error(_("node \"%s\" (ID: %i) is the current primary node, unable to unregister"),
|
log_error(_("node \"%s\" (ID: %i) is the current primary node, unable to unregister"),
|
||||||
target_node_info_ptr->node_name,
|
target_node_info_ptr->node_name,
|
||||||
@@ -575,5 +575,4 @@ do_primary_help(void)
|
|||||||
|
|
||||||
puts("");
|
puts("");
|
||||||
|
|
||||||
printf(_("%s home page: <%s>\n"), "repmgr", REPMGR_URL);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* repmgr-action-primary.h
|
* repmgr-action-primary.h
|
||||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
* repmgr-action-service.c
|
* repmgr-action-service.c
|
||||||
*
|
*
|
||||||
* Implements repmgrd actions for the repmgr command line utility
|
* Implements repmgrd actions for the repmgr command line utility
|
||||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -543,6 +543,4 @@ void do_service_help(void)
|
|||||||
puts("");
|
puts("");
|
||||||
|
|
||||||
puts("");
|
puts("");
|
||||||
|
|
||||||
printf(_("%s home page: <%s>\n"), "repmgr", REPMGR_URL);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* repmgr-action-service.h
|
* repmgr-action-service.h
|
||||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* repmgr-action-standby.h
|
* repmgr-action-standby.h
|
||||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Implements witness actions for the repmgr command line utility
|
* Implements witness actions for the repmgr command line utility
|
||||||
*
|
*
|
||||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -560,7 +560,7 @@ void do_witness_help(void)
|
|||||||
|
|
||||||
printf(_("WITNESS UNREGISTER\n"));
|
printf(_("WITNESS UNREGISTER\n"));
|
||||||
puts("");
|
puts("");
|
||||||
printf(_(" \"witness unregister\" unregisters a witness node.\n"));
|
printf(_(" \"witness register\" unregisters a witness node.\n"));
|
||||||
puts("");
|
puts("");
|
||||||
printf(_(" --dry-run check prerequisites but don't make any changes\n"));
|
printf(_(" --dry-run check prerequisites but don't make any changes\n"));
|
||||||
printf(_(" -F, --force unregister when witness node not running\n"));
|
printf(_(" -F, --force unregister when witness node not running\n"));
|
||||||
@@ -569,5 +569,5 @@ void do_witness_help(void)
|
|||||||
|
|
||||||
puts("");
|
puts("");
|
||||||
|
|
||||||
printf(_("%s home page: <%s>\n"), "repmgr", REPMGR_URL);
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* repmgr-action-witness.h
|
* repmgr-action-witness.h
|
||||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* repmgr-client-global.h
|
* repmgr-client-global.h
|
||||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -48,7 +48,6 @@ typedef struct
|
|||||||
bool no_wait;
|
bool no_wait;
|
||||||
bool compact;
|
bool compact;
|
||||||
bool detail;
|
bool detail;
|
||||||
bool dump_config;
|
|
||||||
|
|
||||||
/* logging options */
|
/* logging options */
|
||||||
char log_level[MAXLEN]; /* overrides setting in repmgr.conf */
|
char log_level[MAXLEN]; /* overrides setting in repmgr.conf */
|
||||||
@@ -84,12 +83,11 @@ typedef struct
|
|||||||
bool fast_checkpoint;
|
bool fast_checkpoint;
|
||||||
bool rsync_only;
|
bool rsync_only;
|
||||||
bool no_upstream_connection;
|
bool no_upstream_connection;
|
||||||
char recovery_min_apply_delay[MAXLEN]; /* overrides setting in repmgr.conf */
|
char recovery_min_apply_delay[MAXLEN];
|
||||||
char replication_user[MAXLEN];
|
char replication_user[MAXLEN];
|
||||||
char upstream_conninfo[MAXLEN];
|
char upstream_conninfo[MAXLEN];
|
||||||
bool without_barman;
|
bool without_barman;
|
||||||
bool replication_conf_only;
|
bool replication_conf_only;
|
||||||
bool verify_backup;
|
|
||||||
|
|
||||||
/* "standby clone"/"standby follow" options */
|
/* "standby clone"/"standby follow" options */
|
||||||
int upstream_node_id;
|
int upstream_node_id;
|
||||||
@@ -122,7 +120,6 @@ typedef struct
|
|||||||
bool replication_connection;
|
bool replication_connection;
|
||||||
bool data_directory_config;
|
bool data_directory_config;
|
||||||
bool replication_config_owner;
|
bool replication_config_owner;
|
||||||
bool db_connection;
|
|
||||||
|
|
||||||
/* "node rejoin" options */
|
/* "node rejoin" options */
|
||||||
char config_files[MAXLEN];
|
char config_files[MAXLEN];
|
||||||
@@ -143,7 +140,7 @@ typedef struct
|
|||||||
|
|
||||||
/* following options for internal use */
|
/* following options for internal use */
|
||||||
char config_archive_dir[MAXPGPATH];
|
char config_archive_dir[MAXPGPATH];
|
||||||
OutputMode output_mode; /* set through provision of --csv, --nagios or --optformat */
|
OutputMode output_mode;
|
||||||
bool disable_wal_receiver;
|
bool disable_wal_receiver;
|
||||||
bool enable_wal_receiver;
|
bool enable_wal_receiver;
|
||||||
} t_runtime_options;
|
} t_runtime_options;
|
||||||
@@ -152,7 +149,7 @@ typedef struct
|
|||||||
/* configuration metadata */ \
|
/* configuration metadata */ \
|
||||||
false, false, false, false, false, \
|
false, false, false, false, false, \
|
||||||
/* general configuration options */ \
|
/* general configuration options */ \
|
||||||
"", false, false, "", -1, false, false, false, false, \
|
"", false, false, "", -1, false, false, false, \
|
||||||
/* logging options */ \
|
/* logging options */ \
|
||||||
"", false, false, false, false, \
|
"", false, false, false, false, \
|
||||||
/* output options */ \
|
/* output options */ \
|
||||||
@@ -165,7 +162,7 @@ typedef struct
|
|||||||
UNKNOWN_NODE_ID, "", "", UNKNOWN_NODE_ID, \
|
UNKNOWN_NODE_ID, "", "", UNKNOWN_NODE_ID, \
|
||||||
/* "standby clone" options */ \
|
/* "standby clone" options */ \
|
||||||
false, CONFIG_FILE_SAMEPATH, false, false, false, "", "", "", \
|
false, CONFIG_FILE_SAMEPATH, false, false, false, "", "", "", \
|
||||||
false, false, false, \
|
false, false, \
|
||||||
/* "standby clone"/"standby follow" options */ \
|
/* "standby clone"/"standby follow" options */ \
|
||||||
NO_UPSTREAM_NODE, \
|
NO_UPSTREAM_NODE, \
|
||||||
/* "standby register" options */ \
|
/* "standby register" options */ \
|
||||||
@@ -175,7 +172,7 @@ typedef struct
|
|||||||
/* "node status" options */ \
|
/* "node status" options */ \
|
||||||
false, \
|
false, \
|
||||||
/* "node check" options */ \
|
/* "node check" options */ \
|
||||||
false, false, false, false, false, false, false, false, false, false, false, false, \
|
false, false, false, false, false, false, false, false, false, false, false, \
|
||||||
/* "node rejoin" options */ \
|
/* "node rejoin" options */ \
|
||||||
"", \
|
"", \
|
||||||
/* "node service" options */ \
|
/* "node service" options */ \
|
||||||
@@ -224,13 +221,6 @@ typedef enum
|
|||||||
JOIN_FAIL_NO_REPLICATION
|
JOIN_FAIL_NO_REPLICATION
|
||||||
} standy_join_status;
|
} standy_join_status;
|
||||||
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
REMOTE_ERROR_UNKNOWN = -1,
|
|
||||||
REMOTE_ERROR_NONE,
|
|
||||||
REMOTE_ERROR_DB_CONNECTION,
|
|
||||||
REMOTE_ERROR_CONNINFO_PARSE
|
|
||||||
} t_remote_error_type;
|
|
||||||
|
|
||||||
typedef struct ColHeader
|
typedef struct ColHeader
|
||||||
{
|
{
|
||||||
@@ -242,17 +232,21 @@ typedef struct ColHeader
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* globally available configuration structures */
|
/* global configuration structures */
|
||||||
extern t_runtime_options runtime_options;
|
extern t_runtime_options runtime_options;
|
||||||
extern t_conninfo_param_list source_conninfo;
|
extern t_configuration_options config_file_options;
|
||||||
extern t_node_info target_node_info;
|
|
||||||
|
t_conninfo_param_list source_conninfo;
|
||||||
|
|
||||||
|
|
||||||
/* global variables */
|
|
||||||
extern bool config_file_required;
|
extern bool config_file_required;
|
||||||
extern char pg_bindir[MAXLEN];
|
extern char pg_bindir[MAXLEN];
|
||||||
|
|
||||||
/* global functions */
|
extern t_node_info target_node_info;
|
||||||
|
|
||||||
|
|
||||||
extern int check_server_version(PGconn *conn, char *server_type, bool exit_on_error, char *server_version_string);
|
extern int check_server_version(PGconn *conn, char *server_type, bool exit_on_error, char *server_version_string);
|
||||||
|
extern void check_93_config(void);
|
||||||
extern bool create_repmgr_extension(PGconn *conn);
|
extern bool create_repmgr_extension(PGconn *conn);
|
||||||
extern int test_ssh_connection(char *host, char *remote_user);
|
extern int test_ssh_connection(char *host, char *remote_user);
|
||||||
|
|
||||||
@@ -263,7 +257,7 @@ extern int copy_remote_files(char *host, char *remote_user, char *remote_path,
|
|||||||
|
|
||||||
extern void print_error_list(ItemList *error_list, int log_level);
|
extern void print_error_list(ItemList *error_list, int log_level);
|
||||||
|
|
||||||
extern void make_pg_path(PQExpBufferData *buf, const char *file);
|
extern char *make_pg_path(const char *file);
|
||||||
|
|
||||||
extern void get_superuser_connection(PGconn **conn, PGconn **superuser_conn, PGconn **privileged_conn);
|
extern void get_superuser_connection(PGconn **conn, PGconn **superuser_conn, PGconn **privileged_conn);
|
||||||
|
|
||||||
@@ -282,8 +276,6 @@ extern void get_node_config_directory(char *config_dir_buf);
|
|||||||
extern void get_node_data_directory(char *data_dir_buf);
|
extern void get_node_data_directory(char *data_dir_buf);
|
||||||
extern void init_node_record(t_node_info *node_record);
|
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 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 bool create_replication_slot(PGconn *conn, char *slot_name, t_node_info *upstream_node_record, PQExpBufferData *error_msg);
|
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);
|
extern bool drop_replication_slot_if_exists(PGconn *conn, int node_id, char *slot_name);
|
||||||
|
|||||||
394
repmgr-client.c
394
repmgr-client.c
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* repmgr-client.c - Command interpreter for the repmgr package
|
* repmgr-client.c - Command interpreter for the repmgr package
|
||||||
*
|
*
|
||||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||||
*
|
*
|
||||||
* This module is a command-line utility to easily setup a cluster of
|
* This module is a command-line utility to easily setup a cluster of
|
||||||
* hot standby servers for an HA environment
|
* hot standby servers for an HA environment
|
||||||
@@ -75,13 +75,15 @@
|
|||||||
* ============================ */
|
* ============================ */
|
||||||
|
|
||||||
t_runtime_options runtime_options = T_RUNTIME_OPTIONS_INITIALIZER;
|
t_runtime_options runtime_options = T_RUNTIME_OPTIONS_INITIALIZER;
|
||||||
|
t_configuration_options config_file_options = T_CONFIGURATION_OPTIONS_INITIALIZER;
|
||||||
|
|
||||||
/* conninfo params for the node we're operating on */
|
/* conninfo params for the node we're operating on */
|
||||||
t_conninfo_param_list source_conninfo = T_CONNINFO_PARAM_LIST_INITIALIZER;
|
t_conninfo_param_list source_conninfo = T_CONNINFO_PARAM_LIST_INITIALIZER;
|
||||||
|
|
||||||
bool config_file_required = true;
|
bool config_file_required = true;
|
||||||
char pg_bindir[MAXPGPATH] = "";
|
char pg_bindir[MAXLEN] = "";
|
||||||
|
|
||||||
|
char path_buf[MAXLEN] = "";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* if --node-id/--node-name provided, place that node's record here
|
* if --node-id/--node-name provided, place that node's record here
|
||||||
@@ -122,7 +124,7 @@ main(int argc, char **argv)
|
|||||||
/*
|
/*
|
||||||
* Tell the logger we're a command-line program - this will ensure any
|
* Tell the logger we're a command-line program - this will ensure any
|
||||||
* output logged before the logger is initialized will be formatted
|
* output logged before the logger is initialized will be formatted
|
||||||
* correctly. Can be overridden with "--log-to-file".
|
* correctly. Can be overriden with "--log-to-file".
|
||||||
*/
|
*/
|
||||||
logger_output_mode = OM_COMMAND_LINE;
|
logger_output_mode = OM_COMMAND_LINE;
|
||||||
|
|
||||||
@@ -277,11 +279,6 @@ main(int argc, char **argv)
|
|||||||
runtime_options.detail = true;
|
runtime_options.detail = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* --dump-config */
|
|
||||||
case OPT_DUMP_CONFIG:
|
|
||||||
runtime_options.dump_config = true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
/*----------------------------
|
/*----------------------------
|
||||||
* database connection options
|
* database connection options
|
||||||
*----------------------------
|
*----------------------------
|
||||||
@@ -438,15 +435,6 @@ main(int argc, char **argv)
|
|||||||
runtime_options.replication_conf_only = true;
|
runtime_options.replication_conf_only = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* --recovery-min-apply-delay */
|
|
||||||
case OPT_RECOVERY_MIN_APPLY_DELAY:
|
|
||||||
strncpy(runtime_options.recovery_min_apply_delay, optarg, sizeof(runtime_options.recovery_min_apply_delay));
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* --verify-backup */
|
|
||||||
case OPT_VERIFY_BACKUP:
|
|
||||||
runtime_options.verify_backup = true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
/*---------------------------
|
/*---------------------------
|
||||||
* "standby register" options
|
* "standby register" options
|
||||||
@@ -553,10 +541,6 @@ main(int argc, char **argv)
|
|||||||
runtime_options.replication_config_owner = true;
|
runtime_options.replication_config_owner = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OPT_DB_CONNECTION:
|
|
||||||
runtime_options.db_connection = true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
/*--------------------
|
/*--------------------
|
||||||
* "node rejoin" options
|
* "node rejoin" options
|
||||||
*--------------------
|
*--------------------
|
||||||
@@ -717,12 +701,9 @@ main(int argc, char **argv)
|
|||||||
if (strcmp(argv[optind - 1], "-?") == 0)
|
if (strcmp(argv[optind - 1], "-?") == 0)
|
||||||
{
|
{
|
||||||
help_option = true;
|
help_option = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
else
|
/* otherwise fall through to default */
|
||||||
{
|
|
||||||
option_error_found = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default: /* invalid option */
|
default: /* invalid option */
|
||||||
option_error_found = true;
|
option_error_found = true;
|
||||||
break;
|
break;
|
||||||
@@ -1092,43 +1073,11 @@ main(int argc, char **argv)
|
|||||||
load_config(runtime_options.config_file,
|
load_config(runtime_options.config_file,
|
||||||
runtime_options.verbose,
|
runtime_options.verbose,
|
||||||
runtime_options.terse,
|
runtime_options.terse,
|
||||||
|
&config_file_options,
|
||||||
argv[0]);
|
argv[0]);
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Handle options which must be executed without a repmgr command
|
|
||||||
*/
|
|
||||||
if (runtime_options.dump_config == true)
|
|
||||||
{
|
|
||||||
if (repmgr_command != NULL)
|
|
||||||
{
|
|
||||||
fprintf(stderr,
|
|
||||||
_("--dump-config cannot be used in combination with a repmgr command"));
|
|
||||||
exit(ERR_BAD_CONFIG);
|
|
||||||
}
|
|
||||||
dump_config();
|
|
||||||
exit(SUCCESS);
|
|
||||||
}
|
|
||||||
|
|
||||||
check_cli_parameters(action);
|
check_cli_parameters(action);
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Command-line parameter --recovery-min-apply-delay overrides the equivalent
|
|
||||||
* setting in the config file. Note we'll need to parse it here to handle
|
|
||||||
* any formatting errors.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (*runtime_options.recovery_min_apply_delay != '\0')
|
|
||||||
{
|
|
||||||
parse_time_unit_parameter("--recovery-min-apply-delay",
|
|
||||||
runtime_options.recovery_min_apply_delay,
|
|
||||||
config_file_options.recovery_min_apply_delay,
|
|
||||||
&cli_errors);
|
|
||||||
|
|
||||||
config_file_options.recovery_min_apply_delay_provided = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Sanity checks for command line parameters completed by now; any further
|
* Sanity checks for command line parameters completed by now; any further
|
||||||
* errors will be runtime ones
|
* errors will be runtime ones
|
||||||
@@ -1189,7 +1138,7 @@ main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check for configuration file items which can be overridden by runtime
|
* Check for configuration file items which can be overriden by runtime
|
||||||
* options
|
* options
|
||||||
* =====================================================================
|
* =====================================================================
|
||||||
*/
|
*/
|
||||||
@@ -1247,7 +1196,7 @@ main(int argc, char **argv)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* If --dry-run specified, ensure log_level is at least LOG_INFO, regardless
|
* If --dry-run specified, ensure log_level is at least LOG_INFO, regardless
|
||||||
* of what's in the configuration file or -L/--log-level parameter, otherwise
|
* of what's in the configuration file or -L/--log-level paremeter, otherwise
|
||||||
* some or output might not be displayed.
|
* some or output might not be displayed.
|
||||||
*/
|
*/
|
||||||
if (runtime_options.dry_run == true)
|
if (runtime_options.dry_run == true)
|
||||||
@@ -1265,6 +1214,8 @@ main(int argc, char **argv)
|
|||||||
logger_set_level(LOG_ERROR);
|
logger_set_level(LOG_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Node configuration information is not needed for all actions, with
|
* Node configuration information is not needed for all actions, with
|
||||||
* STANDBY CLONE being the main exception.
|
* STANDBY CLONE being the main exception.
|
||||||
@@ -2339,7 +2290,7 @@ format_node_status(t_node_info *node_info, PQExpBufferData *node_status, PQExpBu
|
|||||||
node_info->node_id);
|
node_info->node_id);
|
||||||
}
|
}
|
||||||
/* mismatch between reported upstream and upstream in local node's metadata */
|
/* mismatch between reported upstream and upstream in local node's metadata */
|
||||||
else if (node_info->upstream_node_id != remote_node_rec.upstream_node_id)
|
else if(node_info->upstream_node_id != remote_node_rec.upstream_node_id)
|
||||||
{
|
{
|
||||||
appendPQExpBufferStr(upstream, "! ");
|
appendPQExpBufferStr(upstream, "! ");
|
||||||
|
|
||||||
@@ -2400,7 +2351,6 @@ format_node_status(t_node_info *node_info, PQExpBufferData *node_status, PQExpBu
|
|||||||
* connected to the upstream
|
* connected to the upstream
|
||||||
*/
|
*/
|
||||||
NodeAttached attached_to_upstream = NODE_ATTACHED_UNKNOWN;
|
NodeAttached attached_to_upstream = NODE_ATTACHED_UNKNOWN;
|
||||||
char *replication_state = NULL;
|
|
||||||
t_node_info upstream_node_rec = T_NODE_INFO_INITIALIZER;
|
t_node_info upstream_node_rec = T_NODE_INFO_INITIALIZER;
|
||||||
RecordStatus upstream_node_rec_found = get_node_record(node_info->conn,
|
RecordStatus upstream_node_rec_found = get_node_record(node_info->conn,
|
||||||
node_info->upstream_node_id,
|
node_info->upstream_node_id,
|
||||||
@@ -2428,7 +2378,7 @@ format_node_status(t_node_info *node_info, PQExpBufferData *node_status, PQExpBu
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
attached_to_upstream = is_downstream_node_attached(upstream_conn, node_info->node_name, &replication_state);
|
attached_to_upstream = is_downstream_node_attached(upstream_conn, node_info->node_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
PQfinish(upstream_conn);
|
PQfinish(upstream_conn);
|
||||||
@@ -2444,18 +2394,6 @@ format_node_status(t_node_info *node_info, PQExpBufferData *node_status, PQExpBu
|
|||||||
upstream_node_rec.node_name,
|
upstream_node_rec.node_name,
|
||||||
upstream_node_rec.node_id);
|
upstream_node_rec.node_id);
|
||||||
}
|
}
|
||||||
if (attached_to_upstream == NODE_NOT_ATTACHED)
|
|
||||||
{
|
|
||||||
appendPQExpBufferStr(upstream, "? ");
|
|
||||||
item_list_append_format(warnings,
|
|
||||||
"node \"%s\" (ID: %i) attached to its upstream node \"%s\" (ID: %i) in state \"%s\"",
|
|
||||||
node_info->node_name,
|
|
||||||
node_info->node_id,
|
|
||||||
upstream_node_rec.node_name,
|
|
||||||
upstream_node_rec.node_id,
|
|
||||||
replication_state);
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (attached_to_upstream == NODE_DETACHED)
|
else if (attached_to_upstream == NODE_DETACHED)
|
||||||
{
|
{
|
||||||
appendPQExpBufferStr(upstream, "! ");
|
appendPQExpBufferStr(upstream, "! ");
|
||||||
@@ -2724,8 +2662,6 @@ do_help(void)
|
|||||||
printf(_(" -v, --verbose display additional log output (useful for debugging)\n"));
|
printf(_(" -v, --verbose display additional log output (useful for debugging)\n"));
|
||||||
|
|
||||||
puts("");
|
puts("");
|
||||||
|
|
||||||
printf(_("%s home page: <%s>\n"), "repmgr", REPMGR_URL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -2735,7 +2671,7 @@ do_help(void)
|
|||||||
*
|
*
|
||||||
* Note:
|
* Note:
|
||||||
* This is one of two places where superuser rights are required.
|
* This is one of two places where superuser rights are required.
|
||||||
* We should also consider possible scenarios where a non-superuser
|
* We should also consider possible scenarious where a non-superuser
|
||||||
* has sufficient privileges to install the extension.
|
* has sufficient privileges to install the extension.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -2770,7 +2706,7 @@ create_repmgr_extension(PGconn *conn)
|
|||||||
log_detail(_("version %s is installed but newer version %s is available"),
|
log_detail(_("version %s is installed but newer version %s is available"),
|
||||||
extversions.installed_version,
|
extversions.installed_version,
|
||||||
extversions.default_version);
|
extversions.default_version);
|
||||||
log_hint(_("update the installed extension version by executing \"ALTER EXTENSION repmgr UPDATE\" in the repmgr database"));
|
log_hint(_("update the installed extension version by executing \"ALTER EXTENSION repmgr UPDATE\""));
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
case REPMGR_INSTALLED:
|
case REPMGR_INSTALLED:
|
||||||
@@ -2936,7 +2872,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
|
* 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
|
* 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
|
* MAX_UNSUPPORTED_VERSION_NUM in "repmgr.h" to define the first PostgreSQL
|
||||||
* version which can't be supported.
|
* version which can't be suppored.
|
||||||
*/
|
*/
|
||||||
#ifdef MAX_UNSUPPORTED_VERSION_NUM
|
#ifdef MAX_UNSUPPORTED_VERSION_NUM
|
||||||
if (conn_server_version_num >= MAX_UNSUPPORTED_VERSION_NUM)
|
if (conn_server_version_num >= MAX_UNSUPPORTED_VERSION_NUM)
|
||||||
@@ -2967,6 +2903,30 @@ check_server_version(PGconn *conn, char *server_type, bool exit_on_error, char *
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* check_93_config()
|
||||||
|
*
|
||||||
|
* Disable options not compatible with PostgreSQL 9.3
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
check_93_config(void)
|
||||||
|
{
|
||||||
|
if (config_file_options.recovery_min_apply_delay_provided == true)
|
||||||
|
{
|
||||||
|
config_file_options.recovery_min_apply_delay_provided = false;
|
||||||
|
log_warning(_("configuration file option \"recovery_min_apply_delay\" not compatible with PostgreSQL 9.3, ignoring"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config_file_options.use_replication_slots == true)
|
||||||
|
{
|
||||||
|
config_file_options.use_replication_slots = false;
|
||||||
|
log_warning(_("configuration file option \"use_replication_slots\" not compatible with PostgreSQL 9.3, ignoring"));
|
||||||
|
log_hint(_("replication slots are available from PostgreSQL 9.4"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
test_ssh_connection(char *host, char *remote_user)
|
test_ssh_connection(char *host, char *remote_user)
|
||||||
{
|
{
|
||||||
@@ -3079,6 +3039,7 @@ get_superuser_connection(PGconn **conn, PGconn **superuser_conn, PGconn **privil
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
standy_clone_mode
|
standy_clone_mode
|
||||||
get_standby_clone_mode(void)
|
get_standby_clone_mode(void)
|
||||||
{
|
{
|
||||||
@@ -3093,11 +3054,12 @@ get_standby_clone_mode(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
char *
|
||||||
make_pg_path(PQExpBufferData *buf, const char *file)
|
make_pg_path(const char *file)
|
||||||
{
|
{
|
||||||
appendPQExpBuffer(buf, "%s%s",
|
maxlen_snprintf(path_buf, "%s%s", pg_bindir, file);
|
||||||
pg_bindir, file);
|
|
||||||
|
return path_buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -3158,12 +3120,15 @@ copy_remote_files(char *host, char *remote_user, char *remote_path,
|
|||||||
appendPQExpBufferStr(&rsync_flags,
|
appendPQExpBufferStr(&rsync_flags,
|
||||||
" --exclude=recovery.conf --exclude=recovery.done");
|
" --exclude=recovery.conf --exclude=recovery.done");
|
||||||
|
|
||||||
/*
|
if (server_version_num >= 90400)
|
||||||
* Ideally we'd use PG_AUTOCONF_FILENAME from utils/guc.h, but
|
{
|
||||||
* that has too many dependencies for a mere client program.
|
/*
|
||||||
*/
|
* Ideally we'd use PG_AUTOCONF_FILENAME from utils/guc.h, but
|
||||||
appendPQExpBuffer(&rsync_flags, " --exclude=%s.tmp",
|
* that has too many dependencies for a mere client program.
|
||||||
PG_AUTOCONF_FILENAME);
|
*/
|
||||||
|
appendPQExpBuffer(&rsync_flags, " --exclude=%s.tmp",
|
||||||
|
PG_AUTOCONF_FILENAME);
|
||||||
|
}
|
||||||
|
|
||||||
/* Temporary files which we don't want, if they exist */
|
/* Temporary files which we don't want, if they exist */
|
||||||
appendPQExpBuffer(&rsync_flags, " --exclude=%s*",
|
appendPQExpBuffer(&rsync_flags, " --exclude=%s*",
|
||||||
@@ -3174,16 +3139,16 @@ copy_remote_files(char *host, char *remote_user, char *remote_path,
|
|||||||
if (server_version_num >= 100000)
|
if (server_version_num >= 100000)
|
||||||
{
|
{
|
||||||
appendPQExpBufferStr(&rsync_flags,
|
appendPQExpBufferStr(&rsync_flags,
|
||||||
" --exclude=pg_wal/* --exclude=log/*");
|
" --exclude=pg_wal/*");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
appendPQExpBufferStr(&rsync_flags,
|
appendPQExpBufferStr(&rsync_flags,
|
||||||
" --exclude=pg_xlog/* --exclude=pg_log/*");
|
" --exclude=pg_xlog/*");
|
||||||
}
|
}
|
||||||
|
|
||||||
appendPQExpBufferStr(&rsync_flags,
|
appendPQExpBufferStr(&rsync_flags,
|
||||||
" --exclude=pg_stat_tmp/*");
|
" --exclude=pg_log/* --exclude=pg_stat_tmp/*");
|
||||||
|
|
||||||
maxlen_snprintf(script, "rsync %s %s:%s/* %s",
|
maxlen_snprintf(script, "rsync %s %s:%s/* %s",
|
||||||
rsync_flags.data, host_string, remote_path, local_path);
|
rsync_flags.data, host_string, remote_path, local_path);
|
||||||
@@ -3310,10 +3275,9 @@ get_server_action(t_server_action action, char *script, char *data_dir)
|
|||||||
{
|
{
|
||||||
initPQExpBuffer(&command);
|
initPQExpBuffer(&command);
|
||||||
|
|
||||||
make_pg_path(&command, "pg_ctl");
|
|
||||||
|
|
||||||
appendPQExpBuffer(&command,
|
appendPQExpBuffer(&command,
|
||||||
" %s -w -D ",
|
"%s %s -w -D ",
|
||||||
|
make_pg_path("pg_ctl"),
|
||||||
config_file_options.pg_ctl_options);
|
config_file_options.pg_ctl_options);
|
||||||
|
|
||||||
appendShellString(&command,
|
appendShellString(&command,
|
||||||
@@ -3341,10 +3305,9 @@ get_server_action(t_server_action action, char *script, char *data_dir)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
initPQExpBuffer(&command);
|
initPQExpBuffer(&command);
|
||||||
make_pg_path(&command, "pg_ctl");
|
|
||||||
|
|
||||||
appendPQExpBuffer(&command,
|
appendPQExpBuffer(&command,
|
||||||
" %s -D ",
|
"%s %s -D ",
|
||||||
|
make_pg_path("pg_ctl"),
|
||||||
config_file_options.pg_ctl_options);
|
config_file_options.pg_ctl_options);
|
||||||
|
|
||||||
appendShellString(&command,
|
appendShellString(&command,
|
||||||
@@ -3377,11 +3340,9 @@ get_server_action(t_server_action action, char *script, char *data_dir)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
initPQExpBuffer(&command);
|
initPQExpBuffer(&command);
|
||||||
|
|
||||||
make_pg_path(&command, "pg_ctl");
|
|
||||||
|
|
||||||
appendPQExpBuffer(&command,
|
appendPQExpBuffer(&command,
|
||||||
" %s -w -D ",
|
"%s %s -w -D ",
|
||||||
|
make_pg_path("pg_ctl"),
|
||||||
config_file_options.pg_ctl_options);
|
config_file_options.pg_ctl_options);
|
||||||
|
|
||||||
appendShellString(&command,
|
appendShellString(&command,
|
||||||
@@ -3407,11 +3368,9 @@ get_server_action(t_server_action action, char *script, char *data_dir)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
initPQExpBuffer(&command);
|
initPQExpBuffer(&command);
|
||||||
|
|
||||||
make_pg_path(&command, "pg_ctl");
|
|
||||||
|
|
||||||
appendPQExpBuffer(&command,
|
appendPQExpBuffer(&command,
|
||||||
" %s -w -D ",
|
"%s %s -w -D ",
|
||||||
|
make_pg_path("pg_ctl"),
|
||||||
config_file_options.pg_ctl_options);
|
config_file_options.pg_ctl_options);
|
||||||
|
|
||||||
appendShellString(&command,
|
appendShellString(&command,
|
||||||
@@ -3438,11 +3397,9 @@ get_server_action(t_server_action action, char *script, char *data_dir)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
initPQExpBuffer(&command);
|
initPQExpBuffer(&command);
|
||||||
|
|
||||||
make_pg_path(&command, "pg_ctl");
|
|
||||||
|
|
||||||
appendPQExpBuffer(&command,
|
appendPQExpBuffer(&command,
|
||||||
" %s -w -D ",
|
"%s %s -w -D ",
|
||||||
|
make_pg_path("pg_ctl"),
|
||||||
config_file_options.pg_ctl_options);
|
config_file_options.pg_ctl_options);
|
||||||
|
|
||||||
appendShellString(&command,
|
appendShellString(&command,
|
||||||
@@ -3616,6 +3573,27 @@ can_use_pg_rewind(PGconn *conn, const char *data_directory, PQExpBufferData *rea
|
|||||||
{
|
{
|
||||||
bool can_use = true;
|
bool can_use = true;
|
||||||
|
|
||||||
|
/* wal_log_hints not available in 9.3, so just determine if data checksums enabled */
|
||||||
|
if (PQserverVersion(conn) < 90400)
|
||||||
|
{
|
||||||
|
int data_checksum_version = get_data_checksum_version(data_directory);
|
||||||
|
|
||||||
|
if (data_checksum_version < 0)
|
||||||
|
{
|
||||||
|
appendPQExpBuffer(reason,
|
||||||
|
_("unable to determine data checksum version"));
|
||||||
|
can_use = false;
|
||||||
|
}
|
||||||
|
else if (data_checksum_version == 0)
|
||||||
|
{
|
||||||
|
appendPQExpBuffer(reason,
|
||||||
|
_("this cluster was initialised without data checksums"));
|
||||||
|
can_use = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return can_use;
|
||||||
|
}
|
||||||
|
|
||||||
/* "full_page_writes" must be on in any case */
|
/* "full_page_writes" must be on in any case */
|
||||||
if (guc_set(conn, "full_page_writes", "=", "off"))
|
if (guc_set(conn, "full_page_writes", "=", "off"))
|
||||||
{
|
{
|
||||||
@@ -3635,7 +3613,7 @@ can_use_pg_rewind(PGconn *conn, const char *data_directory, PQExpBufferData *rea
|
|||||||
{
|
{
|
||||||
int data_checksum_version = get_data_checksum_version(data_directory);
|
int data_checksum_version = get_data_checksum_version(data_directory);
|
||||||
|
|
||||||
if (data_checksum_version == UNKNOWN_DATA_CHECKSUM_VERSION)
|
if (data_checksum_version < 0)
|
||||||
{
|
{
|
||||||
if (can_use == false)
|
if (can_use == false)
|
||||||
appendPQExpBuffer(reason, "; ");
|
appendPQExpBuffer(reason, "; ");
|
||||||
@@ -3660,64 +3638,8 @@ can_use_pg_rewind(PGconn *conn, const char *data_directory, PQExpBufferData *rea
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
// provided connection should be for the normal repmgr user
|
||||||
make_standby_signal_path(char *buf)
|
// upstream_node_record may be NULL or initialised to default values
|
||||||
{
|
|
||||||
snprintf(buf, MAXPGPATH,
|
|
||||||
"%s/%s",
|
|
||||||
config_file_options.data_directory,
|
|
||||||
STANDBY_SIGNAL_FILE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* create standby.signal (PostgreSQL 12 and later)
|
|
||||||
*/
|
|
||||||
bool
|
|
||||||
write_standby_signal(void)
|
|
||||||
{
|
|
||||||
char standby_signal_file_path[MAXPGPATH] = "";
|
|
||||||
FILE *file;
|
|
||||||
mode_t um;
|
|
||||||
|
|
||||||
make_standby_signal_path(standby_signal_file_path);
|
|
||||||
|
|
||||||
/* Set umask to 0600 */
|
|
||||||
um = umask((~(S_IRUSR | S_IWUSR)) & (S_IRWXG | S_IRWXO));
|
|
||||||
file = fopen(standby_signal_file_path, "w");
|
|
||||||
umask(um);
|
|
||||||
|
|
||||||
if (file == NULL)
|
|
||||||
{
|
|
||||||
log_error(_("unable to create %s file at \"%s\""),
|
|
||||||
STANDBY_SIGNAL_FILE,
|
|
||||||
standby_signal_file_path);
|
|
||||||
log_detail("%s", strerror(errno));
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fputs("# created by repmgr\n", file) == EOF)
|
|
||||||
{
|
|
||||||
log_error(_("unable to write to %s file at \"%s\""),
|
|
||||||
STANDBY_SIGNAL_FILE,
|
|
||||||
standby_signal_file_path);
|
|
||||||
fclose(file);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(file);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* NOTE:
|
|
||||||
* - the provided connection should be for the normal repmgr user
|
|
||||||
* - if upstream_node_record is not NULL, its "repluser" entry, if
|
|
||||||
* set, will be used as the fallback replication user
|
|
||||||
*/
|
|
||||||
bool
|
bool
|
||||||
create_replication_slot(PGconn *conn, char *slot_name, t_node_info *upstream_node_record, PQExpBufferData *error_msg)
|
create_replication_slot(PGconn *conn, char *slot_name, t_node_info *upstream_node_record, PQExpBufferData *error_msg)
|
||||||
{
|
{
|
||||||
@@ -4064,10 +3986,8 @@ check_standby_join(PGconn *upstream_conn, t_node_info *upstream_node_record, t_n
|
|||||||
|
|
||||||
for (; i < config_file_options.node_rejoin_timeout; i++)
|
for (; i < config_file_options.node_rejoin_timeout; i++)
|
||||||
{
|
{
|
||||||
char *node_state = NULL;
|
|
||||||
NodeAttached node_attached = is_downstream_node_attached(upstream_conn,
|
NodeAttached node_attached = is_downstream_node_attached(upstream_conn,
|
||||||
standby_node_record->node_name,
|
standby_node_record->node_name);
|
||||||
&node_state);
|
|
||||||
if (node_attached == NODE_ATTACHED)
|
if (node_attached == NODE_ATTACHED)
|
||||||
{
|
{
|
||||||
log_verbose(LOG_INFO, _("node \"%s\" (ID: %i) has attached to its upstream node"),
|
log_verbose(LOG_INFO, _("node \"%s\" (ID: %i) has attached to its upstream node"),
|
||||||
@@ -4084,19 +4004,9 @@ check_standby_join(PGconn *upstream_conn, t_node_info *upstream_node_record, t_n
|
|||||||
i + 1,
|
i + 1,
|
||||||
config_file_options.node_rejoin_timeout);
|
config_file_options.node_rejoin_timeout);
|
||||||
|
|
||||||
if (node_attached == NODE_NOT_ATTACHED)
|
log_detail(_("checking for record in node \"%s\"'s \"pg_stat_replication\" table where \"application_name\" is \"%s\""),
|
||||||
{
|
upstream_node_record->node_name,
|
||||||
log_detail(_("node \"%s\" (ID: %i) is currently attached to its upstream node in state \"%s\""),
|
standby_node_record->node_name);
|
||||||
upstream_node_record->node_name,
|
|
||||||
standby_node_record->node_id,
|
|
||||||
node_state);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
log_detail(_("checking for record in node \"%s\"'s \"pg_stat_replication\" table where \"application_name\" is \"%s\""),
|
|
||||||
upstream_node_record->node_name,
|
|
||||||
standby_node_record->node_name);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -4116,7 +4026,7 @@ check_standby_join(PGconn *upstream_conn, t_node_info *upstream_node_record, t_n
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Here we'll perform some timeline sanity checks to ensure the follow target
|
* Here we'll perform some timeline sanity checks to ensure the follow target
|
||||||
* can actually be followed or rejoined.
|
* can actually be followed.
|
||||||
*
|
*
|
||||||
* See also comment for check_node_can_follow() in repmgrd-physical.c .
|
* See also comment for check_node_can_follow() in repmgrd-physical.c .
|
||||||
*/
|
*/
|
||||||
@@ -4156,31 +4066,10 @@ check_node_can_attach(TimeLineID local_tli, XLogRecPtr local_xlogpos, PGconn *fo
|
|||||||
local_system_identifier = get_system_identifier(config_file_options.data_directory);
|
local_system_identifier = get_system_identifier(config_file_options.data_directory);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check for things that should never happen, but expect the unexpected anyway.
|
* Check for thing that should never happen, but expect the unexpected anyway.
|
||||||
*/
|
*/
|
||||||
|
if (follow_target_identification.system_identifier != local_system_identifier)
|
||||||
if (local_system_identifier == UNKNOWN_SYSTEM_IDENTIFIER)
|
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
* We don't return immediately here so subsequent checks can be
|
|
||||||
* made, but indicate the node will not be able to rejoin.
|
|
||||||
*/
|
|
||||||
success = false;
|
|
||||||
if (runtime_options.dry_run == true)
|
|
||||||
{
|
|
||||||
log_warning(_("unable to retrieve system identifier from pg_control"));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
log_error(_("unable to retrieve system identifier from pg_control, aborting"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (follow_target_identification.system_identifier != local_system_identifier)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* It's never going to be possible to rejoin a node from another cluster,
|
|
||||||
* so no need to bother with further checks.
|
|
||||||
*/
|
|
||||||
log_error(_("this node is not part of the %s target node's replication cluster"), action);
|
log_error(_("this node is not part of the %s target node's replication cluster"), action);
|
||||||
log_detail(_("this node's system identifier is %lu, %s target node's system identifier is %lu"),
|
log_detail(_("this node's system identifier is %lu, %s target node's system identifier is %lu"),
|
||||||
local_system_identifier,
|
local_system_identifier,
|
||||||
@@ -4189,7 +4078,8 @@ check_node_can_attach(TimeLineID local_tli, XLogRecPtr local_xlogpos, PGconn *fo
|
|||||||
PQfinish(follow_target_repl_conn);
|
PQfinish(follow_target_repl_conn);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if (runtime_options.dry_run == true)
|
|
||||||
|
if (runtime_options.dry_run == true)
|
||||||
{
|
{
|
||||||
log_info(_("local and %s target system identifiers match"), action);
|
log_info(_("local and %s target system identifiers match"), action);
|
||||||
log_detail(_("system identifier is %lu"), local_system_identifier);
|
log_detail(_("system identifier is %lu"), local_system_identifier);
|
||||||
@@ -4202,64 +4092,20 @@ check_node_can_attach(TimeLineID local_tli, XLogRecPtr local_xlogpos, PGconn *fo
|
|||||||
action,
|
action,
|
||||||
follow_target_identification.timeline);
|
follow_target_identification.timeline);
|
||||||
|
|
||||||
/*
|
/* upstream's timeline is lower than ours - impossible case */
|
||||||
* The upstream's timeline is lower than ours - we cannot follow, and rejoin
|
|
||||||
* requires PostgreSQL 9.6 and later.
|
|
||||||
*/
|
|
||||||
if (follow_target_identification.timeline < local_tli)
|
if (follow_target_identification.timeline < local_tli)
|
||||||
{
|
{
|
||||||
/*
|
log_error(_("this node's timeline is ahead of the %s target node's timeline"), action);
|
||||||
* "repmgr standby follow" is impossible in this case
|
log_detail(_("this node's timeline is %i, %s target node's timeline is %i"),
|
||||||
*/
|
local_tli,
|
||||||
if (is_rejoin == false)
|
action,
|
||||||
{
|
follow_target_identification.timeline);
|
||||||
log_error(_("this node's timeline is ahead of the %s target node's timeline"), action);
|
PQfinish(follow_target_repl_conn);
|
||||||
log_detail(_("this node's timeline is %i, %s target node's timeline is %i"),
|
return false;
|
||||||
local_tli,
|
|
||||||
action,
|
|
||||||
follow_target_identification.timeline);
|
|
||||||
|
|
||||||
if (PQserverVersion(follow_target_conn) >= 90600)
|
|
||||||
{
|
|
||||||
log_hint(_("use \"repmgr node rejoin --force-rewind\" to reattach this node"));
|
|
||||||
}
|
|
||||||
|
|
||||||
PQfinish(follow_target_repl_conn);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* pg_rewind can only rejoin to a lower timeline from PostgreSQL 9.6
|
|
||||||
*/
|
|
||||||
if (PQserverVersion(follow_target_conn) < 90600)
|
|
||||||
{
|
|
||||||
log_error(_("this node's timeline is ahead of the %s target node's timeline"), action);
|
|
||||||
log_detail(_("this node's timeline is %i, %s target node's timeline is %i"),
|
|
||||||
local_tli,
|
|
||||||
action,
|
|
||||||
follow_target_identification.timeline);
|
|
||||||
|
|
||||||
if (runtime_options.force_rewind_used == true)
|
|
||||||
{
|
|
||||||
log_hint(_("pg_rewind can only be used to rejoin to a node with a lower timeline from PostgreSQL 9.6"));
|
|
||||||
}
|
|
||||||
|
|
||||||
PQfinish(follow_target_repl_conn);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (runtime_options.force_rewind_used == false)
|
|
||||||
{
|
|
||||||
log_notice(_("pg_rewind execution required for this node to attach to rejoin target node %i"),
|
|
||||||
follow_target_node_record->node_id);
|
|
||||||
log_hint(_("provide --force-rewind"));
|
|
||||||
PQfinish(follow_target_repl_conn);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* timelines are the same - check relative positions */
|
/* timelines are the same - check relative positions */
|
||||||
else if (follow_target_identification.timeline == local_tli)
|
if (follow_target_identification.timeline == local_tli)
|
||||||
{
|
{
|
||||||
XLogRecPtr follow_target_xlogpos = get_node_current_lsn(follow_target_conn);
|
XLogRecPtr follow_target_xlogpos = get_node_current_lsn(follow_target_conn);
|
||||||
|
|
||||||
@@ -4280,26 +4126,12 @@ check_node_can_attach(TimeLineID local_tli, XLogRecPtr local_xlogpos, PGconn *fo
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/*
|
log_error(_("this node is ahead of the %s target"), action);
|
||||||
* Unable to follow or join to a node we're ahead of, if we're on the
|
|
||||||
* same timeline. Also, pg_rewind does not detect this situation,
|
|
||||||
* as there is no definitive fork point.
|
|
||||||
*
|
|
||||||
* Note that Pg will still happily attach to the upstream in state "streaming"
|
|
||||||
* for a while but then detach with an endless stream of
|
|
||||||
* "record with incorrect prev-link" errors.
|
|
||||||
*/
|
|
||||||
log_error(_("this node ahead of the %s target on the same timeline (%i)"), action, local_tli);
|
|
||||||
log_detail(_("local node lsn is %X/%X, %s target lsn is %X/%X"),
|
log_detail(_("local node lsn is %X/%X, %s target lsn is %X/%X"),
|
||||||
format_lsn(local_xlogpos),
|
format_lsn(local_xlogpos),
|
||||||
action,
|
action,
|
||||||
format_lsn(follow_target_xlogpos));
|
format_lsn(follow_target_xlogpos));
|
||||||
|
|
||||||
if (is_rejoin == true)
|
|
||||||
{
|
|
||||||
log_hint(_("the --force-rewind option is ineffective in this case"));
|
|
||||||
}
|
|
||||||
|
|
||||||
success = false;
|
success = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* repmgr-client.h
|
* repmgr-client.h
|
||||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -83,32 +83,27 @@
|
|||||||
#define OPT_DOWNSTREAM 1030
|
#define OPT_DOWNSTREAM 1030
|
||||||
#define OPT_UPSTREAM 1031
|
#define OPT_UPSTREAM 1031
|
||||||
#define OPT_SLOTS 1032
|
#define OPT_SLOTS 1032
|
||||||
#define OPT_HAS_PASSFILE 1033
|
#define OPT_CONFIG_ARCHIVE_DIR 1033
|
||||||
#define OPT_WAIT_START 1034
|
#define OPT_HAS_PASSFILE 1034
|
||||||
#define OPT_REPL_CONN 1035
|
#define OPT_WAIT_START 1035
|
||||||
#define OPT_REMOTE_NODE_ID 1036
|
#define OPT_REPL_CONN 1036
|
||||||
#define OPT_REPLICATION_CONF_ONLY 1037
|
#define OPT_REMOTE_NODE_ID 1037
|
||||||
#define OPT_NO_WAIT 1038
|
#define OPT_REPLICATION_CONF_ONLY 1038
|
||||||
#define OPT_MISSING_SLOTS 1039
|
#define OPT_NO_WAIT 1039
|
||||||
#define OPT_REPMGRD_NO_PAUSE 1040
|
#define OPT_MISSING_SLOTS 1040
|
||||||
#define OPT_VERSION_NUMBER 1041
|
#define OPT_REPMGRD_NO_PAUSE 1041
|
||||||
#define OPT_DATA_DIRECTORY_CONFIG 1042
|
#define OPT_VERSION_NUMBER 1042
|
||||||
#define OPT_COMPACT 1043
|
#define OPT_DATA_DIRECTORY_CONFIG 1043
|
||||||
#define OPT_DETAIL 1044
|
#define OPT_COMPACT 1044
|
||||||
#define OPT_REPMGRD_FORCE_UNPAUSE 1045
|
#define OPT_DISABLE_WAL_RECEIVER 1045
|
||||||
#define OPT_REPLICATION_CONFIG_OWNER 1046
|
#define OPT_ENABLE_WAL_RECEIVER 1046
|
||||||
#define OPT_DB_CONNECTION 1047
|
#define OPT_DETAIL 1047
|
||||||
#define OPT_VERIFY_BACKUP 1048
|
#define OPT_REPMGRD_FORCE_UNPAUSE 1048
|
||||||
#define OPT_RECOVERY_MIN_APPLY_DELAY 1049
|
#define OPT_REPLICATION_CONFIG_OWNER 1049
|
||||||
|
|
||||||
/* These options are for internal use only */
|
|
||||||
#define OPT_CONFIG_ARCHIVE_DIR 2001
|
|
||||||
#define OPT_DISABLE_WAL_RECEIVER 2002
|
|
||||||
#define OPT_ENABLE_WAL_RECEIVER 2003
|
|
||||||
#define OPT_DUMP_CONFIG 2004
|
|
||||||
|
|
||||||
/* deprecated since 4.0 */
|
/* deprecated since 4.0 */
|
||||||
#define OPT_CHECK_UPSTREAM_CONFIG 999
|
#define OPT_CHECK_UPSTREAM_CONFIG 999
|
||||||
|
#define OPT_NODE 998
|
||||||
|
|
||||||
|
|
||||||
static struct option long_options[] =
|
static struct option long_options[] =
|
||||||
@@ -127,7 +122,6 @@ static struct option long_options[] =
|
|||||||
{"no-wait", no_argument, NULL, 'W'},
|
{"no-wait", no_argument, NULL, 'W'},
|
||||||
{"compact", no_argument, NULL, OPT_COMPACT},
|
{"compact", no_argument, NULL, OPT_COMPACT},
|
||||||
{"detail", no_argument, NULL, OPT_DETAIL},
|
{"detail", no_argument, NULL, OPT_DETAIL},
|
||||||
{"dump-config", no_argument, NULL, OPT_DUMP_CONFIG},
|
|
||||||
|
|
||||||
/* connection options */
|
/* connection options */
|
||||||
{"dbname", required_argument, NULL, 'd'},
|
{"dbname", required_argument, NULL, 'd'},
|
||||||
@@ -164,8 +158,6 @@ static struct option long_options[] =
|
|||||||
{"upstream-node-id", required_argument, NULL, OPT_UPSTREAM_NODE_ID},
|
{"upstream-node-id", required_argument, NULL, OPT_UPSTREAM_NODE_ID},
|
||||||
{"without-barman", no_argument, NULL, OPT_WITHOUT_BARMAN},
|
{"without-barman", no_argument, NULL, OPT_WITHOUT_BARMAN},
|
||||||
{"replication-conf-only", no_argument, NULL, OPT_REPLICATION_CONF_ONLY},
|
{"replication-conf-only", no_argument, NULL, OPT_REPLICATION_CONF_ONLY},
|
||||||
{"verify-backup", no_argument, NULL, OPT_VERIFY_BACKUP },
|
|
||||||
{"recovery-min-apply-delay", required_argument, NULL, OPT_RECOVERY_MIN_APPLY_DELAY },
|
|
||||||
/* deprecate this once Pg11 and earlier are unsupported */
|
/* deprecate this once Pg11 and earlier are unsupported */
|
||||||
{"recovery-conf-only", no_argument, NULL, OPT_REPLICATION_CONF_ONLY},
|
{"recovery-conf-only", no_argument, NULL, OPT_REPLICATION_CONF_ONLY},
|
||||||
|
|
||||||
@@ -197,7 +189,6 @@ static struct option long_options[] =
|
|||||||
{"replication-connection", no_argument, NULL, OPT_REPL_CONN},
|
{"replication-connection", no_argument, NULL, OPT_REPL_CONN},
|
||||||
{"data-directory-config", no_argument, NULL, OPT_DATA_DIRECTORY_CONFIG},
|
{"data-directory-config", no_argument, NULL, OPT_DATA_DIRECTORY_CONFIG},
|
||||||
{"replication-config-owner", no_argument, NULL, OPT_REPLICATION_CONFIG_OWNER},
|
{"replication-config-owner", no_argument, NULL, OPT_REPLICATION_CONFIG_OWNER},
|
||||||
{"db-connection", no_argument, NULL, OPT_DB_CONNECTION},
|
|
||||||
|
|
||||||
/* "node rejoin" options */
|
/* "node rejoin" options */
|
||||||
{"config-files", required_argument, NULL, OPT_CONFIG_FILES},
|
{"config-files", required_argument, NULL, OPT_CONFIG_FILES},
|
||||||
@@ -225,6 +216,9 @@ static struct option long_options[] =
|
|||||||
{"check-upstream-config", no_argument, NULL, OPT_CHECK_UPSTREAM_CONFIG},
|
{"check-upstream-config", no_argument, NULL, OPT_CHECK_UPSTREAM_CONFIG},
|
||||||
/* previously used by "standby switchover" */
|
/* previously used by "standby switchover" */
|
||||||
{"remote-config-file", required_argument, NULL, 'C'},
|
{"remote-config-file", required_argument, NULL, 'C'},
|
||||||
|
/* replaced by --node-id */
|
||||||
|
{"node", required_argument, NULL, OPT_NODE},
|
||||||
|
|
||||||
{NULL, 0, NULL, 0}
|
{NULL, 0, NULL, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
15
repmgr.c
15
repmgr.c
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* repmgr.c - repmgr extension
|
* repmgr.c - repmgr extension
|
||||||
*
|
*
|
||||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||||
*
|
*
|
||||||
* This is the actual extension code; see repmgr-client.c for the code which
|
* This is the actual extension code; see repmgr-client.c for the code which
|
||||||
* generates the repmgr binary
|
* generates the repmgr binary
|
||||||
@@ -33,14 +33,22 @@
|
|||||||
#include "storage/shmem.h"
|
#include "storage/shmem.h"
|
||||||
#include "storage/spin.h"
|
#include "storage/spin.h"
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
|
|
||||||
|
#if (PG_VERSION_NUM >= 90400)
|
||||||
#include "utils/pg_lsn.h"
|
#include "utils/pg_lsn.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "utils/timestamp.h"
|
#include "utils/timestamp.h"
|
||||||
|
|
||||||
#include "lib/stringinfo.h"
|
#include "lib/stringinfo.h"
|
||||||
#include "access/xact.h"
|
#include "access/xact.h"
|
||||||
#include "utils/snapmgr.h"
|
#include "utils/snapmgr.h"
|
||||||
|
|
||||||
|
#if (PG_VERSION_NUM >= 90400)
|
||||||
#include "pgstat.h"
|
#include "pgstat.h"
|
||||||
|
#else
|
||||||
|
#define PGSTAT_STAT_PERMANENT_DIRECTORY "pg_stat"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "voting.h"
|
#include "voting.h"
|
||||||
|
|
||||||
@@ -149,6 +157,8 @@ PG_FUNCTION_INFO_V1(get_wal_receiver_pid);
|
|||||||
void
|
void
|
||||||
_PG_init(void)
|
_PG_init(void)
|
||||||
{
|
{
|
||||||
|
elog(DEBUG1, "repmgr init");
|
||||||
|
|
||||||
if (!process_shared_preload_libraries_in_progress)
|
if (!process_shared_preload_libraries_in_progress)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -165,6 +175,7 @@ _PG_init(void)
|
|||||||
*/
|
*/
|
||||||
prev_shmem_startup_hook = shmem_startup_hook;
|
prev_shmem_startup_hook = shmem_startup_hook;
|
||||||
shmem_startup_hook = repmgr_shmem_startup;
|
shmem_startup_hook = repmgr_shmem_startup;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -194,7 +205,7 @@ repmgr_shmem_startup(void)
|
|||||||
shared_state = NULL;
|
shared_state = NULL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create or attach to the shared memory state
|
* Create or attach to the shared memory state, including hash table
|
||||||
*/
|
*/
|
||||||
LWLockAcquire(AddinShmemInitLock, LW_EXCLUSIVE);
|
LWLockAcquire(AddinShmemInitLock, LW_EXCLUSIVE);
|
||||||
|
|
||||||
|
|||||||
@@ -181,8 +181,6 @@
|
|||||||
|
|
||||||
#pg_ctl_options='' # Options to append to "pg_ctl"
|
#pg_ctl_options='' # Options to append to "pg_ctl"
|
||||||
#pg_basebackup_options='' # Options to append to "pg_basebackup"
|
#pg_basebackup_options='' # Options to append to "pg_basebackup"
|
||||||
# (Note: when cloning from Barman, repmgr will honour any
|
|
||||||
# --waldir/--xlogdir setting present in "pg_basebackup_options"
|
|
||||||
#rsync_options='' # Options to append to "rsync"
|
#rsync_options='' # Options to append to "rsync"
|
||||||
ssh_options='-q -o ConnectTimeout=10' # Options to append to "ssh"
|
ssh_options='-q -o ConnectTimeout=10' # Options to append to "ssh"
|
||||||
|
|
||||||
@@ -211,9 +209,7 @@ ssh_options='-q -o ConnectTimeout=10' # Options to append to "ssh"
|
|||||||
# managing WAL archives (see: https://www.pgbarman.org )
|
# managing WAL archives (see: https://www.pgbarman.org )
|
||||||
|
|
||||||
#recovery_min_apply_delay= # If provided, "recovery_min_apply_delay" will be set to
|
#recovery_min_apply_delay= # If provided, "recovery_min_apply_delay" will be set to
|
||||||
# this value (PostgreSQL 9.4 and later). Value can be
|
# this value (PostgreSQL 9.4 and later).
|
||||||
# an integer representing milliseconds, or a string
|
|
||||||
# representing a period of time (e.g. '5 min').
|
|
||||||
|
|
||||||
|
|
||||||
#------------------------------------------------------------------------------
|
#------------------------------------------------------------------------------
|
||||||
@@ -238,10 +234,9 @@ ssh_options='-q -o ConnectTimeout=10' # Options to append to "ssh"
|
|||||||
|
|
||||||
#primary_follow_timeout=60 # The max length of time (in seconds) to wait
|
#primary_follow_timeout=60 # The max length of time (in seconds) to wait
|
||||||
# for the new primary to become available
|
# for the new primary to become available
|
||||||
#standby_follow_timeout=30 # The max length of time (in seconds) to wait
|
#standby_follow_timeout=15 # The max length of time (in seconds) to wait
|
||||||
# for the standby to connect to the primary
|
# 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)
|
|
||||||
|
|
||||||
#------------------------------------------------------------------------------
|
#------------------------------------------------------------------------------
|
||||||
# "standby switchover" settings
|
# "standby switchover" settings
|
||||||
@@ -301,8 +296,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:
|
#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
|
# 'ping': use PQping() to check if the node is accepting connections
|
||||||
# 'connection': attempt to make a new connection to the node
|
# 'connection': execute a throwaway query on the current connection
|
||||||
# '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
|
#reconnect_attempts=6 # Number of attempts which will be made to reconnect to an unreachable
|
||||||
# primary (or other upstream node)
|
# primary (or other upstream node)
|
||||||
#reconnect_interval=10 # Interval between attempts to reconnect to an unreachable
|
#reconnect_interval=10 # Interval between attempts to reconnect to an unreachable
|
||||||
@@ -323,7 +317,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
|
# 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")
|
# executing "follow_command" (defaults to the value set in "standby_reconnect_timeout")
|
||||||
|
|
||||||
#monitoring_history=no # Whether to write monitoring data to the "monitoring_history" table
|
#monitoring_history=no # Whether to write monitoring data to the "montoring_history" table
|
||||||
#monitor_interval_secs=2 # Interval (in seconds) at which to write monitoring data
|
#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
|
#degraded_monitoring_timeout=-1 # Interval (in seconds) after which repmgrd will terminate if the
|
||||||
# server(s) being monitored are no longer available. -1 (default)
|
# server(s) being monitored are no longer available. -1 (default)
|
||||||
@@ -345,7 +339,6 @@ ssh_options='-q -o ConnectTimeout=10' # Options to append to "ssh"
|
|||||||
# WAL receivers
|
# WAL receivers
|
||||||
#primary_visibility_consensus=false # If "true", only continue with failover if no standbys have seen
|
#primary_visibility_consensus=false # If "true", only continue with failover if no standbys have seen
|
||||||
# the primary node recently. *Must* be the same on all nodes.
|
# the primary node recently. *Must* be the same on all nodes.
|
||||||
#always_promote=false # Always promote a node, even if repmgr metadata is outdated
|
|
||||||
#failover_validation_command='' # Script to execute for an external mechanism to validate the failover
|
#failover_validation_command='' # Script to execute for an external mechanism to validate the failover
|
||||||
# decision made by repmgrd. One or both of the following parameter placeholders
|
# decision made by repmgrd. One or both of the following parameter placeholders
|
||||||
# should be provided, which will be replaced by repmgrd with the appropriate
|
# should be provided, which will be replaced by repmgrd with the appropriate
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# repmgr extension
|
# repmgr extension
|
||||||
comment = 'Replication manager for PostgreSQL'
|
comment = 'Replication manager for PostgreSQL'
|
||||||
default_version = '5.2'
|
default_version = '5.1'
|
||||||
module_pathname = '$libdir/repmgr'
|
module_pathname = '$libdir/repmgr'
|
||||||
relocatable = false
|
relocatable = false
|
||||||
schema = repmgr
|
schema = repmgr
|
||||||
|
|||||||
63
repmgr.h
63
repmgr.h
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* repmgr.h
|
* repmgr.h
|
||||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -74,15 +74,16 @@
|
|||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "sysutils.h"
|
#include "sysutils.h"
|
||||||
|
|
||||||
#define MIN_SUPPORTED_VERSION "9.4"
|
#define MIN_SUPPORTED_VERSION "9.3"
|
||||||
#define MIN_SUPPORTED_VERSION_NUM 90400
|
#define MIN_SUPPORTED_VERSION_NUM 90300
|
||||||
|
|
||||||
|
#define REPLICATION_TYPE_PHYSICAL 1
|
||||||
|
|
||||||
#define UNKNOWN_SERVER_VERSION_NUM -1
|
#define UNKNOWN_SERVER_VERSION_NUM -1
|
||||||
#define UNKNOWN_REPMGR_VERSION_NUM -1
|
#define UNKNOWN_REPMGR_VERSION_NUM -1
|
||||||
|
|
||||||
#define UNKNOWN_TIMELINE_ID -1
|
#define UNKNOWN_TIMELINE_ID -1
|
||||||
#define UNKNOWN_SYSTEM_IDENTIFIER 0
|
#define UNKNOWN_SYSTEM_IDENTIFIER 0
|
||||||
#define UNKNOWN_DATA_CHECKSUM_VERSION -1
|
|
||||||
#define UNKNOWN_PID -1
|
#define UNKNOWN_PID -1
|
||||||
#define UNKNOWN_REPLICATION_LAG -1
|
#define UNKNOWN_REPLICATION_LAG -1
|
||||||
#define UNKNOWN_VALUE -1
|
#define UNKNOWN_VALUE -1
|
||||||
@@ -96,58 +97,40 @@
|
|||||||
#define ARCHIVE_STATUS_DIR_ERROR -1
|
#define ARCHIVE_STATUS_DIR_ERROR -1
|
||||||
#define NO_DEGRADED_MONITORING_ELAPSED -1
|
#define NO_DEGRADED_MONITORING_ELAPSED -1
|
||||||
|
|
||||||
#define WALRECEIVER_DISABLE_TIMEOUT_VALUE 86400000 /* milliseconds */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Default command line option parameter values
|
* various default values - ensure repmgr.conf.sample is update
|
||||||
|
* if any of these are changed
|
||||||
*/
|
*/
|
||||||
#define DEFAULT_WAIT_START 30 /* seconds */
|
#define DEFAULT_LOCATION "default"
|
||||||
|
#define DEFAULT_PRIORITY 100
|
||||||
/*
|
#define DEFAULT_RECONNECTION_ATTEMPTS 6 /* seconds */
|
||||||
* Default configuration file parameter values - ensure repmgr.conf.sample
|
#define DEFAULT_RECONNECTION_INTERVAL 10 /* seconds */
|
||||||
* is update if any of these are changed
|
#define DEFAULT_MONITORING_INTERVAL 2 /* seconds */
|
||||||
*/
|
#define DEFAULT_ASYNC_QUERY_TIMEOUT 60 /* seconds */
|
||||||
|
#define DEFAULT_PRIMARY_NOTIFICATION_TIMEOUT 60 /* seconds */
|
||||||
#define DEFAULT_USE_REPLICATION_SLOTS false
|
|
||||||
#define DEFAULT_USE_PRIMARY_CONNINFO_PASSWORD false
|
|
||||||
#define DEFAULT_PROMOTE_CHECK_TIMEOUT 60 /* seconds */
|
|
||||||
#define DEFAULT_PROMOTE_CHECK_INTERVAL 1 /* seconds */
|
|
||||||
#define DEFAULT_PRIMARY_FOLLOW_TIMEOUT 60 /* seconds */
|
#define DEFAULT_PRIMARY_FOLLOW_TIMEOUT 60 /* seconds */
|
||||||
#define DEFAULT_STANDBY_FOLLOW_TIMEOUT 30 /* seconds */
|
#define DEFAULT_STANDBY_FOLLOW_TIMEOUT 30 /* seconds */
|
||||||
#define DEFAULT_STANDBY_FOLLOW_RESTART false
|
|
||||||
#define DEFAULT_SHUTDOWN_CHECK_TIMEOUT 60 /* seconds */
|
|
||||||
#define DEFAULT_STANDBY_RECONNECT_TIMEOUT 60 /* seconds */
|
|
||||||
#define DEFAULT_NODE_REJOIN_TIMEOUT 60 /* seconds */
|
|
||||||
#define DEFAULT_ARCHIVE_READY_WARNING 16 /* WAL files */
|
#define DEFAULT_ARCHIVE_READY_WARNING 16 /* WAL files */
|
||||||
#define DEFAULT_ARCHIVE_READY_CRITICAL 128 /* WAL files */
|
#define DEFAULT_ARCHIVE_READY_CRITICAL 128 /* WAL files */
|
||||||
#define DEFAULT_REPLICATION_TYPE REPLICATION_TYPE_PHYSICAL
|
|
||||||
#define DEFAULT_REPLICATION_LAG_WARNING 300 /* seconds */
|
#define DEFAULT_REPLICATION_LAG_WARNING 300 /* seconds */
|
||||||
#define DEFAULT_REPLICATION_LAG_CRITICAL 600 /* seconds */
|
#define DEFAULT_REPLICATION_LAG_CRITICAL 600 /* seconds */
|
||||||
#define DEFAULT_WITNESS_SYNC_INTERVAL 15 /* seconds */
|
#define DEFAULT_WITNESS_SYNC_INTERVAL 15 /* seconds */
|
||||||
|
#define DEFAULT_WAIT_START 30 /* seconds */
|
||||||
|
#define DEFAULT_PROMOTE_CHECK_TIMEOUT 60 /* seconds */
|
||||||
|
#define DEFAULT_PROMOTE_CHECK_INTERVAL 1 /* seconds */
|
||||||
|
#define DEFAULT_SHUTDOWN_CHECK_TIMEOUT 60 /* seconds */
|
||||||
|
#define DEFAULT_STANDBY_RECONNECT_TIMEOUT 60 /* seconds */
|
||||||
|
#define DEFAULT_NODE_REJOIN_TIMEOUT 60 /* seconds */
|
||||||
#define DEFAULT_WAL_RECEIVE_CHECK_TIMEOUT 30 /* seconds */
|
#define DEFAULT_WAL_RECEIVE_CHECK_TIMEOUT 30 /* seconds */
|
||||||
#define DEFAULT_LOCATION "default"
|
|
||||||
#define DEFAULT_PRIORITY 100
|
|
||||||
#define DEFAULT_MONITORING_INTERVAL 2 /* seconds */
|
|
||||||
#define DEFAULT_RECONNECTION_ATTEMPTS 6 /* seconds */
|
|
||||||
#define DEFAULT_RECONNECTION_INTERVAL 10 /* seconds */
|
|
||||||
#define DEFAULT_MONITORING_HISTORY false
|
|
||||||
#define DEFAULT_DEGRADED_MONITORING_TIMEOUT -1 /* seconds */
|
|
||||||
#define DEFAULT_ASYNC_QUERY_TIMEOUT 60 /* seconds */
|
|
||||||
#define DEFAULT_PRIMARY_NOTIFICATION_TIMEOUT 60 /* seconds */
|
|
||||||
#define DEFAULT_REPMGRD_STANDBY_STARTUP_TIMEOUT -1 /*seconds */
|
|
||||||
#define DEFAULT_STANDBY_DISCONNECT_ON_FAILOVER false
|
|
||||||
#define DEFAULT_SIBLING_NODES_DISCONNECT_TIMEOUT 30 /* seconds */
|
#define DEFAULT_SIBLING_NODES_DISCONNECT_TIMEOUT 30 /* seconds */
|
||||||
#define DEFAULT_CONNECTION_CHECK_TYPE CHECK_PING
|
|
||||||
#define DEFAULT_PRIMARY_VISIBILITY_CONSENSUS false
|
|
||||||
#define DEFAULT_ALWAYS_PROMOTE false
|
|
||||||
#define DEFAULT_ELECTION_RERUN_INTERVAL 15 /* seconds */
|
#define DEFAULT_ELECTION_RERUN_INTERVAL 15 /* seconds */
|
||||||
#define DEFAULT_CHILD_NODES_CHECK_INTERVAL 5 /* seconds */
|
#define DEFAULT_CHILD_NODES_CHECK_INTERVAL 5 /* seconds */
|
||||||
#define DEFAULT_CHILD_NODES_DISCONNECT_MIN_COUNT -1
|
#define DEFAULT_CHILD_NODES_DISCONNECT_MIN_COUNT -1
|
||||||
#define DEFAULT_CHILD_NODES_CONNECTED_MIN_COUNT -1
|
#define DEFAULT_CHILD_NODES_CONNECTED_MIN_COUNT -1
|
||||||
#define DEFAULT_CHILD_NODES_CONNECTED_INCLUDE_WITNESS false
|
|
||||||
#define DEFAULT_CHILD_NODES_DISCONNECT_TIMEOUT 30 /* seconds */
|
#define DEFAULT_CHILD_NODES_DISCONNECT_TIMEOUT 30 /* seconds */
|
||||||
#define DEFAULT_SSH_OPTIONS "-q -o ConnectTimeout=10"
|
#define DEFAULT_CHILD_NODES_CONNECTED_INCLUDE_WITNESS false
|
||||||
|
|
||||||
|
#define WALRECEIVER_DISABLE_TIMEOUT_VALUE 86400000 /* milliseconds */
|
||||||
|
|
||||||
#ifndef RECOVERY_COMMAND_FILE
|
#ifndef RECOVERY_COMMAND_FILE
|
||||||
#define RECOVERY_COMMAND_FILE "recovery.conf"
|
#define RECOVERY_COMMAND_FILE "recovery.conf"
|
||||||
@@ -162,6 +145,6 @@
|
|||||||
#define TABLESPACE_MAP "tablespace_map"
|
#define TABLESPACE_MAP "tablespace_map"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define REPMGR_URL "https://repmgr.org/"
|
|
||||||
|
|
||||||
#endif /* _REPMGR_H_ */
|
#endif /* _REPMGR_H_ */
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#define REPMGR_VERSION_DATE ""
|
#define REPMGR_VERSION_DATE ""
|
||||||
#define REPMGR_VERSION "5.2.1"
|
#define REPMGR_VERSION "5.1.0"
|
||||||
#define REPMGR_VERSION_NUM 50201
|
#define REPMGR_VERSION_NUM 50100
|
||||||
#define REPMGR_RELEASE_DATE "2020-12-07"
|
#define REPMGR_RELEASE_DATE "2020-04-13"
|
||||||
#define PG_ACTUAL_VERSION_NUM
|
#define PG_ACTUAL_VERSION_NUM
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* repmgrd-physical.h
|
* repmgrd-physical.h
|
||||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
110
repmgrd.c
110
repmgrd.c
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* repmgrd.c - Replication manager daemon
|
* repmgrd.c - Replication manager daemon
|
||||||
*
|
*
|
||||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -39,9 +39,13 @@ static bool daemonize = true;
|
|||||||
static bool show_pid_file = false;
|
static bool show_pid_file = false;
|
||||||
static bool no_pid_file = false;
|
static bool no_pid_file = false;
|
||||||
|
|
||||||
|
t_configuration_options config_file_options = T_CONFIGURATION_OPTIONS_INITIALIZER;
|
||||||
|
|
||||||
t_node_info local_node_info = T_NODE_INFO_INITIALIZER;
|
t_node_info local_node_info = T_NODE_INFO_INITIALIZER;
|
||||||
PGconn *local_conn = NULL;
|
PGconn *local_conn = NULL;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Collate command line errors here for friendlier reporting */
|
/* Collate command line errors here for friendlier reporting */
|
||||||
static ItemList cli_errors = {NULL, NULL};
|
static ItemList cli_errors = {NULL, NULL};
|
||||||
|
|
||||||
@@ -131,7 +135,7 @@ main(int argc, char **argv)
|
|||||||
|
|
||||||
memset(pid_file, 0, MAXPGPATH);
|
memset(pid_file, 0, MAXPGPATH);
|
||||||
|
|
||||||
while ((c = getopt_long(argc, argv, "?Vf:L:vdp:sm", long_options, &optindex)) != -1)
|
while ((c = getopt_long(argc, argv, "?Vf:L:vdp:m", long_options, &optindex)) != -1)
|
||||||
{
|
{
|
||||||
switch (c)
|
switch (c)
|
||||||
{
|
{
|
||||||
@@ -249,10 +253,10 @@ main(int argc, char **argv)
|
|||||||
/*
|
/*
|
||||||
* Parse the configuration file, if provided (if no configuration file was
|
* 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
|
* provided, an attempt will be made to find one in one of the default
|
||||||
* locations). If no configuration file is available, or it can't be parsed
|
* locations). If no conifguration file is available, or it can't be parsed
|
||||||
* parse_config() will abort anyway, with an appropriate message.
|
* parse_config() will abort anyway, with an appropriate message.
|
||||||
*/
|
*/
|
||||||
load_config(config_file, verbose, false, argv[0]);
|
load_config(config_file, verbose, false, &config_file_options, argv[0]);
|
||||||
|
|
||||||
/* Determine pid file location, unless --no-pid-file supplied */
|
/* Determine pid file location, unless --no-pid-file supplied */
|
||||||
|
|
||||||
@@ -307,7 +311,7 @@ main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Some configuration file items can be overridden by command line options */
|
/* Some configuration file items can be overriden by command line options */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Command-line parameter -L/--log-level overrides any setting in config
|
* Command-line parameter -L/--log-level overrides any setting in config
|
||||||
@@ -416,7 +420,7 @@ main(int argc, char **argv)
|
|||||||
log_detail(_("\"repmgr\" version %s is installed but extension is version %s"),
|
log_detail(_("\"repmgr\" version %s is installed but extension is version %s"),
|
||||||
REPMGR_VERSION,
|
REPMGR_VERSION,
|
||||||
extversions.installed_version);
|
extversions.installed_version);
|
||||||
log_hint(_("update the installed extension version by executing \"ALTER EXTENSION repmgr UPDATE\" in the repmgr database"));
|
log_hint(_("update the installed extension version by executing \"ALTER EXTENSION repmgr UPDATE\""));
|
||||||
|
|
||||||
close_connection(&local_conn);
|
close_connection(&local_conn);
|
||||||
exit(ERR_BAD_CONFIG);
|
exit(ERR_BAD_CONFIG);
|
||||||
@@ -808,92 +812,42 @@ show_help(void)
|
|||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
check_upstream_connection(PGconn **conn, const char *conninfo, PGconn **paired_conn)
|
check_upstream_connection(PGconn **conn, const char *conninfo)
|
||||||
{
|
{
|
||||||
/* Check the connection status twice in case it changes after reset */
|
/* Check the connection status twice in case it changes after reset */
|
||||||
bool twice = false;
|
bool twice = false;
|
||||||
|
|
||||||
log_debug("connection check type is \"%s\"",
|
if (config_file_options.connection_check_type == CHECK_PING)
|
||||||
print_connection_check_type(config_file_options.connection_check_type));
|
return is_server_available(conninfo);
|
||||||
/*
|
|
||||||
* For the check types which do not involve using the existing database
|
if (config_file_options.connection_check_type == CHECK_CONNECTION)
|
||||||
* connection, we'll perform the actual check, then as an additional
|
|
||||||
* safeguard verify that the connection is still valid (as it might have
|
|
||||||
* gone away during a brief outage between checks).
|
|
||||||
*/
|
|
||||||
if (config_file_options.connection_check_type != CHECK_QUERY)
|
|
||||||
{
|
{
|
||||||
bool success = true;
|
bool success = true;
|
||||||
|
PGconn *test_conn = PQconnectdb(conninfo);
|
||||||
|
|
||||||
if (config_file_options.connection_check_type == CHECK_PING)
|
log_debug("check_upstream_connection(): attempting to connect to \"%s\"", conninfo);
|
||||||
|
|
||||||
|
if (PQstatus(test_conn) != CONNECTION_OK)
|
||||||
{
|
{
|
||||||
success = is_server_available(conninfo);
|
log_warning(_("unable to connect to \"%s\""), conninfo);
|
||||||
|
log_detail("\n%s", PQerrorMessage(test_conn));
|
||||||
|
success = false;
|
||||||
}
|
}
|
||||||
else if (config_file_options.connection_check_type == CHECK_CONNECTION)
|
PQfinish(test_conn);
|
||||||
{
|
|
||||||
/*
|
|
||||||
* This connection is thrown away, and we never execute a query on it.
|
|
||||||
*/
|
|
||||||
PGconn *test_conn = PQconnectdb(conninfo);
|
|
||||||
|
|
||||||
log_debug("check_upstream_connection(): attempting to connect to \"%s\"", conninfo);
|
return success;
|
||||||
|
|
||||||
if (PQstatus(test_conn) != CONNECTION_OK)
|
|
||||||
{
|
|
||||||
log_warning(_("unable to connect to \"%s\""), conninfo);
|
|
||||||
log_detail("\n%s", PQerrorMessage(test_conn));
|
|
||||||
success = false;
|
|
||||||
}
|
|
||||||
PQfinish(test_conn);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (success == false)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (PQstatus(*conn) == CONNECTION_OK)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Checks have succeeded, but the open connection to the primary has gone away,
|
|
||||||
* possibly due to a brief outage between monitoring intervals - attempt to
|
|
||||||
* reset it.
|
|
||||||
*/
|
|
||||||
log_notice(_("upstream is available but upstream connection has gone away, resetting"));
|
|
||||||
|
|
||||||
PQfinish(*conn);
|
|
||||||
*conn = establish_db_connection_quiet(conninfo);
|
|
||||||
|
|
||||||
if (PQstatus(*conn) == CONNECTION_OK)
|
|
||||||
{
|
|
||||||
if (paired_conn != NULL)
|
|
||||||
{
|
|
||||||
log_debug("resetting paired connection");
|
|
||||||
*paired_conn = *conn;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
if (PQstatus(*conn) != CONNECTION_OK)
|
if (PQstatus(*conn) != CONNECTION_OK)
|
||||||
{
|
{
|
||||||
log_debug("check_upstream_connection(): upstream connection has gone away, resetting");
|
log_debug("check_upstream_connection(): connection not OK");
|
||||||
if (twice)
|
if (twice)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* reconnect */
|
/* reconnect */
|
||||||
PQfinish(*conn);
|
PQfinish(*conn);
|
||||||
*conn = establish_db_connection_quiet(conninfo);
|
*conn = PQconnectdb(conninfo);
|
||||||
|
|
||||||
if (paired_conn != NULL)
|
|
||||||
{
|
|
||||||
log_debug("resetting paired connection");
|
|
||||||
*paired_conn = *conn;
|
|
||||||
}
|
|
||||||
twice = true;
|
twice = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -905,7 +859,7 @@ check_upstream_connection(PGconn **conn, const char *conninfo, PGconn **paired_c
|
|||||||
goto failed;
|
goto failed;
|
||||||
|
|
||||||
/* execute a simple query to verify connection availability */
|
/* execute a simple query to verify connection availability */
|
||||||
if (PQsendQuery(*conn, config_file_options.connection_check_query) == 0)
|
if (PQsendQuery(*conn, "SELECT 1") == 0)
|
||||||
{
|
{
|
||||||
log_warning(_("unable to send query to upstream"));
|
log_warning(_("unable to send query to upstream"));
|
||||||
log_detail("%s", PQerrorMessage(*conn));
|
log_detail("%s", PQerrorMessage(*conn));
|
||||||
@@ -923,16 +877,8 @@ check_upstream_connection(PGconn **conn, const char *conninfo, PGconn **paired_c
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* reconnect */
|
/* reconnect */
|
||||||
log_debug("check_upstream_connection(): upstream connection not available, resetting");
|
|
||||||
|
|
||||||
PQfinish(*conn);
|
PQfinish(*conn);
|
||||||
*conn = establish_db_connection_quiet(conninfo);
|
*conn = PQconnectdb(conninfo);
|
||||||
|
|
||||||
if (paired_conn != NULL)
|
|
||||||
{
|
|
||||||
log_debug("resetting paired connection");
|
|
||||||
*paired_conn = *conn;
|
|
||||||
}
|
|
||||||
twice = true;
|
twice = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* repmgrd.h
|
* repmgrd.h
|
||||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
@@ -17,12 +17,13 @@ extern volatile sig_atomic_t got_SIGHUP;
|
|||||||
extern MonitoringState monitoring_state;
|
extern MonitoringState monitoring_state;
|
||||||
extern instr_time degraded_monitoring_start;
|
extern instr_time degraded_monitoring_start;
|
||||||
|
|
||||||
|
extern t_configuration_options config_file_options;
|
||||||
extern t_node_info local_node_info;
|
extern t_node_info local_node_info;
|
||||||
extern PGconn *local_conn;
|
extern PGconn *local_conn;
|
||||||
extern bool startup_event_logged;
|
extern bool startup_event_logged;
|
||||||
extern char pid_file[MAXPGPATH];
|
extern char pid_file[MAXPGPATH];
|
||||||
|
|
||||||
bool check_upstream_connection(PGconn **conn, const char *conninfo, PGconn **paired_conn);
|
bool check_upstream_connection(PGconn **conn, const char *conninfo);
|
||||||
void try_reconnect(PGconn **conn, t_node_info *node_info);
|
void try_reconnect(PGconn **conn, t_node_info *node_info);
|
||||||
|
|
||||||
int calculate_elapsed(instr_time start_time);
|
int calculate_elapsed(instr_time start_time);
|
||||||
|
|||||||
13
strutil.c
13
strutil.c
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* strutil.c
|
* strutil.c
|
||||||
*
|
*
|
||||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -386,9 +386,12 @@ output_check_status(CheckStatus status)
|
|||||||
}
|
}
|
||||||
|
|
||||||
return "UNKNOWN";
|
return "UNKNOWN";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Escape a string for use as a parameter in recovery.conf
|
* Escape a string for use as a parameter in recovery.conf
|
||||||
* Caller must free returned value
|
* Caller must free returned value
|
||||||
@@ -430,6 +433,7 @@ escape_string(PGconn *conn, const char *string)
|
|||||||
/*
|
/*
|
||||||
* simple function to escape double quotes only
|
* simple function to escape double quotes only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
escape_double_quotes(char *string, PQExpBufferData *out)
|
escape_double_quotes(char *string, PQExpBufferData *out)
|
||||||
{
|
{
|
||||||
@@ -560,10 +564,3 @@ parse_follow_command(char *parsed_command, char *template, int node_id)
|
|||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const char *
|
|
||||||
format_bool(bool value)
|
|
||||||
{
|
|
||||||
return value == true ? "true" : "false";
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* strutil.h
|
* strutil.h
|
||||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -166,6 +166,4 @@ extern char *trim(char *s);
|
|||||||
extern void
|
extern void
|
||||||
parse_follow_command(char *parsed_command, char *template, int node_id);
|
parse_follow_command(char *parsed_command, char *template, int node_id);
|
||||||
|
|
||||||
extern const char *format_bool(bool value);
|
|
||||||
|
|
||||||
#endif /* _STRUTIL_H_ */
|
#endif /* _STRUTIL_H_ */
|
||||||
|
|||||||
131
sysutils.c
131
sysutils.c
@@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Functions which need to be executed on the local system.
|
* Functions which need to be executed on the local system.
|
||||||
*
|
*
|
||||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -57,56 +57,27 @@ _local_command(const char *command, PQExpBufferData *outputbuf, bool simple, int
|
|||||||
char output[MAXLEN];
|
char output[MAXLEN];
|
||||||
int retval = 0;
|
int retval = 0;
|
||||||
bool success;
|
bool success;
|
||||||
char tmpfile_path[MAXPGPATH];
|
|
||||||
const char *tmpdir = getenv("TMPDIR");
|
|
||||||
int fd;
|
|
||||||
PQExpBufferData command_final;
|
|
||||||
|
|
||||||
if (!tmpdir)
|
log_verbose(LOG_DEBUG, "executing:\n %s", command);
|
||||||
tmpdir = "/tmp";
|
|
||||||
|
|
||||||
maxpath_snprintf(tmpfile_path, "%s/repmgr_command.XXXXXX",
|
|
||||||
tmpdir);
|
|
||||||
|
|
||||||
fd = mkstemp(tmpfile_path);
|
|
||||||
|
|
||||||
if (fd < 1)
|
|
||||||
{
|
|
||||||
log_error(_("unable to open temporary file"));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
initPQExpBuffer(&command_final);
|
|
||||||
appendPQExpBufferStr(&command_final, command);
|
|
||||||
|
|
||||||
appendPQExpBuffer(&command_final, " 2>%s", tmpfile_path);
|
|
||||||
|
|
||||||
log_verbose(LOG_DEBUG, "executing:\n %s", command_final.data);
|
|
||||||
|
|
||||||
if (outputbuf == NULL)
|
if (outputbuf == NULL)
|
||||||
{
|
{
|
||||||
retval = system(command_final.data);
|
retval = system(command);
|
||||||
termPQExpBuffer(&command_final);
|
|
||||||
|
|
||||||
if (return_value != NULL)
|
if (return_value != NULL)
|
||||||
*return_value = WEXITSTATUS(retval);
|
*return_value = WEXITSTATUS(retval);
|
||||||
|
|
||||||
close(fd);
|
|
||||||
|
|
||||||
return (retval == 0) ? true : false;
|
return (retval == 0) ? true : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
fp = popen(command_final.data, "r");
|
fp = popen(command, "r");
|
||||||
|
|
||||||
if (fp == NULL)
|
if (fp == NULL)
|
||||||
{
|
{
|
||||||
log_error(_("unable to execute local command:\n%s"), command_final.data);
|
log_error(_("unable to execute local command:\n%s"), command);
|
||||||
termPQExpBuffer(&command_final);
|
|
||||||
close(fd);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
termPQExpBuffer(&command_final);
|
|
||||||
|
|
||||||
while (fgets(output, MAXLEN, fp) != NULL)
|
while (fgets(output, MAXLEN, fp) != NULL)
|
||||||
{
|
{
|
||||||
@@ -120,32 +91,11 @@ _local_command(const char *command, PQExpBufferData *outputbuf, bool simple, int
|
|||||||
|
|
||||||
retval = pclose(fp);
|
retval = pclose(fp);
|
||||||
|
|
||||||
/* 141 = SIGPIPE */
|
/* */
|
||||||
success = (WEXITSTATUS(retval) == 0 || WEXITSTATUS(retval) == 141) ? true : false;
|
success = (WEXITSTATUS(retval) == 0 || WEXITSTATUS(retval) == 141) ? true : false;
|
||||||
|
|
||||||
log_verbose(LOG_DEBUG, "result of command was %i (%i)", WEXITSTATUS(retval), retval);
|
log_verbose(LOG_DEBUG, "result of command was %i (%i)", WEXITSTATUS(retval), retval);
|
||||||
|
|
||||||
/*
|
|
||||||
* Append any captured STDERR output
|
|
||||||
*/
|
|
||||||
|
|
||||||
fp = fopen(tmpfile_path, "r");
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Not critical if we can't open the file
|
|
||||||
*/
|
|
||||||
if (fp != NULL)
|
|
||||||
{
|
|
||||||
while (fgets(output, MAXLEN, fp) != NULL)
|
|
||||||
{
|
|
||||||
appendPQExpBufferStr(outputbuf, output);
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(fp);
|
|
||||||
}
|
|
||||||
|
|
||||||
unlink(tmpfile_path);
|
|
||||||
|
|
||||||
if (return_value != NULL)
|
if (return_value != NULL)
|
||||||
*return_value = WEXITSTATUS(retval);
|
*return_value = WEXITSTATUS(retval);
|
||||||
|
|
||||||
@@ -154,7 +104,6 @@ _local_command(const char *command, PQExpBufferData *outputbuf, bool simple, int
|
|||||||
else
|
else
|
||||||
log_verbose(LOG_DEBUG, "local_command(): no output returned");
|
log_verbose(LOG_DEBUG, "local_command(): no output returned");
|
||||||
|
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -169,13 +118,28 @@ remote_command(const char *host, const char *user, const char *command, const ch
|
|||||||
{
|
{
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
PQExpBufferData ssh_command;
|
PQExpBufferData ssh_command;
|
||||||
|
PQExpBufferData ssh_host;
|
||||||
|
|
||||||
char output[MAXLEN] = "";
|
char output[MAXLEN] = "";
|
||||||
|
|
||||||
|
initPQExpBuffer(&ssh_host);
|
||||||
|
|
||||||
|
if (*user != '\0')
|
||||||
|
{
|
||||||
|
appendPQExpBuffer(&ssh_host, "%s@", user);
|
||||||
|
}
|
||||||
|
|
||||||
|
appendPQExpBufferStr(&ssh_host, host);
|
||||||
|
|
||||||
initPQExpBuffer(&ssh_command);
|
initPQExpBuffer(&ssh_command);
|
||||||
|
|
||||||
make_remote_command(host, user, command, ssh_options, &ssh_command);
|
appendPQExpBuffer(&ssh_command,
|
||||||
|
"ssh -o Batchmode=yes %s %s %s",
|
||||||
|
ssh_options,
|
||||||
|
ssh_host.data,
|
||||||
|
command);
|
||||||
|
|
||||||
|
termPQExpBuffer(&ssh_host);
|
||||||
|
|
||||||
log_debug("remote_command():\n %s", ssh_command.data);
|
log_debug("remote_command():\n %s", ssh_command.data);
|
||||||
|
|
||||||
@@ -223,32 +187,6 @@ remote_command(const char *host, const char *user, const char *command, const ch
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
make_remote_command(const char *host, const char *user, const char *command, const char *ssh_options, PQExpBufferData *ssh_command)
|
|
||||||
{
|
|
||||||
PQExpBufferData ssh_host;
|
|
||||||
|
|
||||||
initPQExpBuffer(&ssh_host);
|
|
||||||
|
|
||||||
if (*user != '\0')
|
|
||||||
{
|
|
||||||
appendPQExpBuffer(&ssh_host, "%s@", user);
|
|
||||||
}
|
|
||||||
|
|
||||||
appendPQExpBufferStr(&ssh_host, host);
|
|
||||||
|
|
||||||
|
|
||||||
appendPQExpBuffer(ssh_command,
|
|
||||||
"ssh -o Batchmode=yes %s %s %s",
|
|
||||||
ssh_options,
|
|
||||||
ssh_host.data,
|
|
||||||
command);
|
|
||||||
|
|
||||||
termPQExpBuffer(&ssh_host);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
pid_t
|
pid_t
|
||||||
disable_wal_receiver(PGconn *conn)
|
disable_wal_receiver(PGconn *conn)
|
||||||
{
|
{
|
||||||
@@ -289,19 +227,10 @@ disable_wal_receiver(PGconn *conn)
|
|||||||
|
|
||||||
if (wal_retrieve_retry_interval < WALRECEIVER_DISABLE_TIMEOUT_VALUE)
|
if (wal_retrieve_retry_interval < WALRECEIVER_DISABLE_TIMEOUT_VALUE)
|
||||||
{
|
{
|
||||||
bool success;
|
|
||||||
|
|
||||||
log_notice(_("setting \"wal_retrieve_retry_interval\" to %i milliseconds"),
|
log_notice(_("setting \"wal_retrieve_retry_interval\" to %i milliseconds"),
|
||||||
new_wal_retrieve_retry_interval);
|
new_wal_retrieve_retry_interval);
|
||||||
alter_system_int(conn, "wal_retrieve_retry_interval", new_wal_retrieve_retry_interval);
|
alter_system_int(conn, "wal_retrieve_retry_interval", new_wal_retrieve_retry_interval);
|
||||||
|
pg_reload_conf(conn);
|
||||||
success = pg_reload_conf(conn);
|
|
||||||
|
|
||||||
if (success == false)
|
|
||||||
{
|
|
||||||
log_warning(_("unable to reload configuration"));
|
|
||||||
return UNKNOWN_PID;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -363,12 +292,6 @@ enable_wal_receiver(PGconn *conn, bool wait_startup)
|
|||||||
/* make timeout configurable */
|
/* make timeout configurable */
|
||||||
int i, timeout = 30;
|
int i, timeout = 30;
|
||||||
|
|
||||||
if (PQstatus(conn) != CONNECTION_OK)
|
|
||||||
{
|
|
||||||
log_error(_("database connection not available"));
|
|
||||||
return UNKNOWN_PID;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_superuser_connection(conn, NULL) == false)
|
if (is_superuser_connection(conn, NULL) == false)
|
||||||
{
|
{
|
||||||
log_error(_("superuser connection required"));
|
log_error(_("superuser connection required"));
|
||||||
@@ -409,13 +332,7 @@ enable_wal_receiver(PGconn *conn, bool wait_startup)
|
|||||||
return UNKNOWN_PID;
|
return UNKNOWN_PID;
|
||||||
}
|
}
|
||||||
|
|
||||||
success = pg_reload_conf(conn);
|
pg_reload_conf(conn);
|
||||||
|
|
||||||
if (success == false)
|
|
||||||
{
|
|
||||||
log_warning(_("unable to reload configuration"));
|
|
||||||
return UNKNOWN_PID;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* sysutils.h
|
* sysutils.h
|
||||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -24,7 +24,6 @@ extern bool local_command_return_value(const char *command, PQExpBufferData *out
|
|||||||
extern bool local_command_simple(const char *command, PQExpBufferData *outputbuf);
|
extern bool local_command_simple(const char *command, PQExpBufferData *outputbuf);
|
||||||
|
|
||||||
extern bool remote_command(const char *host, const char *user, const char *command, const char *ssh_options, PQExpBufferData *outputbuf);
|
extern bool remote_command(const char *host, const char *user, const char *command, const char *ssh_options, PQExpBufferData *outputbuf);
|
||||||
extern void make_remote_command(const char *host, const char *user, const char *command, const char *ssh_options, PQExpBufferData *ssh_command);
|
|
||||||
|
|
||||||
extern pid_t disable_wal_receiver(PGconn *conn);
|
extern pid_t disable_wal_receiver(PGconn *conn);
|
||||||
extern pid_t enable_wal_receiver(PGconn *conn, bool wait_startup);
|
extern pid_t enable_wal_receiver(PGconn *conn, bool wait_startup);
|
||||||
|
|||||||
2
voting.h
2
voting.h
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* voting.h
|
* voting.h
|
||||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
Reference in New Issue
Block a user