mirror of
https://github.com/EnterpriseDB/repmgr.git
synced 2026-03-23 07:06:30 +00:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
374f19675d | ||
|
|
ce88f3ec43 | ||
|
|
5acdd69add | ||
|
|
71e23107e7 |
7
.github/CODEOWNERS
vendored
7
.github/CODEOWNERS
vendored
@@ -1,7 +0,0 @@
|
||||
# Each line is a file pattern followed by one or more owners.
|
||||
|
||||
# These owners will be the default owners for everything in
|
||||
# the repo. Unless a later match takes precedence,
|
||||
# @global-owner1 and @global-owner2 will be requested for
|
||||
# review when someone opens a pull request.
|
||||
* @EnterpriseDB/repmgr-dev
|
||||
@@ -2,7 +2,7 @@ License and Contributions
|
||||
=========================
|
||||
|
||||
`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.
|
||||
|
||||
The development of repmgr has primarily been sponsored by 2ndQuadrant customers.
|
||||
@@ -12,10 +12,10 @@ which has received funding from the European Union's Seventh Framework Programme
|
||||
(FP7/2007-2013) under grant agreement 258862.
|
||||
|
||||
Contributions to `repmgr` are welcome, and will be listed in the file `CREDITS`.
|
||||
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
|
||||
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.
|
||||
|
||||
Code style
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2010-2021, EnterpriseDB Corporation
|
||||
Copyright (c) 2010-2020, 2ndQuadrant Limited
|
||||
All rights reserved.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
|
||||
2
FAQ.md
2
FAQ.md
@@ -5,6 +5,6 @@ The repmgr 4 FAQ is located here: [repmgr FAQ (Frequently Asked Questions)](http
|
||||
|
||||
The repmgr 3.x FAQ can be found here:
|
||||
|
||||
https://github.com/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.
|
||||
|
||||
78
HISTORY
78
HISTORY
@@ -1,79 +1,3 @@
|
||||
5.5.0 2024-11-20
|
||||
Support for PostgreSQL 17 added
|
||||
Fix warnings detected by the -Wshadow=compatible-local
|
||||
added in PostgreSQL 16
|
||||
|
||||
5.4.1 2023-07-04
|
||||
repmgrd: ensure witness node metadata is updated (Ian)
|
||||
|
||||
5.4.0 2023-03-16
|
||||
Support cloning replicas using pg-backup-api
|
||||
|
||||
5.3.3 2022-10-17
|
||||
Support for PostgreSQL added
|
||||
repmgrd: ensure event notification script is called for event
|
||||
"repmgrd_upstream_disconnect"; GitHub #760 (Ian)
|
||||
|
||||
5.3.2 2022-05-25
|
||||
standby clone: don't error out if unable to determine cluster size (Ian)
|
||||
node check: fix --downstream --nagios output; GitHub #749 (Ian)
|
||||
repmgrd: ensure witness node marked active (hslightdb)
|
||||
repmgrd: improve walsender disable check (Ian)
|
||||
general: ensure replication slots can be dropped by a
|
||||
replication-only user (Ian)
|
||||
|
||||
5.3.1 2022-02-15
|
||||
repmgrd: fixes for potential connection leaks (hslightdb)
|
||||
repmgr: fix upgrade path from repmgr 4.2 and 4.3 to repmgr 5.3 (Ian)
|
||||
|
||||
5.3.0 2021-10-12
|
||||
standby switchover: improve handling of node rejoin failure (Ian)
|
||||
repmgrd: prefix all shared library functions with "repmgr_" to
|
||||
minimize the risk of clashes with other shared libraries (Ian)
|
||||
repmgrd: at startup, if node record is marked as "inactive", attempt
|
||||
to set it to "active" (Ian)
|
||||
standby clone: set "slot_name" in node record if required (Ian)
|
||||
node rejoin: emit rejoin target note information as NOTICE (Ian)
|
||||
repmgrd: ensure short option "-s" is accepted (Ian)
|
||||
|
||||
5.2.1 2020-12-07
|
||||
config: fix parsing of "replication_type"; GitHub #672 (Ian)
|
||||
standby clone: handle missing "postgresql.auto.conf" (Ian)
|
||||
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
|
||||
repmgr: remove BDR 2.x support
|
||||
repmgr: don't query upstream's data directory (Ian)
|
||||
@@ -81,7 +5,7 @@
|
||||
repmgr: ensure postgresql.auto.conf is created with correct permissions (Ian)
|
||||
repmgr: minimize requirement to check upstream data directory location
|
||||
during "standby clone" (Ian)
|
||||
repmgr: warn about missing pg_rewind prerequisites when executing
|
||||
repmgr: warn about missing pg_rewind prerequisites when excuting
|
||||
"standby clone" (Ian)
|
||||
repmgr: add --upstream option to "node check"
|
||||
repmgr: report error code on follow/rejoin failure due to non-available
|
||||
|
||||
@@ -22,7 +22,7 @@ GIT_WORK_TREE=${repmgr_abs_srcdir}
|
||||
GIT_DIR=${repmgr_abs_srcdir}/.git
|
||||
export GIT_DIR
|
||||
export GIT_WORK_TREE
|
||||
PG_LDFLAGS=-lcurl -ljson-c
|
||||
|
||||
include $(PGXS)
|
||||
|
||||
-include ${repmgr_abs_srcdir}/Makefile.custom
|
||||
|
||||
19
Makefile.in
19
Makefile.in
@@ -12,8 +12,6 @@ EXTENSION = repmgr
|
||||
DATA = \
|
||||
repmgr--unpackaged--4.0.sql \
|
||||
repmgr--unpackaged--5.1.sql \
|
||||
repmgr--unpackaged--5.2.sql \
|
||||
repmgr--unpackaged--5.3.sql \
|
||||
repmgr--4.0.sql \
|
||||
repmgr--4.0--4.1.sql \
|
||||
repmgr--4.1.sql \
|
||||
@@ -26,15 +24,7 @@ DATA = \
|
||||
repmgr--4.4--5.0.sql \
|
||||
repmgr--5.0.sql \
|
||||
repmgr--5.0--5.1.sql \
|
||||
repmgr--5.1.sql \
|
||||
repmgr--5.1--5.2.sql \
|
||||
repmgr--5.2.sql \
|
||||
repmgr--5.2--5.3.sql \
|
||||
repmgr--5.3.sql \
|
||||
repmgr--5.3--5.4.sql \
|
||||
repmgr--5.4.sql \
|
||||
repmgr--5.4--5.5.sql \
|
||||
repmgr--5.5.sql
|
||||
repmgr--5.1.sql
|
||||
|
||||
REGRESS = repmgr_extension
|
||||
|
||||
@@ -67,11 +57,8 @@ $(info Building against PostgreSQL $(MAJORVERSION))
|
||||
REPMGR_CLIENT_OBJS = repmgr-client.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 \
|
||||
configdata.o configfile.o configfile-scan.o log.o strutil.o controldata.o dirutil.o compat.o \
|
||||
dbutils.o sysutils.o pgbackupapi.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
|
||||
|
||||
configfile.o configfile-scan.o log.o strutil.o controldata.o dirutil.o compat.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
|
||||
DATE=$(shell date "+%Y-%m-%d")
|
||||
|
||||
repmgr_version.h: repmgr_version.h.in
|
||||
|
||||
48
README.md
48
README.md
@@ -7,11 +7,10 @@ replication capabilities with utilities to set up standby servers, monitor
|
||||
replication, and perform administrative tasks such as failover or switchover
|
||||
operations.
|
||||
|
||||
The most recent `repmgr` version (5.5.x) supports all PostgreSQL versions from
|
||||
13 to 17. Despite it could be used with some older ones, some features might not
|
||||
be available, however, it's strongly recommended to use the latest version.
|
||||
PostgreSQL 12, 11, 10, 9.6 and 9.5 are fully supported.
|
||||
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
|
||||
-------------
|
||||
@@ -20,6 +19,13 @@ The full `repmgr` documentation is available here:
|
||||
|
||||
> [repmgr documentation](https://repmgr.org/docs/current/index.html)
|
||||
|
||||
The old `README` file for `repmgr` 3.x is available here:
|
||||
|
||||
> 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;
|
||||
please upgrade to the current `repmgr` version as soon as possible.
|
||||
|
||||
Versions
|
||||
--------
|
||||
|
||||
@@ -41,40 +47,47 @@ Directories
|
||||
- `contrib/`: additional utilities
|
||||
- `doc/`: DocBook-based documentation files
|
||||
- `expected/`: expected regression test output
|
||||
- `scripts/`: example scripts
|
||||
- `sql/`: regression test input
|
||||
|
||||
|
||||
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
|
||||
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:
|
||||
|
||||
* https://groups.google.com/group/repmgr
|
||||
|
||||
The IRC channel #repmgr is registered with freenode.
|
||||
|
||||
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/
|
||||
|
||||
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.
|
||||
|
||||
* Israel Barth
|
||||
* Mario González
|
||||
* Martín Marqués
|
||||
* Gianni Ciolli
|
||||
|
||||
Past contributors:
|
||||
|
||||
* Ian Barwick
|
||||
* Jaime Casanova
|
||||
* Abhijit Menon-Sen
|
||||
@@ -87,4 +100,7 @@ Further reading
|
||||
* [repmgr documentation](https://repmgr.org/docs/current/index.html)
|
||||
* [How to Automate PostgreSQL 12 Replication and Failover with repmgr - Part 1](https://www.2ndquadrant.com/en/blog/how-to-automate-postgresql-12-replication-and-failover-with-repmgr-part-1/)
|
||||
* [How to Automate PostgreSQL 12 Replication and Failover with repmgr - Part 2](https://www.2ndquadrant.com/en/blog/how-to-automate-postgresql-12-replication-and-failover-with-repmgr-part-2/)
|
||||
* [How to implement repmgr for PostgreSQL automatic failover](https://www.enterprisedb.com/postgres-tutorials/how-implement-repmgr-postgresql-automatic-failover)
|
||||
* 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
|
||||
====
|
||||
|
||||
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
|
||||
permit.
|
||||
|
||||
@@ -17,4 +17,4 @@ repmgrd nodes to prevent unintended failover; this is obviously inconvenient.
|
||||
We'll need to implement some way of notifying each repmgrd to suspend automatic
|
||||
failover until further notice.
|
||||
|
||||
Requested in GitHub #410 ( https://github.com/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
|
||||
* 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) 1994, Regents of the University of California
|
||||
|
||||
2
compat.h
2
compat.h
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* 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) 1994, Regents of the University of California
|
||||
|
||||
986
configdata.c
986
configdata.c
@@ -1,986 +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 },
|
||||
{},
|
||||
{}
|
||||
},
|
||||
/* pg_backupapi_backup_id*/
|
||||
{
|
||||
"pg_backupapi_backup_id",
|
||||
CONFIG_STRING,
|
||||
{ .strptr = config_file_options.pg_backupapi_backup_id },
|
||||
{ .strdefault = "" },
|
||||
{},
|
||||
{ .strmaxlen = sizeof(config_file_options.pg_backupapi_backup_id) },
|
||||
{}
|
||||
},
|
||||
/* pg_backupapi_host*/
|
||||
{
|
||||
"pg_backupapi_host",
|
||||
CONFIG_STRING,
|
||||
{ .strptr = config_file_options.pg_backupapi_host },
|
||||
{ .strdefault = "" },
|
||||
{},
|
||||
{ .strmaxlen = sizeof(config_file_options.pg_backupapi_host) },
|
||||
{}
|
||||
},
|
||||
/* pg_backupapi_node_name */
|
||||
{
|
||||
"pg_backupapi_node_name",
|
||||
CONFIG_STRING,
|
||||
{ .strptr = config_file_options.pg_backupapi_node_name },
|
||||
{ .strdefault = "" },
|
||||
{},
|
||||
{ .strmaxlen = sizeof(config_file_options.pg_backupapi_node_name) },
|
||||
{}
|
||||
},
|
||||
/* pg_backupapi_remote_ssh_command */
|
||||
{
|
||||
"pg_backupapi_remote_ssh_command",
|
||||
CONFIG_STRING,
|
||||
{ .strptr = config_file_options.pg_backupapi_remote_ssh_command },
|
||||
{ .strdefault = "" },
|
||||
{},
|
||||
{ .strmaxlen = sizeof(config_file_options.pg_backupapi_remote_ssh_command) },
|
||||
{}
|
||||
},
|
||||
|
||||
/* =======================
|
||||
* 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 }
|
||||
},
|
||||
/* repmgrd_exit_on_inactive_node */
|
||||
{
|
||||
"repmgrd_exit_on_inactive_node",
|
||||
CONFIG_BOOL,
|
||||
{ .boolptr = &config_file_options.repmgrd_exit_on_inactive_node},
|
||||
{ .booldefault = DEFAULT_REPMGRD_EXIT_ON_INACTIVE_NODE },
|
||||
{},
|
||||
{},
|
||||
{}
|
||||
},
|
||||
/* standby_disconnect_on_failover */
|
||||
{
|
||||
"standby_disconnect_on_failover",
|
||||
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 <sys/stat.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#include "repmgr.h"
|
||||
#include "configfile.h"
|
||||
@@ -40,13 +38,7 @@ static sigjmp_buf *CONF_flex_fatal_jmp;
|
||||
static char *CONF_scanstr(const char *s);
|
||||
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 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);
|
||||
static bool ProcessConfigFile(FILE *fp, const char *config_file, KeyValueList *contents, t_configuration_options *options, ItemList *error_list, ItemList *warning_list);
|
||||
|
||||
%}
|
||||
|
||||
@@ -98,91 +90,20 @@ STRING \'([^'\\\n]|\\.|\'\')*\'
|
||||
|
||||
%%
|
||||
|
||||
|
||||
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
|
||||
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
|
||||
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)
|
||||
{
|
||||
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)
|
||||
ProcessConfigFile(FILE *fp, const char *config_file, KeyValueList *contents, t_configuration_options *options, ItemList *error_list, ItemList *warning_list)
|
||||
{
|
||||
volatile bool OK = true;
|
||||
volatile YY_BUFFER_STATE lex_buffer = NULL;
|
||||
@@ -258,62 +179,22 @@ ProcessConfigFp(FILE *fp, const char *config_file, const char *calling_file, int
|
||||
ConfigFileLineno++;
|
||||
}
|
||||
|
||||
/* Handle include files */
|
||||
if (base_dir != NULL && strcasecmp(opt_name, "include_dir") == 0)
|
||||
/* OK, process the option name and value */
|
||||
if (contents != NULL)
|
||||
{
|
||||
/*
|
||||
* An include_dir directive isn't a variable and should be
|
||||
* processed immediately.
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
key_value_list_replace_or_set(contents,
|
||||
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 */
|
||||
if (token == 0)
|
||||
@@ -372,132 +253,6 @@ cleanup:
|
||||
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
|
||||
@@ -593,39 +348,6 @@ CONF_scanstr(const char *s)
|
||||
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
|
||||
|
||||
1694
configfile.c
1694
configfile.c
File diff suppressed because it is too large
Load Diff
166
configfile.h
166
configfile.h
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* 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
|
||||
@@ -29,7 +29,7 @@
|
||||
#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.
|
||||
*/
|
||||
#define PG_AUTOCONF_FILENAME "postgresql.auto.conf"
|
||||
@@ -50,11 +50,6 @@ typedef enum
|
||||
CHECK_CONNECTION
|
||||
} ConnectionCheckType;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
REPLICATION_TYPE_PHYSICAL
|
||||
} ReplicationType;
|
||||
|
||||
typedef struct EventNotificationListCell
|
||||
{
|
||||
struct EventNotificationListCell *next;
|
||||
@@ -83,58 +78,6 @@ typedef struct 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
|
||||
{
|
||||
/* node information */
|
||||
@@ -146,7 +89,7 @@ typedef struct
|
||||
char config_directory[MAXPGPATH];
|
||||
char pg_bindir[MAXPGPATH];
|
||||
char repmgr_bindir[MAXPGPATH];
|
||||
ReplicationType replication_type;
|
||||
int replication_type;
|
||||
|
||||
/* log settings */
|
||||
char log_level[MAXLEN];
|
||||
@@ -164,10 +107,6 @@ typedef struct
|
||||
char archive_cleanup_command[MAXLEN];
|
||||
bool use_primary_conninfo_password;
|
||||
char passfile[MAXPGPATH];
|
||||
char pg_backupapi_backup_id[NAMEDATALEN];
|
||||
char pg_backupapi_host[NAMEDATALEN];
|
||||
char pg_backupapi_node_name[NAMEDATALEN];
|
||||
char pg_backupapi_remote_ssh_command[MAXLEN];
|
||||
|
||||
/* standby promote settings */
|
||||
int promote_check_timeout;
|
||||
@@ -176,7 +115,6 @@ typedef struct
|
||||
/* standby follow settings */
|
||||
int primary_follow_timeout;
|
||||
int standby_follow_timeout;
|
||||
bool standby_follow_restart;
|
||||
|
||||
/* standby switchover settings */
|
||||
int shutdown_check_timeout;
|
||||
@@ -210,12 +148,10 @@ typedef struct
|
||||
int primary_notification_timeout;
|
||||
int repmgrd_standby_startup_timeout;
|
||||
char repmgrd_pid_file[MAXPGPATH];
|
||||
bool repmgrd_exit_on_inactive_node;
|
||||
bool standby_disconnect_on_failover;
|
||||
int sibling_nodes_disconnect_timeout;
|
||||
ConnectionCheckType connection_check_type;
|
||||
bool primary_visibility_consensus;
|
||||
bool always_promote;
|
||||
char failover_validation_command[MAXPGPATH];
|
||||
int election_rerun_interval;
|
||||
int child_nodes_check_interval;
|
||||
@@ -251,35 +187,77 @@ typedef struct
|
||||
char rsync_options[MAXLEN];
|
||||
char ssh_options[MAXLEN];
|
||||
|
||||
/*
|
||||
* undocumented settings
|
||||
*
|
||||
* These settings are for testing or experimental features
|
||||
* and may be changed without notice.
|
||||
*/
|
||||
|
||||
/* experimental settings */
|
||||
bool reconnect_loop_sync;
|
||||
|
||||
/* test settings */
|
||||
/* undocumented test settings */
|
||||
int promote_delay;
|
||||
int failover_delay;
|
||||
char connection_check_query[MAXLEN];
|
||||
} 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
|
||||
{
|
||||
char slot[MAXLEN];
|
||||
char wal_method[MAXLEN];
|
||||
char waldir[MAXPGPATH];
|
||||
bool no_slot; /* from PostgreSQL 10 */
|
||||
} t_basebackup_options;
|
||||
|
||||
#define T_BASEBACKUP_OPTIONS_INITIALIZER { "", "", "", false }
|
||||
#define T_BASEBACKUP_OPTIONS_INITIALIZER { "", "", false }
|
||||
|
||||
|
||||
typedef enum
|
||||
@@ -336,11 +314,10 @@ typedef struct
|
||||
void set_progname(const char *argv0);
|
||||
const char *progname(void);
|
||||
|
||||
void load_config(const char *config_file, bool verbose, bool terse, char *argv0);
|
||||
bool reload_config(t_server_type server_type);
|
||||
void dump_config(void);
|
||||
void load_config(const char *config_file, bool verbose, bool terse, t_configuration_options *options, char *argv0);
|
||||
bool reload_config(t_configuration_options *orig_options, t_server_type server_type);
|
||||
|
||||
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);
|
||||
|
||||
@@ -353,9 +330,6 @@ int repmgr_atoi(const char *s,
|
||||
ItemList *error_list,
|
||||
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,
|
||||
t_basebackup_options *backup_options,
|
||||
int server_version_num,
|
||||
@@ -363,21 +337,17 @@ bool parse_pg_basebackup_options(const char *pg_basebackup_options,
|
||||
|
||||
int parse_output_to_argv(const char *string, 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 */
|
||||
void exit_with_cli_errors(ItemList *error_list, const char *repmgr_command);
|
||||
|
||||
void print_item_list(ItemList *item_list);
|
||||
const char *print_replication_type(ReplicationType 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 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_ */
|
||||
|
||||
30
configure
vendored
30
configure
vendored
@@ -1,6 +1,6 @@
|
||||
#! /bin/sh
|
||||
# Guess values for system-dependent variables and create Makefiles.
|
||||
# Generated by GNU Autoconf 2.69 for repmgr 5.4.0.
|
||||
# Generated by GNU Autoconf 2.69 for repmgr 5.1.0.
|
||||
#
|
||||
# Report bugs to <repmgr@googlegroups.com>.
|
||||
#
|
||||
@@ -11,7 +11,7 @@
|
||||
# This configure script is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy, distribute and modify it.
|
||||
#
|
||||
# Copyright (c) 2010-2021, EnterpriseDB Corporation
|
||||
# Copyright (c) 2010-2020, 2ndQuadrant Ltd.
|
||||
## -------------------- ##
|
||||
## M4sh Initialization. ##
|
||||
## -------------------- ##
|
||||
@@ -582,8 +582,8 @@ MAKEFLAGS=
|
||||
# Identity of this package.
|
||||
PACKAGE_NAME='repmgr'
|
||||
PACKAGE_TARNAME='repmgr'
|
||||
PACKAGE_VERSION='5.4.0'
|
||||
PACKAGE_STRING='repmgr 5.4.0'
|
||||
PACKAGE_VERSION='5.1.0'
|
||||
PACKAGE_STRING='repmgr 5.1.0'
|
||||
PACKAGE_BUGREPORT='repmgr@googlegroups.com'
|
||||
PACKAGE_URL='https://repmgr.org/'
|
||||
|
||||
@@ -1181,7 +1181,7 @@ if test "$ac_init_help" = "long"; then
|
||||
# Omit some internal or obsolete options to make the list less imposing.
|
||||
# This message is too long to be a string in the A/UX 3.1 sh.
|
||||
cat <<_ACEOF
|
||||
\`configure' configures repmgr 5.4.0 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]...
|
||||
|
||||
@@ -1242,7 +1242,7 @@ fi
|
||||
|
||||
if test -n "$ac_init_help"; then
|
||||
case $ac_init_help in
|
||||
short | recursive ) echo "Configuration of repmgr 5.4.0:";;
|
||||
short | recursive ) echo "Configuration of repmgr 5.1.0:";;
|
||||
esac
|
||||
cat <<\_ACEOF
|
||||
|
||||
@@ -1316,14 +1316,14 @@ fi
|
||||
test -n "$ac_init_help" && exit $ac_status
|
||||
if $ac_init_version; then
|
||||
cat <<\_ACEOF
|
||||
repmgr configure 5.4.0
|
||||
repmgr configure 5.1.0
|
||||
generated by GNU Autoconf 2.69
|
||||
|
||||
Copyright (C) 2012 Free Software Foundation, Inc.
|
||||
This configure script is free software; the Free Software Foundation
|
||||
gives unlimited permission to copy, distribute and modify it.
|
||||
|
||||
Copyright (c) 2010-2021, EnterpriseDB Corporation
|
||||
Copyright (c) 2010-2020, 2ndQuadrant Ltd.
|
||||
_ACEOF
|
||||
exit
|
||||
fi
|
||||
@@ -1335,7 +1335,7 @@ cat >config.log <<_ACEOF
|
||||
This file contains any messages produced by compilers while
|
||||
running configure, to aid debugging if configure makes a mistake.
|
||||
|
||||
It was created by repmgr $as_me 5.4.0, which was
|
||||
It was created by repmgr $as_me 5.1.0, which was
|
||||
generated by GNU Autoconf 2.69. Invocation command line was
|
||||
|
||||
$ $0 $@
|
||||
@@ -1811,11 +1811,11 @@ fi
|
||||
pgac_pg_config_version=$($PG_CONFIG --version 2>/dev/null)
|
||||
|
||||
major_version_num=$(echo "$pgac_pg_config_version"|
|
||||
$SED -e 's/^[^0-9]\+ \([0-9]\{1,2\}\).*$/\1/')
|
||||
$SED -e 's/^PostgreSQL \([0-9]\{1,2\}\).*$/\1/')
|
||||
|
||||
if test "$major_version_num" -lt '10'; then
|
||||
version_num=$(echo "$pgac_pg_config_version"|
|
||||
$SED -e 's/^[^0-9]\+ \([0-9]*\)\.\([0-9]*\)\([a-zA-Z0-9.]*\)$/\1.\2/')
|
||||
$SED -e 's/^PostgreSQL \([0-9]*\)\.\([0-9]*\)\([a-zA-Z0-9.]*\)$/\1.\2/')
|
||||
|
||||
if test -z "$version_num"; then
|
||||
as_fn_error $? "could not detect the PostgreSQL version, wrong or broken pg_config?" "$LINENO" 5
|
||||
@@ -1824,12 +1824,12 @@ if test "$major_version_num" -lt '10'; then
|
||||
version_num_int=$(echo "$version_num"|
|
||||
$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
|
||||
fi
|
||||
else
|
||||
version_num=$(echo "$pgac_pg_config_version"|
|
||||
$SED -e 's/^[^0-9]\+ \(.\+\)$/\1/')
|
||||
$SED -e 's/^PostgreSQL \(.\+\)$/\1/')
|
||||
|
||||
if test -z "$version_num"; then
|
||||
as_fn_error $? "could not detect the PostgreSQL version, wrong or broken pg_config?" "$LINENO" 5
|
||||
@@ -2487,7 +2487,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
|
||||
# report actual input values of CONFIG_FILES etc. instead of their
|
||||
# values after options handling.
|
||||
ac_log="
|
||||
This file was extended by repmgr $as_me 5.4.0, 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
|
||||
|
||||
CONFIG_FILES = $CONFIG_FILES
|
||||
@@ -2550,7 +2550,7 @@ _ACEOF
|
||||
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
||||
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
|
||||
ac_cs_version="\\
|
||||
repmgr config.status 5.4.0
|
||||
repmgr config.status 5.1.0
|
||||
configured by $0, generated by GNU Autoconf 2.69,
|
||||
with options \\"\$ac_cs_config\\"
|
||||
|
||||
|
||||
32
configure.in
32
configure.in
@@ -1,6 +1,6 @@
|
||||
AC_INIT([repmgr], [5.5.0], [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-2024, EnterpriseDB Corporation])
|
||||
AC_COPYRIGHT([Copyright (c) 2010-2020, 2ndQuadrant Ltd.])
|
||||
|
||||
AC_CONFIG_HEADER(config.h)
|
||||
|
||||
@@ -19,11 +19,11 @@ fi
|
||||
pgac_pg_config_version=$($PG_CONFIG --version 2>/dev/null)
|
||||
|
||||
major_version_num=$(echo "$pgac_pg_config_version"|
|
||||
$SED -e 's/^[[^0-9]]\+ \([[0-9]]\{1,2\}\).*$/\1/')
|
||||
$SED -e 's/^PostgreSQL \([[0-9]]\{1,2\}\).*$/\1/')
|
||||
|
||||
if test "$major_version_num" -lt '10'; then
|
||||
version_num=$(echo "$pgac_pg_config_version"|
|
||||
$SED -e 's/^[[^0-9]]\+ \([[0-9]]*\)\.\([[0-9]]*\)\([[a-zA-Z0-9.]]*\)$/\1.\2/')
|
||||
$SED -e 's/^PostgreSQL \([[0-9]]*\)\.\([[0-9]]*\)\([[a-zA-Z0-9.]]*\)$/\1.\2/')
|
||||
|
||||
if test -z "$version_num"; then
|
||||
AC_MSG_ERROR([could not detect the PostgreSQL version, wrong or broken pg_config?])
|
||||
@@ -32,12 +32,12 @@ if test "$major_version_num" -lt '10'; then
|
||||
version_num_int=$(echo "$version_num"|
|
||||
$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])
|
||||
fi
|
||||
else
|
||||
version_num=$(echo "$pgac_pg_config_version"|
|
||||
$SED -e 's/^[[^0-9]]\+ \(.\+\)$/\1/')
|
||||
$SED -e 's/^PostgreSQL \(.\+\)$/\1/')
|
||||
|
||||
if test -z "$version_num"; then
|
||||
AC_MSG_ERROR([could not detect the PostgreSQL version, wrong or broken pg_config?])
|
||||
@@ -60,7 +60,6 @@ AC_SUBST(vpath_build)
|
||||
AC_CHECK_PROG(HAVE_GNUSED,gnused,yes,no)
|
||||
AC_CHECK_PROG(HAVE_GSED,gsed,yes,no)
|
||||
AC_CHECK_PROG(HAVE_SED,sed,yes,no)
|
||||
AC_CHECK_PROG(HAVE_FLEX,flex,yes,no)
|
||||
|
||||
if test "$HAVE_GNUSED" = yes; then
|
||||
SED=gnused
|
||||
@@ -73,25 +72,6 @@ else
|
||||
fi
|
||||
AC_SUBST(SED)
|
||||
|
||||
AS_IF([test x"$HAVE_FLEX" != x"yes"], AC_MSG_ERROR([flex should be installed first]))
|
||||
|
||||
#Checking libraries
|
||||
GENERIC_LIB_FAILED_MSG="library should be installed"
|
||||
|
||||
AC_CHECK_LIB(selinux, is_selinux_enabled, [],
|
||||
[AC_MSG_ERROR(['selinux' $GENERIC_LIB_FAILED_MSG])])
|
||||
|
||||
AC_CHECK_LIB(lz4, LZ4_compress_default, [],
|
||||
[AC_MSG_ERROR(['Z4' $GENERIC_LIB_FAILED_MSG])])
|
||||
|
||||
AC_CHECK_LIB(xslt, xsltCleanupGlobals, [],
|
||||
[AC_MSG_ERROR(['xslt' $GENERIC_LIB_FAILED_MSG])])
|
||||
|
||||
AC_CHECK_LIB(pam, pam_start, [],
|
||||
[AC_MSG_ERROR(['pam' $GENERIC_LIB_FAILED_MSG])])
|
||||
|
||||
AC_CHECK_LIB(gssapi_krb5, gss_init_sec_context, [],
|
||||
[AC_MSG_ERROR([gssapi_krb5 $GENERIC_LIB_FAILED_MSG])])
|
||||
|
||||
AC_CONFIG_FILES([Makefile])
|
||||
AC_CONFIG_FILES([Makefile.global])
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
* controldata.c - functions for reading the pg_control file
|
||||
*
|
||||
* The functions provided here enable repmgr to read a pg_control file
|
||||
* in a version-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
|
||||
* 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) 1994, Regents of the University of California
|
||||
@@ -90,9 +90,7 @@ get_system_identifier(const char *data_directory)
|
||||
uint64 system_identifier = UNKNOWN_SYSTEM_IDENTIFIER;
|
||||
|
||||
control_file_info = get_controlfile(data_directory);
|
||||
|
||||
if (control_file_info->control_file_processed == true)
|
||||
system_identifier = control_file_info->system_identifier;
|
||||
system_identifier = control_file_info->system_identifier;
|
||||
|
||||
pfree(control_file_info);
|
||||
|
||||
@@ -100,21 +98,19 @@ get_system_identifier(const char *data_directory)
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
get_db_state(const char *data_directory, DBState *state)
|
||||
DBState
|
||||
get_db_state(const char *data_directory)
|
||||
{
|
||||
ControlFileInfo *control_file_info = NULL;
|
||||
bool control_file_processed;
|
||||
DBState state;
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
if (control_file_info->control_file_processed == true)
|
||||
checkPoint = control_file_info->checkPoint;
|
||||
checkPoint = control_file_info->checkPoint;
|
||||
|
||||
pfree(control_file_info);
|
||||
|
||||
@@ -139,12 +134,11 @@ int
|
||||
get_data_checksum_version(const char *data_directory)
|
||||
{
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
@@ -283,19 +277,8 @@ get_controlfile(const char *DataDir)
|
||||
return control_file_info;
|
||||
}
|
||||
|
||||
if (version_num >= 120000)
|
||||
{
|
||||
#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)
|
||||
|
||||
if (version_num >= 90500)
|
||||
{
|
||||
expected_size = sizeof(ControlFileData95);
|
||||
ControlFileDataPtr = palloc0(expected_size);
|
||||
@@ -305,6 +288,12 @@ get_controlfile(const char *DataDir)
|
||||
expected_size = sizeof(ControlFileData94);
|
||||
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)
|
||||
{
|
||||
@@ -333,7 +322,7 @@ get_controlfile(const char *DataDir)
|
||||
control_file_info->minRecoveryPointTLI = ptr->minRecoveryPointTLI;
|
||||
control_file_info->minRecoveryPoint = ptr->minRecoveryPoint;
|
||||
#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);
|
||||
#endif
|
||||
}
|
||||
@@ -370,6 +359,17 @@ get_controlfile(const char *DataDir)
|
||||
control_file_info->minRecoveryPointTLI = ptr->minRecoveryPointTLI;
|
||||
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);
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* 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) 1994, Regents of the University of California
|
||||
@@ -31,7 +31,9 @@ typedef struct
|
||||
} ControlFileInfo;
|
||||
|
||||
|
||||
typedef struct CheckPoint94
|
||||
|
||||
/* Same for 9.3, 9.4 */
|
||||
typedef struct CheckPoint93
|
||||
{
|
||||
XLogRecPtr redo; /* next RecPtr available when we began to
|
||||
* create CheckPoint (i.e. REDO start point) */
|
||||
@@ -51,7 +53,7 @@ typedef struct CheckPoint94
|
||||
pg_time_t time; /* time stamp of checkpoint */
|
||||
|
||||
TransactionId oldestActiveXid;
|
||||
} CheckPoint94;
|
||||
} CheckPoint93;
|
||||
|
||||
|
||||
/* Same for 9.5, 9.6, 10, 11 */
|
||||
@@ -126,6 +128,65 @@ typedef struct CheckPoint12
|
||||
} CheckPoint12;
|
||||
#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
|
||||
{
|
||||
@@ -139,7 +200,7 @@ typedef struct ControlFileData94
|
||||
XLogRecPtr checkPoint; /* last 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 */
|
||||
|
||||
@@ -377,7 +438,7 @@ typedef struct ControlFileData12
|
||||
#endif
|
||||
|
||||
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 int get_data_checksum_version(const char *data_directory);
|
||||
extern uint64 get_system_identifier(const char *data_directory);
|
||||
|
||||
529
dbutils.c
529
dbutils.c
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* 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
|
||||
@@ -61,8 +61,6 @@ static ReplSlotStatus _verify_replication_slot(PGconn *conn, char *slot_name, PQ
|
||||
|
||||
static bool _create_event(PGconn *conn, t_configuration_options *options, int node_id, char *event, bool successful, char *details, t_event_info *event_info, bool send_notification);
|
||||
|
||||
static NodeAttached _is_downstream_node_attached(PGconn *conn, char *node_name, char **node_state, bool quiet);
|
||||
|
||||
/*
|
||||
* This provides a standardized way of logging database errors. Note
|
||||
* that the provided PGconn can be a normal or a replication connection;
|
||||
@@ -155,9 +153,6 @@ _establish_db_connection(const char *conninfo, const bool exit_on_error, const b
|
||||
if (param_get(&conninfo_params, "replication") != NULL)
|
||||
is_replication_connection = true;
|
||||
|
||||
/* use a secure search_path */
|
||||
param_set(&conninfo_params, "options", "-csearch_path=");
|
||||
|
||||
connection_string = param_list_to_string(&conninfo_params);
|
||||
|
||||
log_debug(_("connecting to: \"%s\""), connection_string);
|
||||
@@ -308,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, "fallback_application_name", "repmgr");
|
||||
|
||||
/* use a secure search_path */
|
||||
param_set(param_list, "options", "-csearch_path=");
|
||||
|
||||
/* Connect to the database using the provided parameters */
|
||||
conn = PQconnectdbParams((const char **) param_list->keywords, (const char **) param_list->values, true);
|
||||
|
||||
@@ -713,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
|
||||
*
|
||||
* See conn_to_param_list() to do the same for a PGconn.
|
||||
*
|
||||
* "errmsg": passed to PQconninfoParse(), may be NULL
|
||||
* See conn_to_param_list() to do the same for a PGconn
|
||||
*
|
||||
* "ignore_local_params": ignores those parameters specific
|
||||
* to a local installation, i.e. when parsing an upstream
|
||||
@@ -764,7 +729,8 @@ parse_conninfo_string(const char *conninfo_str, t_conninfo_param_list *param_lis
|
||||
for (option = connOptions; option && option->keyword; option++)
|
||||
{
|
||||
/* 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;
|
||||
|
||||
/* Ignore settings specific to the upstream node */
|
||||
@@ -809,7 +775,8 @@ conn_to_param_list(PGconn *conn, t_conninfo_param_list *param_list)
|
||||
for (option = connOptions; option && option->keyword; option++)
|
||||
{
|
||||
/* 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;
|
||||
|
||||
/* Ignore "password" */
|
||||
@@ -1259,7 +1226,7 @@ bool
|
||||
pg_reload_conf(PGconn *conn)
|
||||
{
|
||||
PGresult *res = NULL;
|
||||
bool success = true;
|
||||
bool success = false;
|
||||
|
||||
res = PQexec(conn, "SELECT pg_catalog.pg_reload_conf()");
|
||||
|
||||
@@ -1291,16 +1258,21 @@ get_cluster_size(PGconn *conn, char *size)
|
||||
initPQExpBuffer(&query);
|
||||
appendPQExpBufferStr(&query,
|
||||
"SELECT pg_catalog.pg_size_pretty(pg_catalog.sum(pg_catalog.pg_database_size(oid))::bigint) "
|
||||
" FROM pg_catalog.pg_database ");
|
||||
" FROM pg_catalog.pg_database ");
|
||||
|
||||
log_verbose(LOG_DEBUG, "get_cluster_size():\n%s", query.data);
|
||||
|
||||
res = PQexec(conn, query.data);
|
||||
|
||||
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
||||
{
|
||||
log_db_error(conn, query.data, _("get_cluster_size(): unable to execute query"));
|
||||
success = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(size, MAXLEN, "%s", PQgetvalue(res, 0, 0));
|
||||
}
|
||||
|
||||
termPQExpBuffer(&query);
|
||||
PQclear(res);
|
||||
@@ -1624,7 +1596,7 @@ get_ready_archive_files(PGconn *conn, const char *data_directory)
|
||||
|
||||
while ((arcdir_ent = readdir(arcdir)) != NULL)
|
||||
{
|
||||
struct stat local_statbuf;
|
||||
struct stat statbuf;
|
||||
char file_path[MAXPGPATH + sizeof(arcdir_ent->d_name)];
|
||||
int basenamelen = 0;
|
||||
|
||||
@@ -1634,7 +1606,7 @@ get_ready_archive_files(PGconn *conn, const char *data_directory)
|
||||
arcdir_ent->d_name);
|
||||
|
||||
/* skip non-files */
|
||||
if (stat(file_path, &local_statbuf) == 0 && !S_ISREG(local_statbuf.st_mode))
|
||||
if (stat(file_path, &statbuf) == 0 && !S_ISREG(statbuf.st_mode))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -1671,12 +1643,7 @@ identify_system(PGconn *repl_conn, t_system_identification *identification)
|
||||
return false;
|
||||
}
|
||||
|
||||
#if defined(__i386__) || defined(__i386)
|
||||
identification->system_identifier = atoll(PQgetvalue(res, 0, 0));
|
||||
#else
|
||||
identification->system_identifier = atol(PQgetvalue(res, 0, 0));
|
||||
#endif
|
||||
|
||||
identification->timeline = atoi(PQgetvalue(res, 0, 1));
|
||||
identification->xlogpos = parse_lsn(PQgetvalue(res, 0, 2));
|
||||
|
||||
@@ -1713,11 +1680,7 @@ system_identifier(PGconn *conn)
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined(__i386__) || defined(__i386)
|
||||
system_identifier = atoll(PQgetvalue(res, 0, 0));
|
||||
#else
|
||||
system_identifier = atol(PQgetvalue(res, 0, 0));
|
||||
#endif
|
||||
}
|
||||
|
||||
PQclear(res);
|
||||
@@ -1823,80 +1786,11 @@ get_timeline_history(PGconn *repl_conn, TimeLineID tli)
|
||||
}
|
||||
|
||||
|
||||
pid_t
|
||||
get_wal_receiver_pid(PGconn *conn)
|
||||
{
|
||||
PGresult *res = NULL;
|
||||
pid_t wal_receiver_pid = UNKNOWN_PID;
|
||||
|
||||
res = PQexec(conn, "SELECT repmgr.get_wal_receiver_pid()");
|
||||
|
||||
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
||||
{
|
||||
log_error(_("unable to execute \"SELECT repmgr.get_wal_receiver_pid()\""));
|
||||
log_detail("%s", PQerrorMessage(conn));
|
||||
}
|
||||
else if (!PQgetisnull(res, 0, 0))
|
||||
{
|
||||
wal_receiver_pid = atoi(PQgetvalue(res, 0, 0));
|
||||
}
|
||||
|
||||
PQclear(res);
|
||||
|
||||
return wal_receiver_pid;
|
||||
}
|
||||
|
||||
|
||||
/* =============================== */
|
||||
/* user/role information functions */
|
||||
/* =============================== */
|
||||
|
||||
|
||||
/*
|
||||
* Determine if the user associated with the current connection can execute CHECKPOINT command.
|
||||
* User must be a supersuer or a member of the pg_checkpoint default role (available from PostgreSQL 15).
|
||||
*/
|
||||
bool
|
||||
can_execute_checkpoint(PGconn *conn)
|
||||
{
|
||||
PQExpBufferData query;
|
||||
PGresult *res;
|
||||
bool has_pg_checkpoint_role = false;
|
||||
|
||||
/* superusers can do anything, no role check needed */
|
||||
if (is_superuser_connection(conn, NULL) == true)
|
||||
return true;
|
||||
|
||||
/* pg_checkpoint available from PostgreSQL 15 */
|
||||
if (PQserverVersion(conn) < 150000)
|
||||
return false;
|
||||
|
||||
initPQExpBuffer(&query);
|
||||
appendPQExpBufferStr(&query,
|
||||
" SELECT pg_catalog.pg_has_role('pg_checkpoint','USAGE') ");
|
||||
|
||||
res = PQexec(conn, query.data);
|
||||
|
||||
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
||||
{
|
||||
log_db_error(conn, query.data,
|
||||
_("can_execute_checkpoint(): unable to query user roles"));
|
||||
}
|
||||
else
|
||||
{
|
||||
has_pg_checkpoint_role = atobool(PQgetvalue(res, 0, 0));
|
||||
}
|
||||
termPQExpBuffer(&query);
|
||||
PQclear(res);
|
||||
|
||||
return has_pg_checkpoint_role;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Determine if the user associated with the current connection
|
||||
* has sufficient permissions to use pg_promote function
|
||||
*/
|
||||
bool
|
||||
can_execute_pg_promote(PGconn *conn)
|
||||
{
|
||||
@@ -1905,7 +1799,7 @@ can_execute_pg_promote(PGconn *conn)
|
||||
bool has_pg_promote= false;
|
||||
|
||||
/* pg_promote() available from PostgreSQL 12 */
|
||||
if (PQserverVersion(conn) < 120000)
|
||||
if(PQserverVersion(conn) < 120000)
|
||||
return false;
|
||||
|
||||
initPQExpBuffer(&query);
|
||||
@@ -1933,127 +1827,48 @@ can_execute_pg_promote(PGconn *conn)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Determine if the user associated with the current connection
|
||||
* has sufficient permissions to disable the walsender
|
||||
*/
|
||||
bool
|
||||
can_disable_walsender(PGconn *conn)
|
||||
connection_has_pg_settings(PGconn *conn)
|
||||
{
|
||||
/*
|
||||
* Requires PostgreSQL 9.5 or later, because ALTER SYSTEM
|
||||
*/
|
||||
if (PQserverVersion(conn) < 90500)
|
||||
{
|
||||
log_warning(_("\"standby_disconnect_on_failover\" specified, but not available for this PostgreSQL version"));
|
||||
/* TODO: format server version */
|
||||
log_detail(_("available from PostgreSQL 9.5; this PostgreSQL version is %i"), PQserverVersion(conn));
|
||||
bool has_pg_settings = false;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Superusers can do anything
|
||||
*/
|
||||
/* superusers can always read pg_settings */
|
||||
if (is_superuser_connection(conn, NULL) == true)
|
||||
return true;
|
||||
|
||||
PQExpBufferData query;
|
||||
PGresult *res;
|
||||
bool has_alter_system_priv = false;
|
||||
|
||||
/* GRANT ALTER SYSTEM available from PostgreSQL 15 */
|
||||
if (PQserverVersion(conn) >= 150000)
|
||||
{
|
||||
has_pg_settings = true;
|
||||
}
|
||||
/* from PostgreSQL 10, a non-superuser may have been granted access */
|
||||
else if(PQserverVersion(conn) >= 100000)
|
||||
{
|
||||
PQExpBufferData query;
|
||||
PGresult *res;
|
||||
|
||||
initPQExpBuffer(&query);
|
||||
appendPQExpBufferStr(&query,
|
||||
" SELECT pg_catalog.has_parameter_privilege('wal_retrieve_retry_interval', 'ALTER SYSTEM') ");
|
||||
" 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,
|
||||
_("can_disable_walsender(): unable to query user parameter privileges"));
|
||||
_("connection_has_pg_settings(): unable to query user roles"));
|
||||
}
|
||||
else
|
||||
{
|
||||
has_alter_system_priv = atobool(PQgetvalue(res, 0, 0));
|
||||
has_pg_settings = atobool(PQgetvalue(res, 0, 0));
|
||||
}
|
||||
termPQExpBuffer(&query);
|
||||
PQclear(res);
|
||||
}
|
||||
|
||||
if (has_alter_system_priv == false)
|
||||
{
|
||||
log_warning(_("\"standby_disconnect_on_failover\" specified, but repmgr user is not authorized to perform ALTER SYSTEM wal_retrieve_retry_interval"));
|
||||
|
||||
if (PQserverVersion(conn) >= 150000)
|
||||
{
|
||||
log_detail(_("superuser or ALTER SYSTEM wal_retrieve_retry_interval permission required to disable standbys on failover"));
|
||||
}
|
||||
else
|
||||
{
|
||||
log_detail(_("superuser permission required to disable standbys on failover"));
|
||||
}
|
||||
}
|
||||
|
||||
return has_alter_system_priv;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
connection_has_pg_monitor_role(PGconn *conn, const char *subrole)
|
||||
{
|
||||
PQExpBufferData query;
|
||||
PGresult *res;
|
||||
bool has_pg_monitor_role = false;
|
||||
|
||||
/* superusers can read anything, no role check needed */
|
||||
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','USAGE') "
|
||||
" THEN TRUE ");
|
||||
|
||||
if (subrole != NULL)
|
||||
{
|
||||
appendPQExpBuffer(&query,
|
||||
" WHEN pg_catalog.pg_has_role('%s','USAGE') "
|
||||
" THEN TRUE ",
|
||||
subrole);
|
||||
}
|
||||
|
||||
appendPQExpBufferStr(&query,
|
||||
" 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;
|
||||
return has_pg_settings;
|
||||
}
|
||||
|
||||
|
||||
@@ -2216,13 +2031,7 @@ server_in_exclusive_backup_mode(PGconn *conn)
|
||||
{
|
||||
BackupState backup_state = BACKUP_STATE_UNKNOWN;
|
||||
const char *sqlquery = "SELECT pg_catalog.pg_is_in_backup()";
|
||||
PGresult *res = NULL;
|
||||
|
||||
/* Exclusive backup removed from PostgreSQL 15 */
|
||||
if (PQserverVersion(conn) >= 150000)
|
||||
return BACKUP_STATE_NO_BACKUP;
|
||||
|
||||
res = PQexec(conn, sqlquery);
|
||||
PGresult *res = PQexec(conn, sqlquery);
|
||||
|
||||
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
||||
{
|
||||
@@ -2386,6 +2195,29 @@ repmgrd_pause(PGconn *conn, bool pause)
|
||||
return success;
|
||||
}
|
||||
|
||||
pid_t
|
||||
get_wal_receiver_pid(PGconn *conn)
|
||||
{
|
||||
PGresult *res = NULL;
|
||||
pid_t wal_receiver_pid = UNKNOWN_PID;
|
||||
|
||||
res = PQexec(conn, "SELECT repmgr.get_wal_receiver_pid()");
|
||||
|
||||
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
||||
{
|
||||
log_error(_("unable to execute \"SELECT repmgr.get_wal_receiver_pid()\""));
|
||||
log_detail("%s", PQerrorMessage(conn));
|
||||
}
|
||||
else if (!PQgetisnull(res, 0, 0))
|
||||
{
|
||||
wal_receiver_pid = atoi(PQgetvalue(res, 0, 0));
|
||||
}
|
||||
|
||||
PQclear(res);
|
||||
|
||||
return wal_receiver_pid;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
repmgrd_get_upstream_node_id(PGconn *conn)
|
||||
@@ -2537,10 +2369,7 @@ get_repmgr_extension_status(PGconn *conn, t_extension_versions *extversions)
|
||||
/* node management functions */
|
||||
/* ========================= */
|
||||
|
||||
/*
|
||||
* Assumes the connection can execute CHECKPOINT command.
|
||||
* A check can be executed via 'can_execute_checkpoint' function.
|
||||
*/
|
||||
/* assumes superuser connection */
|
||||
void
|
||||
checkpoint(PGconn *conn)
|
||||
{
|
||||
@@ -2668,10 +2497,7 @@ resume_wal_replay(PGconn *conn)
|
||||
/* Node record functions */
|
||||
/* ===================== */
|
||||
|
||||
/*
|
||||
* Note: init_defaults may only be false when the caller is refreshing a previously
|
||||
* populated record.
|
||||
*/
|
||||
|
||||
static RecordStatus
|
||||
_get_node_record(PGconn *conn, char *sqlquery, t_node_info *node_info, bool init_defaults)
|
||||
{
|
||||
@@ -2702,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
|
||||
_populate_node_record(PGresult *res, t_node_info *node_info, int row, bool init_defaults)
|
||||
{
|
||||
@@ -3036,37 +2858,6 @@ get_all_node_records(PGconn *conn, NodeInfoList *node_list)
|
||||
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
|
||||
get_downstream_node_records(PGconn *conn, int node_id, NodeInfoList *node_list)
|
||||
@@ -3160,7 +2951,7 @@ get_child_nodes(PGconn *conn, int node_id, NodeInfoList *node_list)
|
||||
" WHERE n.upstream_node_id = %i ",
|
||||
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);
|
||||
|
||||
@@ -3723,21 +3514,11 @@ witness_copy_node_records(PGconn *primary_conn, PGconn *witness_conn)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (get_all_node_records(primary_conn, &nodes) == false)
|
||||
{
|
||||
rollback_transaction(witness_conn);
|
||||
|
||||
return false;
|
||||
}
|
||||
get_all_node_records(primary_conn, &nodes);
|
||||
|
||||
for (cell = nodes.head; cell; cell = cell->next)
|
||||
{
|
||||
if (create_node_record(witness_conn, NULL, cell->node_info) == false)
|
||||
{
|
||||
rollback_transaction(witness_conn);
|
||||
|
||||
return false;
|
||||
}
|
||||
create_node_record(witness_conn, NULL, cell->node_info);
|
||||
}
|
||||
|
||||
/* and done */
|
||||
@@ -4362,7 +4143,7 @@ _create_event(PGconn *conn, t_configuration_options *options, int node_id, char
|
||||
}
|
||||
break;
|
||||
case 'p':
|
||||
/* %p: primary id ("standby_switchover"/"repmgrd_failover_promote": former primary id) */
|
||||
/* %p: primary id ("standby_switchover": former primary id) */
|
||||
src_ptr++;
|
||||
if (event_info->node_id != UNKNOWN_NODE_ID)
|
||||
{
|
||||
@@ -4696,17 +4477,17 @@ drop_replication_slot_replprot(PGconn *repl_conn, char *slot_name)
|
||||
initPQExpBuffer(&query);
|
||||
|
||||
appendPQExpBuffer(&query,
|
||||
"DROP_REPLICATION_SLOT %s;",
|
||||
"DROP_REPLICATION_SLOT %s",
|
||||
slot_name);
|
||||
|
||||
log_verbose(LOG_DEBUG, "drop_replication_slot_replprot():\n %s", query.data);
|
||||
|
||||
res = PQexec(repl_conn, query.data);
|
||||
|
||||
if (PQresultStatus(res) != PGRES_TUPLES_OK || !PQntuples(res))
|
||||
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
||||
{
|
||||
log_db_error(repl_conn, query.data,
|
||||
_("drop_replication_slot_replprot(): unable to drop replication slot \"%s\""),
|
||||
_("drop_replication_slot_sql(): unable to drop replication slot \"%s\""),
|
||||
slot_name);
|
||||
|
||||
success = false;
|
||||
@@ -4947,7 +4728,7 @@ cancel_query(PGconn *conn, int timeout)
|
||||
* Wait until current query finishes, ignoring any results.
|
||||
* Usually this will be an async query or query cancellation.
|
||||
*
|
||||
* Returns 1 for success; 0 if any error occurred; -1 if timeout reached.
|
||||
* Returns 1 for success; 0 if any error ocurred; -1 if timeout reached.
|
||||
*/
|
||||
int
|
||||
wait_connection_availability(PGconn *conn, int timeout)
|
||||
@@ -5698,9 +5479,21 @@ get_replication_info(PGconn *conn, t_server_type node_type, ReplInfo *replicatio
|
||||
}
|
||||
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,
|
||||
" 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 "
|
||||
" THEN FALSE "
|
||||
" ELSE pg_catalog.pg_is_xlog_replay_paused() "
|
||||
@@ -5824,7 +5617,7 @@ get_node_timeline(PGconn *conn, char *timeline_id_str)
|
||||
TimeLineID timeline_id = UNKNOWN_TIMELINE_ID;
|
||||
|
||||
/*
|
||||
* pg_control_checkpoint() was introduced in PostgreSQL 9.6
|
||||
* PG_control_checkpoint() was introduced in PostgreSQL 9.6
|
||||
*/
|
||||
if (PQserverVersion(conn) >= 90600)
|
||||
{
|
||||
@@ -5871,11 +5664,28 @@ get_node_replication_stats(PGconn *conn, t_node_info *node_info)
|
||||
|
||||
appendPQExpBufferStr(&query,
|
||||
" 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, "
|
||||
" 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, "
|
||||
" (SELECT pg_catalog.count(*) FROM pg_catalog.pg_stat_replication) AS attached_wal_receivers, ");
|
||||
|
||||
/* no replication slots in PostgreSQL 9.3 */
|
||||
if (PQserverVersion(conn) < 90400)
|
||||
{
|
||||
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");
|
||||
|
||||
log_verbose(LOG_DEBUG, "get_node_replication_stats():\n%s", query.data);
|
||||
@@ -5910,28 +5720,16 @@ get_node_replication_stats(PGconn *conn, t_node_info *node_info)
|
||||
|
||||
|
||||
NodeAttached
|
||||
is_downstream_node_attached(PGconn *conn, char *node_name, char **node_state)
|
||||
is_downstream_node_attached(PGconn *conn, char *node_name)
|
||||
{
|
||||
return _is_downstream_node_attached(conn, node_name, node_state, false);
|
||||
}
|
||||
|
||||
NodeAttached
|
||||
is_downstream_node_attached_quiet(PGconn *conn, char *node_name, char **node_state)
|
||||
{
|
||||
return _is_downstream_node_attached(conn, node_name, node_state, true);
|
||||
}
|
||||
|
||||
NodeAttached
|
||||
_is_downstream_node_attached(PGconn *conn, char *node_name, char **node_state, bool quiet)
|
||||
{
|
||||
|
||||
PQExpBufferData query;
|
||||
PGresult *res = NULL;
|
||||
int c = 0;
|
||||
|
||||
initPQExpBuffer(&query);
|
||||
|
||||
appendPQExpBuffer(&query,
|
||||
" SELECT pid, state "
|
||||
" SELECT pg_catalog.count(*) "
|
||||
" FROM pg_catalog.pg_stat_replication "
|
||||
" WHERE application_name = '%s'",
|
||||
node_name);
|
||||
@@ -5950,73 +5748,31 @@ _is_downstream_node_attached(PGconn *conn, char *node_name, char **node_state, b
|
||||
return NODE_ATTACHED_UNKNOWN;
|
||||
}
|
||||
|
||||
termPQExpBuffer(&query);
|
||||
|
||||
/*
|
||||
* 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)
|
||||
if (PQntuples(res) != 1)
|
||||
{
|
||||
if (quiet == false)
|
||||
{
|
||||
log_error(_("multiple entries with \"application_name\" set to \"%s\" found in \"pg_stat_replication\""),
|
||||
node_name);
|
||||
log_hint(_("verify that a unique node name is configured for each node"));
|
||||
}
|
||||
log_verbose(LOG_WARNING, _("unexpected number of tuples (%i) returned"), PQntuples(res));
|
||||
|
||||
termPQExpBuffer(&query);
|
||||
PQclear(res);
|
||||
|
||||
return NODE_ATTACHED_UNKNOWN;
|
||||
}
|
||||
|
||||
if (PQntuples(res) == 0)
|
||||
{
|
||||
if (quiet == false)
|
||||
log_warning(_("node \"%s\" not found in \"pg_stat_replication\""), node_name);
|
||||
c = atoi(PQgetvalue(res, 0, 0));
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the connection is not a superuser or member of pg_read_all_stats, we
|
||||
* won't be able to retrieve the "state" column, so we'll assume
|
||||
* 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)
|
||||
{
|
||||
if (quiet == false)
|
||||
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);
|
||||
if (c > 1)
|
||||
log_verbose(LOG_WARNING, _("multiple entries with \"application_name\" set to \"%s\" found in \"pg_stat_replication\""),
|
||||
node_name);
|
||||
|
||||
return NODE_ATTACHED;
|
||||
}
|
||||
@@ -6146,43 +5902,6 @@ is_wal_replay_paused(PGconn *conn, bool check_pending_wal)
|
||||
return is_paused;
|
||||
}
|
||||
|
||||
/* repmgrd status functions */
|
||||
|
||||
CheckStatus
|
||||
get_repmgrd_status(PGconn *conn)
|
||||
{
|
||||
PQExpBufferData query;
|
||||
PGresult *res = NULL;
|
||||
CheckStatus repmgrd_status = CHECK_STATUS_CRITICAL;
|
||||
|
||||
initPQExpBuffer(&query);
|
||||
|
||||
appendPQExpBufferStr(&query,
|
||||
" SELECT "
|
||||
" CASE "
|
||||
" WHEN repmgr.repmgrd_is_running() "
|
||||
" THEN "
|
||||
" CASE "
|
||||
" WHEN repmgr.repmgrd_is_paused() THEN 1 ELSE 0 "
|
||||
" END "
|
||||
" ELSE 2 "
|
||||
" END AS repmgrd_status");
|
||||
res = PQexec(conn, query.data);
|
||||
|
||||
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
||||
{
|
||||
log_db_error(conn, query.data, _("unable to execute repmgrd status query"));
|
||||
}
|
||||
else
|
||||
{
|
||||
repmgrd_status = atoi(PQgetvalue(res, 0, 0));
|
||||
}
|
||||
|
||||
termPQExpBuffer(&query);
|
||||
PQclear(res);
|
||||
return repmgrd_status;
|
||||
}
|
||||
|
||||
|
||||
/* miscellaneous debugging functions */
|
||||
|
||||
|
||||
25
dbutils.h
25
dbutils.h
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* 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
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -119,14 +119,9 @@ typedef enum
|
||||
|
||||
typedef enum
|
||||
{
|
||||
/* unable to query "pg_stat_replication" or other error */
|
||||
NODE_ATTACHED_UNKNOWN = -1,
|
||||
/* node has record in "pg_stat_replication" and state is not "streaming" */
|
||||
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
|
||||
NODE_DETACHED,
|
||||
NODE_ATTACHED
|
||||
} NodeAttached;
|
||||
|
||||
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_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);
|
||||
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);
|
||||
char *param_list_to_string(t_conninfo_param_list *param_list);
|
||||
char *normalize_conninfo_string(const char *conninfo_str);
|
||||
@@ -450,13 +444,10 @@ int get_ready_archive_files(PGconn *conn, const char *data_directory);
|
||||
bool identify_system(PGconn *repl_conn, t_system_identification *identification);
|
||||
uint64 system_identifier(PGconn *conn);
|
||||
TimeLineHistoryEntry *get_timeline_history(PGconn *repl_conn, TimeLineID tli);
|
||||
pid_t get_wal_receiver_pid(PGconn *conn);
|
||||
|
||||
/* user/role information functions */
|
||||
bool can_execute_checkpoint(PGconn *conn);
|
||||
bool can_execute_pg_promote(PGconn *conn);
|
||||
bool can_disable_walsender(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_superuser_connection(PGconn *conn, t_connection_user *userinfo);
|
||||
|
||||
@@ -470,6 +461,7 @@ pid_t repmgrd_get_pid(PGconn *conn);
|
||||
bool repmgrd_is_running(PGconn *conn);
|
||||
bool repmgrd_is_paused(PGconn *conn);
|
||||
bool repmgrd_pause(PGconn *conn, bool pause);
|
||||
pid_t get_wal_receiver_pid(PGconn *conn);
|
||||
int repmgrd_get_upstream_node_id(PGconn *conn);
|
||||
bool repmgrd_set_upstream_node_id(PGconn *conn, int node_id);
|
||||
|
||||
@@ -498,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_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_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);
|
||||
@@ -598,16 +589,12 @@ bool get_replication_info(PGconn *conn, t_server_type node_type, ReplInfo *repl
|
||||
int get_replication_lag_seconds(PGconn *conn);
|
||||
TimeLineID get_node_timeline(PGconn *conn, char *timeline_id_str);
|
||||
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_quiet(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);
|
||||
int get_upstream_last_seen(PGconn *conn, t_server_type node_type);
|
||||
|
||||
bool is_wal_replay_paused(PGconn *conn, bool check_pending_wal);
|
||||
|
||||
/* repmgrd status functions */
|
||||
CheckStatus get_repmgrd_status(PGconn *conn);
|
||||
|
||||
/* miscellaneous debugging functions */
|
||||
const char *print_node_status(NodeStatus node_status);
|
||||
const char *print_pqping_status(PGPing ping_status);
|
||||
|
||||
76
dirutil.c
76
dirutil.c
@@ -3,7 +3,7 @@
|
||||
* dirmod.c
|
||||
* 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
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -109,56 +109,9 @@ create_dir(const char *path)
|
||||
|
||||
|
||||
bool
|
||||
set_dir_permissions(const char *path, int server_version_num)
|
||||
set_dir_permissions(const char *path)
|
||||
{
|
||||
struct stat stat_buf;
|
||||
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;
|
||||
return (chmod(path, 0700) != 0) ? false : true;
|
||||
}
|
||||
|
||||
|
||||
@@ -205,7 +158,7 @@ mkdir_p(char *path, mode_t omode)
|
||||
/*
|
||||
* POSIX 1003.2: For each dir operand that does not name an
|
||||
* existing directory, effects equivalent to those caused by the
|
||||
* following command shall occur:
|
||||
* following command shall occcur:
|
||||
*
|
||||
* mkdir -p -m $(umask -S),u+wx $(dirname dir) && mkdir [-m mode]
|
||||
* dir
|
||||
@@ -289,7 +242,7 @@ is_pg_running(const char *path)
|
||||
{
|
||||
/*
|
||||
* 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
|
||||
* that PostgreSQL will still be running.
|
||||
*/
|
||||
@@ -350,7 +303,7 @@ create_pg_dir(const char *path, bool force)
|
||||
switch (check_dir(path))
|
||||
{
|
||||
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);
|
||||
|
||||
if (!create_dir(path))
|
||||
@@ -361,23 +314,14 @@ create_pg_dir(const char *path, bool force)
|
||||
}
|
||||
break;
|
||||
case DIR_EMPTY:
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
/* exists but empty, fix permissions and use it */
|
||||
log_info(_("checking and correcting permissions on existing directory \"%s\""),
|
||||
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;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* 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
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -35,7 +35,7 @@ typedef enum
|
||||
} PgDirState;
|
||||
|
||||
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 bool create_dir(const char *path);
|
||||
|
||||
@@ -95,8 +95,6 @@ clean:
|
||||
rm -f repmgr.html
|
||||
rm -f repmgr-A4.pdf
|
||||
rm -f repmgr-US.pdf
|
||||
rm -f *.fo
|
||||
rm -f html/*
|
||||
|
||||
maintainer-clean:
|
||||
rm -rf html
|
||||
|
||||
@@ -22,9 +22,6 @@
|
||||
&repmgr; 5 is fundamentally the same code base as &repmgr; 4, but provides
|
||||
support for the revised replication configuration mechanism in PostgreSQL 12.
|
||||
</para>
|
||||
<para>
|
||||
Support for PostgreSQL 9.3 is no longer available from &repmgr; 5.2.
|
||||
</para>
|
||||
</note>
|
||||
<para>
|
||||
&repmgr; 3.x builds on the improved replication facilities added
|
||||
@@ -62,7 +59,7 @@
|
||||
|
||||
<tip>
|
||||
<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
|
||||
source of WAL files, rather than maintain replication slots for
|
||||
each standby. See also: <link linkend="cloning-from-barman-restore-command">Using Barman as a WAL file source</link>.
|
||||
@@ -127,7 +124,7 @@
|
||||
filesystem layouts.
|
||||
</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.
|
||||
</para>
|
||||
</sect2>
|
||||
@@ -170,7 +167,7 @@
|
||||
<para>
|
||||
If different "minor" &repmgr; versions (e.g. 4.1.1 and 4.1.6) are installed,
|
||||
&repmgr; will function, but we strongly recommend always running the same version
|
||||
to ensure there are no unexpected 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.
|
||||
</para>
|
||||
<para>
|
||||
@@ -212,11 +209,11 @@
|
||||
</para>
|
||||
</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>
|
||||
<para>
|
||||
&repmgr; packages provided by EnterpriseDB are compatible with the community-provided PostgreSQL
|
||||
packages and specified software provided by EnterpriseDB.
|
||||
&repmgr; packages provided by 2ndQuadrant are compatible with the community-provided PostgreSQL
|
||||
packages and any software provided by 2ndQuadrant.
|
||||
</para>
|
||||
<para>
|
||||
A number of other vendors provide their own versions of PostgreSQL packages, often with different
|
||||
@@ -249,16 +246,16 @@
|
||||
For a standby which has been manually cloned or recovered from an external
|
||||
backup manager such as Barman, the command
|
||||
<command><link linkend="repmgr-standby-clone">repmgr standby clone --replication-conf-only</link></command>
|
||||
can be used to create the correct replication configuration file for
|
||||
can be used to create the correct <filename>recovery.conf</filename> file for
|
||||
use with &repmgr; (and will create a replication slot if required). Once this has been done,
|
||||
<link linkend="repmgr-standby-register">register the node</link> as usual.
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="faq-repmgr-recovery-conf" >
|
||||
<title>What does &repmgr; write in the replication configuration, and what options can be set there?</title>
|
||||
<title>What does &repmgr; write in <filename>recovery.conf</filename>, and what options can be set there?</title>
|
||||
<para>
|
||||
See section <link linkend="repmgr-standby-clone-recovery-conf">Customising replication configuration</link>.
|
||||
See section <link linkend="repmgr-standby-clone-recovery-conf">Customising recovery.conf</link>.
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
@@ -311,7 +308,7 @@
|
||||
</para>
|
||||
</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>
|
||||
in <filename>postgresql.conf</filename> if I'm not using &repmgrd;?</title>
|
||||
<para>
|
||||
@@ -350,9 +347,6 @@
|
||||
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"/>.
|
||||
</para>
|
||||
<para>
|
||||
In &repmgr; 5.2 and later, this setting will also be honoured when cloning from Barman.
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="faq-repmgr-events-no-fkey" xreflabel="No foreign key on node_id in repmgr.events">
|
||||
@@ -366,11 +360,11 @@
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="faq-repmgr-recovery-conf-quoted-values" xreflabel="Quoted values in replication.conf">
|
||||
<title>Why are some values in <filename>recovery.conf</filename> (PostgreSQL 11 and earlier) surrounded by pairs of single quotes?</title>
|
||||
<sect2 id="faq-repmgr-recovery-conf-quoted-values" xreflabel="Quoted values in recovery.conf">
|
||||
<title>Why are some values in <filename>recovery.conf</filename> surrounded by pairs of single quotes?</title>
|
||||
<para>
|
||||
This is to ensure that user-supplied values which are written as parameter values in <filename>recovery.conf</filename>
|
||||
are escaped correctly and do not cause errors when the file is parsed.
|
||||
are escaped correctly and do not cause errors when <filename>recovery.conf</filename> is parsed.
|
||||
</para>
|
||||
<para>
|
||||
The escaping is performed by an internal PostgreSQL routine, which leaves strings consisting
|
||||
@@ -379,22 +373,6 @@
|
||||
</para>
|
||||
</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>
|
||||
|
||||
@@ -419,9 +397,9 @@
|
||||
<para>
|
||||
&repmgrd; can monitor delayed standbys - those set up with
|
||||
<varname>recovery_min_apply_delay</varname> set to a non-zero value
|
||||
in the replication configuration. However &repmgrd; does not currently
|
||||
consider this setting, and therefore may not be able to properly evaluate
|
||||
the node as a promotion candidate.
|
||||
in <filename>recovery.conf</filename> - but as it's not currently possible
|
||||
to directly examine the value applied to the standby, &repmgrd;
|
||||
may not be able to properly evaluate the node as a promotion candidate.
|
||||
</para>
|
||||
<para>
|
||||
We recommend that delayed standbys are explicitly excluded from promotion
|
||||
@@ -459,7 +437,7 @@
|
||||
</title>
|
||||
<para>
|
||||
<varname>promote_command</varname> or <varname>follow_command</varname> can be user-defined scripts,
|
||||
so &repmgr; will not apply <option>pg_bindir</option> even if 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.
|
||||
</para>
|
||||
</sect2>
|
||||
@@ -479,7 +457,7 @@
|
||||
is out-of-date, which may lead to incorrect failover behaviour.
|
||||
</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;.
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
@@ -50,18 +50,19 @@
|
||||
<title>CentOS repositories</title>
|
||||
|
||||
<para>
|
||||
&repmgr; packages are available from the public EDB repository, and also the
|
||||
PostgreSQL community repository. The EDB repository is updated immediately
|
||||
after each &repmgr; release.
|
||||
&repmgr; packages are available from the public 2ndQuadrant repository, and also the
|
||||
PostgreSQL community repository. The 2ndQuadrant repository is updated immediately
|
||||
after each
|
||||
&repmgr; release.
|
||||
</para>
|
||||
|
||||
<table id="centos-2ndquadrant-repository">
|
||||
<title>EDB public repository</title>
|
||||
<title>2ndQuadrant public repository</title>
|
||||
<tgroup cols="2">
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>Repository URL:</entry>
|
||||
<entry><ulink url="https://dl.enterprisedb.com/">https://dl.enterprisedb.com/</ulink></entry>
|
||||
<entry><ulink url="https://dl.2ndquadrant.com/">https://dl.2ndquadrant.com/</ulink></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>Repository documentation:</entry>
|
||||
@@ -252,7 +253,7 @@
|
||||
</indexterm>
|
||||
|
||||
<para>
|
||||
&repmgr; <literal>.deb</literal> packages are provided by EDB as well as the
|
||||
&repmgr; <literal>.deb</literal> packages are provided by 2ndQuadrant as well as the
|
||||
PostgreSQL Community APT repository, and are available for each community-supported
|
||||
PostgreSQL version, currently supported Debian releases, and currently supported
|
||||
Ubuntu LTS releases.
|
||||
@@ -262,12 +263,12 @@
|
||||
<title>APT repositories</title>
|
||||
|
||||
<table id="apt-2ndquadrant-repository">
|
||||
<title>EDB public repository</title>
|
||||
<title>2ndQuadrant public repository</title>
|
||||
<tgroup cols="2">
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>Repository URL:</entry>
|
||||
<entry><ulink url="https://dl.enterprisedb.com/">https://dl.enterprisedb.com/</ulink></entry>
|
||||
<entry><ulink url="https://dl.2ndquadrant.com/">https://dl.2ndquadrant.com/</ulink></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>Repository documentation:</entry>
|
||||
@@ -397,11 +398,11 @@
|
||||
</indexterm>
|
||||
<indexterm>
|
||||
<primary>packages</primary>
|
||||
<secondary>snapshots</secondary>
|
||||
<secondary>snaphots</secondary>
|
||||
</indexterm>
|
||||
|
||||
<para>
|
||||
For testing new features and bug fixes, from time to time EDB provides
|
||||
For testing new features and bug fixes, from time to time 2ndQuadrant provides
|
||||
so-called "snapshot packages" via its public repository. These packages
|
||||
are built from the &repmgr; source at a particular point in time, and are not formal
|
||||
releases.
|
||||
@@ -413,22 +414,22 @@
|
||||
</para>
|
||||
</note>
|
||||
<para>
|
||||
To install a snapshot package, it's necessary to install the EDB public snapshot repository,
|
||||
following the instructions here: <ulink url="https://dl.enterprisedb.com/default/release/site/">https://dl.enterprisedb.com/default/release/site/</ulink> but replace <literal>release</literal> with <literal>snapshot</literal>
|
||||
To install a snapshot package, it's necessary to install the 2ndQuadrant public snapshot repository,
|
||||
following the instructions here: <ulink url="https://dl.2ndquadrant.com/default/release/site/">https://dl.2ndquadrant.com/default/release/site/</ulink> but replace <literal>release</literal> with <literal>snapshot</literal>
|
||||
in the appropriate URL.
|
||||
</para>
|
||||
<para>
|
||||
For example, to install the snapshot RPM repository for PostgreSQL 9.6, execute (as <literal>root</literal>):
|
||||
<programlisting>
|
||||
curl https://dl.enterprisedb.com/default/snapshot/get/9.6/rpm | bash</programlisting>
|
||||
curl https://dl.2ndquadrant.com/default/snapshot/get/9.6/rpm | bash</programlisting>
|
||||
|
||||
or as a normal user with root sudo access:
|
||||
<programlisting>
|
||||
curl https://dl.enterprisedb.com/default/snapshot/get/9.6/rpm | sudo bash</programlisting>
|
||||
curl https://dl.2ndquadrant.com/default/snapshot/get/9.6/rpm | sudo bash</programlisting>
|
||||
</para>
|
||||
<para>
|
||||
Alternatively you can browse the repository here:
|
||||
<ulink url="https://dl.enterprisedb.com/default/snapshot/browse/">https://dl.enterprisedb.com/default/snapshot/browse/</ulink>.
|
||||
<ulink url="https://dl.2ndquadrant.com/default/snapshot/browse/">https://dl.2ndquadrant.com/default/snapshot/browse/</ulink>.
|
||||
</para>
|
||||
<para>
|
||||
Once the repository is installed, installing or updating &repmgr; will result in the latest snapshot
|
||||
@@ -438,7 +439,7 @@ curl https://dl.enterprisedb.com/default/snapshot/get/9.6/rpm | sudo bash</progr
|
||||
The package name will be formatted like this:
|
||||
<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>).
|
||||
</para>
|
||||
|
||||
@@ -470,7 +471,7 @@ repmgr96-4.1.1-0.0git320.g5113ab0.1.el7.x86_64.rpm</programlisting>
|
||||
<title>Debian/Ubuntu</title>
|
||||
<para>
|
||||
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>
|
||||
</sect2>
|
||||
|
||||
@@ -493,6 +494,32 @@ repmgr96-4.1.1-0.0git320.g5113ab0.1.el7.x86_64.rpm</programlisting>
|
||||
yum install repmgr96-4.0.6-1.rhel6</programlisting>
|
||||
</para>
|
||||
|
||||
<sect3 id="packages-old-versions-rhel-centos-repmgr3">
|
||||
<title>repmgr 3 packages</title>
|
||||
<para>
|
||||
Old &repmgr; 3 RPM packages (<literal>3.2</literal> and later) can be retrieved from the
|
||||
(deprecated) 2ndQuadrant repository at
|
||||
<ulink url="http://packages.2ndquadrant.com/repmgr/yum/">http://packages.2ndquadrant.com/repmgr/yum/</ulink>
|
||||
by installing the appropriate repository RPM:
|
||||
</para>
|
||||
|
||||
<itemizedlist spacing="compact" mark="bullet">
|
||||
|
||||
<listitem>
|
||||
<simpara>
|
||||
<ulink url="http://packages.2ndquadrant.com/repmgr/yum-repo-rpms/repmgr-fedora-1.0-1.noarch.rpm">http://packages.2ndquadrant.com/repmgr/yum-repo-rpms/repmgr-fedora-1.0-1.noarch.rpm</ulink>
|
||||
</simpara>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<simpara>
|
||||
<ulink url="http://packages.2ndquadrant.com/repmgr/yum-repo-rpms/repmgr-rhel-1.0-1.noarch.rpm">http://packages.2ndquadrant.com/repmgr/yum-repo-rpms/repmgr-rhel-1.0-1.noarch.rpm</ulink>
|
||||
</simpara>
|
||||
</listitem>
|
||||
|
||||
</itemizedlist>
|
||||
</sect3>
|
||||
|
||||
</sect2>
|
||||
</sect1>
|
||||
|
||||
|
||||
@@ -15,578 +15,9 @@
|
||||
See also: <xref linkend="upgrading-repmgr"/>
|
||||
</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.5.0">
|
||||
<title>Release 5.5.0</title>
|
||||
<para><emphasis>Wed 20 November, 2024</emphasis></para>
|
||||
<para>
|
||||
&repmgr; 5.5.0 is a major release.
|
||||
</para>
|
||||
<para>
|
||||
This release adds support for PostgreSQL 17
|
||||
</para>
|
||||
<para>
|
||||
Fixes warnings detected by the -Wshadow gcc flag added in PostgreSQL 16.
|
||||
</para>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="release-5.4.1">
|
||||
<title id="release-current">Release 5.4.1</title>
|
||||
<para><emphasis>Tue 04 Jul, 2023</emphasis></para>
|
||||
<para>
|
||||
&repmgr; 5.4.1 is a minor release providing ...
|
||||
</para>
|
||||
<sect2>
|
||||
<title>Bug fixes</title>
|
||||
<para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
&repmgrd;: ensure witness node metadata is updated if the primary
|
||||
node changed while the witness &repmgrd; was not running.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
</sect2>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="release-5.4.0">
|
||||
<title>Release 5.4.0</title>
|
||||
<para><emphasis>Thu 15 March, 2023</emphasis></para>
|
||||
<para>
|
||||
&repmgr; 5.4.0 is a major release.
|
||||
</para>
|
||||
<para>
|
||||
This release provides support for cloning standbys using backups taken with <ulink url="http://www.pgbarman.org">barman</ulink>
|
||||
with the use of <ulink url="https://github.com/EnterpriseDB/pg-backup-api">pg-backup-api</ulink>.
|
||||
</para>
|
||||
<para>
|
||||
Minor fixes to the documentation.
|
||||
</para>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="release-5.3.3">
|
||||
<title>Release 5.3.3</title>
|
||||
<para><emphasis>Mon 17 October, 2022</emphasis></para>
|
||||
<para>
|
||||
&repmgr; 5.3.3 is a minor release providing support for
|
||||
<ulink url="https://www.postgresql.org/docs/15/release-15.html">PostgreSQL 15</ulink>
|
||||
and a &repmgrd; bug fix.
|
||||
</para>
|
||||
<para>
|
||||
If upgrading from an earlier &repmgr; version, any running &repmgrd; instances should be restarted.
|
||||
</para>
|
||||
<para>
|
||||
If upgrading from &repmgr; 5.2.1 or earlier, a PostgreSQL restart <emphasis>is</emphasis> required.
|
||||
</para>
|
||||
|
||||
<sect2>
|
||||
<title>Bug fixes</title>
|
||||
<para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
&repmgrd;: ensure <link linkend="event-notifications">event notification</link> script is called for event
|
||||
<literal>repmgrd_upstream_disconnect</literal>. GitHub #760.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
</sect2>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="release-5.3.2">
|
||||
<title>Release 5.3.2</title>
|
||||
<para><emphasis>Wed 25 May, 2022</emphasis></para>
|
||||
<para>
|
||||
&repmgr; 5.3.2 is a minor release.
|
||||
</para>
|
||||
<para>
|
||||
Any running &repmgrd; instances should be restarted following this upgrade.
|
||||
</para>
|
||||
<para>
|
||||
If upgrading from &repmgr; 5.2.1 or earlier, a PostgreSQL restart <emphasis>is</emphasis> required.
|
||||
</para>
|
||||
|
||||
<sect2>
|
||||
<title>Bug fixes</title>
|
||||
<para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
<command><link linkend="repmgr-node-status">repmgr node status</link></command>:
|
||||
fix output with <option>--downstream</option> <option>--nagios</option> option combination.
|
||||
GitHub #749.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<command><link linkend="repmgr-standby-clone">repmgr standby clone</link></command>:
|
||||
don't treat inability to determine the cluster size as a fatal error.
|
||||
</para>
|
||||
<para>
|
||||
The cluster size is displayed for informational purposes and is not essential
|
||||
for execution of the clone operation. As the &repmgr; user may not have permissions
|
||||
for all databases in the cluster, ignore the cluster size query if it fails.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
&repmgrd;: ensure the witness node record on the primary is always marked
|
||||
as <literal>active</literal> if previously marked <literal>inactive</literal>.
|
||||
GitHub #754.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
&repmgrd;: if <varname>standby_disconnect_on_failover</varname> is set, verify
|
||||
&repmgr; is a superuser before attempting to disable the WAL receiver.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
If the &repmgr; user is a non-superuser, and a replication-only user exists,
|
||||
ensure redundant replication slots are dropped correctly even
|
||||
if the <option>-S/--superuser</option> option is not provided.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
</sect2>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="release-5.3.1">
|
||||
<title>Release 5.3.1</title>
|
||||
<para><emphasis>Tue 15 February, 2022</emphasis></para>
|
||||
<para>
|
||||
&repmgr; 5.3.1 is a minor release.
|
||||
</para>
|
||||
<para>
|
||||
If &repmgrd; is in use, it should be restarted on all nodes where it is running.
|
||||
</para>
|
||||
<para>
|
||||
If upgrading from &repmgr; 5.2.1 or earlier, a PostgreSQL restart <emphasis>is</emphasis> required.
|
||||
</para>
|
||||
<sect2>
|
||||
<title>Bug fixes</title>
|
||||
<para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
Fix upgrade path from &repmgr; 4.2 and 4.3 to &repmgr; 5.3.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
&repmgrd;: ensure potentially open connections are closed.
|
||||
</para>
|
||||
<para>
|
||||
In some cases, when recovering from degraded state in local node monitoring,
|
||||
new connection was opened to the local node without closing
|
||||
the old one, which will result in memory leakage.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
</sect2>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="release-5.3.0">
|
||||
<title>Release 5.3.0</title>
|
||||
<para><emphasis>Tue 12 October, 2021</emphasis></para>
|
||||
<para>
|
||||
&repmgr; 5.3.0 is a major release.
|
||||
</para>
|
||||
<para>
|
||||
This release provides support for <ulink url="https://www.postgresql.org/docs/14/release-14.html">PostgreSQL 14</ulink>,
|
||||
released in September 2021.
|
||||
</para>
|
||||
<para>
|
||||
Note that this release includes changes to the &repmgr; shared library module, meaning a
|
||||
PostgreSQL restart <emphasis>is</emphasis> required on all nodes where &repmgr; is installed.
|
||||
</para>
|
||||
|
||||
<sect2>
|
||||
<title>Improvements</title>
|
||||
<para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
<link linkend="repmgr-standby-switchover"><command>repmgr standby switchover</command></link>:
|
||||
Improve handling of node rejoin failure on the demotion candidate.
|
||||
</para>
|
||||
<para>
|
||||
Previously &repmgr; did not check whether <command>repmgr node rejoin</command> actually
|
||||
succeeded on the demotion candidate, and would always wait up to <varname>node_rejoin_timeout</varname>
|
||||
seconds for it to attach to the promotion candidate, even if this would never happen.
|
||||
</para>
|
||||
<para>
|
||||
This makes it easier to identify unexpected events during a switchover operation, such as
|
||||
the demotion candidate being unexpectedly restarted by an external process.
|
||||
</para>
|
||||
<para>
|
||||
Note that the output of the <link linkend="repmgr-node-rejoin"><command>repmgr node rejoin</command></link>
|
||||
operation on the demotion candidate will now be logged to a temporary file on that node;
|
||||
the location of the file will be reported in the error message, if one is emitted.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
&repmgrd;: at startup, if node record is marked as "inactive", attempt
|
||||
to set it to "active".
|
||||
</para>
|
||||
<para>
|
||||
This behaviour can be overridden by setting the configuration parameter
|
||||
<varname>repmgrd_exit_on_inactive_node</varname> to <literal>true</literal>.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<command><link linkend="repmgr-node-rejoin">repmgr node rejoin</link></command>:
|
||||
emit rejoin target note information as <literal>NOTICE</literal>.
|
||||
</para>
|
||||
<para>
|
||||
This makes it clearer what &repmgr; is trying to do.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
<link linkend="repmgr-node-check">repmgr node check</link>:
|
||||
option <option>--repmgrd</option> added to check &repmgrd;
|
||||
status.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
Add <literal>%p</literal> <link linkend="event-notifications">event notification parameter</link>
|
||||
providing the node ID of the former primary for the <literal>repmgrd_failover_promote</literal> event.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
</itemizedlist>
|
||||
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
<sect2>
|
||||
<title>Bug fixes</title>
|
||||
<para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
<command><link linkend="repmgr-standby-clone">repmgr standby clone</link></command>:
|
||||
if using <option>--replication-conf-only</option> on a node
|
||||
which was set up without replication slots, but the &repmgr; configuration
|
||||
was since changed to <option>use_replication_slots=1</option>,
|
||||
&repmgr; will now set <varname>slot_name</varname> in the
|
||||
node record, if it was previously empty.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
&repmgrd;: rename internal shared library functions to minimize the
|
||||
risk of clashes with other shared libraries.
|
||||
</para>
|
||||
<para>
|
||||
This does not affect user-facing SQL functions. Howe
|
||||
</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">
|
||||
<sect1 id="release-5.1-0">
|
||||
<title>Release 5.1.0</title>
|
||||
<para><emphasis>Mon 13 April, 2020</emphasis></para>
|
||||
|
||||
@@ -780,7 +211,7 @@
|
||||
</sect1>
|
||||
|
||||
<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>
|
||||
@@ -1490,7 +921,7 @@ REPMGRD_OPTS="--daemonize=false"</programlisting>
|
||||
</para>
|
||||
<para>
|
||||
Possible values are <literal>ping</literal> (default; uses <command>PQping()</command> to
|
||||
determine server availability), <literal>connection</literal> (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
|
||||
by executing an SQL statement on the node via the existing connection).
|
||||
</para>
|
||||
|
||||
@@ -7,20 +7,20 @@
|
||||
</indexterm>
|
||||
|
||||
<para>
|
||||
<ulink url="https://www.enterprisedb.com/">EDB</ulink> provides 24x7
|
||||
<ulink url="https://2ndquadrant.com/">2ndQuadrant</ulink> provides 24x7
|
||||
production support for &repmgr; and other PostgreSQL
|
||||
products, including configuration assistance, installation
|
||||
verification and training for running a robust replication cluster.
|
||||
</para>
|
||||
<para>
|
||||
For further details see: <ulink url="https://www.enterprisedb.com/support/postgresql-support-overview-get-the-most-out-of-postgresql">Support Center</ulink>
|
||||
For further details see: <ulink url="https://2ndquadrant.com/en/support/">https://2ndquadrant.com/en/support/</ulink>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
A mailing list/forum is provided via Google groups to discuss contributions or issues: <ulink url="https://groups.google.com/group/repmgr">https://groups.google.com/group/repmgr</ulink>.
|
||||
</para>
|
||||
<para>
|
||||
Please report bugs and other issues to: <ulink url="https://github.com/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>
|
||||
|
||||
<important>
|
||||
@@ -64,7 +64,7 @@
|
||||
|
||||
<listitem>
|
||||
<simpara>
|
||||
<filename>repmgr.conf</filename> files (suitably anonymized if necessary)
|
||||
<filename>repmpgr.conf</filename> files (suitably anonymized if necessary)
|
||||
</simpara>
|
||||
</listitem>
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
<para>
|
||||
<xref linkend="repmgr-standby-clone"/> can use
|
||||
<ulink url="https://www.enterprisedb.com/">EDB</ulink>'s
|
||||
<ulink url="https://www.2ndquadrant.com/">2ndQuadrant</ulink>'s
|
||||
<ulink url="https://www.pgbarman.org/">Barman</ulink> application
|
||||
to clone a standby (and also as a fallback source for WAL files).
|
||||
</para>
|
||||
@@ -46,7 +46,6 @@
|
||||
<para>
|
||||
WAL management on the primary becomes much easier as there's no need
|
||||
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.
|
||||
</para>
|
||||
</listitem>
|
||||
@@ -148,15 +147,6 @@ description = "Main cluster"
|
||||
section in <command>man 5 ssh_config</command> for more details.
|
||||
</simpara>
|
||||
</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>
|
||||
It's now possible to clone a standby from Barman, e.g.:
|
||||
<programlisting>
|
||||
@@ -197,7 +187,7 @@ description = "Main cluster"
|
||||
<para>
|
||||
As a fallback in case streaming replication is interrupted, PostgreSQL can optionally
|
||||
retrieve WAL files from an archive, such as that provided by Barman. This is done by
|
||||
setting <varname>restore_command</varname> in the replication configuration to
|
||||
setting <varname>restore_command</varname> in <filename>recovery.conf</filename> to
|
||||
a valid shell command which can retrieve a specified WAL file from the archive.
|
||||
</para>
|
||||
<para>
|
||||
@@ -225,109 +215,6 @@ description = "Main cluster"
|
||||
</note>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="cloning-from-barman-pg_backupapi-mode" xreflabel="Using Barman through its API (pg-backup-api)">
|
||||
<title>Using Barman through its API (pg-backup-api)</title>
|
||||
<indexterm>
|
||||
<primary>cloning</primary>
|
||||
<secondary>pg-backup-api</secondary>
|
||||
</indexterm>
|
||||
|
||||
<para>
|
||||
You can find information on how to install and setup pg-backup-api in
|
||||
<ulink url="https://www.enterprisedb.com/docs/supported-open-source/barman/pg-backup-api/">the pg-backup-api
|
||||
documentation</ulink>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
This mode (`pg-backupapi`) was introduced in v5.4.0 as a way to further integrate with Barman letting Barman
|
||||
handle the restore. This also reduces the ssh keys that need to share between the backup and postgres nodes.
|
||||
As long as you have access to the API service by HTTP calls, you could perform recoveries right away.
|
||||
You just need to instruct Barman through the API which backup you need and on which node the backup needs to
|
||||
to be restored on.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
In order to enable <literal>pg_backupapi mode</literal> support for <command>repmgr standby clone</command>,
|
||||
you need the following lines in repmgr.conf:
|
||||
<itemizedlist spacing="compact" mark="bullet">
|
||||
<listitem><para>pg_backupapi_host: Where pg-backup-api is hosted</para></listitem>
|
||||
<listitem><para>pg_backupapi_node_name: Name of the server as understood by Barman</para></listitem>
|
||||
<listitem><para>pg_backupapi_remote_ssh_command: How Barman will be connecting as to the node</para></listitem>
|
||||
<listitem><para>pg_backupapi_backup_id: ID of the existing backup you need to restore</para></listitem>
|
||||
</itemizedlist>
|
||||
|
||||
This is an example of how repmgr.conf would look like:
|
||||
|
||||
<programlisting>
|
||||
pg_backupapi_host = '192.168.122.154'
|
||||
pg_backupapi_node_name = 'burrito'
|
||||
pg_backupapi_remote_ssh_command = 'ssh john_doe@192.168.122.1'
|
||||
pg_backupapi_backup_id = '20230223T093201'
|
||||
</programlisting>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<literal>pg_backupapi_host</literal> is the variable name that enables this mode, and when you set it,
|
||||
all the rest of the above variables are required. Also, remember that this service is just an interface
|
||||
between Barman and repmgr, hence if something fails during a recovery, you should check Barman's logs upon
|
||||
why the process couldn't finish properly.
|
||||
</para>
|
||||
|
||||
<note>
|
||||
<simpara>
|
||||
Despite in Barman you can define shortcuts like "lastest" or "oldest", they are not supported for the
|
||||
time being in pg-backup-api. These shortcuts will be supported in a future release.
|
||||
</simpara>
|
||||
</note>
|
||||
|
||||
<para>
|
||||
This is a real example of repmgr's output cloning with the API. Note that during this operation, we stopped
|
||||
the service for a little while and repmgr had to retry but that doesn't affect the final outcome. The primary
|
||||
is listening on localhost's port 6001:
|
||||
|
||||
<programlisting>
|
||||
$ repmgr -f ~/nodes/node_3/repmgr.conf standby clone -U repmgr -p 6001 -h localhost
|
||||
NOTICE: destination directory "/home/mario/nodes/node_3/data" provided
|
||||
INFO: Attempting to use `pg_backupapi` new restore mode
|
||||
INFO: connecting to source node
|
||||
DETAIL: connection string is: user=repmgr port=6001 host=localhost
|
||||
DETAIL: current installation size is 8541 MB
|
||||
DEBUG: 1 node records returned by source node
|
||||
DEBUG: connecting to: "user=repmgr dbname=repmgr host=localhost port=6001 connect_timeout=2 fallback_application_name=repmgr options=-csearch_path="
|
||||
DEBUG: upstream_node_id determined as 1
|
||||
INFO: Attempting to use `pg_backupapi` new restore mode
|
||||
INFO: replication slot usage not requested; no replication slot will be set up for this standby
|
||||
NOTICE: starting backup (using pg_backupapi)...
|
||||
INFO: Success creating the task: operation id '20230309T150647'
|
||||
INFO: status IN_PROGRESS
|
||||
INFO: status IN_PROGRESS
|
||||
Incorrect reply received for that operation ID.
|
||||
INFO: Retrying...
|
||||
INFO: status IN_PROGRESS
|
||||
INFO: status IN_PROGRESS
|
||||
INFO: status IN_PROGRESS
|
||||
INFO: status IN_PROGRESS
|
||||
INFO: status IN_PROGRESS
|
||||
INFO: status IN_PROGRESS
|
||||
INFO: status IN_PROGRESS
|
||||
INFO: status IN_PROGRESS
|
||||
INFO: status IN_PROGRESS
|
||||
INFO: status IN_PROGRESS
|
||||
INFO: status IN_PROGRESS
|
||||
INFO: status IN_PROGRESS
|
||||
INFO: status IN_PROGRESS
|
||||
INFO: status IN_PROGRESS
|
||||
INFO: status IN_PROGRESS
|
||||
INFO: status DONE
|
||||
NOTICE: standby clone (from pg_backupapi) complete
|
||||
NOTICE: you can now start your PostgreSQL server
|
||||
HINT: for example: pg_ctl -D /home/mario/nodes/node_3/data start
|
||||
HINT: after starting the server, you need to register this standby with "repmgr standby register"
|
||||
</programlisting>
|
||||
|
||||
</para>
|
||||
</sect2> <!--END cloning-from-barman-pg_backupapi-mode !-->
|
||||
</sect1>
|
||||
|
||||
<sect1 id="cloning-replication-slots" xreflabel="Cloning and replication slots">
|
||||
@@ -347,8 +234,7 @@ HINT: after starting the server, you need to register this standby with "repmgr
|
||||
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
|
||||
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>
|
||||
(PostgreSQL 13 and later: <varname>wal_keep_size</varname>).
|
||||
be maintained on the primary using <varname>wal_keep_segments</varname>.
|
||||
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
|
||||
slot is dropped.
|
||||
@@ -402,7 +288,7 @@ HINT: after starting the server, you need to register this standby with "repmgr
|
||||
build up indefinitely, possibly leading to server failure.
|
||||
</simpara>
|
||||
<simpara>
|
||||
As an alternative we recommend using EDB's <ulink url="https://www.pgbarman.org/">Barman</ulink>,
|
||||
As an alternative we recommend using 2ndQuadrant's <ulink url="https://www.pgbarman.org/">Barman</ulink>,
|
||||
which offloads WAL management to a separate server, removing the requirement to use a replication
|
||||
slot for each individual standby to reserve WAL. See section <xref linkend="cloning-from-barman"/>
|
||||
for more details on using &repmgr; together with Barman.
|
||||
@@ -422,7 +308,7 @@ HINT: after starting the server, you need to register this standby with "repmgr
|
||||
Cascading replication, introduced with PostgreSQL 9.2, enables a standby server
|
||||
to replicate from another standby server rather than directly from the primary,
|
||||
meaning replication changes "cascade" down through a hierarchy of servers. This
|
||||
can be used to reduce load on the primary and minimize bandwidth usage between
|
||||
can be used to reduce load on the primary and minimize bandwith usage between
|
||||
sites. For more details, see the
|
||||
<ulink url="https://www.postgresql.org/docs/current/warm-standby.html#CASCADING-REPLICATION">
|
||||
PostgreSQL cascading replication documentation</ulink>.
|
||||
@@ -431,9 +317,9 @@ HINT: after starting the server, you need to register this standby with "repmgr
|
||||
&repmgr; supports cascading replication. When cloning a standby,
|
||||
set the command-line parameter <literal>--upstream-node-id</literal> to the
|
||||
<varname>node_id</varname> of the server the standby should connect to, and
|
||||
&repmgr; will create a replication configuration file to point to it. Note
|
||||
&repmgr; will create <filename>recovery.conf</filename> to point to it. Note
|
||||
that if <literal>--upstream-node-id</literal> is not explicitly provided,
|
||||
&repmgr; will set the standby's replication configuration to
|
||||
&repmgr; will set the standby's <filename>recovery.conf</filename> to
|
||||
point to the primary node.
|
||||
</para>
|
||||
<para>
|
||||
@@ -494,8 +380,8 @@ HINT: after starting the server, you need to register this standby with "repmgr
|
||||
cluster, you may wish to clone a downstream standby whose upstream node
|
||||
does not yet exist. In this case you can clone from the primary (or
|
||||
another upstream node); provide the parameter <literal>--upstream-conninfo</literal>
|
||||
to explicitly set the upstream's <varname>primary_conninfo</varname> string
|
||||
in the replication configuration.
|
||||
to explictly set the upstream's <varname>primary_conninfo</varname> string
|
||||
in <filename>recovery.conf</filename>.
|
||||
</simpara>
|
||||
</tip>
|
||||
</sect1>
|
||||
@@ -552,13 +438,6 @@ HINT: after starting the server, you need to register this standby with "repmgr
|
||||
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.
|
||||
</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>
|
||||
See the <ulink url="https://www.postgresql.org/docs/current/app-pgbasebackup.html">PostgreSQL pg_basebackup documentation</ulink>
|
||||
for more details of available options.
|
||||
@@ -594,12 +473,12 @@ HINT: after starting the server, you need to register this standby with "repmgr
|
||||
</note>
|
||||
|
||||
<para>
|
||||
If, for whatever reason, you wish to include the password in the replication configuration file,
|
||||
If, for whatever reason, you wish to include the password in <filename>recovery.conf</filename>,
|
||||
set <varname>use_primary_conninfo_password</varname> to <literal>true</literal> in
|
||||
<filename>repmgr.conf</filename>. This will read a password set in <varname>PGPASSWORD</varname>
|
||||
(but not <filename>~/.pgpass</filename>) and place it into the <varname>primary_conninfo</varname>
|
||||
string in the replication configuration. Note that <varname>PGPASSWORD</varname>
|
||||
will need to be set during any action which causes the replication configuration file to be
|
||||
string in <filename>recovery.conf</filename>. Note that <varname>PGPASSWORD</varname>
|
||||
will need to be set during any action which causes <filename>recovery.conf</filename> to be
|
||||
rewritten, e.g. <xref linkend="repmgr-standby-follow"/>.
|
||||
</para>
|
||||
</sect2>
|
||||
@@ -611,7 +490,7 @@ HINT: after starting the server, you need to register this standby with "repmgr
|
||||
user (in addition to the user who manages the &repmgr; metadata). In this case,
|
||||
the replication user should be set in <filename>repmgr.conf</filename> via the parameter
|
||||
<varname>replication_user</varname>; &repmgr; will use this value when making
|
||||
replication connections and generating the replication configuration. This
|
||||
replication connections and generating <filename>recovery.conf</filename>. This
|
||||
value will also be stored in the parameter <literal>repmgr.nodes</literal>
|
||||
table for each node; it no longer needs to be explicitly specified when
|
||||
cloning a node or executing <xref linkend="repmgr-standby-follow"/>.
|
||||
|
||||
@@ -7,14 +7,6 @@
|
||||
<secondary>optional settings</secondary>
|
||||
</indexterm>
|
||||
|
||||
<note>
|
||||
<simpara>
|
||||
This section documents a subset of optional configuration settings; for a full
|
||||
and annotated view of all configuration options see the
|
||||
<ulink url="https://raw.githubusercontent.com/EnterpriseDB/repmgr/master/repmgr.conf.sample">sample repmgr.conf file</ulink>
|
||||
</simpara>
|
||||
</note>
|
||||
|
||||
<variablelist>
|
||||
|
||||
|
||||
@@ -140,50 +132,5 @@ ssh_options='-q -o ConnectTimeout=10'</programlisting>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry id="repmgr-conf-pg-bindir" xreflabel="pg_bindir">
|
||||
<term><varname>pg_bindir</varname> (<type>string</type>)
|
||||
<indexterm>
|
||||
<primary><varname>pg_bindir</varname> configuration file parameter</primary>
|
||||
</indexterm>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Path to the PostgreSQL binary directory (location of <application>pg_ctl</application>,
|
||||
<application>pg_basebackup</application> etc.). Only required
|
||||
if these are not in the system <varname>PATH</varname>.
|
||||
</para>
|
||||
<tip>
|
||||
<para>
|
||||
When &repmgr; is executed via <application>SSH</application> (e.g. when running
|
||||
<command><link linkend="repmgr-standby-switchover">repmgr standby switchover</link></command>,
|
||||
<command><link linkend="repmgr-cluster-matrix">repmgr cluster matrix</link></command> or
|
||||
<command><link linkend="repmgr-cluster-crosscheck">repmgr cluster crosscheck</link></command>,
|
||||
or if it is executed as cronjob), a login shell will not be used and only the
|
||||
default system <varname>PATH</varname> will be set. Therefore it's recommended to set
|
||||
<varname>pg_bindir</varname> so &repmgr; can correctly invoke binaries on a remote
|
||||
system and avoid potential path issues.
|
||||
</para>
|
||||
</tip>
|
||||
|
||||
<para>
|
||||
Debian/Ubuntu users: you will probably need to set this to the directory where
|
||||
<application>pg_ctl</application> is located, e.g. <filename>/usr/lib/postgresql/9.6/bin/</filename>.
|
||||
</para>
|
||||
<para>
|
||||
<emphasis>NOTE</emphasis>: <varname>pg_bindir</varname> is only used when &repmgr; directly
|
||||
executes PostgreSQL binaries; any user-defined scripts
|
||||
<emphasis>must</emphasis> be specified with the full path.
|
||||
</para>
|
||||
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
|
||||
<tip>
|
||||
<simpara>
|
||||
See the <ulink url="https://raw.githubusercontent.com/EnterpriseDB/repmgr/master/repmgr.conf.sample">sample repmgr.conf file</ulink>
|
||||
for a full and annotated view of all configuration options.
|
||||
</simpara>
|
||||
</tip>
|
||||
|
||||
</sect1>
|
||||
|
||||
@@ -96,9 +96,6 @@
|
||||
</variablelist>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
See <xref linkend="configuration-file-optional-settings"/> for further configuration options.
|
||||
</para>
|
||||
|
||||
|
||||
</sect1>
|
||||
|
||||
@@ -27,9 +27,7 @@
|
||||
<note>
|
||||
<para>
|
||||
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
|
||||
<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>
|
||||
See the <ulink url="https://wiki.postgresql.org/wiki/Systemd">systemd</ulink>
|
||||
entry in the <ulink url="https://wiki.postgresql.org/wiki/Main_Page">PostgreSQL wiki</ulink> for details.
|
||||
</para>
|
||||
</note>
|
||||
|
||||
@@ -80,51 +80,6 @@ conninfo='host=node1 user=repmgr dbname=repmgr connect_timeout=2'</programlistin
|
||||
</para>
|
||||
</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>
|
||||
|
||||
|
||||
@@ -164,7 +119,7 @@ conninfo='host=node1 user=repmgr dbname=repmgr connect_timeout=2'</programlistin
|
||||
</para>
|
||||
<para>
|
||||
For a full list of annotated configuration items, 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>.
|
||||
</para>
|
||||
<para>
|
||||
For &repmgrd;-specific settings, see <xref linkend="repmgrd-configuration"/>.
|
||||
@@ -227,14 +182,6 @@ conninfo='host=node1 user=repmgr dbname=repmgr connect_timeout=2'</programlistin
|
||||
</itemizedlist>
|
||||
</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>
|
||||
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
|
||||
@@ -255,61 +202,6 @@ conninfo='host=node1 user=repmgr dbname=repmgr connect_timeout=2'</programlistin
|
||||
<filename>/path/to/repmgr.conf</filename>).
|
||||
</para>
|
||||
</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>PostgreSQL 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>
|
||||
</sect1>
|
||||
|
||||
@@ -127,31 +127,8 @@ node2:5432:repmgr:repmgr:foo
|
||||
node2:5432:replication:repluser:foo
|
||||
node3:5432:repmgr:repmgr:foo
|
||||
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>
|
||||
|
||||
<note>
|
||||
<para>
|
||||
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
|
||||
local node.
|
||||
</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>
|
||||
|
||||
</sect2>
|
||||
|
||||
@@ -7,194 +7,19 @@
|
||||
</indexterm>
|
||||
|
||||
<para>
|
||||
If the &repmgr; database user (the PostgreSQL user defined in the
|
||||
<varname>conninfo</varname> setting is a superuser, no further user permissions need
|
||||
to be granted.
|
||||
&repmgr; requires that the database defined in the <varname>conninfo</varname>
|
||||
setting contains the <literal>repmgr</literal> extension. The database user defined in the
|
||||
<varname>conninfo</varname> setting must be able to access this database and
|
||||
the database objects contained within the extension.
|
||||
</para>
|
||||
<para>
|
||||
The <literal>repmgr</literal> extension can only be installed by a superuser.
|
||||
If the &repmgr; user is a superuser, &repmgr; will create the extension automatically.
|
||||
</para>
|
||||
|
||||
<sect2 id="configuration-permissions-no-superuser" xreflabel="Non-super user permissions">
|
||||
<title>repmgr user as a non-superuser</title>
|
||||
<para>
|
||||
In principle the &repmgr; database user does not need to be a superuser.
|
||||
In this case the &repmgr; will need to be granted execution permissions on certain
|
||||
functions, and membership of certain roles. However be aware that &repmgr; does
|
||||
expect to be able to execute certain commands which are restricted to superusers;
|
||||
in this case either a superuser must be specified with the <option>-S</option>/<option>--superuser</option>
|
||||
(where available) option, or the corresponding action should be executed manually as a superuser.
|
||||
</para>
|
||||
<para>
|
||||
The following sections describe the actions needed to use &repmgr; with a non-superuser,
|
||||
and relevant caveats.
|
||||
</para>
|
||||
<sect3 id="configuration-permissions-replication" xreflabel="Replication role">
|
||||
<title>Replication role</title>
|
||||
<para>
|
||||
&repmgr; requires a database user with the <literal>REPLICATION</literal> role
|
||||
to be able to create a replication connection and (if configured) to administer
|
||||
replication slots.
|
||||
</para>
|
||||
<para>
|
||||
By default this is the database user defined in the <varname>conninfo</varname>
|
||||
setting. This user can be:
|
||||
<itemizedlist spacing="compact" mark="bullet">
|
||||
<listitem>
|
||||
<simpara>
|
||||
a superuser
|
||||
</simpara>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<simpara>
|
||||
a non-superuser with the <literal>REPLICATION</literal> role
|
||||
</simpara>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<simpara>
|
||||
another user defined in the <filename>repmgr.conf</filename> parameter <varname>replication_user</varname> with the <literal>REPLICATION</literal> role
|
||||
</simpara>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
</sect3>
|
||||
|
||||
<sect3 id="configuration-permissions-roles" xreflabel="Database roles for non-superusers">
|
||||
<title>Database roles</title>
|
||||
<para>
|
||||
A non-superuser &repmgr; database user should be a member of the following
|
||||
<ulink url="https://www.postgresql.org/docs/current/predefined-roles.html">predefined roles</ulink>
|
||||
(PostgreSQL 10 and later):
|
||||
<itemizedlist spacing="compact" mark="bullet">
|
||||
<listitem>
|
||||
<simpara>
|
||||
<varname>pg_read_all_stats</varname>
|
||||
(to read the <varname>status</varname> column of <literal>pg_stat_replication</literal>
|
||||
and execute <function>pg_database_size()</function> on all databases)
|
||||
</simpara>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<simpara>
|
||||
<varname>pg_read_all_settings</varname> (to access the <varname>data_directory</varname> setting)
|
||||
</simpara>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
Alternatively the meta-role <varname>pg_monitor</varname> can be granted, which includes membership
|
||||
of the above predefined roles.
|
||||
</para>
|
||||
<para>
|
||||
PostgreSQL 15 introduced the <varname>pg_checkpoint</varname> predefined role which allows a
|
||||
non-superuser &repmgr; database user to perform a CHECKPOINT command.
|
||||
</para>
|
||||
<para>
|
||||
Membership of these roles can be granted with e.g. <command>GRANT pg_read_all_stats TO repmgr</command>.
|
||||
</para>
|
||||
<para>
|
||||
Users of PostgreSQL 9.6 or earlier should upgrade to a supported PostgreSQL version, or provide
|
||||
the <option>-S</option>/<option>--superuser</option> where available.
|
||||
</para>
|
||||
</sect3>
|
||||
|
||||
<sect3 id="configuration-permissions-extension" xreflabel="Extension creation">
|
||||
<title>Extension creation</title>
|
||||
<para>
|
||||
&repmgr; requires that the database defined in the <varname>conninfo</varname>
|
||||
setting contains the <literal>repmgr</literal> extension. The database user defined in the
|
||||
<varname>conninfo</varname> setting must be able to access this database and
|
||||
the database objects contained within the extension.
|
||||
</para>
|
||||
<para>
|
||||
The <literal>repmgr</literal> extension can only be installed by a superuser.
|
||||
If the &repmgr; user is a superuser, &repmgr; will create the extension automatically.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Alternatively, the extension can be created manually by a superuser
|
||||
(with "<command>CREATE EXTENSION repmgr</command>") before executing
|
||||
<link linkend="repmgr-primary-register">repmgr primary register</link>.
|
||||
</para>
|
||||
</sect3>
|
||||
|
||||
|
||||
<sect3 id="configuration-permissions-functions" xreflabel="Function permissions for non-superusers">
|
||||
<title>Function permissions</title>
|
||||
<para>
|
||||
If the &repmgr; database user is not a superuser, <literal>EXECUTE</literal> permission should be
|
||||
granted on the following function:
|
||||
<itemizedlist spacing="compact" mark="bullet">
|
||||
<listitem>
|
||||
<simpara>
|
||||
<function>pg_wal_replay_resume()</function> (required by &repmgrd; during failover operations;
|
||||
if permission is not granted, the failoved process may not function reliably if a node
|
||||
has WAL replay paused)
|
||||
</simpara>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<simpara>
|
||||
<function>pg_promote()</function> (PostgreSQL 12 and later; if permission is not granted,
|
||||
&repmgr; will fall back to <command>pg_ctl promote</command>)
|
||||
</simpara>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
<para>
|
||||
<literal>EXECUTE</literal> permission on functions can be granted with e.g.:
|
||||
<command>GRANT EXECUTE ON FUNCTION pg_catalog.pg_wal_replay_resume() TO repmgr</command>.
|
||||
</para>
|
||||
</sect3>
|
||||
|
||||
<sect3 id="configuration-permissions-superuser-required" xreflabel="repmgr actions requiring a superuser">
|
||||
<title>repmgr actions requiring a superuser</title>
|
||||
<para>
|
||||
In some circumstances, &repmgr; may need to perform an operation which cannot be delegated to a
|
||||
non-superuser.
|
||||
<itemizedlist spacing="compact" mark="bullet">
|
||||
<listitem>
|
||||
<simpara>
|
||||
The <command>CHECKPOINT</command> command is executed by
|
||||
<link linkend="repmgr-standby-switchover">repmgr standby switchover</link>. This can only
|
||||
be executed by a superuser; if the &repmgr; user is not a superuser,
|
||||
the <option>-S</option>/<option>--superuser</option> should be used.
|
||||
From PostgreSQL 15 the <varname>pg_checkpoint</varname> predefined role removes the need of
|
||||
superuser permissions to perform <command>CHECKPOINT</command> command.
|
||||
</simpara>
|
||||
<simpara>
|
||||
If &repmgr; is not able to execute <command>CHECKPOINT</command>,
|
||||
there is a risk that the demotion candidate may not be able to shut down as smoothly as might otherwise
|
||||
have been the case.
|
||||
</simpara>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<simpara>
|
||||
The <command>ALTER SYSTEM</command> is executed by &repmgrd; if
|
||||
<varname>standby_disconnect_on_failover</varname> is set to <literal>true</literal> in
|
||||
<filename>repmgr.conf</filename>. Until PostgreSQL 14 <command>ALTER SYSTEM</command> can only be executed by
|
||||
a superuser; if the &repmgr; user is not a superuser, this functionality will not be available.
|
||||
From PostgreSQL 15 a specific ALTER SYSTEM privilege can be granted with e.g.
|
||||
<command>GRANT ALTER SYSTEM ON PARAMETER wal_retrieve_retry_interval TO repmgr</command>.
|
||||
</simpara>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
</sect3>
|
||||
|
||||
<sect3 id="configuration-permissions-superuser-option" xreflabel="repmgr commands with --superuser option">
|
||||
<title>repmgr commands with --superuser option</title>
|
||||
<para>
|
||||
The following repmgr commands provide the <option>-S</option>/<option>--superuser</option> option:
|
||||
<itemizedlist spacing="compact" mark="bullet">
|
||||
<listitem>
|
||||
<simpara><link linkend="repmgr-standby-clone">repmgr standby clone</link> (to be able to copy configuration files outside of the data directory if <option>--copy-external-config-files</option> provided)</simpara>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<simpara><link linkend="repmgr-standby-switchover">repmgr standby switchover</link> (to execute <command>CHECKPOINT</command>)</simpara>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<simpara><link linkend="repmgr-node-check">repmgr node check</link> (to execute <command>repmgr node check --data-directory-config</command>; note this is also called by <link linkend="repmgr-standby-switchover">repmgr standby switchover</link>)</simpara>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<simpara><link linkend="repmgr-node-service">repmgr node service</link> (to execute <command>CHECKPOINT</command> via the <option>--checkpoint</option>; note this is also called by <link linkend="repmgr-standby-switchover">repmgr standby switchover</link>)</simpara>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
</sect3>
|
||||
|
||||
</sect2>
|
||||
<para>
|
||||
Alternatively, the extension can be created manually by a superuser
|
||||
(with "<command>CREATE EXTENSION repmgr</command>") before executing
|
||||
<link linkend="repmgr-primary-register">repmgr primary register</link>.
|
||||
</para>
|
||||
</sect1>
|
||||
|
||||
@@ -270,7 +270,7 @@
|
||||
|
||||
<varlistentry>
|
||||
|
||||
<term><option>wal_keep_segments</option> / <option>wal_keep_size</option></term>
|
||||
<term><option>wal_keep_segments</option></term>
|
||||
|
||||
<listitem>
|
||||
|
||||
@@ -279,36 +279,25 @@
|
||||
<secondary>PostgreSQL configuration</secondary>
|
||||
</indexterm>
|
||||
|
||||
|
||||
<indexterm>
|
||||
<primary>wal_keep_size</primary>
|
||||
<secondary>PostgreSQL configuration</secondary>
|
||||
</indexterm>
|
||||
|
||||
<para>
|
||||
Normally there is no need to set <option>wal_keep_segments</option>
|
||||
(PostgreSQL 13 and later: <varname>wal_keep_size</varname>; default: <literal>0</literal>),
|
||||
as it is <emphasis>not</emphasis> a reliable way of ensuring that all required WAL
|
||||
segments are available to standbys. Replication slots and/or an archiving solution
|
||||
such as Barman are recommended to ensure standbys have a reliable
|
||||
Normally there is no need to set <option>wal_keep_segments</option> (default: <literal>0</literal>), as it
|
||||
is <emphasis>not</emphasis> a reliable way of ensuring that all required WAL 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.
|
||||
</para>
|
||||
<para>
|
||||
The only reason ever to set <option>wal_keep_segments</option> / <option>wal_keep_size</option>
|
||||
is you have you have configured <option>pg_basebackup_options</option>
|
||||
The only reason ever to set <option>wal_keep_segments</option> is you have
|
||||
you have configured <option>pg_basebackup_options</option>
|
||||
in <filename>repmgr.conf</filename> to include the setting <literal>--wal-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>
|
||||
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>
|
||||
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>
|
||||
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>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
@@ -95,8 +95,7 @@
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The following parameters are provided for a subset of event notifications; their meaning may
|
||||
change according to context:
|
||||
The following parameters are provided for a subset of event notifications:
|
||||
</para>
|
||||
|
||||
<variablelist>
|
||||
@@ -109,9 +108,6 @@
|
||||
<para>
|
||||
node ID of the demoted primary (<xref linkend="repmgr-standby-switchover"/> only)
|
||||
</para>
|
||||
<para>
|
||||
node ID of the former primary (<literal>repmgrd_failover_promote</literal> only)
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
@@ -137,7 +133,7 @@
|
||||
|
||||
<para>
|
||||
The values provided for <literal>%c</literal> and <literal>%a</literal>
|
||||
may contain spaces, so should always be quoted.
|
||||
will probably contain spaces, so should always be quoted.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
|
||||
@@ -22,15 +22,16 @@
|
||||
|
||||
<para>
|
||||
&repmgr; RPM packages for RedHat/CentOS variants and Fedora are available from the
|
||||
<ulink url="https://www.enterprisedb.com">EDB</ulink>
|
||||
<ulink url="https://dl.enterprisedb.com/">public repository</ulink>; see following
|
||||
<ulink url="https://2ndquadrant.com">2ndQuadrant</ulink>
|
||||
<ulink url="https://dl.2ndquadrant.com/">public repository</ulink>; see following
|
||||
section for details.
|
||||
</para>
|
||||
<note>
|
||||
<para>
|
||||
Currently the <ulink url="https://www.enterprisedb.com">EDB</ulink>
|
||||
<ulink url="https://dl.enterprisedb.com/">public repository</ulink> provides
|
||||
support for RedHat/CentOS versions 6,7 and 8.
|
||||
Currently the <ulink url="https://2ndquadrant.com">2ndQuadrant</ulink>
|
||||
<ulink url="https://dl.2ndquadrant.com/">public repository</ulink> provides
|
||||
support for RedHat/CentOS versions 5, 6 and 7. Support for version 8 is
|
||||
available via the PGDG repository; see below for details.
|
||||
</para>
|
||||
</note>
|
||||
<para>
|
||||
@@ -44,7 +45,7 @@
|
||||
<note>
|
||||
<para>
|
||||
&repmgr; RPM packages are designed to be compatible with the community-provided PostgreSQL packages
|
||||
and EDB's PostgreSQL Extended Server (formerly 2ndQPostgres).
|
||||
and 2ndQuadrant's <ulink url="https://www.2ndquadrant.com/en/resources/2ndqpostgres/">2ndQPostgres</ulink>.
|
||||
They may not work with vendor-specific packages such as those provided by RedHat for RHEL
|
||||
customers, as the PostgreSQL filesystem layout may be different to the community RPMs.
|
||||
Please contact your support vendor for assistance.
|
||||
@@ -63,16 +64,16 @@
|
||||
|
||||
|
||||
<sect3 id="installation-packages-redhat-2ndq">
|
||||
<title>EDB public RPM yum repository</title>
|
||||
<title>2ndQuadrant public RPM yum repository</title>
|
||||
|
||||
<para>
|
||||
<ulink url="https://www.enterprisedb.com/">EDB</ulink> provides a dedicated <literal>yum</literal>
|
||||
<ulink url="https://dl.enterprisedb.com/">public repository</ulink> for EDB software,
|
||||
<ulink url="https://2ndquadrant.com/">2ndQuadrant</ulink> provides a dedicated <literal>yum</literal>
|
||||
<ulink url="https://dl.2ndquadrant.com/">public repository</ulink> for 2ndQuadrant software,
|
||||
including &repmgr;. We recommend using this for all future &repmgr; releases.
|
||||
</para>
|
||||
<para>
|
||||
General instructions for using this repository can be found on its
|
||||
<ulink url="https://dl.enterprisedb.com/">homepage</ulink>. Specific instructions
|
||||
<ulink url="https://dl.2ndquadrant.com/">homepage</ulink>. Specific instructions
|
||||
for installing &repmgr; follow below.
|
||||
</para>
|
||||
<para>
|
||||
@@ -82,46 +83,57 @@
|
||||
<listitem>
|
||||
<para>
|
||||
Locate the repository RPM for your PostgreSQL version from the list at:
|
||||
<ulink url="https://dl.enterprisedb.com/">https://dl.enterprisedb.com/</ulink>
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
Install the repository definition for your distribution and PostgreSQL version
|
||||
(this enables the EDB repository as a source of &repmgr; packages).
|
||||
</para>
|
||||
<para>
|
||||
For example, for PostgreSQL 14 on Rocky Linux 8, execute:
|
||||
<programlisting>
|
||||
curl https://dl.enterprisedb.com/default/release/get/14/rpm | sudo bash</programlisting>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Verify that the repository is installed with:
|
||||
<programlisting>
|
||||
sudo dnf repolist</programlisting>
|
||||
The output should contain two entries like this:
|
||||
<programlisting>
|
||||
2ndquadrant-dl-default-release-pg14 2ndQuadrant packages (PG14) for 8 - x86_64
|
||||
2ndquadrant-dl-default-release-pg14-debug 2ndQuadrant packages (PG14) for 8 - x86_64 - Debug</programlisting>
|
||||
<ulink url="https://dl.2ndquadrant.com/">https://dl.2ndquadrant.com/</ulink>
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
Install the &repmgr; version appropriate for your PostgreSQL version (e.g. <literal>repmgr14</literal>):
|
||||
Install the repository definition for your distribution and PostgreSQL version
|
||||
(this enables the 2ndQuadrant repository as a source of &repmgr; packages).
|
||||
</para>
|
||||
<para>
|
||||
For example, for PostgreSQL 11 on CentOS, execute:
|
||||
<programlisting>
|
||||
curl https://dl.2ndquadrant.com/default/release/get/11/rpm | sudo bash</programlisting>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
For PostgreSQL 9.6 on CentOS, execute:
|
||||
<programlisting>
|
||||
curl https://dl.2ndquadrant.com/default/release/get/9.6/rpm | sudo bash</programlisting>
|
||||
</para>
|
||||
|
||||
|
||||
<para>
|
||||
Verify that the repository is installed with:
|
||||
<programlisting>
|
||||
sudo yum repolist</programlisting>
|
||||
The output should contain two entries like this:
|
||||
<programlisting>
|
||||
2ndquadrant-dl-default-release-pg11/7/x86_64 2ndQuadrant packages (PG11) for 7 - x86_64 18
|
||||
2ndquadrant-dl-default-release-pg11-debug/7/x86_64 2ndQuadrant packages (PG11) for 7 - x86_64 - Debug 8</programlisting>
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
Install the &repmgr; version appropriate for your PostgreSQL version (e.g. <literal>repmgr10</literal>):
|
||||
<programlisting>
|
||||
sudo dnf install repmgr14</programlisting>
|
||||
sudo yum install repmgr11</programlisting>
|
||||
</para>
|
||||
<note>
|
||||
<para>
|
||||
For packages for PostgreSQL 9.6 and earlier, the package name does not contain
|
||||
a period between major and minor version numbers, e.g.
|
||||
<literal>repmgr96</literal>.
|
||||
</para>
|
||||
</note>
|
||||
<tip>
|
||||
<para>
|
||||
To determine the names of available packages, execute:
|
||||
<programlisting>
|
||||
dnf search repmgr</programlisting>
|
||||
</para>
|
||||
<para>
|
||||
In CentOS 7 and earlier, use <literal>yum</literal> instead of <literal>dnf</literal>.
|
||||
yum search repmgr</programlisting>
|
||||
</para>
|
||||
</tip>
|
||||
|
||||
@@ -133,7 +145,7 @@ dnf search repmgr</programlisting>
|
||||
<emphasis>Compatibility with PGDG Repositories</emphasis>
|
||||
</para>
|
||||
<para>
|
||||
The EDB &repmgr; yum repository packages use the same definitions and file system layout as the
|
||||
The 2ndQuadrant &repmgr; yum repository packages use the same definitions and file system layout as the
|
||||
main PGDG repository.
|
||||
</para>
|
||||
<para>
|
||||
@@ -142,42 +154,36 @@ dnf search repmgr</programlisting>
|
||||
the packages are installed from.
|
||||
</para>
|
||||
<para>
|
||||
To ensure the EDB repository is always prioritised, set the <literal>priority</literal> option
|
||||
in the repository configuration file (e.g. <filename>/etc/yum.repos.d/2ndquadrant-dl-default-release-pg14.repo</filename>
|
||||
accordingly.
|
||||
To ensure the 2ndQuadrant repository is always prioritised, install <literal>yum-plugin-priorities</literal>
|
||||
and set the repository priorities accordingly.
|
||||
</para>
|
||||
<note>
|
||||
<para>
|
||||
With CentOS 7 and earlier, the package <literal>yum-plugin-priorities</literal> must be installed
|
||||
to be able to set the repository priority.
|
||||
</para>
|
||||
</note>
|
||||
|
||||
<para>
|
||||
<emphasis>Installing a specific package version</emphasis>
|
||||
</para>
|
||||
<para>
|
||||
To install a specific package version, execute <command>dnf --showduplicates list</command>
|
||||
To install a specific package version, execute <command>yum --showduplicates list</command>
|
||||
for the package in question:
|
||||
<programlisting>
|
||||
[root@localhost ~]# dnf --showduplicates list repmgr10
|
||||
Last metadata expiration check: 0:09:15 ago on Fri 11 Mar 2022 01:09:19 AM UTC.
|
||||
[root@localhost ~]# yum --showduplicates list repmgr11
|
||||
Loaded plugins: fastestmirror
|
||||
Loading mirror speeds from cached hostfile
|
||||
* base: ftp.tsukuba.wide.ad.jp
|
||||
* epel: nrt.edge.kernel.org
|
||||
* extras: ftp.tsukuba.wide.ad.jp
|
||||
* updates: ftp.tsukuba.wide.ad.jp
|
||||
Installed Packages
|
||||
repmgr10.x86_64 5.3.1-1.el8 @2ndquadrant-dl-default-release-pg10
|
||||
repmgr11.x86_64 4.4.0-1.rhel7 @pgdg11
|
||||
Available Packages
|
||||
repmgr10.x86_64 5.0.0-1.rhel8 pgdg10
|
||||
repmgr10.x86_64 5.1.0-1.el8 2ndquadrant-dl-default-release-pg10
|
||||
repmgr10.x86_64 5.1.0-1.rhel8 pgdg10
|
||||
repmgr10.x86_64 5.1.0-2.el8 2ndquadrant-dl-default-release-pg10
|
||||
repmgr10.x86_64 5.2.0-1.el8 2ndquadrant-dl-default-release-pg10
|
||||
repmgr10.x86_64 5.2.0-1.rhel8 pgdg10
|
||||
repmgr10.x86_64 5.2.1-1.el8 2ndquadrant-dl-default-release-pg10
|
||||
repmgr10.x86_64 5.3.0-1.el8 2ndquadrant-dl-default-release-pg10
|
||||
repmgr10.x86_64 5.3.1-1.el8 2ndquadrant-dl-default-release-pg10</programlisting>
|
||||
repmgr11.x86_64 4.2-1.el7 2ndquadrant-dl-default-release-pg11
|
||||
repmgr11.x86_64 4.2-2.el7 2ndquadrant-dl-default-release-pg11
|
||||
repmgr11.x86_64 4.3-1.el7 2ndquadrant-dl-default-release-pg11
|
||||
repmgr11.x86_64 4.4-1.el7 2ndquadrant-dl-default-release-pg11</programlisting>
|
||||
then append the appropriate version number to the package name with a hyphen, e.g.:
|
||||
<programlisting>
|
||||
[root@localhost ~]# dnf install repmgr10-5.3.0-1.el8</programlisting>
|
||||
[root@localhost ~]# yum install repmgr11-4.3-1.el7</programlisting>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<emphasis>Installing old packages</emphasis>
|
||||
</para>
|
||||
@@ -185,6 +191,7 @@ repmgr10.x86_64 5.3.1-1.el8
|
||||
See appendix <link linkend="packages-old-versions-rhel-centos">Installing old package versions</link>
|
||||
for details on how to retrieve older package versions.
|
||||
</para>
|
||||
|
||||
</sect3>
|
||||
|
||||
</sect2>
|
||||
@@ -210,16 +217,16 @@ repmgr10.x86_64 5.3.1-1.el8
|
||||
</para>
|
||||
|
||||
<sect3 id="installation-packages-debian-ubuntu-2ndq">
|
||||
<title>EDB public apt repository for Debian/Ubuntu</title>
|
||||
<title>2ndQuadrant public apt repository for Debian/Ubuntu</title>
|
||||
|
||||
<para>
|
||||
<ulink url="https://www.enterprisedb.com/">EDB</ulink> provides a
|
||||
<ulink url="https://dl.enterprisedb.com/">public apt repository</ulink> for EDB software,
|
||||
<ulink url="https://2ndquadrant.com/">2ndQuadrant</ulink> provides a
|
||||
<ulink url="https://dl.2ndquadrant.com/">public apt repository</ulink> for 2ndQuadrant software,
|
||||
including &repmgr;.
|
||||
</para>
|
||||
<para>
|
||||
General instructions for using this repository can be found on its
|
||||
<ulink url="https://dl.enterprisedb.com/">homepage</ulink>. Specific instructions
|
||||
<ulink url="https://dl.2ndquadrant.com/">homepage</ulink>. Specific instructions
|
||||
for installing &repmgr; follow below.
|
||||
</para>
|
||||
|
||||
@@ -232,9 +239,9 @@ repmgr10.x86_64 5.3.1-1.el8
|
||||
<listitem>
|
||||
<para>
|
||||
Install the repository definition for your distribution and PostgreSQL version
|
||||
(this enables the EDB repository as a source of &repmgr; packages) by executing:
|
||||
(this enables the 2ndQuadrant repository as a source of &repmgr; packages) by executing:
|
||||
<programlisting>
|
||||
curl https://dl.enterprisedb.com/default/release/get/deb | sudo bash</programlisting>
|
||||
curl https://dl.2ndquadrant.com/default/release/get/deb | sudo bash</programlisting>
|
||||
</para>
|
||||
<note>
|
||||
<para>
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
</para>
|
||||
|
||||
<para>
|
||||
&repmgr; &repmgrversion; is compatible with all supported PostgreSQL versions from 13.x. See
|
||||
&repmgr; &repmgrversion; is compatible with all PostgreSQL versions from 9.3. See
|
||||
section <link linkend="install-compatibility-matrix">&repmgr; compatibility matrix</link>
|
||||
for an overview of version compatibility.
|
||||
</para>
|
||||
@@ -45,7 +45,7 @@
|
||||
of incompatibilities.
|
||||
</simpara>
|
||||
<simpara>
|
||||
If different "major" &repmgr; versions (e.g. 5.2.x and &repmgrversion;)
|
||||
If different "major" &repmgr; versions (e.g. 4.1.x and &repmgrversion;.x)
|
||||
are installed on different nodes, in the best case &repmgr; (in particular &repmgrd;)
|
||||
will not run. In the worst case, you will end up with a broken cluster.
|
||||
</simpara>
|
||||
@@ -89,10 +89,11 @@
|
||||
which PostgreSQL version.
|
||||
</para>
|
||||
|
||||
|
||||
<table id="repmgr-compatibility-matrix">
|
||||
<title>&repmgr; compatibility matrix</title>
|
||||
|
||||
<tgroup cols="4">
|
||||
<tgroup cols="3">
|
||||
<thead>
|
||||
<row>
|
||||
<entry>
|
||||
@@ -107,128 +108,32 @@
|
||||
<entry>
|
||||
Supported PostgreSQL versions
|
||||
</entry>
|
||||
<entry>
|
||||
Notes
|
||||
</entry>
|
||||
</row>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>
|
||||
&repmgr; 5.5
|
||||
</entry>
|
||||
<entry>
|
||||
Yes
|
||||
</entry>
|
||||
<entry>
|
||||
<link linkend="release-5.5.0">&repmgrversion;</link> (&releasedate;)
|
||||
</entry>
|
||||
<entry>
|
||||
13, 14, 15, 16, 17
|
||||
</entry>
|
||||
<entry>
|
||||
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>
|
||||
&repmgr; 5.4.1
|
||||
&repmgr; 5.x
|
||||
</entry>
|
||||
<entry>
|
||||
Yes
|
||||
YES
|
||||
</entry>
|
||||
<entry>
|
||||
<link linkend="release-5.4.1">5.4.1</link> (2023-04-04)
|
||||
</entry>
|
||||
<entry>
|
||||
10, 11, 12, 13, 14, 15
|
||||
</entry>
|
||||
<entry>
|
||||
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>
|
||||
&repmgr; 5.3.1
|
||||
</entry>
|
||||
<entry>
|
||||
Yes
|
||||
</entry>
|
||||
<entry>
|
||||
<link linkend="release-5.3.1">5.3.1</link> (2022-02-15)
|
||||
</entry>
|
||||
<entry>
|
||||
9.4, 9.5, 9.6, 10, 11, 12, 13, 14, 15
|
||||
</entry>
|
||||
<entry>
|
||||
PostgreSQL 15 supported from &repmgr; 5.3.3
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>
|
||||
&repmgr; 5.2
|
||||
</entry>
|
||||
<entry>
|
||||
No
|
||||
</entry>
|
||||
<entry>
|
||||
<link linkend="release-5.2.1">5.2.1</link> (2020-12-07)
|
||||
</entry>
|
||||
<entry>
|
||||
9.4, 9.5, 9.6, 10, 11, 12, 13
|
||||
</entry>
|
||||
<entry>
|
||||
|
||||
</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)
|
||||
<link linkend="release-current">&repmgrversion;</link> (&releasedate;)
|
||||
</entry>
|
||||
<entry>
|
||||
9.3, 9.4, 9.5, 9.6, 10, 11, 12
|
||||
</entry>
|
||||
<entry>
|
||||
|
||||
</entry>
|
||||
</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>
|
||||
<entry>
|
||||
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
|
||||
<row>
|
||||
<entry>
|
||||
&repmgr; 4.x
|
||||
</entry>
|
||||
<entry>
|
||||
No
|
||||
NO
|
||||
</entry>
|
||||
<entry>
|
||||
<link linkend="release-4.4">4.4</link> (2019-06-27)
|
||||
@@ -236,9 +141,6 @@
|
||||
<entry>
|
||||
9.3, 9.4, 9.5, 9.6, 10, 11
|
||||
</entry>
|
||||
<entry>
|
||||
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
@@ -246,7 +148,7 @@
|
||||
&repmgr; 3.x
|
||||
</entry>
|
||||
<entry>
|
||||
No
|
||||
NO
|
||||
</entry>
|
||||
<entry>
|
||||
<ulink url="https://repmgr.org/release-notes-3.3.2.html">3.3.2</ulink> (2017-05-30)
|
||||
@@ -254,9 +156,6 @@
|
||||
<entry>
|
||||
9.3, 9.4, 9.5, 9.6
|
||||
</entry>
|
||||
<entry>
|
||||
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
@@ -264,7 +163,7 @@
|
||||
&repmgr; 2.x
|
||||
</entry>
|
||||
<entry>
|
||||
No
|
||||
NO
|
||||
</entry>
|
||||
<entry>
|
||||
<ulink url="https://repmgr.org/release-notes-2.0.3.html">2.0.3</ulink> (2015-04-16)
|
||||
@@ -272,9 +171,6 @@
|
||||
<entry>
|
||||
9.0, 9.1, 9.2, 9.3, 9.4
|
||||
</entry>
|
||||
<entry>
|
||||
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
|
||||
@@ -283,12 +179,12 @@
|
||||
|
||||
<important>
|
||||
<para>
|
||||
The &repmgr; series older than 5.x are no longer maintained or supported.
|
||||
The &repmgr; 2.x and 3.x series are no longer maintained or supported.
|
||||
We strongly recommend upgrading to the latest &repmgr; version.
|
||||
</para>
|
||||
<para>
|
||||
Following the release of &repmgr; 5.0, there will be no further releases of
|
||||
the &repmgr; 4.x series or older. Note that &repmgr; 5.x is an incremental development
|
||||
the &repmgr; 4.x series. Note that &repmgr; 5.x is an incremental development
|
||||
of the 4.x series and &repmgr; 4.x users should upgrade to this as soon as possible.
|
||||
</para>
|
||||
</important>
|
||||
@@ -297,49 +193,52 @@
|
||||
|
||||
<sect2 id="install-postgresql-93-94">
|
||||
|
||||
<title>PostgreSQL 9.4 support</title>
|
||||
<title>PostgreSQL 9.3 and 9.4 support</title>
|
||||
|
||||
<indexterm>
|
||||
<primary>PostgreSQL 9.4</primary>
|
||||
<primary>PostgreSQL 9.3</primary>
|
||||
<secondary>repmgr support</secondary>
|
||||
</indexterm>
|
||||
|
||||
<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>
|
||||
<itemizedlist spacing="compact" mark="bullet">
|
||||
|
||||
<listitem>
|
||||
<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
|
||||
to use any &repmgr; functionality which takes advantage of it.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<warning>
|
||||
<important>
|
||||
<para>
|
||||
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>
|
||||
in November 2018) and will no longer be updated with security or bugfixes.
|
||||
</para>
|
||||
<para>
|
||||
Beginning with &repmgr; 5.2, &repmgr; no longer supports PostgreSQL 9.3.
|
||||
</para>
|
||||
<para>
|
||||
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>
|
||||
in February 2020) and will no longer be updated with security or bugfixes.
|
||||
</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.
|
||||
</para>
|
||||
<para>
|
||||
For further details, see the <ulink url="https://www.postgresql.org/support/versioning/">PostgreSQL Versioning Policy</ulink>.
|
||||
</para>
|
||||
</warning>
|
||||
</important>
|
||||
|
||||
</sect2>
|
||||
|
||||
|
||||
@@ -178,18 +178,18 @@ deb-src https://apt.postgresql.org/pub/repos/apt/ stretch-pgdg main</programlist
|
||||
|
||||
<para>
|
||||
The source for &repmgr; is maintained at
|
||||
<ulink url="https://github.com/EnterpriseDB/repmgr">https://github.com/EnterpriseDB/repmgr</ulink>.
|
||||
<ulink url="https://github.com/2ndQuadrant/repmgr">https://github.com/2ndQuadrant/repmgr</ulink>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
There are also tags for each <ulink url="https://github.com/EnterpriseDB/repmgr/releases">&repmgr; release</ulink>, e.g.
|
||||
<literal><ulink url="https://github.com/EnterpriseDB/repmgr/releases/tag/v4.4.0">v4.4.0</ulink></literal>.
|
||||
There are also tags for each <ulink url="https://github.com/2ndQuadrant/repmgr/releases">&repmgr; release</ulink>, e.g.
|
||||
<literal><ulink url="https://github.com/2ndQuadrant/repmgr/releases/tag/v4.4.0">v4.4.0</ulink></literal>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Clone the source code using <application>git</application>:
|
||||
<programlisting>
|
||||
git clone https://github.com/EnterpriseDB/repmgr</programlisting>
|
||||
git clone https://github.com/2ndQuadrant/repmgr</programlisting>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
<!-- doc/legal.xml -->
|
||||
|
||||
<date>2025</date>
|
||||
<date>2017</date>
|
||||
|
||||
<copyright>
|
||||
<year>2010-2025</year>
|
||||
<holder>EDB</holder>
|
||||
<year>2010-2020</year>
|
||||
<holder>2ndQuadrant, Ltd.</holder>
|
||||
</copyright>
|
||||
|
||||
<legalnotice id="legalnotice">
|
||||
<title>Legal Notice</title>
|
||||
|
||||
<para>
|
||||
<productname>repmgr</productname> is Copyright © 2010-2025
|
||||
by EDB All rights reserved.
|
||||
<productname>repmgr</productname> is Copyright © 2010-2020
|
||||
by 2ndQuadrant, Ltd. All rights reserved.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
|
||||
@@ -284,7 +284,7 @@
|
||||
|
||||
<tip>
|
||||
<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
|
||||
not in the standard path are located. For PostgreSQL 9.6 this would be <filename>/usr/lib/postgresql/9.6/bin/</filename>.
|
||||
</simpara>
|
||||
@@ -302,7 +302,7 @@
|
||||
|
||||
<para>
|
||||
See the file
|
||||
<ulink url="https://raw.githubusercontent.com/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.
|
||||
</para>
|
||||
|
||||
@@ -405,10 +405,9 @@
|
||||
</programlisting>
|
||||
<para>
|
||||
This has cloned the PostgreSQL data directory files from the primary <literal>node1</literal>
|
||||
using PostgreSQL's <command>pg_basebackup</command> utility. Replication configuration
|
||||
containing the correct parameters to start streaming from this primary server will be
|
||||
automatically appended to <filename>postgresql.auto.conf</filename>. (In PostgreSQL 11
|
||||
and earlier the file <filename>recovery.conf</filename> will be created).
|
||||
using PostgreSQL's <command>pg_basebackup</command> utility. A <filename>recovery.conf</filename>
|
||||
file containing the correct parameters to start streaming from this primary server will be created
|
||||
automatically.
|
||||
</para>
|
||||
<note>
|
||||
<simpara>
|
||||
@@ -482,10 +481,9 @@
|
||||
sender_port | 5432
|
||||
conninfo | user=repmgr dbname=replication host=node1 application_name=node2
|
||||
</programlisting>
|
||||
Note that the <varname>conninfo</varname> value is that generated in <filename>postgresql.auto.conf</filename>
|
||||
(PostgreSQL 11 and earlier: <filename>recovery.conf</filename>) and will differ slightly from the primary's
|
||||
<varname>conninfo</varname> as set in <filename>repmgr.conf</filename> - among others it will contain the
|
||||
connecting node's name as <varname>application_name</varname>.
|
||||
Note that the <varname>conninfo</varname> value is that generated in <filename>recovery.conf</filename>
|
||||
and will differ slightly from the primary's <varname>conninfo</varname> as set in <filename>repmgr.conf</filename> -
|
||||
among others it will contain the connecting node's name as <varname>application_name</varname>.
|
||||
</para>
|
||||
</sect1>
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
</para>
|
||||
<para>
|
||||
By default, &repmgr; will wait for up to 15 seconds to confirm that &repmgrd;
|
||||
started. This behaviour can be overridden by specifying a 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.
|
||||
</para>
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
<para>
|
||||
By default, &repmgr; will wait for up to 15 seconds to confirm that &repmgrd;
|
||||
stopped. This behaviour can be overridden by specifying a 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.
|
||||
</para>
|
||||
<note>
|
||||
|
||||
@@ -125,69 +125,12 @@
|
||||
is correctly configured.
|
||||
</simpara>
|
||||
</listitem>
|
||||
|
||||
|
||||
</itemizedlist>
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
|
||||
<refsect1>
|
||||
<title>repmgrd</title>
|
||||
<para>
|
||||
A separate check is available to verify whether &repmgrd; is running,
|
||||
This is not included in the general output, as this does not
|
||||
per-se constitute a check of the node's replication status.
|
||||
</para>
|
||||
<itemizedlist spacing="compact" mark="bullet">
|
||||
<listitem>
|
||||
<simpara>
|
||||
<option>--repmgrd</option>: checks whether &repmgrd; is running.
|
||||
If &repmgrd; is running but paused, status <literal>1</literal>
|
||||
(<literal>WARNING</literal>) is returned.
|
||||
</simpara>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Additional checks</title>
|
||||
<para>
|
||||
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>
|
||||
<title>Connection options</title>
|
||||
<para>
|
||||
|
||||
@@ -22,10 +22,6 @@
|
||||
This can optionally use <application>pg_rewind</application> to re-integrate
|
||||
a node which has diverged from the rest of the cluster, typically a failed primary.
|
||||
</para>
|
||||
<para>
|
||||
Note that <command>repmgr node rejoin</command> can only be used to attach
|
||||
a standby to the current primary, not another standby.
|
||||
</para>
|
||||
|
||||
<tip>
|
||||
<para>
|
||||
@@ -47,12 +43,7 @@
|
||||
<programlisting>
|
||||
repmgr node rejoin -d '$conninfo'</programlisting>
|
||||
|
||||
where <literal>$conninfo</literal> is the PostgreSQL <literal>conninfo</literal> string of the
|
||||
<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>
|
||||
where <literal>$conninfo</literal> is the conninfo string of any reachable node in the cluster.
|
||||
<filename>repmgr.conf</filename> for the stopped node *must* be supplied explicitly if not
|
||||
otherwise available.
|
||||
</para>
|
||||
@@ -73,16 +64,16 @@
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--force-rewind</option></term>
|
||||
<term><option>--force-rewind[=/path/to/pg_rewind]</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Execute <application>pg_rewind</application>.
|
||||
</para>
|
||||
<para>
|
||||
See <xref linkend="repmgr-node-rejoin-pg-rewind"/> for more details on using
|
||||
<application>pg_rewind</application>.
|
||||
It is only necessary to provide the <application>pg_rewind</application> path
|
||||
if using PostgreSQL 9.3 or 9.4, and <application>pg_rewind</application>
|
||||
is not installed in the PostgreSQL <filename>bin</filename> directory.
|
||||
</para>
|
||||
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
@@ -216,18 +207,9 @@
|
||||
a standby to the current primary, not another standby.
|
||||
</para>
|
||||
<para>
|
||||
The node's PostgreSQL instance must have been shut down cleanly. If this was not the
|
||||
case, it will need to be started up 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.
|
||||
The node must have been shut down cleanly; if this was not the case, it will
|
||||
need to be manually started (remove any existing <filename>recovery.conf</filename> file first)
|
||||
until it has reached a consistent recovery point, then shut down cleanly.
|
||||
</para>
|
||||
<tip>
|
||||
<para>
|
||||
@@ -239,14 +221,11 @@
|
||||
rm -f /var/lib/pgsql/data/recovery.conf
|
||||
postgres --single -D /var/lib/pgsql/data/ < /dev/null</programlisting>
|
||||
</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>
|
||||
|
||||
<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 id="repmgr-node-rejoin-pg-rewind" xreflabel="Using pg_rewind">
|
||||
@@ -261,6 +240,8 @@
|
||||
<para>
|
||||
<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.
|
||||
<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.3 and 9.4.
|
||||
</para>
|
||||
<note>
|
||||
<para>
|
||||
@@ -269,10 +250,6 @@
|
||||
data checksums were enabled when the cluster was initialized. See the
|
||||
<ulink url="https://www.postgresql.org/docs/current/app-pgrewind.html"><command>pg_rewind</command> documentation</ulink> for details.
|
||||
</para>
|
||||
<para>
|
||||
Additionally, <varname>full_page_writes</varname> must be enabled; this is the default and
|
||||
normally should never be disabled.
|
||||
</para>
|
||||
</note>
|
||||
|
||||
<para>
|
||||
@@ -287,7 +264,6 @@
|
||||
<programlisting>
|
||||
$ repmgr node rejoin -f /etc/repmgr.conf -d 'host=node3 dbname=repmgr user=repmgr' \
|
||||
--force-rewind --config-files=postgresql.local.conf,postgresql.conf --verbose --dry-run
|
||||
NOTICE: rejoin target is node "node3" (node ID: 3)
|
||||
INFO: replication connection to the rejoin target node was successful
|
||||
INFO: local and rejoin target system identifiers match
|
||||
DETAIL: system identifier is 6652184002263212600
|
||||
@@ -307,15 +283,7 @@
|
||||
to execute <command>pg_rewind</command> to ensure the node can be rejoined successfully.
|
||||
</para>
|
||||
|
||||
<refsect2 id="repmgr-node-rejoin-pg-rewind-config-files" xreflabel="pg_rewind and configuration files">
|
||||
|
||||
<title><command>pg_rewind</command> and configuration file retention</title>
|
||||
|
||||
<indexterm>
|
||||
<primary>pg_rewind</primary>
|
||||
<secondary>configuration file retention</secondary>
|
||||
</indexterm>
|
||||
|
||||
<important>
|
||||
<para>
|
||||
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
|
||||
@@ -323,30 +291,19 @@
|
||||
</para>
|
||||
<para>
|
||||
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
|
||||
<option>--config-archive-dir</option>, default: <filename>/tmp</filename>)
|
||||
and restored once the rewind operation is complete.
|
||||
<literal>--config-archive-dir</literal>) and restored once the rewind operation is
|
||||
complete.
|
||||
</para>
|
||||
</refsect2>
|
||||
</important>
|
||||
|
||||
<refsect2 id="repmgr-node-rejoin-pg-rewind-example" xreflabel="example using repmgr node rejoin and pg_rewind">
|
||||
|
||||
<title>Example using <command>repmgr node rejoin</command> and <command>pg_rewind</command></title>
|
||||
|
||||
<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>
|
||||
<para>
|
||||
Example, first using <literal>--dry-run</literal>, then actually executing the
|
||||
<literal>node rejoin command</literal>.
|
||||
<programlisting>
|
||||
$ repmgr node rejoin -f /etc/repmgr.conf -d 'host=node3 dbname=repmgr user=repmgr' \
|
||||
--config-files=postgresql.local.conf,postgresql.conf --verbose --force-rewind --dry-run
|
||||
NOTICE: rejoin target is node "node3" (node ID: 3)
|
||||
INFO: replication connection to the rejoin target node was successful
|
||||
INFO: local and rejoin target system identifiers match
|
||||
DETAIL: system identifier is 6652460429293670710
|
||||
@@ -360,17 +317,17 @@
|
||||
pg_rewind -D '/var/lib/postgresql/data' --source-server='host=node3 dbname=repmgr user=repmgr'
|
||||
INFO: prerequisites for executing NODE REJOIN are met</programlisting>
|
||||
|
||||
<note>
|
||||
<para>
|
||||
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
|
||||
not an absolute guarantee that actually executing <application>pg_rewind</application>
|
||||
will succeed. See also section <xref linkend="repmgr-node-rejoin-caveats"/> below.
|
||||
</para>
|
||||
<note>
|
||||
<para>
|
||||
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
|
||||
not an absolute guarantee that actually executing <application>pg_rewind</application>
|
||||
will succeed. See also section <xref linkend="repmgr-node-rejoin-caveats"/> below.
|
||||
</para>
|
||||
|
||||
</note>
|
||||
</note>
|
||||
|
||||
<programlisting>
|
||||
<programlisting>
|
||||
$ repmgr node rejoin -f /etc/repmgr.conf -d 'host=node3 dbname=repmgr user=repmgr' \
|
||||
--config-files=postgresql.local.conf,postgresql.conf --verbose --force-rewind
|
||||
NOTICE: pg_rewind execution required for this node to attach to rejoin target node 3
|
||||
@@ -382,31 +339,8 @@
|
||||
NOTICE: starting server using "pg_ctl -l /var/log/postgres/startup.log -w -D '/var/lib/pgsql/data' start"
|
||||
NOTICE: NODE REJOIN successful
|
||||
DETAIL: node 2 is now attached to node 3</programlisting>
|
||||
</para>
|
||||
</refsect2>
|
||||
</para>
|
||||
|
||||
<refsect2 id="repmgr-node-rejoin-postgresql-94" xreflabel="pg_rewind and PostgreSQL 9.4">
|
||||
|
||||
<title><command>pg_rewind</command> and PostgreSQL 9.4</title>
|
||||
|
||||
<indexterm>
|
||||
<primary>pg_rewind</primary>
|
||||
<secondary>PostgreSQL 9.4</secondary>
|
||||
</indexterm>
|
||||
|
||||
<para>
|
||||
<application>pg_rewind</application> is available in PostgreSQL 9.5 and later as part of the core distribution.
|
||||
Users of PostgreSQL 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>.
|
||||
If the <application>pg_rewind</application>
|
||||
binary is not installed in the PostgreSQL <filename>bin</filename> directory, provide
|
||||
its full path on the demotion candidate with <option>--force-rewind</option>.
|
||||
</para>
|
||||
<para>
|
||||
Note that building the 9.4 version of <application>pg_rewind</application> requires the PostgreSQL
|
||||
source code.
|
||||
</para>
|
||||
</refsect2>
|
||||
</refsect1>
|
||||
|
||||
<refsect1 id="repmgr-node-rejoin-caveats" xreflabel="Caveats">
|
||||
@@ -435,11 +369,6 @@
|
||||
the current standby's PostgreSQL log will contain entries with the text
|
||||
"<literal>record with incorrect prev-link</literal>".
|
||||
</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>
|
||||
We strongly recommend running <command>repmgr node rejoin</command> with the
|
||||
<option>--dry-run</option> option first. Additionally it might be a good idea
|
||||
@@ -449,57 +378,12 @@
|
||||
is running in <option>--dry-run</option> mode.
|
||||
</para>
|
||||
|
||||
<warning>
|
||||
<para>
|
||||
In all PostgreSQL released before February 2021, <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>
|
||||
was submitted and is included in all PostgreSQL versions released in February 2021 or later.
|
||||
</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>
|
||||
<title>See also</title>
|
||||
<para>
|
||||
<xref linkend="repmgr-standby-follow"/>, <xref linkend="repmgr-standby-switchover"/>
|
||||
<xref linkend="repmgr-standby-follow"/>
|
||||
</para>
|
||||
</refsect1>
|
||||
</refentry>
|
||||
|
||||
@@ -77,8 +77,7 @@
|
||||
</para>
|
||||
<para>
|
||||
Note that a superuser connection is required to be able to execute the
|
||||
<command>CHECKPOINT</command> command. From PostgreSQL 15 the <varname>pg_checkpoint</varname>
|
||||
predefined role removes the need for superuser permissions to perform <command>CHECKPOINT</command> command.
|
||||
<command>CHECKPOINT</command> command.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
@@ -60,17 +60,6 @@
|
||||
</listitem>
|
||||
</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>
|
||||
|
||||
</refsect1>
|
||||
|
||||
@@ -104,6 +104,14 @@
|
||||
|
||||
<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>
|
||||
<simpara><varname>primary_conninfo</varname></simpara>
|
||||
</listitem>
|
||||
@@ -114,21 +122,6 @@
|
||||
|
||||
</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>
|
||||
The following additional parameters can be specified in <filename>repmgr.conf</filename>
|
||||
for inclusion in the replication configuration:
|
||||
@@ -182,10 +175,7 @@
|
||||
<programlisting>
|
||||
pg_basebackup_options='--wal-method=fetch'</programlisting>
|
||||
|
||||
and ensure that <literal>wal_keep_segments</literal> (PostgreSQL 13 and later:
|
||||
<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.
|
||||
and ensure that <literal>wal_keep_segments</literal> is set to an appropriately high value.
|
||||
See the <ulink url="https://www.postgresql.org/docs/current/app-pgbasebackup.html">
|
||||
pg_basebackup</ulink> documentation for details.
|
||||
</para>
|
||||
@@ -198,25 +188,6 @@
|
||||
</note>
|
||||
</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 -->
|
||||
<refsect1 id="repmgr-standby-create-recovery-conf">
|
||||
|
||||
@@ -260,29 +231,16 @@ pg_basebackup_options='--waldir=/path/to/wal-directory'</programlisting>
|
||||
upstream node if required.
|
||||
</para>
|
||||
<para>
|
||||
The upstream node must be running so the correct replication configuration can be obtained.
|
||||
</para>
|
||||
<para>
|
||||
If the standby is running, the replication configuration will not be written unless the
|
||||
Note that the upstream node must be running. In PostgreSQL 11 and earlier, an existing
|
||||
<filename>recovery.conf</filename> will not be overwritten unless the
|
||||
<option>-F/--force</option> option is provided.
|
||||
</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>
|
||||
In PostgreSQL 13 and later, the PostgreSQL configuration must be reloaded for replication
|
||||
configuration changes to take effect.
|
||||
Execute <command>repmgr standby clone --replication-conf-only --dry-run</command>
|
||||
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>
|
||||
In PostgreSQL 12 and earlier, the PostgreSQL instance must be restarted for replication
|
||||
configuration changes to take effect.
|
||||
</para>
|
||||
|
||||
|
||||
</refsect1>
|
||||
|
||||
@@ -332,12 +290,6 @@ pg_basebackup_options='--waldir=/path/to/wal-directory'</programlisting>
|
||||
node to the same path on the standby (default) or to the
|
||||
PostgreSQL data directory.
|
||||
</para>
|
||||
<para>
|
||||
Note that to be able to use this option, the &repmgr; user must be a superuser or
|
||||
member of the <literal>pg_read_all_settings</literal> predefined role.
|
||||
If this is not the case, provide a valid superuser with the
|
||||
<option>-S</option>/<option>--superuser</option> option.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
@@ -350,25 +302,6 @@ pg_basebackup_options='--waldir=/path/to/wal-directory'</programlisting>
|
||||
</listitem>
|
||||
</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>
|
||||
<term><option>-R, --remote-user=USERNAME</option></term>
|
||||
<listitem>
|
||||
@@ -384,14 +317,14 @@ pg_basebackup_options='--waldir=/path/to/wal-directory'</programlisting>
|
||||
<para>
|
||||
Create recovery configuration for a previously cloned instance.
|
||||
</para>
|
||||
<para>
|
||||
In PostgreSQL 12 and later, the replication configuration will be
|
||||
written to <filename>postgresql.auto.conf</filename>.
|
||||
</para>
|
||||
<para>
|
||||
In PostgreSQL 11 and earlier, the replication configuration will be
|
||||
written to <filename>recovery.conf</filename>.
|
||||
</para>
|
||||
<para>
|
||||
In PostgreSQL 12 and later, the replication configuration will be
|
||||
written to <filename>postgresql.auto.conf</filename>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
@@ -405,15 +338,11 @@ pg_basebackup_options='--waldir=/path/to/wal-directory'</programlisting>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>-S</option>/<option>--superuser</option></term>
|
||||
<term><option>--superuser</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
The name of a valid PostgreSQL superuser can be provided with this option.
|
||||
</para>
|
||||
<para>
|
||||
This is only required if the <option>--copy-external-config-files</option> was provided
|
||||
and the &repmgr; user is not a superuser or member of the <literal>pg_read_all_settings</literal>
|
||||
predefined role.
|
||||
If the &repmgr; user is not a superuser, the name of a valid superuser must
|
||||
be provided with this option.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
@@ -441,23 +370,6 @@ pg_basebackup_options='--waldir=/path/to/wal-directory'</programlisting>
|
||||
</para>
|
||||
</listitem>
|
||||
</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>
|
||||
<term><option>--without-barman </option></term>
|
||||
<listitem>
|
||||
|
||||
@@ -47,15 +47,7 @@
|
||||
</para>
|
||||
|
||||
<para>
|
||||
In PostgreSQL 12 and earlier, 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.
|
||||
This command will force a restart of PostgreSQL on the standby node.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
|
||||
@@ -66,10 +66,10 @@
|
||||
Both values can be defined in <filename>repmgr.conf</filename>.
|
||||
</para>
|
||||
|
||||
<warning>
|
||||
<note>
|
||||
<para>
|
||||
In PostgreSQL 12 and earlier, if WAL replay is paused on the standby, and not all
|
||||
WAL files on the standby have been replayed, &repmgr; will not attempt to promote it.
|
||||
If WAL replay is paused on the standby, and not all WAL files on the standby have been
|
||||
replayed, &repmgr; will not attempt to promote it.
|
||||
</para>
|
||||
<para>
|
||||
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
|
||||
if more WAL is pending replay, and will abort the promotion attempt if WAL replay is paused.
|
||||
</para>
|
||||
<para>
|
||||
This restriction does <emphasis>not</emphasis> apply to PostgreSQL 13 and later.
|
||||
</para>
|
||||
</warning>
|
||||
</note>
|
||||
|
||||
</refsect1>
|
||||
|
||||
@@ -98,6 +95,7 @@
|
||||
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"
|
||||
server promoting
|
||||
DEBUG: setting node 2 as primary and marking existing primary as failed
|
||||
NOTICE: STANDBY PROMOTE successful
|
||||
DETAIL: server "node2" (ID: 2) was successfully promoted to primary</programlisting>
|
||||
</para>
|
||||
@@ -172,42 +170,6 @@
|
||||
</listitem>
|
||||
</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>
|
||||
</refsect1>
|
||||
|
||||
|
||||
@@ -64,13 +64,6 @@
|
||||
|
||||
<refsect1>
|
||||
<title>User permission requirements</title>
|
||||
<para><emphasis>data_directory</emphasis></para>
|
||||
<para>
|
||||
&repmgr; needs to be able to determine the location of the data directory on the
|
||||
demotion candidate. If the &repmgr; is not a superuser or member of the <varname>pg_read_all_settings</varname>
|
||||
<ulink url="https://www.postgresql.org/docs/current/predefined-roles.html">predefined roles</ulink>,
|
||||
the name of a superuser should be provided with the <option>-S</option>/<option>--superuser</option> option.
|
||||
</para>
|
||||
<para><emphasis>CHECKPOINT</emphasis></para>
|
||||
<para>
|
||||
&repmgr; executes <command>CHECKPOINT</command> on the demotion candidate as part of the shutdown
|
||||
@@ -79,8 +72,7 @@
|
||||
<para>
|
||||
Note that <command>CHECKPOINT</command> requires database superuser permissions to execute.
|
||||
If the <literal>repmgr</literal> user is not a superuser, the name of a superuser should be
|
||||
provided with the <option>-S</option>/<option>--superuser</option> option. From PostgreSQL 15 the <varname>pg_checkpoint</varname>
|
||||
predefined role removes the need for superuser permissions to perform <command>CHECKPOINT</command> command.
|
||||
provided with the <option>-S</option>/<option>--superuser</option>.
|
||||
</para>
|
||||
<para>
|
||||
If &repmgr; is unable to execute the <command>CHECKPOINT</command> command, the switchover
|
||||
@@ -155,12 +147,9 @@
|
||||
<para>
|
||||
Use <application>pg_rewind</application> to reintegrate the old primary if necessary
|
||||
(and the prerequisites for using <application>pg_rewind</application> are met).
|
||||
</para>
|
||||
<para>
|
||||
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,
|
||||
provide its full path. For more details see also <xref linkend="switchover-pg-rewind"/>
|
||||
and <xref linkend="repmgr-node-rejoin-pg-rewind"/>.
|
||||
provide its full path. For more details see also <xref linkend="switchover-pg-rewind"/>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
@@ -63,34 +63,6 @@
|
||||
</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">
|
||||
<title>Event notifications</title>
|
||||
<para>
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
<title>repmgr &repmgrversion; Documentation</title>
|
||||
|
||||
<bookinfo>
|
||||
<corpauthor>EDB</corpauthor>
|
||||
<corpauthor>2ndQuadrant Ltd</corpauthor>
|
||||
<productname>repmgr</productname>
|
||||
<productnumber>&repmgrversion;</productnumber>
|
||||
&legal;
|
||||
@@ -26,7 +26,7 @@
|
||||
<abstract>
|
||||
<para>
|
||||
This is the official documentation of &repmgr; &repmgrversion; for
|
||||
use with PostgreSQL 12 - PostgreSQL 17.
|
||||
use with PostgreSQL 9.3 - PostgreSQL 12.
|
||||
</para>
|
||||
<para>
|
||||
&repmgr; is being continually developed and we strongly recommend using the
|
||||
@@ -38,19 +38,20 @@
|
||||
|
||||
<para>
|
||||
&repmgr; is developed by
|
||||
<ulink url="https://www.enterprisedb.com/">EDB</ulink>
|
||||
<ulink url="https://2ndquadrant.com">2ndQuadrant</ulink>
|
||||
along with contributions from other individuals and organisations.
|
||||
Contributions from the community are appreciated and welcome - get
|
||||
in touch via <ulink url="https://github.com/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>.
|
||||
Multiple EDB customers contribute funding to make &repmgr; development possible.
|
||||
Multiple 2ndQuadrant customers contribute funding
|
||||
to make repmgr development possible.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
&repmgr; is fully supported by EDB's
|
||||
<ulink url="https://www.enterprisedb.com/support/postgresql-support-overview-get-the-most-out-of-postgresql">24/7 Production Support</ulink>.
|
||||
EDB, a Major Sponsor of the PostgreSQL project, continues to maintain &repmgr;.
|
||||
We welcome participation from other organisations and individual developers.
|
||||
&repmgr; is fully supported by 2ndQuadrant's
|
||||
<ulink url="https://www.2ndquadrant.com/en/support/support-postgresql/">24/7 Production Support</ulink>.
|
||||
2ndQuadrant, a Major Sponsor of the PostgreSQL project, continues to develop and maintain &repmgr;.
|
||||
Other organisations as well as individual developers are welcome to participate in the efforts.
|
||||
</para>
|
||||
</abstract>
|
||||
|
||||
|
||||
@@ -81,15 +81,11 @@
|
||||
</para>
|
||||
<note>
|
||||
<simpara>
|
||||
A PostgreSQL instance can only accommodate a single witness server.
|
||||
</simpara>
|
||||
<simpara>
|
||||
If you are planning to use a single server to support more than one
|
||||
witness server, a separate PostgreSQL instance is required for each
|
||||
witness server in use.
|
||||
&repmgr; 3.3 and earlier provided a <command>repmgr create witness</command>
|
||||
command, which would automatically create a PostgreSQL instance. However
|
||||
this often resulted in an unsatisfactory, hard-to-customise instance.
|
||||
</simpara>
|
||||
</note>
|
||||
|
||||
<para>
|
||||
The witness server should be configured in the same way as a normal
|
||||
&repmgr; node; see section <xref linkend="configuration"/>.
|
||||
@@ -279,9 +275,7 @@
|
||||
<note>
|
||||
<para>
|
||||
<option>standby_disconnect_on_failover</option> is available with PostgreSQL 9.5 and later.
|
||||
Until PostgreSQL 14 this requires that the <literal>repmgr</literal> database user is a superuser.
|
||||
From PostgreSQL 15 a specific ALTER SYSTEM privilege can be granted to the <literal>repmgr</literal> database
|
||||
user with e.g. <command>GRANT ALTER SYSTEM ON PARAMETER wal_retrieve_retry_interval TO repmgr</command>.
|
||||
Additionally this requires that the <literal>repmgr</literal> database user is a superuser.
|
||||
</para>
|
||||
</note>
|
||||
<para>
|
||||
@@ -337,12 +331,11 @@
|
||||
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.:
|
||||
<programlisting>
|
||||
failover_validation_command=/path/to/script.sh %n</programlisting>
|
||||
failover_validation_command=/path/to/script.sh %n %a</programlisting>
|
||||
</para>
|
||||
<para>
|
||||
The <literal>%n</literal> parameter will be replaced with the node ID when the script is
|
||||
executed. A number of other parameters are also available, see section
|
||||
"<xref linkend="repmgrd-automatic-failover-configuration-optional"/>" for details.
|
||||
The <literal>%n</literal> parameter will be replaced with the node ID, and the
|
||||
<literal>%a</literal> parameter will be replaced by the node name when the script is executed.
|
||||
</para>
|
||||
<para>
|
||||
This script must return an exit code of <literal>0</literal> to indicate the node should promote itself.
|
||||
@@ -592,7 +585,7 @@ INFO: node 3 received notification to rerun promotion candidate election
|
||||
<sect2 id="repmgrd-primary-child-disconnection-caveats">
|
||||
<title>Standby disconnections monitoring caveats</title>
|
||||
<para>
|
||||
The 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>
|
||||
<itemizedlist mark="bullet">
|
||||
|
||||
@@ -15,13 +15,9 @@
|
||||
</para>
|
||||
<para>
|
||||
&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.
|
||||
</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">
|
||||
<title>repmgrd configuration</title>
|
||||
@@ -89,10 +85,6 @@
|
||||
<literal>query</literal> - determines server availability
|
||||
by executing an SQL statement on the node via the existing connection
|
||||
</simpara>
|
||||
<simpara>
|
||||
The query is a minimal throwaway query - <command>SELECT 1</command> -
|
||||
which is used to determine that the server can accept queries.
|
||||
</simpara>
|
||||
</listitem>
|
||||
|
||||
</itemizedlist>
|
||||
@@ -156,7 +148,7 @@
|
||||
</variablelist>
|
||||
|
||||
<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>
|
||||
|
||||
<sect2 id="repmgrd-automatic-failover-configuration">
|
||||
@@ -329,11 +321,11 @@
|
||||
|
||||
</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>
|
||||
|
||||
<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>
|
||||
<variablelist>
|
||||
|
||||
@@ -345,18 +337,14 @@
|
||||
</indexterm>
|
||||
|
||||
<para>
|
||||
Indicates a preferred priority (default: <literal>100</literal>) for promoting nodes.
|
||||
Indicates a preferred priority (default: <literal>100</literal>) for promoting nodes;
|
||||
a value of zero prevents the node being promoted to primary.
|
||||
</para>
|
||||
<para>
|
||||
Note that the priority setting is only applied if two or more nodes are
|
||||
determined as promotion candidates; in that case the node with the
|
||||
higher priority is selected.
|
||||
</para>
|
||||
<para>
|
||||
A value of zero will always prevent the node being promoted to primary, even if there
|
||||
is no other promotion candidate.
|
||||
</para>
|
||||
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
@@ -378,8 +366,8 @@
|
||||
</para>
|
||||
</note>
|
||||
<para>
|
||||
One or more of the following parameter placeholders
|
||||
may be provided, which will be replaced by repmgrd with the appropriate
|
||||
One or both of the following parameter placeholders
|
||||
should be provided, which will be replaced by repmgrd with the appropriate
|
||||
value:
|
||||
<itemizedlist spacing="compact" mark="bullet">
|
||||
<listitem>
|
||||
@@ -388,15 +376,6 @@
|
||||
<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>
|
||||
<para>
|
||||
@@ -427,33 +406,6 @@
|
||||
</listitem>
|
||||
</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>
|
||||
|
||||
<term><option>standby_disconnect_on_failover</option></term>
|
||||
@@ -489,32 +441,6 @@
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
|
||||
<term><option>repmgrd_exit_on_inactive_node</option></term>
|
||||
<listitem>
|
||||
<indexterm>
|
||||
<primary>repmgrd_exit_on_inactive_node</primary>
|
||||
</indexterm>
|
||||
<para>
|
||||
This parameter is available in &repmgr; 5.3 and later.
|
||||
</para>
|
||||
<para>
|
||||
If a node was marked as inactive but is running, and this option is set to
|
||||
<literal>true</literal>, &repmgrd; will abort on startup.
|
||||
</para>
|
||||
<para>
|
||||
By default, <option>repmgrd_exit_on_inactive_node</option> is set
|
||||
to <literal>false</literal>, in which case &repmgrd; will set the
|
||||
node record to active on startup.
|
||||
</para>
|
||||
<para>
|
||||
Setting this parameter to <literal>true</literal> causes &repmgrd;
|
||||
to behave in the same way it did in &repmgr; 5.2 and earlier.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
|
||||
<para>
|
||||
@@ -573,7 +499,7 @@
|
||||
</indexterm>
|
||||
<para>
|
||||
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>
|
||||
</sect2>
|
||||
|
||||
@@ -657,8 +583,7 @@ repmgrd_service_stop_command='sudo systemctl repmgr12 stop'
|
||||
the option <option>monitor_interval_secs</option> (see above).
|
||||
</para>
|
||||
<para>
|
||||
For more details on monitoring, see <xref linkend="repmgrd-monitoring"/>. For information on
|
||||
monitoring standby disconnections, see <xref linkend="repmgrd-primary-child-disconnection"/>.
|
||||
For more details on monitoring, see <xref linkend="repmgrd-monitoring"/>.
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
@@ -826,12 +751,6 @@ repmgrd_service_stop_command='sudo systemctl repmgr12 stop'
|
||||
</simpara>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<simpara>
|
||||
<varname>always_promote</varname>
|
||||
</simpara>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<simpara>
|
||||
<varname>promote_command</varname>
|
||||
@@ -1003,7 +922,7 @@ repmgrd_service_stop_command='sudo systemctl repmgr12 stop'
|
||||
</para>
|
||||
<para>
|
||||
If none of the above apply, &repmgrd; will create a PID file
|
||||
in the operating system's temporary directory (as 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>).
|
||||
</para>
|
||||
<para>
|
||||
@@ -1083,29 +1002,6 @@ REPMGRD_OPTS="--daemonize=false"
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="repmgrd-daemon-monitoring">
|
||||
<title>repmgrd daemon monitoring</title>
|
||||
<indexterm>
|
||||
<primary>repmgrd</primary>
|
||||
<secondary>monitoring</secondary>
|
||||
</indexterm>
|
||||
<indexterm>
|
||||
<primary>monitoring</primary>
|
||||
<secondary>repmgrd</secondary>
|
||||
</indexterm>
|
||||
|
||||
<para>
|
||||
The command <command><link linkend="repmgr-service-status">repmgr service status</link></command>
|
||||
provides an overview of the &repmgrd; daemon status (including pause status)
|
||||
on all nodes in the cluster.
|
||||
</para>
|
||||
<para>
|
||||
From &repmgr; 5.3, <command><link linkend="repmgr-node-check">repmgr node check --repmgrd</link></command>
|
||||
can be used to check the status of &repmgrd; (including pause status)
|
||||
on the local node.
|
||||
</para>
|
||||
</sect2>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="repmgrd-connection-settings">
|
||||
|
||||
@@ -137,7 +137,7 @@ NOTICE: node 3 (node3) paused</programlisting>
|
||||
If the primary becomes available again (e.g. following a software upgrade), &repmgrd;
|
||||
will automatically reconnect, e.g.:
|
||||
<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>
|
||||
@@ -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] [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>
|
||||
|
||||
</para>
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
<listitem>
|
||||
<simpara>
|
||||
option to execute custom scripts ("<link linkend="event-notifications">event notifications</link>")
|
||||
option to execute custom scripts ("<link linkend="event-notifications">event notifications</link>
|
||||
at different points in the failover sequence
|
||||
</simpara>
|
||||
</listitem>
|
||||
|
||||
@@ -120,19 +120,16 @@
|
||||
</important>
|
||||
|
||||
<note>
|
||||
<para>
|
||||
<simpara>
|
||||
On <literal>systemd</literal> systems we strongly recommend using the appropriate
|
||||
<command>systemctl</command> commands (typically run via <command>sudo</command>) to ensure
|
||||
<literal>systemd</literal> is informed about the status of the PostgreSQL service.
|
||||
</para>
|
||||
<para>
|
||||
</simpara>
|
||||
<simpara>
|
||||
If using <command>sudo</command> for the <command>systemctl</command> calls, make sure the
|
||||
<command>sudo</command> specification doesn't require a real tty for the user. If not set
|
||||
this way, <command>repmgr</command> will fail to stop the primary.
|
||||
</para>
|
||||
<para>
|
||||
See the <xref linkend="configuration-file-service-commands"/> documentation section for further details.
|
||||
</para>
|
||||
</simpara>
|
||||
</note>
|
||||
|
||||
<para>
|
||||
@@ -242,12 +239,22 @@
|
||||
</simpara>
|
||||
</note>
|
||||
<para>
|
||||
For more details on <application>pg_rewind</application>, see section <xref linkend="repmgr-node-rejoin-pg-rewind"/>
|
||||
in the <link linkend="repmgr-node-rejoin"><command>repmgr node rejoin</command></link> documentation and
|
||||
the PostgreSQL documentation at
|
||||
For more details on <application>pg_rewind</application>, see:
|
||||
<ulink url="https://www.postgresql.org/docs/current/app-pgrewind.html">https://www.postgresql.org/docs/current/app-pgrewind.html</ulink>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<application>pg_rewind</application> has been part of the core PostgreSQL distribution since
|
||||
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>.
|
||||
If the <application>pg_rewind</application>
|
||||
binary is not installed in the PostgreSQL <filename>bin</filename> directory, provide
|
||||
its full path on the demotion candidate with <option>--force-rewind</option>.
|
||||
</para>
|
||||
<para>
|
||||
Note that building the 9.3/9.4 version of <application>pg_rewind</application> requires the PostgreSQL
|
||||
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>
|
||||
</sect2>
|
||||
|
||||
|
||||
@@ -336,7 +343,7 @@
|
||||
<itemizedlist spacing="compact" mark="bullet">
|
||||
<listitem>
|
||||
<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
|
||||
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>
|
||||
|
||||
@@ -71,12 +71,6 @@
|
||||
<secondary>minor release</secondary>
|
||||
</indexterm>
|
||||
|
||||
<para>
|
||||
A minor release upgrade involves updating &repmgr; from one minor release to another
|
||||
minor release within the same major release (e.g. <literal>5.3.1</literal> to <literal>5.3.2</literal>).
|
||||
An upgrade between minor releases of differing major releases (e.g. <literal>5.2.1</literal> to <literal>5.3.2</literal>)
|
||||
is a <link linkend="upgrading-major-version">major upgrade</link>.
|
||||
</para>
|
||||
<para>
|
||||
The process for installing minor version upgrades is quite straightforward:
|
||||
|
||||
@@ -111,17 +105,15 @@
|
||||
</para>
|
||||
|
||||
<para>
|
||||
A PostgreSQL restart is usually <emphasis>not</emphasis> required for minor version upgrades
|
||||
within the same major version (e.g. <literal>5.3.1</literal> to <literal>5.3.2</literal>).
|
||||
Be sure to check the <link linkend="appendix-release-notes">release notes</link>.
|
||||
A PostgreSQL restart is <emphasis>not</emphasis> required for minor version upgrades.
|
||||
</para>
|
||||
|
||||
<note>
|
||||
<para>
|
||||
The same &repmgr; "major version" (e.g. <literal>5.3</literal>) must be
|
||||
installed on all nodes in the replication cluster. While it's possible to have differing
|
||||
&repmgr; "minor versions" (e.g. <literal>5.3.1</literal> and <literal>5.3.2</literal>)
|
||||
on different nodes, we strongly recommend updating all nodes to the latest minor version.
|
||||
The same &repmgr; "major version" (e.g. <literal>4.2</literal>) must be
|
||||
installed on all nodes in the replication cluster. While it's possible to have differing
|
||||
&repmgr; "minor versions" (e.g. <literal>4.2.1</literal>) on different nodes,
|
||||
we strongly recommend updating all nodes to the latest minor version.
|
||||
</para>
|
||||
</note>
|
||||
|
||||
@@ -209,13 +201,9 @@ ALTER EXTENSION repmgr UPDATE</programlisting>
|
||||
</para>
|
||||
<tip>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<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.
|
||||
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.
|
||||
New PostgreSQL minor version are usually released every couple of months.
|
||||
</para>
|
||||
</tip>
|
||||
</sect2>
|
||||
@@ -320,12 +308,12 @@ ALTER EXTENSION repmgr UPDATE</programlisting>
|
||||
<orderedlist>
|
||||
<listitem>
|
||||
<simpara>
|
||||
converting the <filename>repmgr.conf</filename> configuration files
|
||||
converting the repmgr.conf configuration files
|
||||
</simpara>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<simpara>
|
||||
upgrading the repmgr schema using <command>CREATE EXTENSION</command> (PostgreSQL 12 and earlier)
|
||||
upgrading the repmgr schema using <command>CREATE EXTENSION</command>
|
||||
</simpara>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
@@ -469,31 +457,22 @@ ALTER EXTENSION repmgr UPDATE</programlisting>
|
||||
<para>
|
||||
Please note that the the conversion script will add an empty
|
||||
placeholder parameter for <varname>data_directory</varname>, which
|
||||
is a required parameter from &repmgr; 4. This must be manually modified to contain
|
||||
the correct data directory.
|
||||
is a required parameter from &repmgr; 4.
|
||||
</para>
|
||||
</sect3>
|
||||
</sect2>
|
||||
<sect2>
|
||||
<title>Upgrading the repmgr schema (PostgreSQL 12 and earlier)</title>
|
||||
<title>Upgrading the repmgr schema</title>
|
||||
<para>
|
||||
Ensure &repmgrd; is not running, or any cron jobs which execute the
|
||||
<command>repmgr</command> binary.
|
||||
</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).
|
||||
</para>
|
||||
<sect3>
|
||||
<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>
|
||||
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
|
||||
@@ -505,10 +484,10 @@ ALTER EXTENSION repmgr UPDATE</programlisting>
|
||||
<itemizedlist spacing="compact" mark="bullet">
|
||||
<listitem>
|
||||
<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>
|
||||
<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>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
@@ -522,37 +501,19 @@ ALTER EXTENSION repmgr UPDATE</programlisting>
|
||||
<para>
|
||||
In the database used by the existing &repmgr; installation, execute:
|
||||
<programlisting>
|
||||
CREATE EXTENSION repmgr FROM unpackaged</programlisting>
|
||||
CREATE EXTENSION repmgr FROM unpackaged;</programlisting>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
This will move and convert all objects from the existing schema
|
||||
into the new, standard <literal>repmgr</literal> schema.
|
||||
</para>
|
||||
<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.
|
||||
</simpara>
|
||||
</note>
|
||||
</sect3>
|
||||
</sect2>
|
||||
|
||||
<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">
|
||||
<sect3>
|
||||
<title>Re-register each node</title>
|
||||
<para>
|
||||
This is necessary to update the <literal>repmgr</literal> metadata with some additional items.
|
||||
@@ -562,10 +523,6 @@ ALTER EXTENSION repmgr UPDATE</programlisting>
|
||||
<programlisting>
|
||||
repmgr primary register -f /etc/repmgr.conf --force</programlisting>
|
||||
</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>
|
||||
On each standby node, execute e.g.
|
||||
<programlisting>
|
||||
@@ -578,20 +535,18 @@ ALTER EXTENSION repmgr UPDATE</programlisting>
|
||||
<para>
|
||||
The original <literal>repmgr_$cluster</literal> schema can be dropped at any time.
|
||||
</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 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>
|
||||
|
||||
</chapter>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* 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
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -49,6 +49,5 @@
|
||||
#define ERR_NODE_STATUS 25
|
||||
#define ERR_REPMGRD_PAUSE 26
|
||||
#define ERR_REPMGRD_SERVICE 27
|
||||
#define ERR_PGBACKUPAPI_SERVICE 28
|
||||
|
||||
#endif /* _ERRCODE_H_ */
|
||||
|
||||
2
log.c
2
log.c
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* 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
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
2
log.h
2
log.h
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* log.h
|
||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
||||
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||
*
|
||||
* 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
|
||||
|
||||
147
pgbackupapi.c
147
pgbackupapi.c
@@ -1,147 +0,0 @@
|
||||
/*
|
||||
* pgbackupapi.c
|
||||
* 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 <string.h>
|
||||
|
||||
#include <curl/curl.h>
|
||||
#include <json-c/json.h>
|
||||
|
||||
#include "repmgr.h"
|
||||
#include "pgbackupapi.h"
|
||||
|
||||
|
||||
size_t receive_operations_cb(void *content, size_t size, size_t nmemb, char *buffer) {
|
||||
short int max_chars_to_copy = MAX_BUFFER_LENGTH -2;
|
||||
short int i = 0;
|
||||
int operation_length = 0;
|
||||
json_object *value;
|
||||
|
||||
json_object *root = json_tokener_parse(content);
|
||||
json_object *operations = json_object_object_get(root, "operations");
|
||||
|
||||
operation_length = strlen(json_object_get_string(operations));
|
||||
if (operation_length < max_chars_to_copy) {
|
||||
max_chars_to_copy = operation_length;
|
||||
}
|
||||
|
||||
strncpy(buffer, json_object_get_string(operations), max_chars_to_copy);
|
||||
|
||||
fprintf(stdout, "Success! The following operations were found\n");
|
||||
for (i=0; i<json_object_array_length(operations); i++) {
|
||||
value = json_object_array_get_idx(operations, i);
|
||||
printf("%s\n", json_object_get_string(value));
|
||||
}
|
||||
return size * nmemb;
|
||||
}
|
||||
|
||||
char * define_base_url(operation_task *task) {
|
||||
char *format = "http://%s:7480/servers/%s/operations";
|
||||
char *url = malloc(MAX_BUFFER_LENGTH);
|
||||
|
||||
snprintf(url, MAX_BUFFER_LENGTH-1, format, task->host, task->node_name);
|
||||
|
||||
//`url` is freed on the function that called this
|
||||
return url;
|
||||
}
|
||||
|
||||
CURLcode get_operations_on_server(CURL *curl, operation_task *task) {
|
||||
char buffer[MAX_BUFFER_LENGTH];
|
||||
char *url = define_base_url(task);
|
||||
CURLcode ret;
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, receive_operations_cb);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buffer);
|
||||
curl_easy_setopt(curl, CURLOPT_URL, url);
|
||||
|
||||
ret = curl_easy_perform(curl);
|
||||
free(url);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
size_t receive_operation_id(void *content, size_t size, size_t nmemb, char *buffer) {
|
||||
json_object *root = json_tokener_parse(content);
|
||||
json_object *operation = json_object_object_get(root, "operation_id");
|
||||
|
||||
if (operation != NULL) {
|
||||
strncpy(buffer, json_object_get_string(operation), MAX_BUFFER_LENGTH-2);
|
||||
}
|
||||
|
||||
return size * nmemb;
|
||||
}
|
||||
|
||||
|
||||
CURLcode create_new_task(CURL *curl, operation_task *task) {
|
||||
PQExpBufferData payload;
|
||||
char *url = define_base_url(task);
|
||||
CURLcode ret;
|
||||
json_object *root = json_object_new_object();
|
||||
struct curl_slist *chunk = NULL;
|
||||
|
||||
json_object_object_add(root, "operation_type", json_object_new_string(task->operation_type));
|
||||
json_object_object_add(root, "backup_id", json_object_new_string(task->backup_id));
|
||||
json_object_object_add(root, "remote_ssh_command", json_object_new_string(task->remote_ssh_command));
|
||||
json_object_object_add(root, "destination_directory", json_object_new_string(task->destination_directory));
|
||||
|
||||
initPQExpBuffer(&payload);
|
||||
appendPQExpBufferStr(&payload, json_object_to_json_string(root));
|
||||
|
||||
chunk = curl_slist_append(chunk, "Content-type: application/json");
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk);
|
||||
curl_easy_setopt(curl, CURLOPT_URL, url);
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, payload.data);
|
||||
curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L);
|
||||
//curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, receive_operation_id);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, task->operation_id);
|
||||
ret = curl_easy_perform(curl);
|
||||
free(url);
|
||||
termPQExpBuffer(&payload);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
size_t receive_operation_status(void *content, size_t size, size_t nmemb, char *buffer) {
|
||||
json_object *root = json_tokener_parse(content);
|
||||
json_object *status = json_object_object_get(root, "status");
|
||||
if (status != NULL) {
|
||||
strncpy(buffer, json_object_get_string(status), MAX_BUFFER_LENGTH-2);
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "Incorrect reply received for that operation ID.\n");
|
||||
strcpy(buffer, "\0");
|
||||
}
|
||||
return size * nmemb;
|
||||
}
|
||||
|
||||
CURLcode get_status_of_operation(CURL *curl, operation_task *task) {
|
||||
CURLcode ret;
|
||||
char *url = define_base_url(task);
|
||||
|
||||
strcat(url, "/");
|
||||
strcat(url, task->operation_id);
|
||||
curl_easy_setopt(curl, CURLOPT_URL, url);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, receive_operation_status);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, task->operation_status);
|
||||
|
||||
ret = curl_easy_perform(curl);
|
||||
free(url);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
* pgbackupapi.h
|
||||
* 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 <curl/curl.h>
|
||||
#include <json-c/json.h>
|
||||
|
||||
typedef struct operation_task {
|
||||
char *backup_id;
|
||||
char *destination_directory;
|
||||
char *operation_type;
|
||||
char *operation_id;
|
||||
char *operation_status;
|
||||
char *remote_ssh_command;
|
||||
char *host;
|
||||
char *node_name;
|
||||
} operation_task;
|
||||
|
||||
//Default simplebuffer size in most of operations
|
||||
#define MAX_BUFFER_LENGTH 72
|
||||
|
||||
//Callbacks to send/receive data from pg-backup-api endpoints
|
||||
size_t receive_operations_cb(void *content, size_t size, size_t nmemb, char *buffer);
|
||||
size_t receive_operation_id(void *content, size_t size, size_t nmemb, char *buffer);
|
||||
size_t receive_operation_status(void *content, size_t size, size_t nmemb, char *buffer);
|
||||
|
||||
//Functions that implement the logic and know what to do and how to comunnicate wuth the API
|
||||
CURLcode get_operations_on_server(CURL *curl, operation_task *task);
|
||||
CURLcode create_new_task(CURL *curl, operation_task *task);
|
||||
CURLcode get_status_of_operation(CURL *curl, operation_task *task);
|
||||
|
||||
//Helper to make simpler to read the handler where we set the URL
|
||||
char * define_base_url(operation_task *task);
|
||||
@@ -1,10 +1,17 @@
|
||||
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
|
||||
\echo Use "ALTER EXTENSION repmgr UPDATE" to load this file. \quit
|
||||
\echo Use "CREATE EXTENSION repmgr" to load this file. \quit
|
||||
|
||||
-- This script is intentionally empty and exists to skip the CREATE FUNCTION
|
||||
-- commands contained in the 4.2--4.3 and 4.3--4.4 extension upgrade scripts,
|
||||
-- which reference C functions which no longer exist in 5.3 and later.
|
||||
--
|
||||
-- These functions will be explicitly created in the 5.2--5.3 extension
|
||||
-- upgrade step with the correct C function references.
|
||||
CREATE FUNCTION set_upstream_last_seen()
|
||||
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_wal_receiver_pid()
|
||||
RETURNS INT
|
||||
AS 'MODULE_PATHNAME', 'get_wal_receiver_pid'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
@@ -1,9 +1,19 @@
|
||||
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
|
||||
\echo Use "ALTER EXTENSION repmgr UPDATE" to load this file. \quit
|
||||
\echo Use "CREATE EXTENSION repmgr" to load this file. \quit
|
||||
|
||||
-- This script is intentionally empty and exists to skip the CREATE FUNCTION
|
||||
-- commands contained in the 4.3--4.4 extension upgrade script, which reference
|
||||
-- C functions which no longer exist in 5.3 and later.
|
||||
--
|
||||
-- These functions will be explicitly created in the 5.2--5.3 extension
|
||||
-- upgrade step with the correct C function references.
|
||||
DROP FUNCTION set_upstream_last_seen();
|
||||
|
||||
CREATE FUNCTION set_upstream_last_seen(INT)
|
||||
RETURNS VOID
|
||||
AS 'MODULE_PATHNAME', 'set_upstream_last_seen'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION get_upstream_node_id()
|
||||
RETURNS INT
|
||||
AS 'MODULE_PATHNAME', 'get_upstream_node_id'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION set_upstream_node_id(INT)
|
||||
RETURNS VOID
|
||||
AS 'MODULE_PATHNAME', 'set_upstream_node_id'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
@@ -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', '');
|
||||
|
||||
@@ -1,64 +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 OR REPLACE FUNCTION set_local_node_id(INT)
|
||||
RETURNS VOID
|
||||
AS 'MODULE_PATHNAME', 'repmgr_set_local_node_id'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE OR REPLACE FUNCTION repmgr.get_local_node_id()
|
||||
RETURNS INT
|
||||
AS 'MODULE_PATHNAME', 'repmgr_get_local_node_id'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE OR REPLACE FUNCTION standby_set_last_updated()
|
||||
RETURNS TIMESTAMP WITH TIME ZONE
|
||||
AS 'MODULE_PATHNAME', 'repmgr_standby_set_last_updated'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE OR REPLACE FUNCTION standby_get_last_updated()
|
||||
RETURNS TIMESTAMP WITH TIME ZONE
|
||||
AS 'MODULE_PATHNAME', 'repmgr_standby_get_last_updated'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE OR REPLACE FUNCTION set_upstream_last_seen(INT)
|
||||
RETURNS VOID
|
||||
AS 'MODULE_PATHNAME', 'repmgr_set_upstream_last_seen'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE OR REPLACE FUNCTION get_upstream_last_seen()
|
||||
RETURNS INT
|
||||
AS 'MODULE_PATHNAME', 'repmgr_get_upstream_last_seen'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE OR REPLACE FUNCTION get_upstream_node_id()
|
||||
RETURNS INT
|
||||
AS 'MODULE_PATHNAME', 'repmgr_get_upstream_node_id'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE OR REPLACE FUNCTION set_upstream_node_id(INT)
|
||||
RETURNS VOID
|
||||
AS 'MODULE_PATHNAME', 'repmgr_set_upstream_node_id'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
/* failover functions */
|
||||
|
||||
CREATE OR REPLACE FUNCTION notify_follow_primary(INT)
|
||||
RETURNS VOID
|
||||
AS 'MODULE_PATHNAME', 'repmgr_notify_follow_primary'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE OR REPLACE FUNCTION get_new_primary()
|
||||
RETURNS INT
|
||||
AS 'MODULE_PATHNAME', 'repmgr_get_new_primary'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE OR REPLACE FUNCTION reset_voting_status()
|
||||
RETURNS VOID
|
||||
AS 'MODULE_PATHNAME', 'repmgr_reset_voting_status'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE OR REPLACE FUNCTION get_wal_receiver_pid()
|
||||
RETURNS INT
|
||||
AS 'MODULE_PATHNAME', 'repmgr_get_wal_receiver_pid'
|
||||
LANGUAGE C STRICT;
|
||||
192
repmgr--5.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,2 +0,0 @@
|
||||
-- complain if script is sourced in psql, rather than via CREAT EXTENSION
|
||||
\echo Use "CREATE EXTENSION repmgr" to load this file. \quit
|
||||
192
repmgr--5.3.sql
192
repmgr--5.3.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', 'repmgr_set_local_node_id'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION get_local_node_id()
|
||||
RETURNS INT
|
||||
AS 'MODULE_PATHNAME', 'repmgr_get_local_node_id'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION standby_set_last_updated()
|
||||
RETURNS TIMESTAMP WITH TIME ZONE
|
||||
AS 'MODULE_PATHNAME', 'repmgr_standby_set_last_updated'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION standby_get_last_updated()
|
||||
RETURNS TIMESTAMP WITH TIME ZONE
|
||||
AS 'MODULE_PATHNAME', 'repmgr_standby_get_last_updated'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION set_upstream_last_seen(INT)
|
||||
RETURNS VOID
|
||||
AS 'MODULE_PATHNAME', 'repmgr_set_upstream_last_seen'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION get_upstream_last_seen()
|
||||
RETURNS INT
|
||||
AS 'MODULE_PATHNAME', 'repmgr_get_upstream_last_seen'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION get_upstream_node_id()
|
||||
RETURNS INT
|
||||
AS 'MODULE_PATHNAME', 'repmgr_get_upstream_node_id'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION set_upstream_node_id(INT)
|
||||
RETURNS VOID
|
||||
AS 'MODULE_PATHNAME', 'repmgr_set_upstream_node_id'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
/* failover functions */
|
||||
|
||||
CREATE FUNCTION notify_follow_primary(INT)
|
||||
RETURNS VOID
|
||||
AS 'MODULE_PATHNAME', 'repmgr_notify_follow_primary'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION get_new_primary()
|
||||
RETURNS INT
|
||||
AS 'MODULE_PATHNAME', 'repmgr_get_new_primary'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION reset_voting_status()
|
||||
RETURNS VOID
|
||||
AS 'MODULE_PATHNAME', 'repmgr_reset_voting_status'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION get_repmgrd_pid()
|
||||
RETURNS INT
|
||||
AS 'MODULE_PATHNAME', 'get_repmgrd_pid'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION get_repmgrd_pidfile()
|
||||
RETURNS TEXT
|
||||
AS 'MODULE_PATHNAME', 'get_repmgrd_pidfile'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION set_repmgrd_pid(INT, TEXT)
|
||||
RETURNS VOID
|
||||
AS 'MODULE_PATHNAME', 'set_repmgrd_pid'
|
||||
LANGUAGE C CALLED ON NULL INPUT;
|
||||
|
||||
CREATE FUNCTION repmgrd_is_running()
|
||||
RETURNS BOOL
|
||||
AS 'MODULE_PATHNAME', 'repmgrd_is_running'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION repmgrd_pause(BOOL)
|
||||
RETURNS VOID
|
||||
AS 'MODULE_PATHNAME', 'repmgrd_pause'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION repmgrd_is_paused()
|
||||
RETURNS BOOL
|
||||
AS 'MODULE_PATHNAME', 'repmgrd_is_paused'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION get_wal_receiver_pid()
|
||||
RETURNS INT
|
||||
AS 'MODULE_PATHNAME', 'repmgr_get_wal_receiver_pid'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
|
||||
|
||||
|
||||
/* views */
|
||||
|
||||
CREATE VIEW repmgr.replication_status AS
|
||||
SELECT m.primary_node_id, m.standby_node_id, n.node_name AS standby_name,
|
||||
n.type AS node_type, n.active, last_monitor_time,
|
||||
CASE WHEN n.type='standby' THEN m.last_wal_primary_location ELSE NULL END AS last_wal_primary_location,
|
||||
m.last_wal_standby_location,
|
||||
CASE WHEN n.type='standby' THEN pg_catalog.pg_size_pretty(m.replication_lag) ELSE NULL END AS replication_lag,
|
||||
CASE WHEN n.type='standby' THEN
|
||||
CASE WHEN replication_lag > 0 THEN age(now(), m.last_apply_time) ELSE '0'::INTERVAL END
|
||||
ELSE NULL
|
||||
END AS replication_time_lag,
|
||||
CASE WHEN n.type='standby' THEN pg_catalog.pg_size_pretty(m.apply_lag) ELSE NULL END AS apply_lag,
|
||||
AGE(NOW(), CASE WHEN pg_catalog.pg_is_in_recovery() THEN repmgr.standby_get_last_updated() ELSE m.last_monitor_time END) AS communication_time_lag
|
||||
FROM repmgr.monitoring_history m
|
||||
JOIN repmgr.nodes n ON m.standby_node_id = n.node_id
|
||||
WHERE (m.standby_node_id, m.last_monitor_time) IN (
|
||||
SELECT m1.standby_node_id, MAX(m1.last_monitor_time)
|
||||
FROM repmgr.monitoring_history m1 GROUP BY 1
|
||||
);
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
-- complain if script is sourced in psql, rather than via CREAT EXTENSION
|
||||
\echo Use "CREATE EXTENSION repmgr" to load this file. \quit
|
||||
192
repmgr--5.4.sql
192
repmgr--5.4.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', 'repmgr_set_local_node_id'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION get_local_node_id()
|
||||
RETURNS INT
|
||||
AS 'MODULE_PATHNAME', 'repmgr_get_local_node_id'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION standby_set_last_updated()
|
||||
RETURNS TIMESTAMP WITH TIME ZONE
|
||||
AS 'MODULE_PATHNAME', 'repmgr_standby_set_last_updated'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION standby_get_last_updated()
|
||||
RETURNS TIMESTAMP WITH TIME ZONE
|
||||
AS 'MODULE_PATHNAME', 'repmgr_standby_get_last_updated'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION set_upstream_last_seen(INT)
|
||||
RETURNS VOID
|
||||
AS 'MODULE_PATHNAME', 'repmgr_set_upstream_last_seen'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION get_upstream_last_seen()
|
||||
RETURNS INT
|
||||
AS 'MODULE_PATHNAME', 'repmgr_get_upstream_last_seen'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION get_upstream_node_id()
|
||||
RETURNS INT
|
||||
AS 'MODULE_PATHNAME', 'repmgr_get_upstream_node_id'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION set_upstream_node_id(INT)
|
||||
RETURNS VOID
|
||||
AS 'MODULE_PATHNAME', 'repmgr_set_upstream_node_id'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
/* failover functions */
|
||||
|
||||
CREATE FUNCTION notify_follow_primary(INT)
|
||||
RETURNS VOID
|
||||
AS 'MODULE_PATHNAME', 'repmgr_notify_follow_primary'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION get_new_primary()
|
||||
RETURNS INT
|
||||
AS 'MODULE_PATHNAME', 'repmgr_get_new_primary'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION reset_voting_status()
|
||||
RETURNS VOID
|
||||
AS 'MODULE_PATHNAME', 'repmgr_reset_voting_status'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION get_repmgrd_pid()
|
||||
RETURNS INT
|
||||
AS 'MODULE_PATHNAME', 'get_repmgrd_pid'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION get_repmgrd_pidfile()
|
||||
RETURNS TEXT
|
||||
AS 'MODULE_PATHNAME', 'get_repmgrd_pidfile'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION set_repmgrd_pid(INT, TEXT)
|
||||
RETURNS VOID
|
||||
AS 'MODULE_PATHNAME', 'set_repmgrd_pid'
|
||||
LANGUAGE C CALLED ON NULL INPUT;
|
||||
|
||||
CREATE FUNCTION repmgrd_is_running()
|
||||
RETURNS BOOL
|
||||
AS 'MODULE_PATHNAME', 'repmgrd_is_running'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION repmgrd_pause(BOOL)
|
||||
RETURNS VOID
|
||||
AS 'MODULE_PATHNAME', 'repmgrd_pause'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION repmgrd_is_paused()
|
||||
RETURNS BOOL
|
||||
AS 'MODULE_PATHNAME', 'repmgrd_is_paused'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION get_wal_receiver_pid()
|
||||
RETURNS INT
|
||||
AS 'MODULE_PATHNAME', 'repmgr_get_wal_receiver_pid'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
|
||||
|
||||
|
||||
/* views */
|
||||
|
||||
CREATE VIEW repmgr.replication_status AS
|
||||
SELECT m.primary_node_id, m.standby_node_id, n.node_name AS standby_name,
|
||||
n.type AS node_type, n.active, last_monitor_time,
|
||||
CASE WHEN n.type='standby' THEN m.last_wal_primary_location ELSE NULL END AS last_wal_primary_location,
|
||||
m.last_wal_standby_location,
|
||||
CASE WHEN n.type='standby' THEN pg_catalog.pg_size_pretty(m.replication_lag) ELSE NULL END AS replication_lag,
|
||||
CASE WHEN n.type='standby' THEN
|
||||
CASE WHEN replication_lag > 0 THEN age(now(), m.last_apply_time) ELSE '0'::INTERVAL END
|
||||
ELSE NULL
|
||||
END AS replication_time_lag,
|
||||
CASE WHEN n.type='standby' THEN pg_catalog.pg_size_pretty(m.apply_lag) ELSE NULL END AS apply_lag,
|
||||
AGE(NOW(), CASE WHEN pg_catalog.pg_is_in_recovery() THEN repmgr.standby_get_last_updated() ELSE m.last_monitor_time END) AS communication_time_lag
|
||||
FROM repmgr.monitoring_history m
|
||||
JOIN repmgr.nodes n ON m.standby_node_id = n.node_id
|
||||
WHERE (m.standby_node_id, m.last_monitor_time) IN (
|
||||
SELECT m1.standby_node_id, MAX(m1.last_monitor_time)
|
||||
FROM repmgr.monitoring_history m1 GROUP BY 1
|
||||
);
|
||||
|
||||
191
repmgr--5.5.sql
191
repmgr--5.5.sql
@@ -1,191 +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', 'repmgr_set_local_node_id'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION get_local_node_id()
|
||||
RETURNS INT
|
||||
AS 'MODULE_PATHNAME', 'repmgr_get_local_node_id'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION standby_set_last_updated()
|
||||
RETURNS TIMESTAMP WITH TIME ZONE
|
||||
AS 'MODULE_PATHNAME', 'repmgr_standby_set_last_updated'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION standby_get_last_updated()
|
||||
RETURNS TIMESTAMP WITH TIME ZONE
|
||||
AS 'MODULE_PATHNAME', 'repmgr_standby_get_last_updated'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION set_upstream_last_seen(INT)
|
||||
RETURNS VOID
|
||||
AS 'MODULE_PATHNAME', 'repmgr_set_upstream_last_seen'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION get_upstream_last_seen()
|
||||
RETURNS INT
|
||||
AS 'MODULE_PATHNAME', 'repmgr_get_upstream_last_seen'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION get_upstream_node_id()
|
||||
RETURNS INT
|
||||
AS 'MODULE_PATHNAME', 'repmgr_get_upstream_node_id'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION set_upstream_node_id(INT)
|
||||
RETURNS VOID
|
||||
AS 'MODULE_PATHNAME', 'repmgr_set_upstream_node_id'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
/* failover functions */
|
||||
|
||||
CREATE FUNCTION notify_follow_primary(INT)
|
||||
RETURNS VOID
|
||||
AS 'MODULE_PATHNAME', 'repmgr_notify_follow_primary'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION get_new_primary()
|
||||
RETURNS INT
|
||||
AS 'MODULE_PATHNAME', 'repmgr_get_new_primary'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION reset_voting_status()
|
||||
RETURNS VOID
|
||||
AS 'MODULE_PATHNAME', 'repmgr_reset_voting_status'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION get_repmgrd_pid()
|
||||
RETURNS INT
|
||||
AS 'MODULE_PATHNAME', 'get_repmgrd_pid'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION get_repmgrd_pidfile()
|
||||
RETURNS TEXT
|
||||
AS 'MODULE_PATHNAME', 'get_repmgrd_pidfile'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION set_repmgrd_pid(INT, TEXT)
|
||||
RETURNS VOID
|
||||
AS 'MODULE_PATHNAME', 'set_repmgrd_pid'
|
||||
LANGUAGE C CALLED ON NULL INPUT;
|
||||
|
||||
CREATE FUNCTION repmgrd_is_running()
|
||||
RETURNS BOOL
|
||||
AS 'MODULE_PATHNAME', 'repmgrd_is_running'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION repmgrd_pause(BOOL)
|
||||
RETURNS VOID
|
||||
AS 'MODULE_PATHNAME', 'repmgrd_pause'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION repmgrd_is_paused()
|
||||
RETURNS BOOL
|
||||
AS 'MODULE_PATHNAME', 'repmgrd_is_paused'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION get_wal_receiver_pid()
|
||||
RETURNS INT
|
||||
AS 'MODULE_PATHNAME', 'repmgr_get_wal_receiver_pid'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
|
||||
|
||||
|
||||
/* views */
|
||||
|
||||
CREATE VIEW repmgr.replication_status AS
|
||||
SELECT m.primary_node_id, m.standby_node_id, n.node_name AS standby_name,
|
||||
n.type AS node_type, n.active, last_monitor_time,
|
||||
CASE WHEN n.type='standby' THEN m.last_wal_primary_location ELSE NULL END AS last_wal_primary_location,
|
||||
m.last_wal_standby_location,
|
||||
CASE WHEN n.type='standby' THEN pg_catalog.pg_size_pretty(m.replication_lag) ELSE NULL END AS replication_lag,
|
||||
CASE WHEN n.type='standby' THEN
|
||||
CASE WHEN replication_lag > 0 THEN age(now(), m.last_apply_time) ELSE '0'::INTERVAL END
|
||||
ELSE NULL
|
||||
END AS replication_time_lag,
|
||||
CASE WHEN n.type='standby' THEN pg_catalog.pg_size_pretty(m.apply_lag) ELSE NULL END AS apply_lag,
|
||||
AGE(NOW(), CASE WHEN pg_catalog.pg_is_in_recovery() THEN repmgr.standby_get_last_updated() ELSE m.last_monitor_time END) AS communication_time_lag
|
||||
FROM repmgr.monitoring_history m
|
||||
JOIN repmgr.nodes n ON m.standby_node_id = n.node_id
|
||||
WHERE (m.standby_node_id, m.last_monitor_time) IN (
|
||||
SELECT m1.standby_node_id, MAX(m1.last_monitor_time)
|
||||
FROM repmgr.monitoring_history m1 GROUP BY 1
|
||||
);
|
||||
@@ -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;
|
||||
@@ -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', 'repmgr_set_local_node_id'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION get_local_node_id()
|
||||
RETURNS INT
|
||||
AS 'MODULE_PATHNAME', 'repmgr_get_local_node_id'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION standby_set_last_updated()
|
||||
RETURNS TIMESTAMP WITH TIME ZONE
|
||||
AS 'MODULE_PATHNAME', 'repmgr_standby_set_last_updated'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION standby_get_last_updated()
|
||||
RETURNS TIMESTAMP WITH TIME ZONE
|
||||
AS 'MODULE_PATHNAME', 'repmgr_standby_get_last_updated'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION set_upstream_last_seen(INT)
|
||||
RETURNS VOID
|
||||
AS 'MODULE_PATHNAME', 'repmgr_set_upstream_last_seen'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION get_upstream_last_seen()
|
||||
RETURNS INT
|
||||
AS 'MODULE_PATHNAME', 'repmgr_get_upstream_last_seen'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION get_upstream_node_id()
|
||||
RETURNS INT
|
||||
AS 'MODULE_PATHNAME', 'repmgr_get_upstream_node_id'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION set_upstream_node_id(INT)
|
||||
RETURNS VOID
|
||||
AS 'MODULE_PATHNAME', 'repmgr_set_upstream_node_id'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
/* failover functions */
|
||||
|
||||
CREATE FUNCTION notify_follow_primary(INT)
|
||||
RETURNS VOID
|
||||
AS 'MODULE_PATHNAME', 'repmgr_notify_follow_primary'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION get_new_primary()
|
||||
RETURNS INT
|
||||
AS 'MODULE_PATHNAME', 'repmgr_get_new_primary'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION reset_voting_status()
|
||||
RETURNS VOID
|
||||
AS 'MODULE_PATHNAME', 'repmgr_reset_voting_status'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION get_repmgrd_pid()
|
||||
RETURNS INT
|
||||
AS 'MODULE_PATHNAME', 'get_repmgrd_pid'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION get_repmgrd_pidfile()
|
||||
RETURNS TEXT
|
||||
AS 'MODULE_PATHNAME', 'get_repmgrd_pidfile'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION set_repmgrd_pid(INT, TEXT)
|
||||
RETURNS VOID
|
||||
AS 'MODULE_PATHNAME', 'set_repmgrd_pid'
|
||||
LANGUAGE C CALLED ON NULL INPUT;
|
||||
|
||||
CREATE FUNCTION repmgrd_is_running()
|
||||
RETURNS BOOL
|
||||
AS 'MODULE_PATHNAME', 'repmgrd_is_running'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION repmgrd_pause(BOOL)
|
||||
RETURNS VOID
|
||||
AS 'MODULE_PATHNAME', 'repmgrd_pause'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION repmgrd_is_paused()
|
||||
RETURNS BOOL
|
||||
AS 'MODULE_PATHNAME', 'repmgrd_is_paused'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION get_wal_receiver_pid()
|
||||
RETURNS INT
|
||||
AS 'MODULE_PATHNAME', 'repmgr_get_wal_receiver_pid'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
|
||||
/* views */
|
||||
|
||||
CREATE VIEW repmgr.replication_status AS
|
||||
SELECT m.primary_node_id, m.standby_node_id, n.node_name AS standby_name,
|
||||
n.type AS node_type, n.active, last_monitor_time,
|
||||
CASE WHEN n.type='standby' THEN m.last_wal_primary_location ELSE NULL END AS last_wal_primary_location,
|
||||
m.last_wal_standby_location,
|
||||
CASE WHEN n.type='standby' THEN pg_catalog.pg_size_pretty(m.replication_lag) ELSE NULL END AS replication_lag,
|
||||
CASE WHEN n.type='standby' THEN
|
||||
CASE WHEN replication_lag > 0 THEN age(now(), m.last_apply_time) ELSE '0'::INTERVAL END
|
||||
ELSE NULL
|
||||
END AS replication_time_lag,
|
||||
CASE WHEN n.type='standby' THEN pg_catalog.pg_size_pretty(m.apply_lag) ELSE NULL END AS apply_lag,
|
||||
AGE(NOW(), CASE WHEN pg_catalog.pg_is_in_recovery() THEN repmgr.standby_get_last_updated() ELSE m.last_monitor_time END) AS communication_time_lag
|
||||
FROM repmgr.monitoring_history m
|
||||
JOIN repmgr.nodes n ON m.standby_node_id = n.node_id
|
||||
WHERE (m.standby_node_id, m.last_monitor_time) IN (
|
||||
SELECT m1.standby_node_id, MAX(m1.last_monitor_time)
|
||||
FROM repmgr.monitoring_history m1 GROUP BY 1
|
||||
);
|
||||
|
||||
|
||||
|
||||
/* drop old tables */
|
||||
DROP TABLE repmgr.repl_nodes;
|
||||
DROP TABLE repmgr.repl_monitor;
|
||||
DROP TABLE repmgr.repl_events;
|
||||
|
||||
-- remove temporary table
|
||||
DROP TABLE repmgr_old_schema;
|
||||
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Implements cluster information actions for the repmgr command line utility
|
||||
*
|
||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
||||
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||
*
|
||||
* 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
|
||||
@@ -55,8 +55,10 @@ typedef enum
|
||||
struct ColHeader headers_show[SHOW_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);
|
||||
|
||||
/*
|
||||
@@ -536,6 +538,9 @@ do_cluster_crosscheck(void)
|
||||
{
|
||||
int i = 0,
|
||||
n = 0;
|
||||
char c;
|
||||
const char *node_header = "Name";
|
||||
int name_length = strlen(node_header);
|
||||
|
||||
t_node_status_cube **cube;
|
||||
|
||||
@@ -543,7 +548,7 @@ do_cluster_crosscheck(void)
|
||||
int error_code = SUCCESS;
|
||||
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)
|
||||
{
|
||||
@@ -577,56 +582,24 @@ do_cluster_crosscheck(void)
|
||||
}
|
||||
else
|
||||
{
|
||||
/* output header contains node name, node ID and one column for each node in the cluster */
|
||||
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);
|
||||
|
||||
printf("%*s | Id ", name_length, node_header);
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
maxlen_snprintf(headers_crosscheck[header_id].title, "%i", cube[i]->node_id);
|
||||
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;
|
||||
}
|
||||
printf("| %2d ", cube[i]->node_id);
|
||||
printf("\n");
|
||||
|
||||
for (i = 0; i < name_length; i++)
|
||||
printf("-");
|
||||
printf("-+----");
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
if (strlen(cube[i]->node_name) > headers_crosscheck[0].max_length)
|
||||
{
|
||||
headers_crosscheck[0].max_length = strlen(cube[i]->node_name);
|
||||
}
|
||||
}
|
||||
|
||||
print_status_header(header_count, headers_crosscheck);
|
||||
printf("+----");
|
||||
printf("\n");
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
int column_node_ix;
|
||||
|
||||
printf(" %-*s | %-*i ",
|
||||
headers_crosscheck[0].max_length,
|
||||
printf("%*s | %2d ", name_length,
|
||||
cube[i]->node_name,
|
||||
headers_crosscheck[1].max_length,
|
||||
cube[i]->node_id);
|
||||
|
||||
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 node_ix = 0;
|
||||
|
||||
char c;
|
||||
|
||||
/*
|
||||
* The value of entry (i,j) is equal to the maximum value of all
|
||||
* the (i,j,k). Indeed:
|
||||
@@ -675,14 +646,12 @@ do_cluster_crosscheck(void)
|
||||
exit(ERR_INTERNAL);
|
||||
}
|
||||
|
||||
printf("| %-*c ", headers_crosscheck[column_node_ix + 2].max_length, c);
|
||||
printf("| %c ", c);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
pfree(headers_crosscheck);
|
||||
|
||||
if (warnings.head != NULL && runtime_options.terse == false)
|
||||
{
|
||||
log_warning(_("following problems detected:"));
|
||||
@@ -739,13 +708,16 @@ do_cluster_matrix()
|
||||
j = 0,
|
||||
n = 0;
|
||||
|
||||
const char *node_header = "Name";
|
||||
int name_length = strlen(node_header);
|
||||
|
||||
t_node_matrix_rec **matrix_rec_list;
|
||||
|
||||
bool connection_error_found = false;
|
||||
int error_code = SUCCESS;
|
||||
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)
|
||||
{
|
||||
@@ -768,60 +740,27 @@ do_cluster_matrix()
|
||||
}
|
||||
else
|
||||
{
|
||||
/* output header contains node name, node ID and one column for each node in the cluster */
|
||||
struct ColHeader *headers_matrix = NULL;
|
||||
char c;
|
||||
|
||||
int header_count = n + 2;
|
||||
int header_id = 2;
|
||||
printf("%*s | Id ", name_length, node_header);
|
||||
for (i = 0; i < n; i++)
|
||||
printf("| %2d ", matrix_rec_list[i]->node_id);
|
||||
printf("\n");
|
||||
|
||||
headers_matrix = palloc0(sizeof(ColHeader) * header_count);
|
||||
|
||||
/* Initialize column headers */
|
||||
strncpy(headers_matrix[0].title, _("Name"), MAXLEN);
|
||||
strncpy(headers_matrix[1].title, _("ID"), MAXLEN);
|
||||
for (i = 0; i < name_length; i++)
|
||||
printf("-");
|
||||
printf("-+----");
|
||||
for (i = 0; i < n; i++)
|
||||
printf("+----");
|
||||
printf("\n");
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
maxlen_snprintf(headers_matrix[header_id].title, "%i", matrix_rec_list[i]->node_id);
|
||||
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,
|
||||
printf("%*s | %2d ", name_length,
|
||||
matrix_rec_list[i]->node_name,
|
||||
headers_matrix[1].max_length,
|
||||
matrix_rec_list[i]->node_id);
|
||||
for (j = 0; j < n; j++)
|
||||
{
|
||||
char c;
|
||||
|
||||
switch (matrix_rec_list[i]->node_status_list[j]->node_status)
|
||||
{
|
||||
case -2:
|
||||
@@ -839,13 +778,11 @@ do_cluster_matrix()
|
||||
exit(ERR_INTERNAL);
|
||||
}
|
||||
|
||||
printf("| %-*c ", headers_matrix[j + 2].max_length, c);
|
||||
printf("| %c ", c);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
pfree(headers_matrix);
|
||||
|
||||
if (warnings.head != NULL && runtime_options.terse == false)
|
||||
{
|
||||
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
|
||||
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;
|
||||
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 */
|
||||
for (cell = nodes.head; cell; cell = cell->next)
|
||||
{
|
||||
int name_length_cur;
|
||||
NodeInfoListCell *cell_j;
|
||||
|
||||
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,
|
||||
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);
|
||||
|
||||
j = 0;
|
||||
@@ -1132,7 +1077,7 @@ build_cluster_matrix(t_node_matrix_rec ***matrix_rec_dest, ItemList *warnings, i
|
||||
|
||||
|
||||
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;
|
||||
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)
|
||||
{
|
||||
int name_length_cur = 0;
|
||||
NodeInfoListCell *cell_i = NULL;
|
||||
|
||||
cube[h] = (t_node_status_cube *) pg_malloc(sizeof(t_node_status_cube));
|
||||
cube[h]->node_id = cell->node_info->node_id;
|
||||
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);
|
||||
|
||||
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"));
|
||||
puts("");
|
||||
|
||||
printf(_("%s home page: <%s>\n"), "repmgr", REPMGR_URL);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* 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
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* repmgr-action-daemon.c
|
||||
*
|
||||
* Implements repmgrd actions for the repmgr command line utility
|
||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
||||
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||
*
|
||||
* 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
|
||||
@@ -339,5 +339,4 @@ void do_daemon_help(void)
|
||||
|
||||
puts("");
|
||||
|
||||
printf(_("%s home page: <%s>\n"), "repmgr", REPMGR_URL);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* 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
|
||||
* 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-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
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Implements primary actions for the repmgr command line utility
|
||||
*
|
||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
||||
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||
*
|
||||
* 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
|
||||
@@ -235,38 +235,6 @@ do_primary_register(void)
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void reset_node_info(t_node_info *info)
|
||||
{
|
||||
info->node_id = NODE_NOT_FOUND;
|
||||
info->upstream_node_id = NO_UPSTREAM_NODE;
|
||||
info->type = UNKNOWN;
|
||||
info->node_name[0] = '\0';
|
||||
info->upstream_node_name[0] = '\0';
|
||||
info->conninfo[0] = '\0';
|
||||
info->repluser[0] = '\0';
|
||||
info->priority = DEFAULT_PRIORITY;
|
||||
info->active = true;
|
||||
info->slot_name[0] = '\0';
|
||||
info->config_file[0] = '\0';
|
||||
info->last_wal_receive_lsn = InvalidXLogRecPtr;
|
||||
info->node_status = NODE_STATUS_UNKNOWN;
|
||||
info->recovery_type = RECTYPE_UNKNOWN;
|
||||
info->monitoring_state = MS_NORMAL;
|
||||
info->conn = NULL;
|
||||
info->details[0] = '\0';
|
||||
info->reachable = true;
|
||||
info->attached = true;
|
||||
/* various statistics */
|
||||
info->max_wal_senders = -1;
|
||||
info->attached_wal_receivers = -1;
|
||||
info->max_replication_slots = -1;
|
||||
info->total_replication_slots = -1;
|
||||
info->active_replication_slots = -1;
|
||||
info->inactive_replication_slots = -1;
|
||||
info->replication_info = NULL;
|
||||
|
||||
strlcpy(info->location, DEFAULT_LOCATION, sizeof(info->location));
|
||||
}
|
||||
|
||||
/*
|
||||
* do_primary_unregister()
|
||||
@@ -468,7 +436,7 @@ do_primary_unregister(void)
|
||||
}
|
||||
else if (recovery_type == RECTYPE_PRIMARY)
|
||||
{
|
||||
reset_node_info(&primary_node_info);
|
||||
t_node_info primary_node_info = T_NODE_INFO_INITIALIZER;
|
||||
bool primary_record_found = false;
|
||||
|
||||
primary_record_found = get_primary_node_record(primary_conn, &primary_node_info);
|
||||
@@ -486,9 +454,9 @@ do_primary_unregister(void)
|
||||
|
||||
/*
|
||||
* 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"),
|
||||
target_node_info_ptr->node_name,
|
||||
@@ -607,5 +575,4 @@ do_primary_help(void)
|
||||
|
||||
puts("");
|
||||
|
||||
printf(_("%s home page: <%s>\n"), "repmgr", REPMGR_URL);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* 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
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* repmgr-action-service.c
|
||||
*
|
||||
* Implements repmgrd actions for the repmgr command line utility
|
||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
||||
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||
*
|
||||
* 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
|
||||
@@ -543,6 +543,4 @@ void do_service_help(void)
|
||||
puts("");
|
||||
|
||||
puts("");
|
||||
|
||||
printf(_("%s home page: <%s>\n"), "repmgr", REPMGR_URL);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* 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
|
||||
* 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
|
||||
* Copyright (c) EnterpriseDB Corporation, 2010-2021
|
||||
* Copyright (c) 2ndQuadrant, 2010-2020
|
||||
*
|
||||
* 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
|
||||
@@ -30,6 +30,6 @@ extern void do_standby_help(void);
|
||||
|
||||
extern bool do_standby_follow_internal(PGconn *primary_conn, PGconn *follow_target_conn, t_node_info *follow_target_node_record, PQExpBufferData *output, int general_error_code, int *error_code);
|
||||
|
||||
void check_pg_backupapi_standby_clone_options(void);
|
||||
|
||||
|
||||
#endif /* _REPMGR_ACTION_STANDBY_H_ */
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* 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
|
||||
* 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"));
|
||||
puts("");
|
||||
printf(_(" \"witness unregister\" unregisters a witness node.\n"));
|
||||
printf(_(" \"witness register\" unregisters a witness node.\n"));
|
||||
puts("");
|
||||
printf(_(" --dry-run check prerequisites but don't make any changes\n"));
|
||||
printf(_(" -F, --force unregister when witness node not running\n"));
|
||||
@@ -569,5 +569,5 @@ void do_witness_help(void)
|
||||
|
||||
puts("");
|
||||
|
||||
printf(_("%s home page: <%s>\n"), "repmgr", REPMGR_URL);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* 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
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* 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
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -48,7 +48,6 @@ typedef struct
|
||||
bool no_wait;
|
||||
bool compact;
|
||||
bool detail;
|
||||
bool dump_config;
|
||||
|
||||
/* logging options */
|
||||
char log_level[MAXLEN]; /* overrides setting in repmgr.conf */
|
||||
@@ -84,12 +83,11 @@ typedef struct
|
||||
bool fast_checkpoint;
|
||||
bool rsync_only;
|
||||
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 upstream_conninfo[MAXLEN];
|
||||
bool without_barman;
|
||||
bool replication_conf_only;
|
||||
bool verify_backup;
|
||||
|
||||
/* "standby clone"/"standby follow" options */
|
||||
int upstream_node_id;
|
||||
@@ -120,10 +118,8 @@ typedef struct
|
||||
bool missing_slots;
|
||||
bool has_passfile;
|
||||
bool replication_connection;
|
||||
bool repmgrd;
|
||||
bool data_directory_config;
|
||||
bool replication_config_owner;
|
||||
bool db_connection;
|
||||
|
||||
/* "node rejoin" options */
|
||||
char config_files[MAXLEN];
|
||||
@@ -144,7 +140,7 @@ typedef struct
|
||||
|
||||
/* following options for internal use */
|
||||
char config_archive_dir[MAXPGPATH];
|
||||
OutputMode output_mode; /* set through provision of --csv, --nagios or --optformat */
|
||||
OutputMode output_mode;
|
||||
bool disable_wal_receiver;
|
||||
bool enable_wal_receiver;
|
||||
} t_runtime_options;
|
||||
@@ -153,7 +149,7 @@ typedef struct
|
||||
/* configuration metadata */ \
|
||||
false, false, false, false, false, \
|
||||
/* general configuration options */ \
|
||||
"", false, false, "", -1, false, false, false, false, \
|
||||
"", false, false, "", -1, false, false, false, \
|
||||
/* logging options */ \
|
||||
"", false, false, false, false, \
|
||||
/* output options */ \
|
||||
@@ -166,7 +162,7 @@ typedef struct
|
||||
UNKNOWN_NODE_ID, "", "", UNKNOWN_NODE_ID, \
|
||||
/* "standby clone" options */ \
|
||||
false, CONFIG_FILE_SAMEPATH, false, false, false, "", "", "", \
|
||||
false, false, false, \
|
||||
false, false, \
|
||||
/* "standby clone"/"standby follow" options */ \
|
||||
NO_UPSTREAM_NODE, \
|
||||
/* "standby register" options */ \
|
||||
@@ -176,7 +172,7 @@ typedef struct
|
||||
/* "node status" options */ \
|
||||
false, \
|
||||
/* "node check" options */ \
|
||||
false, false, false, false, false, false, false, false, false, false, false, false, false, \
|
||||
false, false, false, false, false, false, false, false, false, false, false, \
|
||||
/* "node rejoin" options */ \
|
||||
"", \
|
||||
/* "node service" options */ \
|
||||
@@ -193,8 +189,7 @@ typedef struct
|
||||
typedef enum
|
||||
{
|
||||
barman,
|
||||
pg_basebackup,
|
||||
pg_backupapi
|
||||
pg_basebackup
|
||||
} standy_clone_mode;
|
||||
|
||||
typedef enum
|
||||
@@ -221,20 +216,11 @@ typedef enum
|
||||
|
||||
typedef enum
|
||||
{
|
||||
JOIN_UNKNOWN = -1,
|
||||
JOIN_SUCCESS,
|
||||
JOIN_COMMAND_FAIL,
|
||||
JOIN_FAIL_NO_PING,
|
||||
JOIN_FAIL_NO_REPLICATION
|
||||
} 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
|
||||
{
|
||||
@@ -246,17 +232,21 @@ typedef struct ColHeader
|
||||
|
||||
|
||||
|
||||
/* globally available configuration structures */
|
||||
/* global configuration structures */
|
||||
extern t_runtime_options runtime_options;
|
||||
extern t_conninfo_param_list source_conninfo;
|
||||
extern t_node_info target_node_info;
|
||||
extern t_configuration_options config_file_options;
|
||||
|
||||
t_conninfo_param_list source_conninfo;
|
||||
|
||||
|
||||
/* global variables */
|
||||
extern bool config_file_required;
|
||||
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 void check_93_config(void);
|
||||
extern bool create_repmgr_extension(PGconn *conn);
|
||||
extern int test_ssh_connection(char *host, char *remote_user);
|
||||
|
||||
@@ -267,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 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);
|
||||
|
||||
@@ -286,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 init_node_record(t_node_info *node_record);
|
||||
extern bool can_use_pg_rewind(PGconn *conn, const char *data_directory, PQExpBufferData *reason);
|
||||
extern void make_standby_signal_path(const char *data_dir, char *buf);
|
||||
extern bool write_standby_signal(const char *data_dir);
|
||||
|
||||
extern bool create_replication_slot(PGconn *conn, char *slot_name, t_node_info *upstream_node_record, PQExpBufferData *error_msg);
|
||||
extern bool drop_replication_slot_if_exists(PGconn *conn, int node_id, char *slot_name);
|
||||
|
||||
627
repmgr-client.c
627
repmgr-client.c
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* 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
|
||||
* hot standby servers for an HA environment
|
||||
@@ -51,7 +51,6 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <pwd.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <signal.h>
|
||||
@@ -70,23 +69,21 @@
|
||||
#include "repmgr-action-service.h"
|
||||
#include "repmgr-action-daemon.h"
|
||||
|
||||
#if (PG_VERSION_NUM >= 170000)
|
||||
#include <common/file_utils.h> /* for PG_TEMP_FILE_PREFIX */
|
||||
#else
|
||||
#include <storage/fd.h> /* for PG_TEMP_FILE_PREFIX */
|
||||
#endif
|
||||
|
||||
/* globally available variables *
|
||||
* ============================ */
|
||||
|
||||
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 */
|
||||
t_conninfo_param_list source_conninfo = T_CONNINFO_PARAM_LIST_INITIALIZER;
|
||||
|
||||
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
|
||||
@@ -94,22 +91,17 @@ char pg_bindir[MAXPGPATH] = "";
|
||||
*/
|
||||
t_node_info target_node_info = T_NODE_INFO_INITIALIZER;
|
||||
|
||||
/* set by the first call to _determine_replication_slot_user() */
|
||||
/* used by create_replication_slot() */
|
||||
static t_user_type ReplicationSlotUser = USER_TYPE_UNKNOWN;
|
||||
|
||||
/* Collate command line errors and warnings here for friendlier reporting */
|
||||
static ItemList cli_errors = {NULL, NULL};
|
||||
static ItemList cli_warnings = {NULL, NULL};
|
||||
|
||||
|
||||
static void _determine_replication_slot_user(PGconn *conn,
|
||||
t_node_info *upstream_node_record,
|
||||
char **replication_user);
|
||||
|
||||
static PGconn *_get_replication_slot_connection(PGconn *conn,
|
||||
char *replication_user,
|
||||
bool *use_replication_protocol);
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
@@ -132,7 +124,7 @@ main(int argc, char **argv)
|
||||
/*
|
||||
* Tell the logger we're a command-line program - this will ensure any
|
||||
* output logged before the logger is initialized will be formatted
|
||||
* correctly. Can be overridden with "--log-to-file".
|
||||
* correctly. Can be overriden with "--log-to-file".
|
||||
*/
|
||||
logger_output_mode = OM_COMMAND_LINE;
|
||||
|
||||
@@ -287,11 +279,6 @@ main(int argc, char **argv)
|
||||
runtime_options.detail = true;
|
||||
break;
|
||||
|
||||
/* --dump-config */
|
||||
case OPT_DUMP_CONFIG:
|
||||
runtime_options.dump_config = true;
|
||||
break;
|
||||
|
||||
/*----------------------------
|
||||
* database connection options
|
||||
*----------------------------
|
||||
@@ -448,15 +435,6 @@ main(int argc, char **argv)
|
||||
runtime_options.replication_conf_only = true;
|
||||
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
|
||||
@@ -559,18 +537,10 @@ main(int argc, char **argv)
|
||||
runtime_options.data_directory_config = true;
|
||||
break;
|
||||
|
||||
case OPT_REPMGRD:
|
||||
runtime_options.repmgrd = true;
|
||||
break;
|
||||
|
||||
case OPT_REPLICATION_CONFIG_OWNER:
|
||||
runtime_options.replication_config_owner = true;
|
||||
break;
|
||||
|
||||
case OPT_DB_CONNECTION:
|
||||
runtime_options.db_connection = true;
|
||||
break;
|
||||
|
||||
/*--------------------
|
||||
* "node rejoin" options
|
||||
*--------------------
|
||||
@@ -731,12 +701,9 @@ main(int argc, char **argv)
|
||||
if (strcmp(argv[optind - 1], "-?") == 0)
|
||||
{
|
||||
help_option = true;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
option_error_found = true;
|
||||
}
|
||||
break;
|
||||
/* otherwise fall through to default */
|
||||
default: /* invalid option */
|
||||
option_error_found = true;
|
||||
break;
|
||||
@@ -1106,43 +1073,11 @@ main(int argc, char **argv)
|
||||
load_config(runtime_options.config_file,
|
||||
runtime_options.verbose,
|
||||
runtime_options.terse,
|
||||
&config_file_options,
|
||||
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);
|
||||
|
||||
|
||||
/*
|
||||
* 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
|
||||
* errors will be runtime ones
|
||||
@@ -1203,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
|
||||
* =====================================================================
|
||||
*/
|
||||
@@ -1261,7 +1196,7 @@ main(int argc, char **argv)
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
if (runtime_options.dry_run == true)
|
||||
@@ -1279,6 +1214,8 @@ main(int argc, char **argv)
|
||||
logger_set_level(LOG_ERROR);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Node configuration information is not needed for all actions, with
|
||||
* STANDBY CLONE being the main exception.
|
||||
@@ -2353,7 +2290,7 @@ format_node_status(t_node_info *node_info, PQExpBufferData *node_status, PQExpBu
|
||||
node_info->node_id);
|
||||
}
|
||||
/* 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, "! ");
|
||||
|
||||
@@ -2414,7 +2351,6 @@ format_node_status(t_node_info *node_info, PQExpBufferData *node_status, PQExpBu
|
||||
* connected to the upstream
|
||||
*/
|
||||
NodeAttached attached_to_upstream = NODE_ATTACHED_UNKNOWN;
|
||||
char *replication_state = NULL;
|
||||
t_node_info upstream_node_rec = T_NODE_INFO_INITIALIZER;
|
||||
RecordStatus upstream_node_rec_found = get_node_record(node_info->conn,
|
||||
node_info->upstream_node_id,
|
||||
@@ -2442,7 +2378,7 @@ format_node_status(t_node_info *node_info, PQExpBufferData *node_status, PQExpBu
|
||||
}
|
||||
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);
|
||||
@@ -2458,18 +2394,6 @@ format_node_status(t_node_info *node_info, PQExpBufferData *node_status, PQExpBu
|
||||
upstream_node_rec.node_name,
|
||||
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)
|
||||
{
|
||||
appendPQExpBufferStr(upstream, "! ");
|
||||
@@ -2738,8 +2662,6 @@ do_help(void)
|
||||
printf(_(" -v, --verbose display additional log output (useful for debugging)\n"));
|
||||
|
||||
puts("");
|
||||
|
||||
printf(_("%s home page: <%s>\n"), "repmgr", REPMGR_URL);
|
||||
}
|
||||
|
||||
|
||||
@@ -2749,7 +2671,7 @@ do_help(void)
|
||||
*
|
||||
* Note:
|
||||
* 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.
|
||||
*/
|
||||
|
||||
@@ -2784,7 +2706,7 @@ create_repmgr_extension(PGconn *conn)
|
||||
log_detail(_("version %s is installed but newer version %s is available"),
|
||||
extversions.installed_version,
|
||||
extversions.default_version);
|
||||
log_hint(_("update the installed extension version by executing \"ALTER EXTENSION repmgr UPDATE\" in the repmgr database"));
|
||||
log_hint(_("update the installed extension version by executing \"ALTER EXTENSION repmgr UPDATE\""));
|
||||
return false;
|
||||
|
||||
case REPMGR_INSTALLED:
|
||||
@@ -2950,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
|
||||
* 12 and later due to recovery.conf removal), set MAX_UNSUPPORTED_VERSION and
|
||||
* MAX_UNSUPPORTED_VERSION_NUM in "repmgr.h" to define the first PostgreSQL
|
||||
* version which can't be supported.
|
||||
* version which can't be suppored.
|
||||
*/
|
||||
#ifdef MAX_UNSUPPORTED_VERSION_NUM
|
||||
if (conn_server_version_num >= MAX_UNSUPPORTED_VERSION_NUM)
|
||||
@@ -2981,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
|
||||
test_ssh_connection(char *host, char *remote_user)
|
||||
{
|
||||
@@ -3093,6 +3039,7 @@ get_superuser_connection(PGconn **conn, PGconn **superuser_conn, PGconn **privil
|
||||
}
|
||||
|
||||
|
||||
|
||||
standy_clone_mode
|
||||
get_standby_clone_mode(void)
|
||||
{
|
||||
@@ -3100,23 +3047,19 @@ get_standby_clone_mode(void)
|
||||
|
||||
if (*config_file_options.barman_host != '\0' && runtime_options.without_barman == false)
|
||||
mode = barman;
|
||||
else {
|
||||
if (*config_file_options.pg_backupapi_host != '\0') {
|
||||
log_info("Attempting to use `pg_backupapi` new restore mode");
|
||||
mode = pg_backupapi;
|
||||
}
|
||||
else
|
||||
mode = pg_basebackup;
|
||||
}
|
||||
else
|
||||
mode = pg_basebackup;
|
||||
|
||||
return mode;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
make_pg_path(PQExpBufferData *buf, const char *file)
|
||||
char *
|
||||
make_pg_path(const char *file)
|
||||
{
|
||||
appendPQExpBuffer(buf, "%s%s",
|
||||
pg_bindir, file);
|
||||
maxlen_snprintf(path_buf, "%s%s", pg_bindir, file);
|
||||
|
||||
return path_buf;
|
||||
}
|
||||
|
||||
|
||||
@@ -3177,12 +3120,15 @@ copy_remote_files(char *host, char *remote_user, char *remote_path,
|
||||
appendPQExpBufferStr(&rsync_flags,
|
||||
" --exclude=recovery.conf --exclude=recovery.done");
|
||||
|
||||
/*
|
||||
* Ideally we'd use PG_AUTOCONF_FILENAME from utils/guc.h, but
|
||||
* that has too many dependencies for a mere client program.
|
||||
*/
|
||||
appendPQExpBuffer(&rsync_flags, " --exclude=%s.tmp",
|
||||
PG_AUTOCONF_FILENAME);
|
||||
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.
|
||||
*/
|
||||
appendPQExpBuffer(&rsync_flags, " --exclude=%s.tmp",
|
||||
PG_AUTOCONF_FILENAME);
|
||||
}
|
||||
|
||||
/* Temporary files which we don't want, if they exist */
|
||||
appendPQExpBuffer(&rsync_flags, " --exclude=%s*",
|
||||
@@ -3193,21 +3139,16 @@ copy_remote_files(char *host, char *remote_user, char *remote_path,
|
||||
if (server_version_num >= 100000)
|
||||
{
|
||||
appendPQExpBufferStr(&rsync_flags,
|
||||
" --exclude=pg_wal/* --exclude=log/*");
|
||||
" --exclude=pg_wal/*");
|
||||
}
|
||||
else
|
||||
{
|
||||
appendPQExpBufferStr(&rsync_flags,
|
||||
" --exclude=pg_xlog/* --exclude=pg_log/*");
|
||||
" --exclude=pg_xlog/*");
|
||||
}
|
||||
|
||||
/*
|
||||
* From PostgreSQL 15, the core server no longer uses pg_stat_tmp,
|
||||
* but some extensions (e.g. pg_stat_statements) may still do, so
|
||||
* keep excluding it.
|
||||
*/
|
||||
appendPQExpBufferStr(&rsync_flags,
|
||||
" --exclude=pg_stat_tmp/*");
|
||||
" --exclude=pg_log/* --exclude=pg_stat_tmp/*");
|
||||
|
||||
maxlen_snprintf(script, "rsync %s %s:%s/* %s",
|
||||
rsync_flags.data, host_string, remote_path, local_path);
|
||||
@@ -3334,10 +3275,9 @@ get_server_action(t_server_action action, char *script, char *data_dir)
|
||||
{
|
||||
initPQExpBuffer(&command);
|
||||
|
||||
make_pg_path(&command, "pg_ctl");
|
||||
|
||||
appendPQExpBuffer(&command,
|
||||
" %s -w -D ",
|
||||
"%s %s -w -D ",
|
||||
make_pg_path("pg_ctl"),
|
||||
config_file_options.pg_ctl_options);
|
||||
|
||||
appendShellString(&command,
|
||||
@@ -3365,10 +3305,9 @@ get_server_action(t_server_action action, char *script, char *data_dir)
|
||||
else
|
||||
{
|
||||
initPQExpBuffer(&command);
|
||||
make_pg_path(&command, "pg_ctl");
|
||||
|
||||
appendPQExpBuffer(&command,
|
||||
" %s -D ",
|
||||
"%s %s -D ",
|
||||
make_pg_path("pg_ctl"),
|
||||
config_file_options.pg_ctl_options);
|
||||
|
||||
appendShellString(&command,
|
||||
@@ -3401,11 +3340,9 @@ get_server_action(t_server_action action, char *script, char *data_dir)
|
||||
else
|
||||
{
|
||||
initPQExpBuffer(&command);
|
||||
|
||||
make_pg_path(&command, "pg_ctl");
|
||||
|
||||
appendPQExpBuffer(&command,
|
||||
" %s -w -D ",
|
||||
"%s %s -w -D ",
|
||||
make_pg_path("pg_ctl"),
|
||||
config_file_options.pg_ctl_options);
|
||||
|
||||
appendShellString(&command,
|
||||
@@ -3431,11 +3368,9 @@ get_server_action(t_server_action action, char *script, char *data_dir)
|
||||
else
|
||||
{
|
||||
initPQExpBuffer(&command);
|
||||
|
||||
make_pg_path(&command, "pg_ctl");
|
||||
|
||||
appendPQExpBuffer(&command,
|
||||
" %s -w -D ",
|
||||
"%s %s -w -D ",
|
||||
make_pg_path("pg_ctl"),
|
||||
config_file_options.pg_ctl_options);
|
||||
|
||||
appendShellString(&command,
|
||||
@@ -3462,11 +3397,9 @@ get_server_action(t_server_action action, char *script, char *data_dir)
|
||||
else
|
||||
{
|
||||
initPQExpBuffer(&command);
|
||||
|
||||
make_pg_path(&command, "pg_ctl");
|
||||
|
||||
appendPQExpBuffer(&command,
|
||||
" %s -w -D ",
|
||||
"%s %s -w -D ",
|
||||
make_pg_path("pg_ctl"),
|
||||
config_file_options.pg_ctl_options);
|
||||
|
||||
appendShellString(&command,
|
||||
@@ -3640,11 +3573,32 @@ can_use_pg_rewind(PGconn *conn, const char *data_directory, PQExpBufferData *rea
|
||||
{
|
||||
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 */
|
||||
if (guc_set(conn, "full_page_writes", "=", "off"))
|
||||
{
|
||||
appendPQExpBufferStr(reason,
|
||||
_("\"full_page_writes\" must be set to \"on\""));
|
||||
appendPQExpBuffer(reason,
|
||||
_("\"full_page_writes\" must be set to \"on\""));
|
||||
|
||||
can_use = false;
|
||||
}
|
||||
@@ -3659,21 +3613,21 @@ can_use_pg_rewind(PGconn *conn, const char *data_directory, PQExpBufferData *rea
|
||||
{
|
||||
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)
|
||||
appendPQExpBufferStr(reason, "; ");
|
||||
appendPQExpBuffer(reason, "; ");
|
||||
|
||||
appendPQExpBufferStr(reason,
|
||||
_("\"wal_log_hints\" is set to \"off\" but unable to determine data checksum version"));
|
||||
appendPQExpBuffer(reason,
|
||||
_("\"wal_log_hints\" is set to \"off\" but unable to determine data checksum version"));
|
||||
can_use = false;
|
||||
}
|
||||
else if (data_checksum_version == 0)
|
||||
{
|
||||
if (can_use == false)
|
||||
appendPQExpBufferStr(reason, "; ");
|
||||
appendPQExpBuffer(reason, "; ");
|
||||
|
||||
appendPQExpBufferStr(reason,
|
||||
appendPQExpBuffer(reason,
|
||||
_("\"wal_log_hints\" is set to \"off\" and data checksums are disabled"));
|
||||
|
||||
can_use = false;
|
||||
@@ -3684,66 +3638,8 @@ can_use_pg_rewind(PGconn *conn, const char *data_directory, PQExpBufferData *rea
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
make_standby_signal_path(const char *data_dir, char *buf)
|
||||
{
|
||||
snprintf(buf, MAXPGPATH,
|
||||
"%s/%s",
|
||||
data_dir,
|
||||
STANDBY_SIGNAL_FILE);
|
||||
}
|
||||
|
||||
/*
|
||||
* create standby.signal (PostgreSQL 12 and later)
|
||||
*/
|
||||
bool
|
||||
write_standby_signal(const char *data_dir)
|
||||
{
|
||||
char standby_signal_file_path[MAXPGPATH] = "";
|
||||
FILE *file;
|
||||
mode_t um;
|
||||
|
||||
Assert(data_dir != NULL);
|
||||
|
||||
make_standby_signal_path(data_dir, standby_signal_file_path);
|
||||
|
||||
/* Set umask to 0600 */
|
||||
um = umask((~(S_IRUSR | S_IWUSR)) & (S_IRWXG | S_IRWXO));
|
||||
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
|
||||
*/
|
||||
// provided connection should be for the normal repmgr user
|
||||
// upstream_node_record may be NULL or initialised to default values
|
||||
bool
|
||||
create_replication_slot(PGconn *conn, char *slot_name, t_node_info *upstream_node_record, PQExpBufferData *error_msg)
|
||||
{
|
||||
@@ -3753,7 +3649,6 @@ create_replication_slot(PGconn *conn, char *slot_name, t_node_info *upstream_nod
|
||||
char *replication_user = NULL;
|
||||
|
||||
_determine_replication_slot_user(conn, upstream_node_record, &replication_user);
|
||||
|
||||
/*
|
||||
* If called in --dry-run context, if the replication slot user is not the
|
||||
* repmgr user, attempt to validate the connection.
|
||||
@@ -3765,7 +3660,7 @@ create_replication_slot(PGconn *conn, char *slot_name, t_node_info *upstream_nod
|
||||
case USER_TYPE_UNKNOWN:
|
||||
log_error("unable to determine user for replication slot creation");
|
||||
return false;
|
||||
case REPMGR_USER:
|
||||
case REPMGR_USER:
|
||||
log_info(_("replication slots will be created by user \"%s\""),
|
||||
PQuser(conn));
|
||||
return true;
|
||||
@@ -3811,12 +3706,65 @@ create_replication_slot(PGconn *conn, char *slot_name, t_node_info *upstream_nod
|
||||
PQfinish(superuser_conn);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
slot_conn = _get_replication_slot_connection(conn, replication_user, &use_replication_protocol);
|
||||
/*
|
||||
* If we can't create a replication slot with the connection provided to
|
||||
* the function, create an connection with appropriate permissions.
|
||||
*/
|
||||
switch (ReplicationSlotUser)
|
||||
{
|
||||
case USER_TYPE_UNKNOWN:
|
||||
log_error("unable to determine user for replication slot creation");
|
||||
return false;
|
||||
case REPMGR_USER:
|
||||
slot_conn = conn;
|
||||
log_info(_("creating replication slot as user \"%s\""),
|
||||
PQuser(conn));
|
||||
break;
|
||||
|
||||
if (slot_conn == NULL)
|
||||
return false;
|
||||
case REPLICATION_USER_NODE:
|
||||
case REPLICATION_USER_OPT:
|
||||
{
|
||||
slot_conn = duplicate_connection(conn,
|
||||
replication_user,
|
||||
true);
|
||||
if (slot_conn == NULL || PQstatus(slot_conn) != CONNECTION_OK)
|
||||
{
|
||||
log_error(_("unable to create replication connection as user \"%s\""),
|
||||
runtime_options.replication_user);
|
||||
log_detail("%s", PQerrorMessage(slot_conn));
|
||||
|
||||
PQfinish(slot_conn);
|
||||
return false;
|
||||
}
|
||||
use_replication_protocol = true;
|
||||
log_info(_("creating replication slot as replication user \"%s\""),
|
||||
replication_user);
|
||||
}
|
||||
break;
|
||||
|
||||
case SUPERUSER:
|
||||
{
|
||||
slot_conn = duplicate_connection(conn,
|
||||
runtime_options.superuser,
|
||||
false);
|
||||
if (slot_conn == NULL || PQstatus(slot_conn )!= CONNECTION_OK)
|
||||
{
|
||||
log_error(_("unable to create super connection as user \"%s\""),
|
||||
runtime_options.superuser);
|
||||
log_detail("%s", PQerrorMessage(slot_conn));
|
||||
|
||||
PQfinish(slot_conn);
|
||||
|
||||
return false;
|
||||
}
|
||||
log_info(_("creating replication slot as superuser \"%s\""),
|
||||
runtime_options.superuser);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (use_replication_protocol == true)
|
||||
{
|
||||
@@ -3859,53 +3807,34 @@ drop_replication_slot_if_exists(PGconn *conn, int node_id, char *slot_name)
|
||||
|
||||
if (record_status != RECORD_FOUND)
|
||||
{
|
||||
/* no slot, no problem */
|
||||
/* this is not a bad good thing */
|
||||
log_verbose(LOG_INFO,
|
||||
_("slot \"%s\" does not exist on node %i, nothing to remove"),
|
||||
slot_name, node_id);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (slot_info.active == true)
|
||||
if (slot_info.active == false)
|
||||
{
|
||||
/*
|
||||
* If an active replication slot exists, bail out as we have a problem
|
||||
* we can't solve here.
|
||||
*/
|
||||
log_warning(_("replication slot \"%s\" is still active on node %i"), slot_name, node_id);
|
||||
success = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* Create the appropriate connection with which to drop the slot
|
||||
*/
|
||||
|
||||
bool use_replication_protocol = false;
|
||||
PGconn *slot_conn = _get_replication_slot_connection(conn,
|
||||
replication_user,
|
||||
&use_replication_protocol);
|
||||
|
||||
if (use_replication_protocol == true)
|
||||
{
|
||||
success = drop_replication_slot_replprot(slot_conn, slot_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
success = drop_replication_slot_sql(slot_conn, slot_name);
|
||||
}
|
||||
|
||||
if (success == true)
|
||||
if (drop_replication_slot_sql(conn, slot_name) == true)
|
||||
{
|
||||
log_notice(_("replication slot \"%s\" deleted on node %i"), slot_name, node_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
log_error(_("unable to delete replication slot \"%s\" on node %i"), slot_name, node_id);
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (slot_conn != conn)
|
||||
PQfinish(slot_conn);
|
||||
/*
|
||||
* If an active replication slot exists, call Houston as we have a
|
||||
* problem.
|
||||
*/
|
||||
else
|
||||
{
|
||||
log_warning(_("replication slot \"%s\" is still active on node %i"), slot_name, node_id);
|
||||
success = false;
|
||||
}
|
||||
|
||||
return success;
|
||||
@@ -3967,88 +3896,10 @@ _determine_replication_slot_user(PGconn *conn, t_node_info *upstream_node_record
|
||||
ReplicationSlotUser = REPLICATION_USER_NODE;
|
||||
*replication_user = upstream_node_record->repluser;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* This should never happen */
|
||||
log_error("unable to determine replication slot user");
|
||||
if (upstream_node_record != NULL)
|
||||
{
|
||||
log_debug("%i %s %s", upstream_node_record->node_id, upstream_node_record->repluser, PQuser(conn));
|
||||
}
|
||||
else
|
||||
{
|
||||
log_debug("upstream_node_record not provided");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static PGconn *
|
||||
_get_replication_slot_connection(PGconn *conn, char *replication_user, bool *use_replication_protocol)
|
||||
{
|
||||
PGconn *slot_conn = NULL;
|
||||
/*
|
||||
* If we can't create a replication slot with the connection provided to
|
||||
* the function, create an connection with appropriate permissions.
|
||||
*/
|
||||
switch (ReplicationSlotUser)
|
||||
{
|
||||
case USER_TYPE_UNKNOWN:
|
||||
log_error("unable to determine user for managing replication slots");
|
||||
return NULL;
|
||||
|
||||
case REPMGR_USER:
|
||||
slot_conn = conn;
|
||||
log_verbose(LOG_INFO, _("managing replication slot as user \"%s\""),
|
||||
PQuser(conn));
|
||||
break;
|
||||
|
||||
case REPLICATION_USER_NODE:
|
||||
case REPLICATION_USER_OPT:
|
||||
{
|
||||
slot_conn = duplicate_connection(conn,
|
||||
replication_user,
|
||||
true);
|
||||
if (slot_conn == NULL || PQstatus(slot_conn) != CONNECTION_OK)
|
||||
{
|
||||
log_error(_("unable to manage replication connection as replication user \"%s\""),
|
||||
runtime_options.replication_user);
|
||||
log_detail("%s", PQerrorMessage(slot_conn));
|
||||
|
||||
PQfinish(slot_conn);
|
||||
return NULL;
|
||||
}
|
||||
*use_replication_protocol = true;
|
||||
log_verbose(LOG_INFO, _("managing replication slot as replication user \"%s\""),
|
||||
replication_user);
|
||||
}
|
||||
break;
|
||||
|
||||
case SUPERUSER:
|
||||
{
|
||||
slot_conn = duplicate_connection(conn,
|
||||
runtime_options.superuser,
|
||||
false);
|
||||
if (slot_conn == NULL || PQstatus(slot_conn )!= CONNECTION_OK)
|
||||
{
|
||||
log_error(_("unable to create superuser connection as user \"%s\""),
|
||||
runtime_options.superuser);
|
||||
log_detail("%s", PQerrorMessage(slot_conn));
|
||||
|
||||
PQfinish(slot_conn);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
log_verbose(LOG_INFO, _("creating replication slot as superuser \"%s\""),
|
||||
runtime_options.superuser);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return slot_conn;
|
||||
}
|
||||
|
||||
bool
|
||||
check_replication_slots_available(int node_id, PGconn* conn)
|
||||
{
|
||||
@@ -4135,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++)
|
||||
{
|
||||
char *node_state = NULL;
|
||||
NodeAttached node_attached = is_downstream_node_attached(upstream_conn,
|
||||
standby_node_record->node_name,
|
||||
&node_state);
|
||||
standby_node_record->node_name);
|
||||
if (node_attached == NODE_ATTACHED)
|
||||
{
|
||||
log_verbose(LOG_INFO, _("node \"%s\" (ID: %i) has attached to its upstream node"),
|
||||
@@ -4155,19 +4004,9 @@ check_standby_join(PGconn *upstream_conn, t_node_info *upstream_node_record, t_n
|
||||
i + 1,
|
||||
config_file_options.node_rejoin_timeout);
|
||||
|
||||
if (node_attached == NODE_NOT_ATTACHED)
|
||||
{
|
||||
log_detail(_("node \"%s\" (ID: %i) is currently attached to its upstream node in state \"%s\""),
|
||||
upstream_node_record->node_name,
|
||||
standby_node_record->node_id,
|
||||
node_state);
|
||||
}
|
||||
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);
|
||||
}
|
||||
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
|
||||
{
|
||||
@@ -4187,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
|
||||
* can actually be followed or rejoined.
|
||||
* can actually be followed.
|
||||
*
|
||||
* See also comment for check_node_can_follow() in repmgrd-physical.c .
|
||||
*/
|
||||
@@ -4227,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);
|
||||
|
||||
/*
|
||||
* 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 (local_system_identifier == UNKNOWN_SYSTEM_IDENTIFIER)
|
||||
if (follow_target_identification.system_identifier != local_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_detail(_("this node's system identifier is %lu, %s target node's system identifier is %lu"),
|
||||
local_system_identifier,
|
||||
@@ -4260,7 +4078,8 @@ check_node_can_attach(TimeLineID local_tli, XLogRecPtr local_xlogpos, PGconn *fo
|
||||
PQfinish(follow_target_repl_conn);
|
||||
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_detail(_("system identifier is %lu"), local_system_identifier);
|
||||
@@ -4273,64 +4092,20 @@ check_node_can_attach(TimeLineID local_tli, XLogRecPtr local_xlogpos, PGconn *fo
|
||||
action,
|
||||
follow_target_identification.timeline);
|
||||
|
||||
/*
|
||||
* The upstream's timeline is lower than ours - we cannot follow, and rejoin
|
||||
* requires PostgreSQL 9.6 and later.
|
||||
*/
|
||||
/* upstream's timeline is lower than ours - impossible case */
|
||||
if (follow_target_identification.timeline < local_tli)
|
||||
{
|
||||
/*
|
||||
* "repmgr standby follow" is impossible in this case
|
||||
*/
|
||||
if (is_rejoin == false)
|
||||
{
|
||||
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 (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;
|
||||
}
|
||||
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);
|
||||
PQfinish(follow_target_repl_conn);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
@@ -4351,26 +4126,12 @@ check_node_can_attach(TimeLineID local_tli, XLogRecPtr local_xlogpos, PGconn *fo
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* 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_error(_("this node is ahead of the %s target"), action);
|
||||
log_detail(_("local node lsn is %X/%X, %s target lsn is %X/%X"),
|
||||
format_lsn(local_xlogpos),
|
||||
action,
|
||||
format_lsn(follow_target_xlogpos));
|
||||
|
||||
if (is_rejoin == true)
|
||||
{
|
||||
log_hint(_("the --force-rewind option is ineffective in this case"));
|
||||
}
|
||||
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* 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
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -83,33 +83,27 @@
|
||||
#define OPT_DOWNSTREAM 1030
|
||||
#define OPT_UPSTREAM 1031
|
||||
#define OPT_SLOTS 1032
|
||||
#define OPT_HAS_PASSFILE 1033
|
||||
#define OPT_WAIT_START 1034
|
||||
#define OPT_REPL_CONN 1035
|
||||
#define OPT_REMOTE_NODE_ID 1036
|
||||
#define OPT_REPLICATION_CONF_ONLY 1037
|
||||
#define OPT_NO_WAIT 1038
|
||||
#define OPT_MISSING_SLOTS 1039
|
||||
#define OPT_REPMGRD_NO_PAUSE 1040
|
||||
#define OPT_VERSION_NUMBER 1041
|
||||
#define OPT_DATA_DIRECTORY_CONFIG 1042
|
||||
#define OPT_COMPACT 1043
|
||||
#define OPT_DETAIL 1044
|
||||
#define OPT_REPMGRD_FORCE_UNPAUSE 1045
|
||||
#define OPT_REPLICATION_CONFIG_OWNER 1046
|
||||
#define OPT_DB_CONNECTION 1047
|
||||
#define OPT_VERIFY_BACKUP 1048
|
||||
#define OPT_RECOVERY_MIN_APPLY_DELAY 1049
|
||||
#define OPT_REPMGRD 1050
|
||||
|
||||
/* These options are for internal use only */
|
||||
#define OPT_CONFIG_ARCHIVE_DIR 2001
|
||||
#define OPT_DISABLE_WAL_RECEIVER 2002
|
||||
#define OPT_ENABLE_WAL_RECEIVER 2003
|
||||
#define OPT_DUMP_CONFIG 2004
|
||||
#define OPT_CONFIG_ARCHIVE_DIR 1033
|
||||
#define OPT_HAS_PASSFILE 1034
|
||||
#define OPT_WAIT_START 1035
|
||||
#define OPT_REPL_CONN 1036
|
||||
#define OPT_REMOTE_NODE_ID 1037
|
||||
#define OPT_REPLICATION_CONF_ONLY 1038
|
||||
#define OPT_NO_WAIT 1039
|
||||
#define OPT_MISSING_SLOTS 1040
|
||||
#define OPT_REPMGRD_NO_PAUSE 1041
|
||||
#define OPT_VERSION_NUMBER 1042
|
||||
#define OPT_DATA_DIRECTORY_CONFIG 1043
|
||||
#define OPT_COMPACT 1044
|
||||
#define OPT_DISABLE_WAL_RECEIVER 1045
|
||||
#define OPT_ENABLE_WAL_RECEIVER 1046
|
||||
#define OPT_DETAIL 1047
|
||||
#define OPT_REPMGRD_FORCE_UNPAUSE 1048
|
||||
#define OPT_REPLICATION_CONFIG_OWNER 1049
|
||||
|
||||
/* deprecated since 4.0 */
|
||||
#define OPT_CHECK_UPSTREAM_CONFIG 999
|
||||
#define OPT_NODE 998
|
||||
|
||||
|
||||
static struct option long_options[] =
|
||||
@@ -128,7 +122,6 @@ static struct option long_options[] =
|
||||
{"no-wait", no_argument, NULL, 'W'},
|
||||
{"compact", no_argument, NULL, OPT_COMPACT},
|
||||
{"detail", no_argument, NULL, OPT_DETAIL},
|
||||
{"dump-config", no_argument, NULL, OPT_DUMP_CONFIG},
|
||||
|
||||
/* connection options */
|
||||
{"dbname", required_argument, NULL, 'd'},
|
||||
@@ -165,8 +158,6 @@ static struct option long_options[] =
|
||||
{"upstream-node-id", required_argument, NULL, OPT_UPSTREAM_NODE_ID},
|
||||
{"without-barman", no_argument, NULL, OPT_WITHOUT_BARMAN},
|
||||
{"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 */
|
||||
{"recovery-conf-only", no_argument, NULL, OPT_REPLICATION_CONF_ONLY},
|
||||
|
||||
@@ -194,12 +185,10 @@ static struct option long_options[] =
|
||||
{"role", no_argument, NULL, OPT_ROLE},
|
||||
{"slots", no_argument, NULL, OPT_SLOTS},
|
||||
{"missing-slots", no_argument, NULL, OPT_MISSING_SLOTS},
|
||||
{"repmgrd", no_argument, NULL, OPT_REPMGRD},
|
||||
{"has-passfile", no_argument, NULL, OPT_HAS_PASSFILE},
|
||||
{"replication-connection", no_argument, NULL, OPT_REPL_CONN},
|
||||
{"data-directory-config", no_argument, NULL, OPT_DATA_DIRECTORY_CONFIG},
|
||||
{"replication-config-owner", no_argument, NULL, OPT_REPLICATION_CONFIG_OWNER},
|
||||
{"db-connection", no_argument, NULL, OPT_DB_CONNECTION},
|
||||
|
||||
/* "node rejoin" options */
|
||||
{"config-files", required_argument, NULL, OPT_CONFIG_FILES},
|
||||
@@ -227,6 +216,9 @@ static struct option long_options[] =
|
||||
{"check-upstream-config", no_argument, NULL, OPT_CHECK_UPSTREAM_CONFIG},
|
||||
/* previously used by "standby switchover" */
|
||||
{"remote-config-file", required_argument, NULL, 'C'},
|
||||
/* replaced by --node-id */
|
||||
{"node", required_argument, NULL, OPT_NODE},
|
||||
|
||||
{NULL, 0, NULL, 0}
|
||||
};
|
||||
|
||||
|
||||
134
repmgr.c
134
repmgr.c
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* 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
|
||||
* generates the repmgr binary
|
||||
@@ -33,14 +33,22 @@
|
||||
#include "storage/shmem.h"
|
||||
#include "storage/spin.h"
|
||||
#include "utils/builtins.h"
|
||||
|
||||
#if (PG_VERSION_NUM >= 90400)
|
||||
#include "utils/pg_lsn.h"
|
||||
#endif
|
||||
|
||||
#include "utils/timestamp.h"
|
||||
|
||||
#include "lib/stringinfo.h"
|
||||
#include "access/xact.h"
|
||||
#include "utils/snapmgr.h"
|
||||
|
||||
#if (PG_VERSION_NUM >= 90400)
|
||||
#include "pgstat.h"
|
||||
#else
|
||||
#define PGSTAT_STAT_PERMANENT_DIRECTORY "pg_stat"
|
||||
#endif
|
||||
|
||||
#include "voting.h"
|
||||
|
||||
@@ -80,36 +88,67 @@ typedef struct repmgrdSharedState
|
||||
|
||||
static repmgrdSharedState *shared_state = NULL;
|
||||
|
||||
#if (PG_VERSION_NUM >= 150000)
|
||||
static shmem_request_hook_type prev_shmem_request_hook = NULL;
|
||||
#endif
|
||||
static shmem_startup_hook_type prev_shmem_startup_hook = NULL;
|
||||
|
||||
void _PG_init(void);
|
||||
|
||||
#if (PG_VERSION_NUM >= 150000)
|
||||
static void repmgr_shmem_request(void);
|
||||
#endif
|
||||
void _PG_init(void);
|
||||
void _PG_fini(void);
|
||||
|
||||
static void repmgr_shmem_startup(void);
|
||||
|
||||
PG_FUNCTION_INFO_V1(repmgr_set_local_node_id);
|
||||
PG_FUNCTION_INFO_V1(repmgr_get_local_node_id);
|
||||
PG_FUNCTION_INFO_V1(repmgr_standby_set_last_updated);
|
||||
PG_FUNCTION_INFO_V1(repmgr_standby_get_last_updated);
|
||||
PG_FUNCTION_INFO_V1(repmgr_set_upstream_last_seen);
|
||||
PG_FUNCTION_INFO_V1(repmgr_get_upstream_last_seen);
|
||||
PG_FUNCTION_INFO_V1(repmgr_get_upstream_node_id);
|
||||
PG_FUNCTION_INFO_V1(repmgr_set_upstream_node_id);
|
||||
PG_FUNCTION_INFO_V1(repmgr_notify_follow_primary);
|
||||
PG_FUNCTION_INFO_V1(repmgr_get_new_primary);
|
||||
PG_FUNCTION_INFO_V1(repmgr_reset_voting_status);
|
||||
Datum set_local_node_id(PG_FUNCTION_ARGS);
|
||||
PG_FUNCTION_INFO_V1(set_local_node_id);
|
||||
|
||||
Datum get_local_node_id(PG_FUNCTION_ARGS);
|
||||
PG_FUNCTION_INFO_V1(get_local_node_id);
|
||||
|
||||
Datum standby_set_last_updated(PG_FUNCTION_ARGS);
|
||||
PG_FUNCTION_INFO_V1(standby_set_last_updated);
|
||||
|
||||
Datum standby_get_last_updated(PG_FUNCTION_ARGS);
|
||||
PG_FUNCTION_INFO_V1(standby_get_last_updated);
|
||||
|
||||
Datum set_upstream_last_seen(PG_FUNCTION_ARGS);
|
||||
PG_FUNCTION_INFO_V1(set_upstream_last_seen);
|
||||
|
||||
Datum get_upstream_last_seen(PG_FUNCTION_ARGS);
|
||||
PG_FUNCTION_INFO_V1(get_upstream_last_seen);
|
||||
|
||||
Datum get_upstream_node_id(PG_FUNCTION_ARGS);
|
||||
PG_FUNCTION_INFO_V1(get_upstream_node_id);
|
||||
|
||||
Datum set_upstream_node_id(PG_FUNCTION_ARGS);
|
||||
PG_FUNCTION_INFO_V1(set_upstream_node_id);
|
||||
|
||||
Datum notify_follow_primary(PG_FUNCTION_ARGS);
|
||||
PG_FUNCTION_INFO_V1(notify_follow_primary);
|
||||
|
||||
Datum get_new_primary(PG_FUNCTION_ARGS);
|
||||
PG_FUNCTION_INFO_V1(get_new_primary);
|
||||
|
||||
Datum reset_voting_status(PG_FUNCTION_ARGS);
|
||||
PG_FUNCTION_INFO_V1(reset_voting_status);
|
||||
|
||||
Datum set_repmgrd_pid(PG_FUNCTION_ARGS);
|
||||
PG_FUNCTION_INFO_V1(set_repmgrd_pid);
|
||||
|
||||
Datum get_repmgrd_pid(PG_FUNCTION_ARGS);
|
||||
PG_FUNCTION_INFO_V1(get_repmgrd_pid);
|
||||
|
||||
Datum get_repmgrd_pidfile(PG_FUNCTION_ARGS);
|
||||
PG_FUNCTION_INFO_V1(get_repmgrd_pidfile);
|
||||
|
||||
Datum repmgrd_is_running(PG_FUNCTION_ARGS);
|
||||
PG_FUNCTION_INFO_V1(repmgrd_is_running);
|
||||
|
||||
Datum repmgrd_pause(PG_FUNCTION_ARGS);
|
||||
PG_FUNCTION_INFO_V1(repmgrd_pause);
|
||||
|
||||
Datum repmgrd_is_paused(PG_FUNCTION_ARGS);
|
||||
PG_FUNCTION_INFO_V1(repmgrd_is_paused);
|
||||
PG_FUNCTION_INFO_V1(repmgr_get_wal_receiver_pid);
|
||||
|
||||
Datum get_wal_receiver_pid(PG_FUNCTION_ARGS);
|
||||
PG_FUNCTION_INFO_V1(get_wal_receiver_pid);
|
||||
|
||||
|
||||
/*
|
||||
@@ -118,50 +157,41 @@ PG_FUNCTION_INFO_V1(repmgr_get_wal_receiver_pid);
|
||||
void
|
||||
_PG_init(void)
|
||||
{
|
||||
elog(DEBUG1, "repmgr init");
|
||||
|
||||
if (!process_shared_preload_libraries_in_progress)
|
||||
return;
|
||||
|
||||
#if (PG_VERSION_NUM < 150000)
|
||||
RequestAddinShmemSpace(MAXALIGN(sizeof(repmgrdSharedState)));
|
||||
|
||||
#if (PG_VERSION_NUM >= 90600)
|
||||
RequestNamedLWLockTranche(TRANCHE_NAME, 1);
|
||||
#else
|
||||
RequestAddinLWLocks(1);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Install hooks.
|
||||
*/
|
||||
#if (PG_VERSION_NUM >= 150000)
|
||||
prev_shmem_request_hook = shmem_request_hook;
|
||||
shmem_request_hook = repmgr_shmem_request;
|
||||
#endif
|
||||
|
||||
prev_shmem_startup_hook = shmem_startup_hook;
|
||||
shmem_startup_hook = repmgr_shmem_startup;
|
||||
|
||||
}
|
||||
|
||||
#if (PG_VERSION_NUM >= 150000)
|
||||
|
||||
/*
|
||||
* shmem_requst_hook: request shared memory
|
||||
* Module unload callback
|
||||
*/
|
||||
static void
|
||||
repmgr_shmem_request(void)
|
||||
void
|
||||
_PG_fini(void)
|
||||
{
|
||||
if (prev_shmem_request_hook)
|
||||
prev_shmem_request_hook();
|
||||
|
||||
RequestAddinShmemSpace(MAXALIGN(sizeof(repmgrdSharedState)));
|
||||
|
||||
RequestNamedLWLockTranche(TRANCHE_NAME, 1);
|
||||
/* Uninstall hook */
|
||||
shmem_startup_hook = prev_shmem_startup_hook;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* shmem_startup hook: allocate or attach to shared memory
|
||||
* shmem_startup hook: allocate or attach to shared memory,
|
||||
*/
|
||||
static void
|
||||
repmgr_shmem_startup(void)
|
||||
@@ -175,7 +205,7 @@ repmgr_shmem_startup(void)
|
||||
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);
|
||||
|
||||
@@ -214,7 +244,7 @@ repmgr_shmem_startup(void)
|
||||
/* ==================== */
|
||||
|
||||
Datum
|
||||
repmgr_set_local_node_id(PG_FUNCTION_ARGS)
|
||||
set_local_node_id(PG_FUNCTION_ARGS)
|
||||
{
|
||||
int local_node_id = UNKNOWN_NODE_ID;
|
||||
int stored_node_id = UNKNOWN_NODE_ID;
|
||||
@@ -284,7 +314,7 @@ repmgr_set_local_node_id(PG_FUNCTION_ARGS)
|
||||
|
||||
|
||||
Datum
|
||||
repmgr_get_local_node_id(PG_FUNCTION_ARGS)
|
||||
get_local_node_id(PG_FUNCTION_ARGS)
|
||||
{
|
||||
int local_node_id = UNKNOWN_NODE_ID;
|
||||
|
||||
@@ -301,7 +331,7 @@ repmgr_get_local_node_id(PG_FUNCTION_ARGS)
|
||||
|
||||
/* update and return last updated with current timestamp */
|
||||
Datum
|
||||
repmgr_standby_set_last_updated(PG_FUNCTION_ARGS)
|
||||
standby_set_last_updated(PG_FUNCTION_ARGS)
|
||||
{
|
||||
TimestampTz last_updated = GetCurrentTimestamp();
|
||||
|
||||
@@ -318,7 +348,7 @@ repmgr_standby_set_last_updated(PG_FUNCTION_ARGS)
|
||||
|
||||
/* get last updated timestamp */
|
||||
Datum
|
||||
repmgr_standby_get_last_updated(PG_FUNCTION_ARGS)
|
||||
standby_get_last_updated(PG_FUNCTION_ARGS)
|
||||
{
|
||||
TimestampTz last_updated;
|
||||
|
||||
@@ -335,7 +365,7 @@ repmgr_standby_get_last_updated(PG_FUNCTION_ARGS)
|
||||
|
||||
|
||||
Datum
|
||||
repmgr_set_upstream_last_seen(PG_FUNCTION_ARGS)
|
||||
set_upstream_last_seen(PG_FUNCTION_ARGS)
|
||||
{
|
||||
int upstream_node_id = UNKNOWN_NODE_ID;
|
||||
|
||||
@@ -358,7 +388,7 @@ repmgr_set_upstream_last_seen(PG_FUNCTION_ARGS)
|
||||
|
||||
|
||||
Datum
|
||||
repmgr_get_upstream_last_seen(PG_FUNCTION_ARGS)
|
||||
get_upstream_last_seen(PG_FUNCTION_ARGS)
|
||||
{
|
||||
long secs;
|
||||
int microsecs;
|
||||
@@ -392,7 +422,7 @@ repmgr_get_upstream_last_seen(PG_FUNCTION_ARGS)
|
||||
|
||||
|
||||
Datum
|
||||
repmgr_get_upstream_node_id(PG_FUNCTION_ARGS)
|
||||
get_upstream_node_id(PG_FUNCTION_ARGS)
|
||||
{
|
||||
int upstream_node_id = UNKNOWN_NODE_ID;
|
||||
|
||||
@@ -407,7 +437,7 @@ repmgr_get_upstream_node_id(PG_FUNCTION_ARGS)
|
||||
}
|
||||
|
||||
Datum
|
||||
repmgr_set_upstream_node_id(PG_FUNCTION_ARGS)
|
||||
set_upstream_node_id(PG_FUNCTION_ARGS)
|
||||
{
|
||||
int upstream_node_id = UNKNOWN_NODE_ID;
|
||||
int local_node_id = UNKNOWN_NODE_ID;
|
||||
@@ -443,7 +473,7 @@ repmgr_set_upstream_node_id(PG_FUNCTION_ARGS)
|
||||
|
||||
|
||||
Datum
|
||||
repmgr_notify_follow_primary(PG_FUNCTION_ARGS)
|
||||
notify_follow_primary(PG_FUNCTION_ARGS)
|
||||
{
|
||||
int primary_node_id = UNKNOWN_NODE_ID;
|
||||
|
||||
@@ -486,7 +516,7 @@ repmgr_notify_follow_primary(PG_FUNCTION_ARGS)
|
||||
|
||||
|
||||
Datum
|
||||
repmgr_get_new_primary(PG_FUNCTION_ARGS)
|
||||
get_new_primary(PG_FUNCTION_ARGS)
|
||||
{
|
||||
int new_primary_node_id = UNKNOWN_NODE_ID;
|
||||
|
||||
@@ -508,7 +538,7 @@ repmgr_get_new_primary(PG_FUNCTION_ARGS)
|
||||
|
||||
|
||||
Datum
|
||||
repmgr_reset_voting_status(PG_FUNCTION_ARGS)
|
||||
reset_voting_status(PG_FUNCTION_ARGS)
|
||||
{
|
||||
if (!shared_state)
|
||||
PG_RETURN_NULL();
|
||||
@@ -716,7 +746,7 @@ repmgrd_is_paused(PG_FUNCTION_ARGS)
|
||||
|
||||
|
||||
Datum
|
||||
repmgr_get_wal_receiver_pid(PG_FUNCTION_ARGS)
|
||||
get_wal_receiver_pid(PG_FUNCTION_ARGS)
|
||||
{
|
||||
int wal_receiver_pid;
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#
|
||||
# For details on the configuration file format see the documentation at:
|
||||
#
|
||||
# https://repmgr.org/docs/current/configuration-file.html#CONFIGURATION-FILE-FORMAT
|
||||
# https://repmgr.org/docs/current/configuration-file.html#CONFIGURATION-FILE-FORMAT
|
||||
#
|
||||
# =============================================================================
|
||||
# Required configuration items
|
||||
@@ -69,14 +69,14 @@
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
#replication_user='repmgr' # User to make replication connections with, if not set
|
||||
# defaults to the user defined in "conninfo".
|
||||
# defaults to the user defined in "conninfo".
|
||||
|
||||
#replication_type='physical' # Must "physical" (the default).
|
||||
|
||||
#location='default' # An arbitrary string defining the location of the node; this
|
||||
# is used during failover to check visibility of the
|
||||
# current primary node. For further details see:
|
||||
# https://repmgr.org/docs/current/repmgrd-network-split.html
|
||||
# https://repmgr.org/docs/current/repmgrd-network-split.html
|
||||
|
||||
#use_replication_slots=no # whether to use physical replication slots
|
||||
# NOTE: when using replication slots,
|
||||
@@ -181,8 +181,6 @@
|
||||
|
||||
#pg_ctl_options='' # Options to append to "pg_ctl"
|
||||
#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"
|
||||
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 )
|
||||
|
||||
#recovery_min_apply_delay= # If provided, "recovery_min_apply_delay" will be set to
|
||||
# this value (PostgreSQL 9.4 and later). Value can be
|
||||
# an integer representing milliseconds, or a string
|
||||
# representing a period of time (e.g. '5 min').
|
||||
# this value (PostgreSQL 9.4 and later).
|
||||
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
@@ -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
|
||||
# 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
|
||||
#standby_follow_restart=false # Restart the standby instead of sending a SIGHUP
|
||||
# (only for PostgreSQL 13 and later)
|
||||
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# "standby switchover" settings
|
||||
@@ -299,10 +294,9 @@ ssh_options='-q -o ConnectTimeout=10' # Options to append to "ssh"
|
||||
# a value of zero prevents the node being promoted to primary
|
||||
# (default: 100)
|
||||
|
||||
#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
|
||||
# 'connection': attempt to make a new connection to the node
|
||||
# 'query': execute an SQL statement on the node via the existing connection
|
||||
# 'connection': execute a throwaway query on the current connection
|
||||
#reconnect_attempts=6 # Number of attempts which will be made to reconnect to an unreachable
|
||||
# primary (or other upstream node)
|
||||
#reconnect_interval=10 # Interval between attempts to reconnect to an unreachable
|
||||
@@ -314,7 +308,7 @@ ssh_options='-q -o ConnectTimeout=10' # Options to append to "ssh"
|
||||
#follow_command='' # command repmgrd executes when instructing a standby to follow a new primary;
|
||||
# use something like:
|
||||
#
|
||||
# repmgr standby follow -f /etc/repmgr.conf --upstream-node-id=%n
|
||||
# repmgr standby follow -f /etc/repmgr.conf -W --upstream-node-id=%n
|
||||
#
|
||||
#primary_notification_timeout=60 # Interval (in seconds) which repmgrd on a standby
|
||||
# will wait for a notification from the new primary,
|
||||
@@ -323,7 +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
|
||||
# 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
|
||||
#degraded_monitoring_timeout=-1 # Interval (in seconds) after which repmgrd will terminate if the
|
||||
# server(s) being monitored are no longer available. -1 (default)
|
||||
@@ -337,34 +331,23 @@ ssh_options='-q -o ConnectTimeout=10' # Options to append to "ssh"
|
||||
# "--no-pid-file" will force PID file creation to be skipped.
|
||||
# Note: there is normally no need to set this, particularly if
|
||||
# repmgr was installed from packages.
|
||||
#repmgrd_exit_on_inactive_node=false # If "true", and the node record is marked as "inactive", abort repmgrd startup
|
||||
#standby_disconnect_on_failover=false # If "true", in a failover situation wait for all standbys to
|
||||
# disconnect their WAL receivers before electing a new primary
|
||||
# Can be true in PostgreSQL 9.5 and later only. Until PostgreSQL 14 repmgr user must be a superuser to use this.
|
||||
# From PostgreSQL 15 repmgr must be a superuser or have 'ALTER SYSTEM wal_retrieve_retry_interval' privilege.
|
||||
# (see: https://repmgr.org/docs/current/repmgrd-standby-disconnection-on-failover.html )
|
||||
# (PostgreSQL 9.5 and later only; repmgr user must be a superuser for this)
|
||||
#sibling_nodes_disconnect_timeout=30 # If "standby_disconnect_on_failover" is true, the maximum length of time
|
||||
# (in seconds) to wait for other standbys to confirm they have disconnected their
|
||||
# (in seconds) to wait for other standbys to confirm they have disconnected their
|
||||
# WAL receivers
|
||||
#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.
|
||||
#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
|
||||
# decision made by repmgrd. Each of the following parameter placeholders
|
||||
# should be provided, which will be replaced by repmgrd with the appropriate value:
|
||||
# %n (node_id)
|
||||
# %a (node_name)
|
||||
# %v (number of visible nodes)
|
||||
# %u (number of shared upstream nodes)
|
||||
# %t (total number of nodes)
|
||||
# *Must* be the same on all nodes.
|
||||
#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
|
||||
# should be provided, which will be replaced by repmgrd with the appropriate
|
||||
# value: %n (node_id), %a (node_name). *Must* be the same on all nodes.
|
||||
#election_rerun_interval=15 # if "failover_validation_command" is set, and the command returns
|
||||
# an error, pause the specified amount of seconds before rerunning the election.
|
||||
|
||||
# The following items are relevant for repmgrd running on the primary,
|
||||
# and will be ignored on non-primary nodes.
|
||||
# (see: https://repmgr.org/docs/current/repmgrd-primary-child-disconnection.html )
|
||||
|
||||
#
|
||||
# The following items are relevant for repmgrd running on the primary,
|
||||
# and will be ignored on non-primary nodes
|
||||
#child_nodes_check_interval=5 # Interval (in seconds) to check for attached child nodes (standbys)
|
||||
#child_nodes_connected_min_count=-1 # Minimum number of child nodes which must remain connected, otherwise
|
||||
# disconnection command will be triggered
|
||||
@@ -372,7 +355,6 @@ ssh_options='-q -o ConnectTimeout=10' # Options to append to "ssh"
|
||||
# (ignored if "child_nodes_connected_min_count" set)
|
||||
#child_nodes_disconnect_timeout=30 # Interval between child node disconnection and disconnection command execution
|
||||
#child_nodes_disconnect_command='' # Command to execute if child node disconnection detected
|
||||
#child_nodes_connected_include_witness=false # Whether to count the witness node (if in use) as a child node when determining whether to execute child_nodes_disconnect_command.
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# service control commands
|
||||
@@ -395,20 +377,20 @@ ssh_options='-q -o ConnectTimeout=10' # Options to append to "ssh"
|
||||
#
|
||||
# For example, to use systemd, you can set
|
||||
#
|
||||
# service_start_command = 'sudo systemctl start postgresql-16'
|
||||
# service_start_command = 'sudo systemctl start postgresql-9.6'
|
||||
# (...)
|
||||
#
|
||||
# and then use the following sudoers configuration:
|
||||
#
|
||||
# # this is required when running sudo over ssh without -t:
|
||||
# Defaults:postgres !requiretty
|
||||
# postgres ALL = NOPASSWD: /usr/bin/systemctl stop postgresql-16, \
|
||||
# /usr/bin/systemctl start postgresql-16, \
|
||||
# /usr/bin/systemctl restart postgresql-16
|
||||
# postgres ALL = NOPASSWD: /usr/bin/systemctl stop postgresql-9.6, \
|
||||
# /usr/bin/systemctl start postgresql-9.6, \
|
||||
# /usr/bin/systemctl restart postgresql-9.6
|
||||
#
|
||||
# Debian/Ubuntu users: use "sudo pg_ctlcluster" to execute service control commands.
|
||||
#
|
||||
# For further details, see: https://repmgr.org/docs/current/configuration-file-service-commands.html
|
||||
# For more details, see: https://repmgr.org/docs/current/configuration-service-commands.html
|
||||
|
||||
#service_start_command = ''
|
||||
#service_stop_command = ''
|
||||
@@ -451,3 +433,4 @@ ssh_options='-q -o ConnectTimeout=10' # Options to append to "ssh"
|
||||
# "repmgr standby switchover" to warn about potential
|
||||
# issues with shutting down the demotion candidate.
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
# repmgr extension
|
||||
comment = 'Replication manager for PostgreSQL'
|
||||
default_version = '5.5'
|
||||
default_version = '5.1'
|
||||
module_pathname = '$libdir/repmgr'
|
||||
relocatable = false
|
||||
schema = repmgr
|
||||
|
||||
|
||||
|
||||
65
repmgr.h
65
repmgr.h
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* 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
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -74,15 +74,16 @@
|
||||
#include "log.h"
|
||||
#include "sysutils.h"
|
||||
|
||||
#define MIN_SUPPORTED_VERSION "9.4"
|
||||
#define MIN_SUPPORTED_VERSION_NUM 90400
|
||||
#define MIN_SUPPORTED_VERSION "9.3"
|
||||
#define MIN_SUPPORTED_VERSION_NUM 90300
|
||||
|
||||
#define REPLICATION_TYPE_PHYSICAL 1
|
||||
|
||||
#define UNKNOWN_SERVER_VERSION_NUM -1
|
||||
#define UNKNOWN_REPMGR_VERSION_NUM -1
|
||||
|
||||
#define UNKNOWN_TIMELINE_ID -1
|
||||
#define UNKNOWN_SYSTEM_IDENTIFIER 0
|
||||
#define UNKNOWN_DATA_CHECKSUM_VERSION -1
|
||||
#define UNKNOWN_PID -1
|
||||
#define UNKNOWN_REPLICATION_LAG -1
|
||||
#define UNKNOWN_VALUE -1
|
||||
@@ -96,60 +97,40 @@
|
||||
#define ARCHIVE_STATUS_DIR_ERROR -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 */
|
||||
|
||||
/*
|
||||
* Default configuration file parameter values - ensure repmgr.conf.sample
|
||||
* is update if any of these are changed
|
||||
*/
|
||||
|
||||
#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_LOCATION "default"
|
||||
#define DEFAULT_PRIORITY 100
|
||||
#define DEFAULT_RECONNECTION_ATTEMPTS 6 /* seconds */
|
||||
#define DEFAULT_RECONNECTION_INTERVAL 10 /* seconds */
|
||||
#define DEFAULT_MONITORING_INTERVAL 2 /* seconds */
|
||||
#define DEFAULT_ASYNC_QUERY_TIMEOUT 60 /* seconds */
|
||||
#define DEFAULT_PRIMARY_NOTIFICATION_TIMEOUT 60 /* seconds */
|
||||
#define DEFAULT_PRIMARY_FOLLOW_TIMEOUT 60 /* seconds */
|
||||
#define DEFAULT_STANDBY_FOLLOW_TIMEOUT 30 /* seconds */
|
||||
#define DEFAULT_STANDBY_FOLLOW_RESTART false
|
||||
#define DEFAULT_SHUTDOWN_CHECK_TIMEOUT 60 /* seconds */
|
||||
#define DEFAULT_STANDBY_PG_BACKUPAPI_OP_TYPE "recovery"
|
||||
#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_CRITICAL 128 /* WAL files */
|
||||
#define DEFAULT_REPLICATION_TYPE REPLICATION_TYPE_PHYSICAL
|
||||
#define DEFAULT_REPLICATION_LAG_WARNING 300 /* seconds */
|
||||
#define DEFAULT_REPLICATION_LAG_CRITICAL 600 /* 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_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_REPMGRD_EXIT_ON_INACTIVE_NODE false,
|
||||
#define DEFAULT_STANDBY_DISCONNECT_ON_FAILOVER false
|
||||
#define DEFAULT_SIBLING_NODES_DISCONNECT_TIMEOUT 30 /* seconds */
|
||||
#define DEFAULT_CONNECTION_CHECK_TYPE CHECK_PING
|
||||
#define DEFAULT_PRIMARY_VISIBILITY_CONSENSUS false
|
||||
#define DEFAULT_ALWAYS_PROMOTE false
|
||||
#define DEFAULT_ELECTION_RERUN_INTERVAL 15 /* seconds */
|
||||
#define DEFAULT_CHILD_NODES_CHECK_INTERVAL 5 /* seconds */
|
||||
#define DEFAULT_CHILD_NODES_DISCONNECT_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_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
|
||||
#define RECOVERY_COMMAND_FILE "recovery.conf"
|
||||
@@ -164,6 +145,6 @@
|
||||
#define TABLESPACE_MAP "tablespace_map"
|
||||
#endif
|
||||
|
||||
#define REPMGR_URL "https://repmgr.org/"
|
||||
|
||||
|
||||
#endif /* _REPMGR_H_ */
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
#define REPMGR_VERSION_DATE "2024-11-20"
|
||||
#define REPMGR_VERSION "5.5.0"
|
||||
#define REPMGR_VERSION_NUM 50500
|
||||
#define REPMGR_EXTENSION_VERSION "5.5.0"
|
||||
#define REPMGR_EXTENSION_NUM 50500
|
||||
#define REPMGR_RELEASE_DATE "2024-XX-XX"
|
||||
#define REPMGR_VERSION_DATE ""
|
||||
#define REPMGR_VERSION "5.1.0"
|
||||
#define REPMGR_VERSION_NUM 50100
|
||||
#define REPMGR_RELEASE_DATE "2020-04-13"
|
||||
#define PG_ACTUAL_VERSION_NUM
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user