Compare commits

..

138 Commits

Author SHA1 Message Date
Ian Barwick
ef382dfede doc: update release notes 2019-12-10 16:35:59 +09:00
Ian Barwick
bc93d2996c standby follow: don't attempt to delete slot if current upstream is primary
An attempt will be made to delete an existing replication slot on the
old upstream node (this is important during e.g. a switchover operation
or when attaching a cascaded standby to a new upstream). However if the
standby is currently attached to the follow target node anyway, the
replication slot should never be deleted.
2019-12-10 15:48:49 +09:00
Ian Barwick
0946073406 doc: remove references to putative 4.3.1 release
The changes listed will be part of the upcoming 4.4 release.
2019-05-24 10:08:27 +09:00
Ian Barwick
129c8782a4 doc: update appendix "Installing old package versions"
Move legacy 3.x package info to separate section.
2019-05-24 10:05:10 +09:00
Ian Barwick
5493055a1d doc: fix typos in source install instructions
s/llib/lib/g
2019-05-10 10:30:29 +09:00
Ian Barwick
a50f0e7cc0 doc: update release notes 2019-05-07 15:49:34 +09:00
Ian Barwick
adfde1b681 doc: add &repmgrd; as entity 2019-05-07 15:26:26 +09:00
Ian Barwick
d4b17635fe doc: update release notes 2019-05-07 15:25:54 +09:00
Ian Barwick
e4c573a7f6 repmgrd: add missing PQfinish() calls 2019-05-02 18:52:37 +09:00
Frantisek Holop
492665e34c doc: promote -> follow
PR #565
2019-04-30 10:53:14 +09:00
Frantisek Holop
2d7c38e2ef doc: bit too many e.g.'s
PR #565.
2019-04-30 10:52:45 +09:00
Ian Barwick
9ee2448583 standby switchover: ignore nodes which are unreachable and marked as inactive
Previously "repmgr standby switchover" would abort if any node was unreachable,
as that means it was unable to check if repmgrd is running.

However if the node has been marked as inactive in the repmgr metadata, it's
reasonable to assume the node is no longer part of the replication cluster
and does not need to be checked.
2019-04-29 14:35:58 +09:00
Ian Barwick
cf9458161f Update HISTORY 2019-04-25 14:58:05 +09:00
Ian Barwick
67dc42d2ad Clarify hints about updating the repmgr extension 2019-04-24 11:39:06 +09:00
Ian Barwick
3b96b2afce "primary register": ensure --force works if another primary is registered but not running 2019-04-23 22:06:28 +09:00
Ian Barwick
216f274c15 doc: add note about when a PostgreSQL restart is required
Per query in GitHub #564.
2019-04-17 09:44:29 +09:00
Ian Barwick
8cb101be1d repmgrd: exclude witness server from followability check 2019-04-11 11:20:45 +09:00
Ian Barwick
03b29908e2 Miscellaneous string handling cleanup
This is mainly to prevent effectively spurious truncation warnings
in recent GCC versions.
2019-04-10 16:21:09 +09:00
Ian Barwick
99be03f000 Fix hint message
s/UPGRADE/UPDATE
2019-04-10 12:15:53 +09:00
Ian Barwick
7aaac343f8 standby clone: always ensure directory is created with correct permissions
In Barman mode, if there is an existing, populated data directory, and
the "--force" option is provided, the entire directory was being deleted,
and later recreated as part of the rsync process, but with the default
permissions.

Fix this by recreating the data directory with the correct permissions
after deleting it.
2019-04-09 11:02:06 +09:00
Ian Barwick
68470a9167 standby clone: improve --dry-run behaviour in barman mode
- emit additional informational output
- ensure that provision of --force does not result in an existing
  data directory being modified in any way
2019-04-08 15:13:13 +09:00
Ian Barwick
35320c27bd doc: update release notes 2019-04-08 11:28:13 +09:00
Ian Barwick
b7b9db7e9c Ensure BDR-specific code only runs on BDR 2.x
The BDR support in repmgr is for a specific BDR 2.x use case, and
is not suitable for more recent BDR versions.
2019-04-08 11:28:10 +09:00
Ian Barwick
01e11950a5 doc: add note about BDR replication type in sample config 2019-04-08 11:28:05 +09:00
Ian Barwick
fcaee6e6e8 doc: emphasise that BDR2 support is for BDR2 only 2019-04-05 10:59:20 +09:00
Ian Barwick
538d5f9df0 Use correct sizeof() argument in a couple of strncpy calls
Source and destination buffers are however the same length in both cases.

Per GitHub #561.
2019-04-04 11:03:01 +09:00
Ian Barwick
4e8b94c105 doc: update 4.3 release notes 2019-04-03 15:09:09 +09:00
Ian Barwick
9ee51bb0cb doc: update README
Link to current documentation version
2019-04-03 10:58:19 +09:00
Ian Barwick
bab07cdda1 doc: add a link to the current documentation from the contents page 2019-04-03 10:52:19 +09:00
Ian Barwick
b03f07ca8f doc: finalize 4.3 release notes 2019-04-02 14:42:25 +09:00
Ian Barwick
39fbe02c48 doc: note that --siblings-follow will become default in a future release 2019-04-02 11:04:59 +09:00
Ian Barwick
2249b79811 standby switchover: list nodes which will remain attatched to the old primary
If --siblings-follow is not supplied, list all nodes which repmgr considers
to be siblings (this will include the witness server, if in use), and
which will remain attached to the old primary.
2019-04-02 10:47:05 +09:00
Ian Barwick
bb0fd944ae doc: update quickstart guide
Improve sample PostgreSQL replication configuration, including
links to the PostgreSQL documentation for each configuration item.

Also set "max_replication_slots" to the same value as "max_wal_senders"
to ensure the sample configuration will work regardless of whether
replication slots are in use, though we do still encourage careful
reading of the comments in the sample configuration and the documentation
in general.
2019-04-02 09:10:05 +09:00
Ian Barwick
b4ca6851ab Bump version number
4.3
2019-04-01 15:25:48 +09:00
Ian Barwick
347948b79f Fix default return value in alter_system_int() 2019-04-01 14:52:37 +09:00
Ian Barwick
83e492d4ef Add is_server_available_quiet()
For use in cases where the caller collates node availability information
and doesn't want to prematurely emit log output.
2019-04-01 12:24:57 +09:00
Ian Barwick
1906ea89bd Improve copying of strings from database results
Where feasible, specify the maximum string length via sizeof(), and
use snprintf() in place of strncpy().
2019-04-01 11:29:16 +09:00
Ian Barwick
eab4fd2795 Handle unhandled error situation in enable_wal_receiver() 2019-04-01 11:03:47 +09:00
Ian Barwick
3f1fe9b6c2 Updae BDR repmgrd to handle node_name as a max 63 char string
Follow-up from commit 1953ec7.
2019-03-28 14:29:03 +09:00
Ian Barwick
e672f7e3ee Handle potential NULL return from string_skip_prefix() 2019-03-28 12:46:03 +09:00
Ian Barwick
fd86160dff Add missing break 2019-03-28 12:45:12 +09:00
Ian Barwick
f19cf62f09 Update code comment 2019-03-28 12:45:09 +09:00
Ian Barwick
8018ba97d6 Remove logically dead code 2019-03-28 12:36:05 +09:00
Ian Barwick
73554c6e16 Prevent potential file descriptor resource leak 2019-03-28 12:29:42 +09:00
Ian Barwick
f23a93e12d Put closedir call in correct location 2019-03-28 12:10:16 +09:00
Ian Barwick
d9947a46e8 Add various missing close() calls 2019-03-28 12:10:12 +09:00
Ian Barwick
e3a632e29d Use correct argument for sizeof() 2019-03-28 11:04:57 +09:00
Ian Barwick
939cbd0721 Cast "int" to "long long" 2019-03-28 11:04:53 +09:00
Ian Barwick
c45c5abfb8 doc: note valid characters for "node_name"
"node_name" will be used as "application_name", so should only contain
characters valid for that; see:

    https://www.postgresql.org/docs/current/runtime-config-logging.html#GUC-APPLICATION-NAME

Not yet enforced.
2019-03-28 10:58:23 +09:00
Ian Barwick
1953ec7459 Restrict "node_name" to maximum 63 characters
In "recovery.conf", the configuration parameter "node_name" is used
as the "application_name" value, which will be truncated by PostgreSQL
to 63 characters (NAMEDATALEN - 1).

repmgr sometimes needs to be able to extract the application name from
pg_stat_replication to determine if a node is connected (e.g. when
executing "repmgr standby register"), so the comparison will fail
if "node_name" exceeds 63 characters.
2019-03-28 10:58:18 +09:00
Ian Barwick
a6eacca6e4 standby register: fail if --upstream-node-id is the local node ID 2019-03-27 14:27:59 +09:00
Ian Barwick
948e076ad9 log_db_error(): fix formatted message handling 2019-03-27 14:27:55 +09:00
Ian Barwick
a3bd9d33ff Use sizeof(buf) rather than hard-coding value 2019-03-27 14:27:50 +09:00
Ian Barwick
9dc928a7d5 repmgrd: clean up PQExpBuffer handling
Unless the PQExpBuffer is required for the duration of the function,
ensure it's always a variable local to the relevant code block. This
mitigates the risk of accidentally accessing a generically named
PQExpBuffer which hasn't been initialised or was previously terminated.
2019-03-26 13:39:00 +09:00
Ian Barwick
9acf7bdfea repmgrd: don't terminate uninitialized PQExpBuffer 2019-03-26 13:38:55 +09:00
Ian Barwick
29acd10f37 doc: update release notes 2019-03-22 15:42:12 +09:00
Ian Barwick
9df511eee3 doc: fix syntax 2019-03-22 15:41:44 +09:00
Ian Barwick
6441db23ff repmgrd: during failover, check if a node was already promoted
Previously, repmgrd assumed that during a failover, there would not
already be another primary node. However it's possible a node was
promoted manually. While this is not a desirable situation, it's
conceivable this could happen in the wild, so we should check for
it and react accordingly.

Also sanity-check that the follow target can actually be followed.

Addresses issue raised in GitHub #420.
2019-03-22 15:15:49 +09:00
Ian Barwick
7792de3543 standby follow: set replication user when connecting to local node 2019-03-22 10:12:35 +09:00
Ian Barwick
94fe3e395e standby switchover: don't attempt to pause repmgrd on unreachable nodes 2019-03-22 10:12:28 +09:00
Ian Barwick
ff26173b1e doc: add note about compiling against Pg11 and later with the --with-llvm option 2019-03-22 10:12:23 +09:00
Ian Barwick
4c11a57334 use a constant to denote unknown replication lag 2019-03-22 10:12:19 +09:00
Ian Barwick
1d2d6e3587 doc: consolidate witness server documentation 2019-03-20 16:30:09 +09:00
Ian Barwick
c03913d32a doc: various improvements to repmgrd documentation 2019-03-20 16:10:38 +09:00
Ian Barwick
37a41a66f9 Check node recovery type before attempting to write an event record
In some corner cases (e.g. immediately after a switchover) where
the current primary has not yet been determined, the provided connection
might not be writeable. This prevents error messages such as
"cannot execute INSERT in a read-only transaction" generating unnecessary
noise in the logs.
2019-03-20 12:14:53 +09:00
Ian Barwick
4c2c8ecbab Fix logging related to "connection_check_type"
Also log the selected type at repmgrd startup.
2019-03-20 12:13:51 +09:00
Ian Barwick
b84b6180ee repmgrd: improve witness node monitoring
Mainly fix a couple of places where "standby" was hard-coded into a log
message which can apply either to a witness or a standby.
2019-03-20 12:13:47 +09:00
Ian Barwick
58f55222d9 Explictly log PQping() failures 2019-03-20 12:13:44 +09:00
Ian Barwick
5cbaff8d0a Improve database connection failure logging
Log the output of PQerrorStatus() in a couple of places where it was missing.

Additionally, always log the output of PQerrorStatus() starting with a blank
line, otherwise the first line looks like it was emitted by repmgr, and
it's harder to scan the error message.

Before:

    [2019-03-20 11:24:15] [DETAIL] could not connect to server: Connection refused
            Is the server running on host "localhost" (::1) and accepting
            TCP/IP connections on port 5501?
    could not connect to server: Connection refused
            Is the server running on host "localhost" (127.0.0.1) and accepting
            TCP/IP connections on port 5501?

After:

    [2019-03-20 11:27:21] [DETAIL]
    could not connect to server: Connection refused
            Is the server running on host "localhost" (::1) and accepting
            TCP/IP connections on port 5501?
    could not connect to server: Connection refused
            Is the server running on host "localhost" (127.0.0.1) and accepting
            TCP/IP connections on port 5501?
2019-03-20 12:13:40 +09:00
Ian Barwick
a38e229e61 check_primary_status(): handle case where recovery type unknown 2019-03-20 12:13:34 +09:00
Ian Barwick
272abdd483 Refactor check_primary_status()
Reduce nested if/else branching, and improve documentation.
2019-03-20 12:13:08 +09:00
Ian Barwick
b4f6043abc Update .gitignore
Ignore artefacts from failed patch application.
2019-03-20 12:11:57 +09:00
Ian Barwick
a7f3f899ff doc: update repmgrd example output 2019-03-20 12:10:31 +09:00
Ian Barwick
3ec43eda36 doc: remove references to "primary_visibility_consensus"
Feature remains experimental.
2019-03-18 17:43:16 +09:00
Ian Barwick
ce8e1cccc4 Remove outdated comment
This was only relevant for repmgr3 and earlier; in repmgr4 the schema
is hard-coded.
2019-03-18 15:19:25 +09:00
Ian Barwick
70bfa4c8e1 Clarify calls to check_primary_status()
Use a constant rather than a magic number to indicate non-provision
of elapsed degraded monitoring time.
2019-03-18 14:21:41 +09:00
Ian Barwick
f0d5ad503d doc: clarify "cluster show" error codes 2019-03-18 10:50:05 +09:00
John Naylor
b9ee57ee0f Fix assorted Makefile bugs
1. The target additional-maintainer-clean was misspelled as
maintainer-additional-clean.

2. Add add missing clean targets, in particular sysutils.o, config.h,
repmgr_version.h, and Makefile.global. While at it, use a wildcard
for obj files.

3. Don't delete configure.

4. Remove generated file doc/version.sgml from the repo.

5. Have maintainer-clean recurse to the doc directory.
2019-03-15 16:30:27 +09:00
Ian Barwick
d5d6ed4be7 Bump version
4.3rc1
2019-03-15 14:41:41 +09:00
Ian Barwick
f4655074ae doc: miscellaenous cleanup 2019-03-15 14:39:55 +09:00
Ian Barwick
67d26ab7e2 doc: tweak wording in event notification documentation 2019-03-15 14:08:18 +09:00
Ian Barwick
70a7b45a03 doc: add explanation of the configuration file format 2019-03-15 14:07:19 +09:00
Ian Barwick
4251590833 doc: update "connection_check_type" descriptions 2019-03-15 14:07:13 +09:00
Ian Barwick
9347d34ce0 repmgrd: optionally check upstream availability through connection attempts 2019-03-15 14:07:08 +09:00
John Naylor
feb90ee50c Correct some doc typos 2019-03-15 14:07:05 +09:00
Ian Barwick
0a6486bb7f doc: expand "standby_disconnect_on_failover" documentation 2019-03-15 14:07:01 +09:00
Ian Barwick
39443bbcee Count witness and zero-priority nodes in visibility check 2019-03-15 14:06:58 +09:00
Ian Barwick
fc636b1bd2 Ensure witness node sets last upstream seen time 2019-03-15 14:06:55 +09:00
Ian Barwick
048bad1c88 doc: fix option name typo 2019-03-15 14:06:51 +09:00
Ian Barwick
4528eb1796 doc: expand "failover_validate_command" documentation 2019-03-15 14:06:37 +09:00
Ian Barwick
169c9ccd32 repmgrd: improve logging output when executing "failover_validate_command" 2019-03-15 14:06:34 +09:00
Ian Barwick
5f92fbddf2 doc: various updates 2019-03-15 14:06:30 +09:00
Ian Barwick
617e466f72 doc: merge repmgrd witness server description into failover section 2019-03-13 16:19:41 +09:00
Ian Barwick
435fac297b doc: merge repmgrd split network handling description into failover section 2019-03-13 16:19:37 +09:00
Ian Barwick
4bc12b4c94 doc: merge repmgrd monitoring description into operating section 2019-03-13 16:19:33 +09:00
Ian Barwick
91234994e2 doc: merge repmgrd degraded monitoring description into operation section 2019-03-13 16:19:30 +09:00
Ian Barwick
ee9da30f20 doc: merge repmgrd notes into operation documentation 2019-03-13 16:19:27 +09:00
Ian Barwick
2e67bc1341 doc: merge repmgrd pause documentation into overview 2019-03-13 16:19:24 +09:00
Ian Barwick
18ab5cab4e doc: initial repmgrd doc refactoring 2019-03-13 16:19:20 +09:00
Ian Barwick
60bb4e9fc8 doc: update repmgrd configuration documentation 2019-03-13 16:19:17 +09:00
Ian Barwick
52bee6b98d repmgrd: various minor logging improvements 2019-03-13 16:19:13 +09:00
Ian Barwick
ecb1f379f5 repmgrd: remove global variable
Make the "sibling_nodes" local, and pass by reference where relevant.
2019-03-13 16:19:10 +09:00
Ian Barwick
e1cd2c22d4 repmgrd: enable election rerun
If "failover_validation_command" is set, and the command returns an error,
rerun the election.

There is a pause between reruns to avoid "churn"; the length of this pause
is controlled by the configuration parameter "election_rerun_interval".
2019-03-13 16:19:03 +09:00
Ian Barwick
1dea6b76d9 Remove redundant struct allocation 2019-03-13 16:19:00 +09:00
Ian Barwick
702f90fc9d doc: update list of reloadable repmgrd configuration options 2019-03-13 16:18:56 +09:00
Ian Barwick
c4d1eec6f3 doc: document "failover_validation_command" 2019-03-13 16:18:53 +09:00
Ian Barwick
b241c606c0 doc: expand repmgrd configuration section 2019-03-13 16:18:50 +09:00
Ian Barwick
45c896d716 Execute "failover_validation_command" when only one standby exists 2019-03-08 15:29:17 +09:00
Ian Barwick
514595ea10 Make "failover_validation_command" reloadable 2019-03-08 15:29:12 +09:00
Ian Barwick
531194fa27 Initial implementation of "failover_validation_command" 2019-03-08 15:29:06 +09:00
Ian Barwick
2aa67c992c Make recently added configuration options reloadable 2019-03-08 15:28:59 +09:00
Ian Barwick
37892afcfc Add configuration option "primary_visibility_consensus"
This determines whether repmgrd should continue with a failover if
one or more nodes report they can still see the standby.
2019-03-08 15:28:53 +09:00
Ian Barwick
e4e5e35552 Add configuration option "sibling_nodes_disconnect_timeout"
This controls the maximum length of time in seconds that repmgrd will
wait for other standbys to disconnect their WAL receivers in a failover
situation.

This setting is only used when "standby_disconnect_on_failover" is set to "true".
2019-03-08 15:28:48 +09:00
Ian Barwick
b320c1f0ae Reset "wal_retrieve_retry_interval" for all nodes 2019-03-08 15:28:42 +09:00
Ian Barwick
280654bed6 repmgrd: don't wait for WAL receiver to reconnect during failover
If the WAL receiver has been temporarily disabled, we don't want to
wait for it to start up as it may not be able to at that point; we do
however need to reset "wal_retrieve_retry_interval".
2019-03-08 15:28:27 +09:00
Ian Barwick
ae675059c0 Improve logging/sanity checking for "node control" options 2019-03-08 15:28:22 +09:00
Ian Barwick
454ebabe89 Improve logging when disabling/enabling WAL receiver
Also check action is being run on node which is in recovery.
2019-03-08 15:28:17 +09:00
Ian Barwick
d1d6ef8d12 Check for WAL receiver start up 2019-03-08 15:28:11 +09:00
Ian Barwick
5d6eab74f6 Log warning if "standby_disconnect_on_failover" used on pre-9.5
"standby_disconnect_on_failover" requires availability of "wal_retrieve_retry_interval",
which is available from PostgreSQL 9.5.

9.4 will fall out of community support this year, so it doesn't seem
productive at this point to do anything more than put the onus on the user
to read the documentation and heed any warning messages in the logs.
2019-03-08 15:28:01 +09:00
Ian Barwick
59b7453bbf repmgrd: optionally disconnect WAL receivers during failover
This is intended to ensure that all nodes have a constant LSN while
making the failover decision.

This feature is experimental and needs to be explicitly enabled with the
configuration file option "standby_disconnect_on_failover".

Note enabling this option will result in a delay in the failover decision
until the WAL receiver is disconnected on all nodes.
2019-03-08 15:27:54 +09:00
Ian Barwick
bde8c7e29c repmgrd: handle reconnect to restarted server when using "connection" checks 2019-03-08 15:27:49 +09:00
Ian Barwick
bc6584a90d *_transaction() functions: log error message text as DETAIL
Per behaviour elsewhere.
2019-03-06 13:23:57 +09:00
Ian Barwick
074d79b44f repmgrd: add option "connection_check_type"
This enable selection of the method repmgrd uses to check whether the upstream
node is available. Possible values are:

 - "ping" (default): uses PQping() to check server availability
 - "connection":  executes a query on the connection to check server
   availability (similar to repmgr3.x).
2019-03-06 13:23:53 +09:00
Ian Barwick
2eeb288573 repmgrd: ignore invalid "upstream_last_seen" value 2019-03-06 13:23:47 +09:00
Ian Barwick
48a2274b11 Use appendPQExpBufferStr where approrpriate 2019-03-06 13:23:38 +09:00
Ian Barwick
19bcfa7264 Rename "..._primary_last_seen" functions to "..._upstream_last_seen"
As that better reflects what they do.
2019-03-06 13:23:33 +09:00
Ian Barwick
486877c3d5 repmgrd: log details of nodes which can see primary
If a failover is cancelled because other nodes can still see the primary,
log the identies of those nodes.
2019-03-06 13:23:27 +09:00
Ian Barwick
9753bcc8c3 repmgrd: during failover, check if other nodes have seen the primary
In a situation where only some standbys are cut off from the primary,
a failover would result in a split brain/split cluster situation,
as it's likely one of the cut-off standbys will promote itself, and
other cut-off standbys (but not all standbys) will follow it.

To prevent this happening, interrogate the other sibiling nodes to
check whether they've seen the primary within a reasonably short interval;
if this is the case, do not take any failover action.

This feature is experimental.
2019-03-06 13:23:22 +09:00
Ian Barwick
bd35b450da daemon status: with csv output, show repmgrd status as unknown where appropriate
Previously, if PostgreSQL was not running on the node, repmgrd and
pause status were shown as "0", implying their status was known.

This brings the csv output in line with the human-readable output,
which displays "n/a" in this case.
2019-02-28 12:28:04 +09:00
Ian Barwick
1f256d4d73 doc: upate release notes 2019-02-28 10:02:05 +09:00
Ian Barwick
1524e2449f Split command execution functions into separate library
These may need to be executed by repmgrd.
2019-02-27 14:41:38 +09:00
Ian Barwick
0cd2bd2e91 repmgrd: add additional logging during a failover operation 2019-02-27 11:45:34 +09:00
Ian Barwick
98b78df16c Remove unneeded debugging output 2019-02-26 21:17:17 +09:00
Ian Barwick
b946dce2f0 doc: update introductory blurb 2019-02-26 15:19:41 +09:00
Ian Barwick
39234afcbf standby clone: check upstream connections after data copy operation
With long-running copy operations, it's possible the connection(s) to
the primary/source server may go away for some reason, so recheck
their availability before attempting to reuse.
2019-02-26 14:37:51 +09:00
John Naylor
23569a19b1 Doc fix: PostgreSQL 9.4 is no longer considered recent 2019-02-25 13:02:56 +09:00
John Naylor
c650fd3412 Fix typo 2019-02-25 13:02:51 +09:00
Ian Barwick
c30e65b3f2 Add some missing query error logging 2019-02-25 13:02:45 +09:00
117 changed files with 4391 additions and 11542 deletions

5
.gitignore vendored
View File

@@ -42,6 +42,8 @@ lib*.pc
/regression.diffs
/regression.out
/doc/Makefile
# other
/.lineno
*.dSYM
@@ -53,6 +55,3 @@ repmgr
repmgrd
repmgr4
repmgrd4
# generated files
configfile-scan.c

44
HISTORY
View File

@@ -1,44 +1,6 @@
5.0 2019-10-15
general: add PostgreSQL 12 support (Ian)
general: parse configuration file using flex (Ian)
repmgr: rename "repmgr daemon ..." commands to "repmgr service ..." (Ian)
repmgr: improve data directory check (Ian)
repmgr: improve extension check during "standby clone" (Ian)
repmgr: pass provided log level when executing repmgr remotely (Ian)
repmgrd: fix handling of upstream node change check (Ian)
4.4 2019-06-27
repmgr: improve "daemon status" output (Ian)
repmgr: add "--siblings-follow" option to "standby promote" (Ian)
repmgr: add "--repmgrd-force-unpause" option to "standby switchover" (Ian)
repmgr: fix data directory permissions issue in barman mode where
an existing directory is being overwritten (Ian)
repmgr: improve "--dry-run" behaviour for "standby promote" and
"standby switchover" (Ian)
repmgr: when running "standby clone" with the "--upstream-conninfo" option
ensure that "application_name" is set correctly in "primary_conninfo" (Ian)
repmgr: ensure "--dry-run" together with --force when running "standby clone"
in barman mode does not modify an existing data directory (Ian)
repmgr: improve "--dry-run" output when running "standby clone" in
basebackup mode (Ian)
repmgr: improve upstream walsender checks when running "standby clone" (Ian)
repmgr: display node timeline ID in "cluster show" output (Ian)
repmgr: in "cluster show" and "daemon status", show upstream node name
as reported by each individual node (Ian)
repmgr: in "cluster show" and "daemon status", check if a node is attached
to its advertised upstream node
repmgr: use --compact rather than --terse option in "cluster event" (Ian)
repmgr: prevent a standby being cloned from a witness server (Ian)
repmgr: prevent a witness server being registered on the cluster primary (John)
repmgr: ensure BDR2-specific functionality cannot be used on
BDR3 and later (Ian)
repmgr: canonicalize the data directory path (Ian)
repmgr: note that "standby follow" requires a primary to be available (Ian)
repmgrd: monitor standbys attached to primary (Ian)
repmgrd: add "primary visibility consensus" functionality (Ian)
repmgrd: fix memory leak which occurs while the monitored PostgreSQL
node is not running (Ian)
general: documentation converted to DocBook XML format (Ian)
4.3.1 2019-12-??
repmgr: ensure an existing replication slot is not deleted if the
follow target is the node's current upstream (Ian)
4.3 2019-04-02
repmgr: add "daemon (start|stop)" command; GitHub #528 (Ian)

View File

@@ -2,7 +2,6 @@
# Makefile.global.in
# @configure_input@
# Can only be built using pgxs
USE_PGXS=1
@@ -15,9 +14,6 @@ ifeq ($(vpath_build),yes)
VPATH := $(repmgr_abs_srcdir)/$(repmgr_subdir)
USE_VPATH :=$(VPATH)
endif
SED=@SED@
GIT_WORK_TREE=${repmgr_abs_srcdir}
GIT_DIR=${repmgr_abs_srcdir}/.git
export GIT_DIR
@@ -28,13 +24,4 @@ include $(PGXS)
-include ${repmgr_abs_srcdir}/Makefile.custom
REPMGR_VERSION=$(shell awk '/^\#define REPMGR_VERSION / { print $3; }' ${repmgr_abs_srcdir}/repmgr_version.h.in | cut -d '"' -f 2)
REPMGR_RELEASE_DATE=$(shell awk '/^\#define REPMGR_RELEASE_DATE / { print $3; }' ${repmgr_abs_srcdir}/repmgr_version.h.in | cut -d '"' -f 2)
FLEX = flex
##########################################################################
#
# Global targets and rules
%.c: %.l
$(FLEX) $(FLEXFLAGS) -o'$@' $<

View File

@@ -17,11 +17,7 @@ DATA = \
repmgr--4.1--4.2.sql \
repmgr--4.2.sql \
repmgr--4.2--4.3.sql \
repmgr--4.3.sql \
repmgr--4.3--4.4.sql \
repmgr--4.4.sql \
repmgr--4.4--5.0.sql \
repmgr--5.0.sql
repmgr--4.3.sql
REGRESS = repmgr_extension
@@ -53,16 +49,13 @@ $(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-bdr.o repmgr-action-cluster.o repmgr-action-node.o repmgr-action-service.o repmgr-action-daemon.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 repmgrd-bdr.o configfile.o configfile-scan.o log.o dbutils.o strutil.o controldata.o compat.o sysutils.o
repmgr-action-bdr.o repmgr-action-cluster.o repmgr-action-node.o repmgr-action-daemon.o \
configfile.o log.o strutil.o controldata.o dirutil.o compat.o dbutils.o sysutils.o
REPMGRD_OBJS = repmgrd.o repmgrd-physical.o repmgrd-bdr.o configfile.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
$(SED) -E 's/REPMGR_VERSION_DATE.*""/REPMGR_VERSION_DATE "$(DATE)"/' $< >$@; \
$(SED) -i -E 's/PG_ACTUAL_VERSION_NUM/PG_ACTUAL_VERSION_NUM $(VERSION_NUM)/' $@
configfile-scan.c: configfile-scan.l
sed '0,/REPMGR_VERSION_DATE/s,\(REPMGR_VERSION_DATE\).*,\1 "$(DATE)",' $< >$@
$(REPMGR_CLIENT_OBJS): repmgr-client.h repmgr_version.h
@@ -82,19 +75,10 @@ Makefile: Makefile.in config.status configure
Makefile.global: Makefile.global.in config.status configure
./config.status $@
doc: repmgr_version.h
$(MAKE) -C doc html
doc:
$(MAKE) -C doc all
doc-repmgr.html: repmgr_version.h
$(MAKE) -C doc repmgr.html
doc-repmgr-A4.pdf: repmgr_version.h
$(MAKE) -C doc repmgr-A4.pdf
doc-repmgr-US.pdf: repmgr_version.h
$(MAKE) -C doc repmgr-US.pdf
install-doc: doc
install-doc:
$(MAKE) -C doc install
clean: additional-clean
@@ -103,8 +87,6 @@ maintainer-clean: additional-maintainer-clean
additional-clean:
rm -f *.o
rm -f repmgr_version.h
$(MAKE) -C doc clean
additional-maintainer-clean: clean
$(MAKE) -C doc maintainer-clean
@@ -127,4 +109,3 @@ installdirs-scripts:
.PHONY: installdirs-scripts
endif
.PHONY: doc doc-repmgr.html doc-repmgr-A4.pdf doc-repmgr-US.pdf install-doc

View File

@@ -1,366 +0,0 @@
/*
* Scanner for the configuration file
*/
%{
#include <setjmp.h>
#include "repmgr.h"
#include "configfile.h"
/*
* flex emits a yy_fatal_error() function that it calls in response to
* critical errors like malloc failure, file I/O errors, and detection of
* internal inconsistency. That function prints a message and calls exit().
* Mutate it to instead call our handler, which jumps out of the parser.
*/
#undef fprintf
#define fprintf(file, fmt, msg) CONF_flex_fatal(msg)
enum
{
CONF_ID = 1,
CONF_STRING = 2,
CONF_INTEGER = 3,
CONF_REAL = 4,
CONF_EQUALS = 5,
CONF_UNQUOTED_STRING = 6,
CONF_QUALIFIED_ID = 7,
CONF_EOL = 99,
CONF_ERROR = 100
};
static unsigned int ConfigFileLineno;
static const char *CONF_flex_fatal_errmsg;
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(FILE *fp, const char *config_file, KeyValueList *contents, t_configuration_options *options, ItemList *error_list, ItemList *warning_list);
%}
%option 8bit
%option never-interactive
%option nodefault
%option noinput
%option nounput
%option noyywrap
%option warn
%option prefix="CONF_yy"
SIGN ("-"|"+")
DIGIT [0-9]
HEXDIGIT [0-9a-fA-F]
UNIT_LETTER [a-zA-Z]
INTEGER {SIGN}?({DIGIT}+|0x{HEXDIGIT}+){UNIT_LETTER}*
EXPONENT [Ee]{SIGN}?{DIGIT}+
REAL {SIGN}?{DIGIT}*"."{DIGIT}*{EXPONENT}?
LETTER [A-Za-z_\200-\377]
LETTER_OR_DIGIT [A-Za-z_0-9\200-\377]
ID {LETTER}{LETTER_OR_DIGIT}*
QUALIFIED_ID {ID}"."{ID}
UNQUOTED_STRING {LETTER}({LETTER_OR_DIGIT}|[-._:/])*
STRING \'([^'\\\n]|\\.|\'\')*\'
%%
\n ConfigFileLineno++; return CONF_EOL;
[ \t\r]+ /* eat whitespace */
#.* /* eat comment (.* matches anything until newline) */
{ID} return CONF_ID;
{QUALIFIED_ID} return CONF_QUALIFIED_ID;
{STRING} return CONF_STRING;
{UNQUOTED_STRING} return CONF_UNQUOTED_STRING;
{INTEGER} return CONF_INTEGER;
{REAL} return CONF_REAL;
= return CONF_EQUALS;
. return CONF_ERROR;
%%
extern bool
ProcessRepmgrConfigFile(FILE *fp, const char *config_file, t_configuration_options *options, ItemList *error_list, ItemList *warning_list)
{
return ProcessConfigFile(fp, config_file, NULL, options, error_list, warning_list);
}
extern bool
ProcessPostgresConfigFile(FILE *fp, const char *config_file, KeyValueList *contents, ItemList *error_list, ItemList *warning_list)
{
return ProcessConfigFile(fp, config_file, contents, NULL, error_list, warning_list);
}
static bool
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;
sigjmp_buf flex_fatal_jmp;
int errorcount;
int token;
if (sigsetjmp(flex_fatal_jmp, 1) == 0)
{
CONF_flex_fatal_jmp = &flex_fatal_jmp;
}
else
{
/*
* Regain control after a fatal, internal flex error. It may have
* corrupted parser state. Consequently, abandon the file, but trust
* that the state remains sane enough for yy_delete_buffer().
*/
item_list_append_format(error_list,
"%s at file \"%s\" line %u",
CONF_flex_fatal_errmsg, config_file, ConfigFileLineno);
OK = false;
goto cleanup;
}
/*
* Parse
*/
ConfigFileLineno = 1;
errorcount = 0;
lex_buffer = yy_create_buffer(fp, YY_BUF_SIZE);
yy_switch_to_buffer(lex_buffer);
/* This loop iterates once per logical line */
while ((token = yylex()))
{
char *opt_name = NULL;
char *opt_value = NULL;
if (token == CONF_EOL) /* empty or comment line */
continue;
/* first token on line is option name */
if (token != CONF_ID && token != CONF_QUALIFIED_ID)
goto parse_error;
opt_name = pstrdup(yytext);
/* next we have an optional equal sign; discard if present */
token = yylex();
if (token == CONF_EQUALS)
token = yylex();
/* now we must have the option value */
if (token != CONF_ID &&
token != CONF_STRING &&
token != CONF_INTEGER &&
token != CONF_REAL &&
token != CONF_UNQUOTED_STRING)
goto parse_error;
if (token == CONF_STRING) /* strip quotes and escapes */
opt_value = CONF_scanstr(yytext);
else
opt_value = pstrdup(yytext);
/* now we'd like an end of line, or possibly EOF */
token = yylex();
if (token != CONF_EOL)
{
if (token != 0)
goto parse_error;
/* treat EOF like \n for line numbering purposes, cf bug 4752 */
ConfigFileLineno++;
}
/* OK, process the option name and value */
if (contents != NULL)
{
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)
break;
continue;
parse_error:
/* release storage if we allocated any on this line */
if (opt_name)
pfree(opt_name);
if (opt_value)
pfree(opt_value);
/* report the error */
if (token == CONF_EOL || token == 0)
{
item_list_append_format(error_list,
_("syntax error in file \"%s\" line %u, near end of line"),
config_file, ConfigFileLineno - 1);
}
else
{
item_list_append_format(error_list,
_("syntax error in file \"%s\" line %u, near token \"%s\""),
config_file, ConfigFileLineno, yytext);
}
OK = false;
errorcount++;
/*
* To avoid producing too much noise when fed a totally bogus file,
* give up after 100 syntax errors per file (an arbitrary number).
* Also, if we're only logging the errors at DEBUG level anyway, might
* as well give up immediately. (This prevents postmaster children
* from bloating the logs with duplicate complaints.)
*/
if (errorcount >= 100)
{
fprintf(stderr,
_("too many syntax errors found, abandoning file \"%s\"\n"),
config_file);
break;
}
/* resync to next end-of-line or EOF */
while (token != CONF_EOL && token != 0)
token = yylex();
/* break out of loop on EOF */
if (token == 0)
break;
}
cleanup:
yy_delete_buffer(lex_buffer);
return OK;
}
/*
* scanstr
*
* Strip the quotes surrounding the given string, and collapse any embedded
* '' sequences and backslash escapes.
*
* the string returned is palloc'd and should eventually be pfree'd by the
* caller.
*/
static char *
CONF_scanstr(const char *s)
{
char *newStr;
int len,
i,
j;
Assert(s != NULL && s[0] == '\'');
len = strlen(s);
Assert(s != NULL);
Assert(len >= 2);
Assert(s[len - 1] == '\'');
/* Skip the leading quote; we'll handle the trailing quote below */
s++, len--;
/* Since len still includes trailing quote, this is enough space */
newStr = palloc(len);
for (i = 0, j = 0; i < len; i++)
{
if (s[i] == '\\')
{
i++;
switch (s[i])
{
case 'b':
newStr[j] = '\b';
break;
case 'f':
newStr[j] = '\f';
break;
case 'n':
newStr[j] = '\n';
break;
case 'r':
newStr[j] = '\r';
break;
case 't':
newStr[j] = '\t';
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
{
int k;
long octVal = 0;
for (k = 0;
s[i + k] >= '0' && s[i + k] <= '7' && k < 3;
k++)
octVal = (octVal << 3) + (s[i + k] - '0');
i += k - 1;
newStr[j] = ((char) octVal);
}
break;
default:
newStr[j] = s[i];
break;
} /* switch */
}
else if (s[i] == '\'' && s[i + 1] == '\'')
{
/* doubled quote becomes just one quote */
newStr[j] = s[++i];
}
else
newStr[j] = s[i];
j++;
}
/* We copied the ending quote to newStr, so replace with \0 */
Assert(j > 0 && j <= len);
newStr[--j] = '\0';
return newStr;
}
/*
* Flex fatal errors bring us here. Stash the error message and jump back to
* ParseConfigFp(). Assume all msg arguments point to string constants; this
* holds for flex 2.5.31 (earliest we support) and flex 2.5.35 (latest as of
* this writing). Otherwise, we would need to copy the message.
*
* We return "int" since this takes the place of calls to fprintf().
*/
static int
CONF_flex_fatal(const char *msg)
{
CONF_flex_fatal_errmsg = msg;
siglongjmp(*CONF_flex_fatal_jmp, 1);
return 0; /* keep compiler quiet */
}

File diff suppressed because it is too large Load Diff

View File

@@ -28,12 +28,6 @@
/* magic number for use in t_recovery_conf */
#define TARGET_TIMELINE_LATEST 0
/*
* 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"
extern bool config_file_found;
extern char config_file_path[MAXPGPATH];
@@ -94,7 +88,7 @@ typedef struct
/* log settings */
char log_level[MAXLEN];
char log_facility[MAXLEN];
char log_file[MAXPGPATH];
char log_file[MAXLEN];
int log_status_interval;
/* standby clone settings */
@@ -154,12 +148,6 @@ typedef struct
bool primary_visibility_consensus;
char failover_validation_command[MAXPGPATH];
int election_rerun_interval;
int child_nodes_check_interval;
int child_nodes_disconnect_min_count;
int child_nodes_connected_min_count;
bool child_nodes_connected_include_witness;
int child_nodes_disconnect_timeout;
char child_nodes_disconnect_command[MAXPGPATH];
/* BDR settings */
bool bdr_local_monitoring_only;
@@ -233,11 +221,6 @@ typedef struct
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, "", \
/* BDR settings */ \
false, DEFAULT_BDR_RECOVERY_TIMEOUT, \
/* service settings */ \
@@ -259,7 +242,7 @@ typedef struct
typedef struct
{
char slot[MAXLEN];
char wal_method[MAXLEN];
char xlog_method[MAXLEN];
bool no_slot; /* from PostgreSQL 10 */
} t_basebackup_options;
@@ -323,8 +306,6 @@ const char *progname(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(t_configuration_options *options, ItemList *error_list, ItemList *warning_list, const char *name, const char *value);
bool parse_recovery_conf(const char *data_dir, t_recovery_conf *conf);
bool parse_bool(const char *s,
@@ -350,10 +331,4 @@ void exit_with_cli_errors(ItemList *error_list, const char *repmgr_command);
void print_item_list(ItemList *item_list);
const char *print_connection_check_type(ConnectionCheckType type);
extern bool modify_auto_conf(const char *data_dir, KeyValueList *items);
extern bool ProcessRepmgrConfigFile(FILE *fp, const char *config_file, t_configuration_options *options, 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_ */

151
configure vendored
View File

@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.69 for repmgr 5.0.0.
# Generated by GNU Autoconf 2.69 for repmgr 4.3.
#
# Report bugs to <repmgr@googlegroups.com>.
#
@@ -582,16 +582,13 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='repmgr'
PACKAGE_TARNAME='repmgr'
PACKAGE_VERSION='5.0.0'
PACKAGE_STRING='repmgr 5.0.0'
PACKAGE_VERSION='4.3'
PACKAGE_STRING='repmgr 4.3'
PACKAGE_BUGREPORT='repmgr@googlegroups.com'
PACKAGE_URL='https://repmgr.org/'
ac_subst_vars='LTLIBOBJS
LIBOBJS
HAVE_SED
HAVE_GSED
HAVE_GNUSED
vpath_build
SED
PG_CONFIG
@@ -1181,7 +1178,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.0.0 to adapt to many kinds of systems.
\`configure' configures repmgr 4.3 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1242,7 +1239,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
short | recursive ) echo "Configuration of repmgr 5.0.0:";;
short | recursive ) echo "Configuration of repmgr 4.3:";;
esac
cat <<\_ACEOF
@@ -1316,7 +1313,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
repmgr configure 5.0.0
repmgr configure 4.3
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
@@ -1335,7 +1332,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.0.0, which was
It was created by repmgr $as_me 4.3, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
@@ -1850,137 +1847,12 @@ else
fi
# Extract the first word of "gnused", so it can be a program name with args.
set dummy gnused; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if ${ac_cv_prog_HAVE_GNUSED+:} false; then :
$as_echo_n "(cached) " >&6
else
if test -n "$HAVE_GNUSED"; then
ac_cv_prog_HAVE_GNUSED="$HAVE_GNUSED" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_prog_HAVE_GNUSED="yes"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
fi
done
done
IFS=$as_save_IFS
test -z "$ac_cv_prog_HAVE_GNUSED" && ac_cv_prog_HAVE_GNUSED="no"
fi
fi
HAVE_GNUSED=$ac_cv_prog_HAVE_GNUSED
if test -n "$HAVE_GNUSED"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $HAVE_GNUSED" >&5
$as_echo "$HAVE_GNUSED" >&6; }
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi
# Extract the first word of "gsed", so it can be a program name with args.
set dummy gsed; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if ${ac_cv_prog_HAVE_GSED+:} false; then :
$as_echo_n "(cached) " >&6
else
if test -n "$HAVE_GSED"; then
ac_cv_prog_HAVE_GSED="$HAVE_GSED" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_prog_HAVE_GSED="yes"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
fi
done
done
IFS=$as_save_IFS
test -z "$ac_cv_prog_HAVE_GSED" && ac_cv_prog_HAVE_GSED="no"
fi
fi
HAVE_GSED=$ac_cv_prog_HAVE_GSED
if test -n "$HAVE_GSED"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $HAVE_GSED" >&5
$as_echo "$HAVE_GSED" >&6; }
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi
# Extract the first word of "sed", so it can be a program name with args.
set dummy sed; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if ${ac_cv_prog_HAVE_SED+:} false; then :
$as_echo_n "(cached) " >&6
else
if test -n "$HAVE_SED"; then
ac_cv_prog_HAVE_SED="$HAVE_SED" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_prog_HAVE_SED="yes"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
fi
done
done
IFS=$as_save_IFS
test -z "$ac_cv_prog_HAVE_SED" && ac_cv_prog_HAVE_SED="no"
fi
fi
HAVE_SED=$ac_cv_prog_HAVE_SED
if test -n "$HAVE_SED"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $HAVE_SED" >&5
$as_echo "$HAVE_SED" >&6; }
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi
if test "$HAVE_GNUSED" = yes; then
SED=gnused
else
if test "$HAVE_GSED" = yes; then
SED=gsed
else
SED=sed
fi
fi
ac_config_files="$ac_config_files Makefile"
ac_config_files="$ac_config_files Makefile.global"
ac_config_files="$ac_config_files doc/Makefile"
cat >confcache <<\_ACEOF
# This file is a shell script that caches the results of configure
# tests run on this system so they can be shared between configure
@@ -2487,7 +2359,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.0.0, which was
This file was extended by repmgr $as_me 4.3, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -2550,7 +2422,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.0.0
repmgr config.status 4.3
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"
@@ -2674,6 +2546,7 @@ do
"config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
"Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
"Makefile.global") CONFIG_FILES="$CONFIG_FILES Makefile.global" ;;
"doc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;;
*) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
esac

View File

@@ -1,4 +1,4 @@
AC_INIT([repmgr], [5.0.0], [repmgr@googlegroups.com], [repmgr], [https://repmgr.org/])
AC_INIT([repmgr], [4.3], [repmgr@googlegroups.com], [repmgr], [https://repmgr.org/])
AC_COPYRIGHT([Copyright (c) 2010-2019, 2ndQuadrant Ltd.])
@@ -57,23 +57,8 @@ else
fi
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)
if test "$HAVE_GNUSED" = yes; then
SED=gnused
else
if test "$HAVE_GSED" = yes; then
SED=gsed
else
SED=sed
fi
fi
AC_SUBST(SED)
AC_CONFIG_FILES([Makefile])
AC_CONFIG_FILES([Makefile.global])
AC_CONFIG_FILES([doc/Makefile])
AC_OUTPUT

View File

@@ -73,16 +73,7 @@ while(<$fh>) {
if ($param eq 'data_directory') {
$data_directory_found = 1;
}
# Don't quote numbers
if ($value =~ /^\d+$/) {
push @outp, sprintf(q|%s=%s|, $param, $value);
}
# Quote everything else
else {
$value =~ s/'/''/g;
push @outp, sprintf(q|%s='%s'|, $param, $value);
}
push @outp, $line;
}
}
@@ -92,6 +83,6 @@ print join("\n", @outp);
print "\n";
if ($data_directory_found == 0) {
print "data_directory=''\n";
print "data_directory=\n";
}

View File

@@ -310,23 +310,7 @@ get_controlfile(const char *DataDir)
control_file_info->control_file_processed = true;
if (version_num >= 120000)
{
#if PG_ACTUAL_VERSION_NUM >= 120000
ControlFileData12 *ptr = (struct ControlFileData12 *)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;
#else
fprintf(stderr, "ERROR: please use a repmgr version built for PostgreSQL 12\n");
exit(ERR_BAD_CONFIG);
#endif
}
else if (version_num >= 110000)
if (version_num >= 110000)
{
ControlFileData11 *ptr = (struct ControlFileData11 *)ControlFileDataPtr;
control_file_info->system_identifier = ptr->system_identifier;

View File

@@ -12,7 +12,6 @@
#include "postgres_fe.h"
#include "catalog/pg_control.h"
#define MAX_VERSION_STRING 24
/*
* A simplified representation of pg_control containing only those fields
@@ -56,7 +55,7 @@ typedef struct CheckPoint93
} CheckPoint93;
/* Same for 9.5, 9.6, 10, 11 */
/* Same for 9.5, 9.6, 10, HEAD */
typedef struct CheckPoint95
{
XLogRecPtr redo; /* next RecPtr available when we began to
@@ -84,50 +83,6 @@ typedef struct CheckPoint95
} CheckPoint95;
#if PG_ACTUAL_VERSION_NUM >= 120000
/*
* Following fields removed in PostgreSQL 12;
*
* uint32 nextXidEpoch;
* TransactionId nextXid;
*
* and replaced by:
*
* FullTransactionId nextFullXid;
*/
typedef struct CheckPoint12
{
XLogRecPtr redo; /* next RecPtr available when we began to
* create CheckPoint (i.e. REDO start point) */
TimeLineID ThisTimeLineID; /* current TLI */
TimeLineID PrevTimeLineID; /* previous TLI, if this record begins a new
* timeline (equals ThisTimeLineID otherwise) */
bool fullPageWrites; /* current full_page_writes */
FullTransactionId nextFullXid; /* next free full transaction ID */
Oid nextOid; /* next free OID */
MultiXactId nextMulti; /* next free MultiXactId */
MultiXactOffset nextMultiOffset; /* next free MultiXact offset */
TransactionId oldestXid; /* cluster-wide minimum datfrozenxid */
Oid oldestXidDB; /* database with minimum datfrozenxid */
MultiXactId oldestMulti; /* cluster-wide minimum datminmxid */
Oid oldestMultiDB; /* database with minimum datminmxid */
pg_time_t time; /* time stamp of checkpoint */
TransactionId oldestCommitTsXid; /* oldest Xid with valid commit
* timestamp */
TransactionId newestCommitTsXid; /* newest Xid with valid commit
* timestamp */
/*
* Oldest XID still running. This is only needed to initialize hot standby
* mode from an online checkpoint, so we only bother calculating this for
* online checkpoints and only when wal_level is replica. Otherwise it's
* set to InvalidTransactionId.
*/
TransactionId oldestActiveXid;
} CheckPoint12;
#endif
typedef struct ControlFileData93
{
uint64 system_identifier;
@@ -378,65 +333,6 @@ typedef struct ControlFileData11
} ControlFileData11;
#if PG_ACTUAL_VERSION_NUM >= 120000
/*
* Following field added in Pg12:
*
* int max_wal_senders;
*/
typedef struct ControlFileData12
{
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 */
CheckPoint12 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;
bool wal_log_hints;
int MaxConnections;
int max_worker_processes;
int max_wal_senders;
int max_prepared_xacts;
int max_locks_per_xact;
bool track_commit_timestamp;
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 */
uint32 loblksize; /* chunk size in pg_largeobject */
bool float4ByVal; /* float4 pass-by-value? */
bool float8ByVal; /* float8, int8, etc pass-by-value? */
uint32 data_checksum_version;
} ControlFileData12;
#endif
extern int get_pg_version(const char *data_directory, char *version_string);
extern DBState get_db_state(const char *data_directory);
extern const char *describe_db_state(DBState state);

382
dbutils.c
View File

@@ -53,8 +53,6 @@ static PGconn *_establish_db_connection(const char *conninfo,
static PGconn *_get_primary_connection(PGconn *standby_conn, int *primary_id, char *primary_conninfo_out, bool quiet);
static bool _set_config(PGconn *conn, const char *config_param, const char *sqlquery);
static bool _get_pg_setting(PGconn *conn, const char *setting, char *str_output, int *int_output);
static RecordStatus _get_node_record(PGconn *conn, char *sqlquery, t_node_info *node_info, bool init_defaults);
static void _populate_node_record(PGresult *res, t_node_info *node_info, int row, bool init_defaults);
@@ -336,10 +334,12 @@ establish_db_connection_by_params(t_conninfo_param_list *param_list,
bool
is_superuser_connection(PGconn *conn, t_connection_user *userinfo)
{
char *current_user = NULL;
const char *superuser_status = NULL;
bool is_superuser = false;
const char *current_user = PQuser(conn);
const char *superuser_status = PQparameterStatus(conn, "is_superuser");
current_user = PQuser(conn);
superuser_status = PQparameterStatus(conn, "is_superuser");
is_superuser = (strcmp(superuser_status, "on") == 0) ? true : false;
if (userinfo != NULL)
@@ -354,51 +354,6 @@ is_superuser_connection(PGconn *conn, t_connection_user *userinfo)
}
bool
connection_has_pg_settings(PGconn *conn)
{
bool has_pg_settings = false;
/* superusers can always read pg_settings */
if (is_superuser_connection(conn, NULL) == true)
{
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 CASE "
" WHEN pg_catalog.pg_has_role('pg_monitor','MEMBER') "
" THEN TRUE "
" WHEN pg_catalog.pg_has_role('pg_read_all_settings','MEMBER') "
" THEN TRUE "
" ELSE FALSE "
" END AS has_pg_settings");
res = PQexec(conn, query.data);
if (PQresultStatus(res) != PGRES_TUPLES_OK)
{
log_db_error(conn, query.data,
_("connection_has_pg_settings(): unable to query user roles"));
}
else
{
has_pg_settings = atobool(PQgetvalue(res, 0, 0));
}
termPQExpBuffer(&query);
PQclear(res);
}
return has_pg_settings;
}
void
close_connection(PGconn **conn)
{
@@ -1040,37 +995,52 @@ guc_set(PGconn *conn, const char *parameter, const char *op,
return retval;
}
/**
* Just like guc_set except with an extra parameter containing the name of
* the pg datatype so that the comparison can be done properly.
*/
int
guc_set_typed(PGconn *conn, const char *parameter, const char *op,
const char *value, const char *datatype)
{
PQExpBufferData query;
PGresult *res = NULL;
int retval = 1;
char *escaped_parameter = escape_string(conn, parameter);
char *escaped_value = escape_string(conn, value);
initPQExpBuffer(&query);
appendPQExpBuffer(&query,
"SELECT true FROM pg_catalog.pg_settings "
" WHERE name = '%s' AND setting::%s %s '%s'::%s",
parameter, datatype, op, value, datatype);
log_verbose(LOG_DEBUG, "guc_set_typed():\n%s", query.data);
res = PQexec(conn, query.data);
if (PQresultStatus(res) != PGRES_TUPLES_OK)
{
log_db_error(conn, query.data, _("guc_set_typed(): unable to execute query"));
retval = -1;
}
else if (PQntuples(res) == 0)
{
retval = 0;
}
pfree(escaped_parameter);
pfree(escaped_value);
termPQExpBuffer(&query);
PQclear(res);
return retval;
}
bool
get_pg_setting(PGconn *conn, const char *setting, char *output)
{
bool success = _get_pg_setting(conn, setting, output, NULL);
if (success == true)
{
log_verbose(LOG_DEBUG, _("get_pg_setting(): returned value is \"%s\""), output);
}
return success;
}
bool
get_pg_setting_int(PGconn *conn, const char *setting, int *output)
{
bool success = _get_pg_setting(conn, setting, NULL, output);
if (success == true)
{
log_verbose(LOG_DEBUG, _("get_pg_setting_int(): returned value is \"%i\""), *output);
}
return success;
}
bool
_get_pg_setting(PGconn *conn, const char *setting, char *str_output, int *int_output)
{
PQExpBufferData query;
PGresult *res = NULL;
@@ -1111,11 +1081,7 @@ _get_pg_setting(PGconn *conn, const char *setting, char *str_output, int *int_ou
{
if (strcmp(PQgetvalue(res, i, 0), setting) == 0)
{
if (str_output != NULL)
snprintf(str_output, MAXLEN, "%s", PQgetvalue(res, i, 1));
else if (int_output != NULL)
*int_output = atoi(PQgetvalue(res, i, 1));
snprintf(output, MAXLEN, "%s", PQgetvalue(res, i, 1));
success = true;
break;
}
@@ -1126,6 +1092,10 @@ _get_pg_setting(PGconn *conn, const char *setting, char *str_output, int *int_ou
}
}
if (success == true)
{
log_verbose(LOG_DEBUG, _("get_pg_setting(): returned value is \"%s\""), output);
}
termPQExpBuffer(&query);
PQclear(res);
@@ -1134,7 +1104,6 @@ _get_pg_setting(PGconn *conn, const char *setting, char *str_output, int *int_ou
}
bool
alter_system_int(PGconn *conn, const char *name, int value)
{
@@ -1582,12 +1551,12 @@ get_ready_archive_files(PGconn *conn, const char *data_directory)
}
bool
identify_system(PGconn *repl_conn, t_system_identification *identification)
{
PGresult *res = NULL;
/* semicolon required here */
res = PQexec(repl_conn, "IDENTIFY_SYSTEM;");
if (PQresultStatus(res) != PGRES_TUPLES_OK || !PQntuples(res))
@@ -1606,44 +1575,6 @@ identify_system(PGconn *repl_conn, t_system_identification *identification)
return true;
}
/*
* Return the system identifier by querying pg_control_system().
*
* Note there is a similar function in controldata.c ("get_system_identifier()")
* which reads the control file.
*/
uint64
system_identifier(PGconn *conn)
{
uint64 system_identifier = UNKNOWN_SYSTEM_IDENTIFIER;
PGresult *res = NULL;
/*
* pg_control_system() was introduced in PostgreSQL 9.6
*/
if (PQserverVersion(conn) < 90600)
{
return UNKNOWN_SYSTEM_IDENTIFIER;
}
res = PQexec(conn, "SELECT system_identifier FROM pg_catalog.pg_control_system()");
if (PQresultStatus(res) != PGRES_TUPLES_OK)
{
log_db_error(conn, NULL, _("system_identifier(): unable to query pg_control_system()"));
}
else
{
system_identifier = atol(PQgetvalue(res, 0, 0));
}
PQclear(res);
return system_identifier;
}
TimeLineHistoryEntry *
get_timeline_history(PGconn *repl_conn, TimeLineID tli)
{
@@ -1741,46 +1672,6 @@ get_timeline_history(PGconn *repl_conn, TimeLineID tli)
}
bool
get_child_nodes(PGconn *conn, int node_id, NodeInfoList *node_list)
{
PQExpBufferData query;
PGresult *res = NULL;
bool success = true;
initPQExpBuffer(&query);
appendPQExpBuffer(&query,
" SELECT n.node_id, n.type, n.upstream_node_id, n.node_name, n.conninfo, n.repluser, "
" n.slot_name, n.location, n.priority, n.active, n.config_file, "
" '' AS upstream_node_name, "
" CASE WHEN sr.application_name IS NULL THEN FALSE ELSE TRUE END AS attached "
" FROM repmgr.nodes n "
" LEFT JOIN pg_catalog.pg_stat_replication sr "
" ON sr.application_name = n.node_name "
" WHERE n.upstream_node_id = %i ",
node_id);
log_verbose(LOG_DEBUG, "get_active_sibling_node_records():\n%s", query.data);
res = PQexec(conn, query.data);
if (PQresultStatus(res) != PGRES_TUPLES_OK)
{
log_db_error(conn, query.data, _("get_active_sibling_records(): unable to execute query"));
success = false;
}
termPQExpBuffer(&query);
/* this will return an empty list if there was an error executing the query */
_populate_node_records(res, node_list);
PQclear(res);
return success;
}
/* =============================== */
/* repmgrd shared memory functions */
/* =============================== */
@@ -1908,20 +1799,8 @@ repmgrd_set_pid(PGconn *conn, pid_t repmgrd_pid, const char *pidfile)
initPQExpBuffer(&query);
appendPQExpBuffer(&query,
"SELECT repmgr.set_repmgrd_pid(%i, ",
(int) repmgrd_pid);
if (pidfile != NULL)
{
appendPQExpBuffer(&query,
" '%s')",
pidfile);
}
else
{
appendPQExpBufferStr(&query,
" NULL)");
}
"SELECT repmgr.set_repmgrd_pid(%i, '%s')",
(int) repmgrd_pid, pidfile);
res = PQexec(conn, query.data);
termPQExpBuffer(&query);
@@ -2061,61 +1940,6 @@ get_wal_receiver_pid(PGconn *conn)
return wal_receiver_pid;
}
int
repmgrd_get_upstream_node_id(PGconn *conn)
{
PGresult *res = NULL;
int upstream_node_id = UNKNOWN_NODE_ID;
const char *sqlquery = "SELECT repmgr.get_upstream_node_id()";
res = PQexec(conn, sqlquery);
if (PQresultStatus(res) != PGRES_TUPLES_OK)
{
log_db_error(conn, sqlquery, _("repmgrd_get_upstream_node_id(): unable to execute query"));
}
else if (!PQgetisnull(res, 0, 0))
{
upstream_node_id = atoi(PQgetvalue(res, 0, 0));
}
PQclear(res);
return upstream_node_id;
}
bool
repmgrd_set_upstream_node_id(PGconn *conn, int node_id)
{
PQExpBufferData query;
PGresult *res = NULL;
bool success = true;
initPQExpBuffer(&query);
appendPQExpBuffer(&query,
" SELECT repmgr.set_upstream_node_id(%i) ",
node_id);
log_verbose(LOG_DEBUG, "repmgrd_set_upstream_node_id():\n %s", query.data);
res = PQexec(conn, query.data);
if (PQresultStatus(res) != PGRES_TUPLES_OK)
{
log_db_error(conn, query.data,
_("repmgrd_set_upstream_node_id(): unable to set upstream node ID (provided value: %i)"), node_id);
success = false;
}
termPQExpBuffer(&query);
PQclear(res);
return success;
}
/* ================ */
/* result functions */
/* ================ */
@@ -2147,9 +1971,9 @@ get_repmgr_extension_status(PGconn *conn, t_extension_versions *extversions)
appendPQExpBufferStr(&query,
" SELECT ae.name, e.extname, "
" ae.default_version, "
" (((FLOOR(ae.default_version::NUMERIC)::INT) * 10000) + (ae.default_version::NUMERIC - FLOOR(ae.default_version::NUMERIC)::INT) * 1000)::INT AS available, "
" (((ae.default_version::NUMERIC::INT) * 10000) + (ae.default_version::NUMERIC - ae.default_version::NUMERIC::INT) * 1000)::INT AS available, "
" ae.installed_version, "
" (((FLOOR(ae.installed_version::NUMERIC)::INT) * 10000) + (ae.installed_version::NUMERIC - FLOOR(ae.installed_version::NUMERIC)::INT) * 1000)::INT AS installed "
" (((ae.installed_version::NUMERIC::INT) * 10000) + (ae.installed_version::NUMERIC - ae.installed_version::NUMERIC::INT) * 1000)::INT AS installed "
" FROM pg_catalog.pg_available_extensions ae "
"LEFT JOIN pg_catalog.pg_extension e "
" ON e.extname=ae.name "
@@ -2394,18 +2218,9 @@ _populate_node_record(PGresult *res, t_node_info *node_info, int row, bool init_
node_info->active = atobool(PQgetvalue(res, row, 9));
snprintf(node_info->config_file, sizeof(node_info->config_file), "%s", PQgetvalue(res, row, 10));
/* These are only set by certain queries */
/* This won't normally be set */
snprintf(node_info->upstream_node_name, sizeof(node_info->upstream_node_name), "%s", PQgetvalue(res, row, 11));
if (PQgetisnull(res, row, 12))
{
node_info->attached = NODE_ATTACHED_UNKNOWN;
}
else
{
node_info->attached = atobool(PQgetvalue(res, row, 12)) ? NODE_ATTACHED : NODE_DETACHED;
}
/* Set remaining struct fields with default values */
if (init_defaults == true)
@@ -2527,7 +2342,8 @@ get_node_record_with_upstream(PGconn *conn, int node_id, t_node_info *node_info)
initPQExpBuffer(&query);
appendPQExpBuffer(&query,
" SELECT " REPMGR_NODES_COLUMNS_WITH_UPSTREAM
" SELECT n.node_id, n.type, n.upstream_node_id, n.node_name, n.conninfo, n.repluser, "
" n.slot_name, n.location, n.priority, n.active, n.config_file, un.node_name AS upstream_node_name "
" FROM repmgr.nodes n "
" LEFT JOIN repmgr.nodes un "
" ON un.node_id = n.upstream_node_id"
@@ -2570,7 +2386,7 @@ get_node_record_by_name(PGconn *conn, const char *node_name, t_node_info *node_i
if (record_status == RECORD_NOT_FOUND)
{
log_verbose(LOG_DEBUG, "get_node_record_by_name(): no record found for node \"%s\"",
log_verbose(LOG_DEBUG, "get_node_record_by_name(): no record found for node %s",
node_name);
}
@@ -2826,7 +2642,8 @@ get_all_node_records_with_upstream(PGconn *conn, NodeInfoList *node_list)
initPQExpBuffer(&query);
appendPQExpBufferStr(&query,
" SELECT " REPMGR_NODES_COLUMNS_WITH_UPSTREAM
" SELECT n.node_id, n.type, n.upstream_node_id, n.node_name, n.conninfo, n.repluser, "
" n.slot_name, n.location, n.priority, n.active, n.config_file, un.node_name AS upstream_node_name "
" FROM repmgr.nodes n "
" LEFT JOIN repmgr.nodes un "
" ON un.node_id = n.upstream_node_id"
@@ -3450,10 +3267,6 @@ clear_node_info_list(NodeInfoList *nodes)
while (cell != NULL)
{
next_cell = cell->next;
if (cell->node_info->replication_info != NULL)
pfree(cell->node_info->replication_info);
pfree(cell->node_info);
pfree(cell);
cell = next_cell;
@@ -5120,7 +4933,6 @@ init_replication_info(ReplInfo *replication_info)
{
memset(replication_info->current_timestamp, 0, sizeof(replication_info->current_timestamp));
replication_info->in_recovery = false;
replication_info->timeline_id = UNKNOWN_TIMELINE_ID;
replication_info->last_wal_receive_lsn = InvalidXLogRecPtr;
replication_info->last_wal_replay_lsn = InvalidXLogRecPtr;
memset(replication_info->last_xact_replay_timestamp, 0, sizeof(replication_info->last_xact_replay_timestamp));
@@ -5128,7 +4940,6 @@ init_replication_info(ReplInfo *replication_info)
replication_info->receiving_streamed_wal = true;
replication_info->wal_replay_paused = false;
replication_info->upstream_last_seen = -1;
replication_info->upstream_node_id = UNKNOWN_NODE_ID;
}
@@ -5157,8 +4968,7 @@ get_replication_info(PGconn *conn, t_server_type node_type, ReplInfo *replicatio
" END AS replication_lag_time, "
" last_wal_receive_lsn >= last_wal_replay_lsn AS receiving_streamed_wal, "
" wal_replay_paused, "
" upstream_last_seen, "
" upstream_node_id "
" upstream_last_seen "
" FROM ( "
" SELECT CURRENT_TIMESTAMP AS ts, "
" pg_catalog.pg_is_in_recovery() AS in_recovery, "
@@ -5198,12 +5008,10 @@ get_replication_info(PGconn *conn, t_server_type node_type, ReplInfo *replicatio
" END AS wal_replay_paused, ");
}
/* Add information about upstream node from shared memory */
if (node_type == WITNESS)
{
appendPQExpBufferStr(&query,
" repmgr.get_upstream_last_seen() AS upstream_last_seen, "
" repmgr.get_upstream_node_id() AS upstream_node_id ");
" repmgr.get_upstream_last_seen() AS upstream_last_seen");
}
else
{
@@ -5211,12 +5019,7 @@ get_replication_info(PGconn *conn, t_server_type node_type, ReplInfo *replicatio
" CASE WHEN pg_catalog.pg_is_in_recovery() IS FALSE "
" THEN -1 "
" ELSE repmgr.get_upstream_last_seen() "
" END AS upstream_last_seen, ");
appendPQExpBufferStr(&query,
" CASE WHEN pg_catalog.pg_is_in_recovery() IS FALSE "
" THEN -1 "
" ELSE repmgr.get_upstream_node_id() "
" END AS upstream_node_id ");
" END AS upstream_last_seen ");
}
appendPQExpBufferStr(&query,
@@ -5247,7 +5050,6 @@ get_replication_info(PGconn *conn, t_server_type node_type, ReplInfo *replicatio
replication_info->receiving_streamed_wal = atobool(PQgetvalue(res, 0, 6));
replication_info->wal_replay_paused = atobool(PQgetvalue(res, 0, 7));
replication_info->upstream_last_seen = atoi(PQgetvalue(res, 0, 8));
replication_info->upstream_node_id = atoi(PQgetvalue(res, 0, 9));
}
termPQExpBuffer(&query);
@@ -5308,38 +5110,6 @@ get_replication_lag_seconds(PGconn *conn)
}
TimeLineID
get_node_timeline(PGconn *conn)
{
TimeLineID timeline_id = UNKNOWN_TIMELINE_ID;
PGresult *res = NULL;
/*
* PG_control_checkpoint() was introduced in PostgreSQL 9.6
*/
if (PQserverVersion(conn) < 90600)
{
return UNKNOWN_TIMELINE_ID;
}
res = PQexec(conn, "SELECT timeline_id FROM pg_catalog.pg_control_checkpoint()");
if (PQresultStatus(res) != PGRES_TUPLES_OK)
{
log_db_error(conn, NULL, _("get_node_timeline(): unable to query pg_control_system()"));
}
else
{
timeline_id = atoi(PQgetvalue(res, 0, 0));
}
PQclear(res);
return timeline_id;
}
void
get_node_replication_stats(PGconn *conn, t_node_info *node_info)
{
@@ -5405,7 +5175,7 @@ get_node_replication_stats(PGconn *conn, t_node_info *node_info)
}
NodeAttached
bool
is_downstream_node_attached(PGconn *conn, char *node_name)
{
PQExpBufferData query;
@@ -5415,8 +5185,7 @@ is_downstream_node_attached(PGconn *conn, char *node_name)
initPQExpBuffer(&query);
appendPQExpBuffer(&query,
" SELECT pg_catalog.count(*) "
" FROM pg_catalog.pg_stat_replication "
" SELECT pg_catalog.count(*) FROM pg_catalog.pg_stat_replication "
" WHERE application_name = '%s'",
node_name);
@@ -5431,7 +5200,7 @@ is_downstream_node_attached(PGconn *conn, char *node_name)
termPQExpBuffer(&query);
PQclear(res);
return NODE_ATTACHED_UNKNOWN;
return false;
}
if (PQntuples(res) != 1)
@@ -5441,7 +5210,7 @@ is_downstream_node_attached(PGconn *conn, char *node_name)
termPQExpBuffer(&query);
PQclear(res);
return NODE_ATTACHED_UNKNOWN;
return false;
}
c = atoi(PQgetvalue(res, 0, 0));
@@ -5453,28 +5222,27 @@ is_downstream_node_attached(PGconn *conn, char *node_name)
{
log_verbose(LOG_WARNING, _("node \"%s\" not found in \"pg_stat_replication\""), node_name);
return NODE_DETACHED;
return false;
}
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;
return true;
}
void
set_upstream_last_seen(PGconn *conn, int upstream_node_id)
set_upstream_last_seen(PGconn *conn)
{
PQExpBufferData query;
PGresult *res = NULL;
initPQExpBuffer(&query);
appendPQExpBuffer(&query,
"SELECT repmgr.set_upstream_last_seen(%i)",
upstream_node_id);
appendPQExpBufferStr(&query,
"SELECT repmgr.set_upstream_last_seen()");
res = PQexec(conn, query.data);

View File

@@ -29,38 +29,7 @@
#include "strutil.h"
#include "voting.h"
#define REPMGR_NODES_COLUMNS \
"n.node_id, " \
"n.type, " \
"n.upstream_node_id, " \
"n.node_name, " \
"n.conninfo, " \
"n.repluser, " \
"n.slot_name, " \
"n.location, " \
"n.priority, " \
"n.active, " \
"n.config_file, " \
"'' AS upstream_node_name, " \
"NULL AS attached "
#define REPMGR_NODES_COLUMNS_WITH_UPSTREAM \
"n.node_id, " \
"n.type, " \
"n.upstream_node_id, " \
"n.node_name, " \
"n.conninfo, " \
"n.repluser, " \
"n.slot_name, " \
"n.location, " \
"n.priority, " \
"n.active, "\
"n.config_file, " \
"un.node_name AS upstream_node_name, " \
"NULL AS attached "
#define REPMGR_NODES_COLUMNS "n.node_id, n.type, n.upstream_node_id, n.node_name, n.conninfo, n.repluser, n.slot_name, n.location, n.priority, n.active, n.config_file, '' AS upstream_node_name "
#define BDR2_NODES_COLUMNS "node_sysid, node_timeline, node_dboid, node_name, node_local_dsn, ''"
#define BDR3_NODES_COLUMNS "ns.node_id, 0, 0, ns.node_name, ns.interface_connstr, ns.peer_state_name"
@@ -123,13 +92,6 @@ typedef enum
CONN_ERROR
} ConnectionStatus;
typedef enum
{
NODE_ATTACHED_UNKNOWN = -1,
NODE_DETACHED,
NODE_ATTACHED
} NodeAttached;
typedef enum
{
SLOT_UNKNOWN = -1,
@@ -145,7 +107,6 @@ typedef enum
} BackupState;
/*
* Struct to store extension version information
*/
@@ -164,28 +125,8 @@ typedef struct s_extension_versions {
UNKNOWN_SERVER_VERSION_NUM \
}
typedef struct
{
char current_timestamp[MAXLEN];
bool in_recovery;
TimeLineID timeline_id;
XLogRecPtr last_wal_receive_lsn;
XLogRecPtr last_wal_replay_lsn;
char last_xact_replay_timestamp[MAXLEN];
int replication_lag_time;
bool receiving_streamed_wal;
bool wal_replay_paused;
int upstream_last_seen;
int upstream_node_id;
} ReplInfo;
/*
* Struct to store node information.
*
* The first section represents the contents of the "repmgr.nodes"
* table; subsequent section contain information collated in
* various contexts.
* Struct to store node information
*/
typedef struct s_node_info
{
@@ -211,7 +152,7 @@ typedef struct s_node_info
/* for ad-hoc use e.g. when working with a list of nodes */
char details[MAXLEN];
bool reachable;
NodeAttached attached;
bool attached;
/* various statistics */
int max_wal_senders;
int attached_wal_receivers;
@@ -219,8 +160,6 @@ typedef struct s_node_info
int total_replication_slots;
int active_replication_slots;
int inactive_replication_slots;
/* replication info */
ReplInfo *replication_info;
} t_node_info;
@@ -247,8 +186,7 @@ typedef struct s_node_info
/* for ad-hoc use e.g. when working with a list of nodes */ \
"", true, true, \
/* various statistics */ \
-1, -1, -1, -1, -1, -1, \
NULL \
-1, -1, -1, -1, -1, -1 \
}
@@ -361,7 +299,18 @@ typedef struct BdrNodeInfoList
0 \
}
typedef struct
{
char current_timestamp[MAXLEN];
bool in_recovery;
XLogRecPtr last_wal_receive_lsn;
XLogRecPtr last_wal_replay_lsn;
char last_xact_replay_timestamp[MAXLEN];
int replication_lag_time;
bool receiving_streamed_wal;
bool wal_replay_paused;
int upstream_last_seen;
} ReplInfo;
typedef struct
{
@@ -438,7 +387,6 @@ PGconn *get_primary_connection(PGconn *standby_conn, int *primary_id, char *p
PGconn *get_primary_connection_quiet(PGconn *standby_conn, int *primary_id, char *primary_conninfo_out);
bool is_superuser_connection(PGconn *conn, t_connection_user *userinfo);
bool connection_has_pg_settings(PGconn *conn);
void close_connection(PGconn **conn);
/* conninfo manipulation functions */
@@ -466,8 +414,8 @@ bool rollback_transaction(PGconn *conn);
bool set_config(PGconn *conn, const char *config_param, const char *config_value);
bool set_config_bool(PGconn *conn, const char *config_param, bool state);
int guc_set(PGconn *conn, const char *parameter, const char *op, const char *value);
int guc_set_typed(PGconn *conn, const char *parameter, const char *op, const char *value, const char *datatype);
bool get_pg_setting(PGconn *conn, const char *setting, char *output);
bool get_pg_setting_int(PGconn *conn, const char *setting, int *output);
bool alter_system_int(PGconn *conn, const char *name, int value);
bool pg_reload_conf(PGconn *conn);
@@ -479,7 +427,6 @@ RecoveryType get_recovery_type(PGconn *conn);
int get_primary_node_id(PGconn *conn);
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);
/* repmgrd shared memory functions */
@@ -493,8 +440,6 @@ 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);
/* extension functions */
ExtensionStatus get_repmgr_extension_status(PGconn *conn, t_extension_versions *extversions);
@@ -523,7 +468,6 @@ bool get_primary_node_record(PGconn *conn, t_node_info *node_info);
bool get_all_node_records(PGconn *conn, NodeInfoList *node_list);
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);
void get_node_records_by_priority(PGconn *conn, NodeInfoList *node_list);
bool get_all_node_records_with_upstream(PGconn *conn, NodeInfoList *node_list);
bool get_downstream_nodes_with_missing_slot(PGconn *conn, int this_node_id, NodeInfoList *noede_list);
@@ -614,12 +558,10 @@ XLogRecPtr get_last_wal_receive_location(PGconn *conn);
void init_replication_info(ReplInfo *replication_info);
bool get_replication_info(PGconn *conn, t_server_type node_type, ReplInfo *replication_info);
int get_replication_lag_seconds(PGconn *conn);
TimeLineID get_node_timeline(PGconn *conn);
void get_node_replication_stats(PGconn *conn, t_node_info *node_info);
NodeAttached is_downstream_node_attached(PGconn *conn, char *node_name);
void set_upstream_last_seen(PGconn *conn, int upstream_node_id);
bool is_downstream_node_attached(PGconn *conn, char *node_name);
void set_upstream_last_seen(PGconn *conn);
int get_upstream_last_seen(PGconn *conn, t_server_type node_type);
bool is_wal_replay_paused(PGconn *conn, bool check_pending_wal);
/* BDR functions */

8
doc/.gitignore vendored
View File

@@ -1,9 +1,7 @@
HTML.index
bookindex.xml
bookindex.sgml
html-stamp
html/
nochunks.dsl
repmgr.html
version.xml
*.fo
*.pdf
*.sgml
version.sgml

View File

@@ -1,102 +0,0 @@
# Make "html" the default target, since that is what most people tend
# to want to use.
html:
all: html
subdir = doc
repmgr_top_builddir = ..
include $(repmgr_top_builddir)/Makefile.global
XMLINCLUDE = --path .
ifndef XMLLINT
XMLLINT = $(missing) xmllint
endif
ifndef XSLTPROC
XSLTPROC = $(missing) xsltproc
endif
ifndef FOP
FOP = $(missing) fop
endif
override XSLTPROCFLAGS += --stringparam repmgr.version '$(REPMGR_VERSION)'
GENERATED_XML = version.xml
ALLXML := $(wildcard $(srcdir)/*.xml) $(GENERATED_XML)
version.xml: $(repmgr_top_builddir)/repmgr_version.h
{ \
echo "<!ENTITY repmgrversion \"$(REPMGR_VERSION)\">"; \
echo "<!ENTITY releasedate \"$(REPMGR_RELEASE_DATE)\">"; \
} > $@
##
## HTML
##
html: html-stamp
html-stamp: stylesheet.xsl repmgr.xml $(ALLXML)
$(XMLLINT) $(XMLINCLUDE) --noout --valid $(word 2,$^)
$(XSLTPROC) $(XMLINCLUDE) $(XSLTPROCFLAGS) $(XSLTPROC_HTML_FLAGS) $(wordlist 1,2,$^)
cp $(srcdir)/stylesheet.css $(srcdir)/website-docs.css html/
touch $@
# single-page HTML
repmgr.html: stylesheet-html-nochunk.xsl repmgr.xml $(ALLXML)
$(XMLLINT) $(XMLINCLUDE) --noout --valid $(word 2,$^)
$(XSLTPROC) $(XMLINCLUDE) $(XSLTPROCFLAGS) $(XSLTPROC_HTML_FLAGS) -o $@ $(wordlist 1,2,$^)
zip: html
cp -r html repmgr-docs-$(REPMGR_VERSION)
zip -r repmgr-docs-$(REPMGR_VERSION).zip repmgr-docs-$(REPMGR_VERSION)
rm -rf repmgr-docs-$(REPMGR_VERSION)
##
## Print
##
repmgr.pdf:
$(error Invalid target; use repmgr-A4.pdf or repmgr-US.pdf as targets)
# Standard paper size
repmgr-A4.fo: stylesheet-fo.xsl repmgr.xml $(ALLXML)
$(XMLLINT) $(XMLINCLUDE) --noout --valid $(word 2,$^)
$(XSLTPROC) $(XMLINCLUDE) $(XSLTPROCFLAGS) --stringparam paper.type A4 -o $@ $(wordlist 1,2,$^)
repmgr-A4.pdf: repmgr-A4.fo
$(FOP) -fo $< -pdf $@
# North American paper size
repmgr-US.fo: stylesheet-fo.xsl repmgr.xml $(ALLXML)
$(XMLLINT) $(XMLINCLUDE) --noout --valid $(word 2,$^)
$(XSLTPROC) $(XMLINCLUDE) $(XSLTPROCFLAGS) --stringparam paper.type USletter -o $@ $(wordlist 1,2,$^)
repmgr-US.pdf: repmgr-US.fo
$(FOP) -fo $< -pdf $@
install: html
@$(MKDIR_P) $(DESTDIR)$(docdir)/$(docmoduledir)/repmgr
@$(INSTALL_DATA) $(wildcard html/*.html) $(wildcard html/*.css) $(DESTDIR)$(docdir)/$(docmoduledir)/repmgr
@echo Installed docs to $(DESTDIR)$(docdir)/$(docmoduledir)/repmgr
clean:
rm -f html-stamp
rm -f HTML.index $(GENERATED_XML)
rm -f repmgr.html
rm -f repmgr-A4.pdf
rm -f repmgr-US.pdf
maintainer-clean:
rm -rf html
.PHONY: html

76
doc/Makefile.in Normal file
View File

@@ -0,0 +1,76 @@
repmgr_subdir = doc
repmgr_top_builddir = ..
include $(repmgr_top_builddir)/Makefile.global
ifndef JADE
JADE = $(missing) jade
endif
SGMLINCLUDE = -D . -D ${srcdir}
SPFLAGS += -wall -wno-unused-param -wno-empty -wfully-tagged
JADE.html.call = $(JADE) $(JADEFLAGS) $(SPFLAGS) $(SGMLINCLUDE) $(CATALOG) -t sgml -i output-html
ALLSGML := $(wildcard $(srcdir)/*.sgml)
# to build bookindex
ALMOSTALLSGML := $(filter-out %bookindex.sgml,$(ALLSGML))
GENERATED_SGML = version.sgml bookindex.sgml
Makefile: Makefile.in
cd $(repmgr_top_builddir) && ./config.status doc/Makefile
all: html
html: html-stamp
html-stamp: repmgr.sgml $(ALLSGML) $(GENERATED_SGML) stylesheet.dsl website-docs.css
$(MKDIR_P) html
$(JADE.html.call) -d stylesheet.dsl -i include-index $<
cp $(srcdir)/stylesheet.css $(srcdir)/website-docs.css html/
touch $@
repmgr.html: repmgr.sgml $(ALLSGML) $(GENERATED_SGML) stylesheet.dsl website-docs.css
sed '/html-index-filename/a\
(define nochunks #t)' <stylesheet.dsl >nochunks.dsl
$(JADE.html.call) -d nochunks.dsl -i include-index $< >repmgr.html
version.sgml: ${repmgr_top_builddir}/repmgr_version.h
{ \
echo "<!ENTITY repmgrversion \"$(REPMGR_VERSION)\">"; \
} > $@
HTML.index: repmgr.sgml $(ALMOSTALLSGML) stylesheet.dsl
@$(MKDIR_P) html
$(JADE.html.call) -d stylesheet.dsl -V html-index $<
website-docs.css:
@$(MKDIR_P) html
curl http://www.postgresql.org/media/css/docs.css > ${srcdir}/website-docs.css
bookindex.sgml: HTML.index
ifdef COLLATEINDEX
LC_ALL=C $(PERL) $(COLLATEINDEX) -f -g -i 'bookindex' -o $@ $<
else
@$(missing) collateindex.pl $< $@
endif
clean:
rm -f html-stamp
rm -f HTML.index $(GENERATED_SGML)
maintainer-clean:
rm -rf html
rm -f Makefile
zip: html
cp -r html repmgr-docs-$(REPMGR_VERSION)
zip -r repmgr-docs-$(REPMGR_VERSION).zip repmgr-docs-$(REPMGR_VERSION)
rm -rf repmgr-docs-$(REPMGR_VERSION)
install: html
@$(MKDIR_P) $(DESTDIR)$(docdir)/$(docmoduledir)/repmgr
@$(INSTALL_DATA) $(wildcard html/*.html) $(wildcard html/*.css) $(DESTDIR)$(docdir)/$(docmoduledir)/repmgr
@echo Installed docs to $(DESTDIR)$(docdir)/$(docmoduledir)/repmgr
.PHONY: html all

438
doc/appendix-faq.sgml Normal file
View File

@@ -0,0 +1,438 @@
<appendix id="appendix-faq" xreflabel="FAQ">
<indexterm>
<primary>FAQ (Frequently Asked Questions)</primary>
</indexterm>
<title>FAQ (Frequently Asked Questions)</title>
<sect1 id="faq-general" xreflabel="General">
<title>General</title>
<sect2 id="faq-xrepmgr-version-diff" xreflabel="Version differences">
<title>What's the difference between the repmgr versions?</title>
<para>
&repmgr; 4 is a complete rewrite of the existing &repmgr; code base
and implements &repmgr; as a PostgreSQL extension. It
supports all PostgreSQL versions from 9.3 (although some &repmgr;
features are not available for PostgreSQL 9.3 and 9.4).
</para>
<para>
&repmgr; 3.x builds on the improved replication facilities added
in PostgreSQL 9.3, as well as improved automated failover support
via <application>repmgrd</application>, and is not compatible with PostgreSQL 9.2
and earlier. We recommend upgrading to &repmgr; 4, as the &repmgr; 3.x
series is no longer maintained.
</para>
<para>
&repmgr; 2.x supports PostgreSQL 9.0 ~ 9.3. While it is compatible
with PostgreSQL 9.3, we recommend using repmgr 4.x. &repmgr; 2.x is
no longer maintained.
</para>
<para>
See also <link linkend="install-compatibility-matrix">&repmgr; compatibility matrix</link>
and <link linkend="faq-upgrade-repmgr">Should I upgrade &repmgr;?</link>.
</para>
</sect2>
<sect2 id="faq-replication-slots-advantage" xreflabel="Advantages of replication slots">
<title>What's the advantage of using replication slots?</title>
<para>
Replication slots, introduced in PostgreSQL 9.4, ensure that the
primary server will retain WAL files until they have been consumed
by all standby servers. This means standby servers should never
fail due to not being able to retrieve required WAL files from the
primary.
</para>
<para>
However this does mean that if a standby is no longer connected to the
primary, the presence of the replication slot will cause WAL files
to be retained indefinitely, and eventually lead to disk space
exhaustion.
</para>
<tip>
<para>
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>.
</para>
</tip>
</sect2>
<sect2 id="faq-replication-slots-number" xreflabel="Number of replication slots">
<title>How many replication slots should I define in <varname>max_replication_slots</varname>?</title>
<para>
Normally at least same number as the number of standbys which will connect
to the node. Note that changes to <varname>max_replication_slots</varname> require a server
restart to take effect, and as there is no particular penalty for unused
replication slots, setting a higher figure will make adding new nodes
easier.
</para>
</sect2>
<sect2 id="faq-hash-index" xreflabel="Hash indexes">
<title>Does &repmgr; support hash indexes?</title>
<para>
Before PostgreSQL 10, hash indexes were not WAL logged and are therefore not suitable
for use in streaming replication in PostgreSQL 9.6 and earlier. See the
<ulink url="https://www.postgresql.org/docs/9.6/sql-createindex.html#AEN80279">PostgreSQL documentation</ulink>
for details.
</para>
<para>
From PostgreSQL 10, this restriction has been lifted and hash indexes can be used
in a streaming replication cluster.
</para>
</sect2>
<sect2 id="faq-upgrades" xreflabel="Upgrading PostgreSQL with repmgr">
<title>Can &repmgr; assist with upgrading a PostgreSQL cluster?</title>
<para>
For <emphasis>minor</emphasis> version upgrades, e.g. from 9.6.7 to 9.6.8, a common
approach is to upgrade a standby to the latest version, perform a
<link linkend="performing-switchover">switchover</link> promoting it to a primary,
then upgrade the former primary.
</para>
<para>
For <emphasis>major</emphasis> version upgrades (e.g. from PostgreSQL 9.6 to PostgreSQL 10),
the traditional approach is to "reseed" a cluster by upgrading a single
node with <ulink url="https://www.postgresql.org/docs/current/pgupgrade.html">pg_upgrade</ulink>
and recloning standbys from this.
</para>
<para>
To minimize downtime during major upgrades from PostgreSQL 9.4 and later,
<ulink url="https://www.2ndquadrant.com/en/resources/pglogical/">pglogical</ulink>
can be used to set up a parallel cluster using the newer PostgreSQL version,
which can be kept in sync with the existing production cluster until the
new cluster is ready to be put into production.
</para>
</sect2>
<sect2 id="faq-libdir-repmgr-error">
<title>What does this error mean: <literal>ERROR: could not access file "$libdir/repmgr"</literal>?</title>
<para>
It means the &repmgr; extension code is not installed in the
PostgreSQL application directory. This typically happens when using PostgreSQL
packages provided by a third-party vendor, which often have different
filesystem layouts.
</para>
<para>
Either use PostgreSQL packages provided by the community or 2ndQuadrant; if this
is not possible, contact your vendor for assistance.
</para>
</sect2>
<sect2 id="faq-old-packages">
<title>How can I obtain old versions of &repmgr; packages?</title>
<para>
See appendix <xref linkend="packages-old-versions"> for details.
</para>
</sect2>
<sect2 id="faq-repmgr-required-for-replication">
<title>Is &repmgr; required for streaming replication?</title>
<para>
No.
</para>
<para>
&repmgr; (together with <application>repmgrd</application>) assists with
<emphasis>managing</emphasis> replication. It does not actually perform replication, which
is part of the core PostgreSQL functionality.
</para>
</sect2>
<sect2 id="faq-what-if-repmgr-uninstalled">
<title>Will replication stop working if &repmgr; is uninstalled?</title>
<para>
No. See preceding question.
</para>
</sect2>
<sect2 id="faq-version-mix">
<title>Does it matter if different &repmgr; versions are present in the replication cluster?</title>
<para>
Yes. If different &quot;major&quot; &repmgr; versions (e.g. 3.3.x and 4.1.x) are present,
&repmgr; (in particular <application>repmgrd</application>)
may not run, or run properly, or in the worst case (if different <application>repmgrd</application>
versions are running and there are differences in the failover implementation) break
your replication cluster.
</para>
<para>
If different &quot;minor&quot; &repmgr; versions (e.g. 4.1.1 and 4.1.6) are installed,
&repmgr; will function, but we strongly recommend always running the same version
to ensure there are no unexpected suprises, e.g. a newer version behaving slightly
differently to the older version.
</para>
<para>
See also <link linkend="faq-upgrade-repmgr">Should I upgrade &repmgr;?</link>.
</para>
</sect2>
<sect2 id="faq-upgrade-repmgr">
<title>Should I upgrade &repmgr;?</title>
<para>
Yes.
</para>
<para>
We don't release new versions for fun, you know. Upgrading may require a little effort,
but running an older &repmgr; version with bugs which have since been fixed may end up
costing you more effort. The same applies to PostgreSQL itself.
</para>
</sect2>
<sect2 id="faq-repmgr-conf-data-directory">
<title>Why do I need to specify the data directory location in repmgr.conf?</title>
<para>
In some circumstances &repmgr; may need to access a PostgreSQL data
directory while the PostgreSQL server is not running, e.g. to confirm
it shut down cleanly during a <link linkend="performing-switchover">switchover</link>.
</para>
<para>
Additionally, this provides support when using &repmgr; on PostgreSQL 9.6 and
earlier, where the <literal>repmgr</literal> user is not a superuser; in that
case the <literal>repmgr</literal> user will not be able to access the
<literal>data_directory</literal> configuration setting, access to which is restricted
to superusers. (In PostgreSQL 10 and later, non-superusers can be added to the
group <option>pg_read_all_settings</option> which will enable them to read this setting).
</para>
</sect2>
</sect1>
<sect1 id="faq-repmgr" xreflabel="repmgr">
<title><command>repmgr</command></title>
<sect2 id="faq-register-existing-node" xreflabel="registering an existing node">
<title>Can I register an existing PostgreSQL server with repmgr?</title>
<para>
Yes, any existing PostgreSQL server which is part of the same replication
cluster can be registered with &repmgr;. There's no requirement for a
standby to have been cloned using &repmgr;.
</para>
</sect2>
<sect2 id="faq-repmgr-clone-other-source" >
<title>Can I use a standby not cloned by &repmgr; as a &repmgr; node?</title>
<para>
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 --recovery-conf-only</link></command>
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 <filename>recovery.conf</filename>, and what options can be set there?</title>
<para>
See section <link linkend="repmgr-standby-clone-recovery-conf">Customising recovery.conf</link>.
</para>
</sect2>
<sect2 id="faq-repmgr-failed-primary-standby" xreflabel="Reintegrate a failed primary as a standby">
<title>How can a failed primary be re-added as a standby?</title>
<para>
This is a two-stage process. First, the failed primary's data directory
must be re-synced with the current primary; secondly the failed primary
needs to be re-registered as a standby.
</para>
<para>
It's possible to use <command>pg_rewind</command> to re-synchronise the existing data
directory, which will usually be much
faster than re-cloning the server. However <command>pg_rewind</command> can only
be used if PostgreSQL either has <varname>wal_log_hints</varname> enabled, or
data checksums were enabled when the cluster was initialized.
</para>
<para>
Note that <command>pg_rewind</command> is available as part of the core PostgreSQL
distribution from PostgreSQL 9.5, and as a third-party utility for PostgreSQL 9.3 and 9.4.
</para>
<para>
&repmgr; provides the command <command>repmgr node rejoin</command> which can
optionally execute <command>pg_rewind</command>; see the <xref linkend="repmgr-node-rejoin">
documentation for details, in particular the section <xref linkend="repmgr-node-rejoin-pg-rewind">.
</para>
<para>
If <command>pg_rewind</command> cannot be used, then the data directory will need
to be re-cloned from scratch.
</para>
</sect2>
<sect2 id="faq-repmgr-check-configuration" xreflabel="Check PostgreSQL configuration">
<title>Is there an easy way to check my primary server is correctly configured for use with &repmgr;?</title>
<para>
Execute <command><link linkend="repmgr-standby-clone">repmgr standby clone</link></command>
with the <literal>--dry-run</literal> option; this will report any configuration problems
which need to be rectified.
</para>
</sect2>
<sect2 id="faq-repmgr-clone-skip-config-files" xreflabel="">
<title>When cloning a standby, how can I get &repmgr; to copy
<filename>postgresql.conf</filename> and <filename>pg_hba.conf</filename> from the PostgreSQL configuration
directory in <filename>/etc</filename>?</title>
<para>
Use the command line option <literal>--copy-external-config-files</literal>. For more details
see <xref linkend="repmgr-standby-clone-config-file-copying">.
</para>
</sect2>
<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 <application>repmgrd</application>?</title>
<para>
No, the <literal>repmgr</literal> shared library is only needed when running <application>repmgrd</application>.
If you later decide to run <application>repmgrd</application>, you just need to add
<literal>shared_preload_libraries = 'repmgr'</literal> and restart PostgreSQL.
</para>
</sect2>
<sect2 id="faq-repmgr-permissions" xreflabel="Replication permission problems">
<title>I've provided replication permission for the <literal>repmgr</literal> user in <filename>pg_hba.conf</filename>
but <command>repmgr</command>/<application>repmgrd</application> complains it can't connect to the server... Why?</title>
<para>
<command>repmgr</command> and <application>repmgrd</application> need to be able to connect to the repmgr database
with a normal connection to query metadata. The <literal>replication</literal> connection
permission is for PostgreSQL's streaming replication (and doesn't necessarily need to be the <literal>repmgr</literal> user).
</para>
</sect2>
<sect2 id="faq-repmgr-clone-provide-primary-conninfo" xreflabel="Providing primary connection parameters">
<title>When cloning a standby, why do I need to provide the connection parameters
for the primary server on the command line, not in the configuration file?</title>
<para>
Cloning a standby is a one-time action; the role of the server being cloned
from could change, so fixing it in the configuration file would create
confusion. If &repmgr; needs to establish a connection to the primary
server, it can retrieve this from the <literal>repmgr.nodes</literal> table on the local
node, and if necessary scan the replication cluster until it locates the active primary.
</para>
</sect2>
<sect2 id="faq-repmgr-clone-waldir-xlogdir" xreflabel="Providing a custom WAL directory">
<title>When cloning a standby, how do I ensure the WAL files are placed in a custom directory?</title>
<para>
Provide the option <literal>--waldir</literal> (<literal>--xlogdir</literal> in PostgreSQL 9.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>
</sect2>
<sect2 id="faq-repmgr-events-no-fkey" xreflabel="No foreign key on node_id in repmgr.events">
<title>Why is there no foreign key on the <literal>node_id</literal> column in the <literal>repmgr.events</literal>
table?</title>
<para>
Under some circumstances event notifications can be generated for servers
which have not yet been registered; it's also useful to retain a record
of events which includes servers removed from the replication cluster
which no longer have an entry in the <literal>repmgr.nodes</literal> table.
</para>
</sect2>
<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 <filename>recovery.conf</filename> is parsed.
</para>
<para>
The escaping is performed by an internal PostgreSQL routine, which leaves strings consisting
of digits and alphabetical characters only as-is, but wraps everything else in pairs of single quotes,
even if the string does not contain any characters which need escaping.
</para>
</sect2>
</sect1>
<sect1 id="faq-repmgrd" xreflabel="repmgrd">
<title><application>repmgrd</application></title>
<sect2 id="faq-repmgrd-prevent-promotion" xreflabel="Prevent standby from being promoted to primary">
<title>How can I prevent a node from ever being promoted to primary?</title>
<para>
In <filename>repmgr.conf</filename>, set its priority to a value of <literal>0</literal>; apply the changed setting with
<command><link linkend="repmgr-standby-register">repmgr standby register --force</link></command>.
</para>
<para>
Additionally, if <varname>failover</varname> is set to <literal>manual</literal>, the node will never
be considered as a promotion candidate.
</para>
</sect2>
<sect2 id="faq-repmgrd-delayed-standby" xreflabel="Delayed standby support">
<title>Does <application>repmgrd</application> support delayed standbys?</title>
<para>
<application>repmgrd</application> can monitor delayed standbys - those set up with
<varname>recovery_min_apply_delay</varname> set to a non-zero value
in <filename>recovery.conf</filename> - but as it's not currently possible
to directly examine the value applied to the standby, <application>repmgrd</application>
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
by setting <varname>priority</varname> to <literal>0</literal> in
<filename>repmgr.conf</filename>.
</para>
<para>
Note that after registering a delayed standby, <application>repmgrd</application> will only start
once the metadata added in the primary node has been replicated.
</para>
</sect2>
<sect2 id="faq-repmgrd-logfile-rotate" xreflabel="repmgrd logfile rotation">
<title>How can I get <application>repmgrd</application> to rotate its logfile?</title>
<para>
Configure your system's <literal>logrotate</literal> service to do this; see <xref linkend="repmgrd-log-rotation">.
</para>
</sect2>
<sect2 id="faq-repmgrd-recloned-no-start" xreflabel="repmgrd not restarting after node cloned">
<title>I've recloned a failed primary as a standby, but <application>repmgrd</application> refuses to start?</title>
<para>
Check you registered the standby after recloning. If unregistered, the standby
cannot be considered as a promotion candidate even if <varname>failover</varname> is set to
<literal>automatic</literal>, which is probably not what you want. <application>repmgrd</application> will start if
<varname>failover</varname> is set to <literal>manual</literal> so the node's replication status can still
be monitored, if desired.
</para>
</sect2>
<sect2 id="faq-repmgrd-pg-bindir" xreflabel="repmgrd does not apply pg_bindir to promote_command or follow_command">
<title>
<application>repmgrd</application> ignores pg_bindir when executing <varname>promote_command</varname> or <varname>follow_command</varname>
</title>
<para>
<varname>promote_command</varname> or <varname>follow_command</varname> can be user-defined scripts,
so &repmgr; will not apply <option>pg_bindir</option> even if excuting &repmgr;. Always provide the full
path; see <xref linkend="repmgrd-automatic-failover-configuration"> for more details.
</para>
</sect2>
<sect2 id="faq-repmgrd-startup-no-upstream" xreflabel="repmgrd does not start if upstream node is not running">
<title>
<application>repmgrd</application> aborts startup with the error "<literal>upstream node must be running before repmgrd can start</literal>"
</title>
<para>
<application>repmgrd</application> does this to avoid starting up on a replication cluster
which is not in a healthy state. If the upstream is unavailable, <application>repmgrd</application>
may initiate a failover immediately after starting up, which could have unintended side-effects,
particularly if <application>repmgrd</application> is not running on other nodes.
</para>
<para>
In particular, it's possible that the node's local copy of the <literal>repmgr.nodes</literal> copy
is out-of-date, which may lead to incorrect failover behaviour.
</para>
<para>
The onus is therefore on the adminstrator to manually set the cluster to a stable, healthy state before
starting <application>repmgrd</application>.
</para>
</sect2>
</sect1>
</appendix>

View File

@@ -1,466 +0,0 @@
<appendix id="appendix-faq" xreflabel="FAQ">
<title>FAQ (Frequently Asked Questions)</title>
<indexterm>
<primary>FAQ (Frequently Asked Questions)</primary>
</indexterm>
<sect1 id="faq-general" xreflabel="General">
<title>General</title>
<sect2 id="faq-xrepmgr-version-diff" xreflabel="Version differences">
<title>What's the difference between the repmgr versions?</title>
<para>
&repmgr; 4 is a complete rewrite of the previous &repmgr; code base
and implements &repmgr; as a PostgreSQL extension. It
supports all PostgreSQL versions from 9.3 (although some &repmgr;
features are not available for PostgreSQL 9.3 and 9.4).
</para>
<note>
<para>
&repmgr; 5 is fundamentally the same code base as &repmgr; 4, but provides
support for the revised replication configuration mechanism in PostgreSQL 12.
</para>
</note>
<para>
&repmgr; 3.x builds on the improved replication facilities added
in PostgreSQL 9.3, as well as improved automated failover support
via &repmgrd;, and is not compatible with PostgreSQL 9.2
and earlier. We recommend upgrading to &repmgr; 4, as the &repmgr; 3.x
series is no longer maintained.
</para>
<para>
&repmgr; 2.x supports PostgreSQL 9.0 ~ 9.3. While it is compatible
with PostgreSQL 9.3, we recommend using repmgr 4.x. &repmgr; 2.x is
no longer maintained.
</para>
<para>
See also <link linkend="install-compatibility-matrix">&repmgr; compatibility matrix</link>
and <link linkend="faq-upgrade-repmgr">Should I upgrade &repmgr;?</link>.
</para>
</sect2>
<sect2 id="faq-replication-slots-advantage" xreflabel="Advantages of replication slots">
<title>What's the advantage of using replication slots?</title>
<para>
Replication slots, introduced in PostgreSQL 9.4, ensure that the
primary server will retain WAL files until they have been consumed
by all standby servers. This means standby servers should never
fail due to not being able to retrieve required WAL files from the
primary.
</para>
<para>
However this does mean that if a standby is no longer connected to the
primary, the presence of the replication slot will cause WAL files
to be retained indefinitely, and eventually lead to disk space
exhaustion.
</para>
<tip>
<para>
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>.
</para>
</tip>
</sect2>
<sect2 id="faq-replication-slots-number" xreflabel="Number of replication slots">
<title>How many replication slots should I define in <varname>max_replication_slots</varname>?</title>
<para>
Normally at least same number as the number of standbys which will connect
to the node. Note that changes to <varname>max_replication_slots</varname> require a server
restart to take effect, and as there is no particular penalty for unused
replication slots, setting a higher figure will make adding new nodes
easier.
</para>
</sect2>
<sect2 id="faq-hash-index" xreflabel="Hash indexes">
<title>Does &repmgr; support hash indexes?</title>
<para>
Before PostgreSQL 10, hash indexes were not WAL logged and are therefore not suitable
for use in streaming replication in PostgreSQL 9.6 and earlier. See the
<ulink url="https://www.postgresql.org/docs/9.6/sql-createindex.html#AEN80279">PostgreSQL documentation</ulink>
for details.
</para>
<para>
From PostgreSQL 10, this restriction has been lifted and hash indexes can be used
in a streaming replication cluster.
</para>
</sect2>
<sect2 id="faq-upgrades" xreflabel="Upgrading PostgreSQL with repmgr">
<title>Can &repmgr; assist with upgrading a PostgreSQL cluster?</title>
<para>
For <emphasis>minor</emphasis> version upgrades, e.g. from 9.6.7 to 9.6.8, a common
approach is to upgrade a standby to the latest version, perform a
<link linkend="performing-switchover">switchover</link> promoting it to a primary,
then upgrade the former primary.
</para>
<para>
For <emphasis>major</emphasis> version upgrades (e.g. from PostgreSQL 9.6 to PostgreSQL 10),
the traditional approach is to "reseed" a cluster by upgrading a single
node with <ulink url="https://www.postgresql.org/docs/current/pgupgrade.html">pg_upgrade</ulink>
and recloning standbys from this.
</para>
<para>
To minimize downtime during major upgrades from PostgreSQL 9.4 and later,
<ulink url="https://www.2ndquadrant.com/en/resources/pglogical/">pglogical</ulink>
can be used to set up a parallel cluster using the newer PostgreSQL version,
which can be kept in sync with the existing production cluster until the
new cluster is ready to be put into production.
</para>
</sect2>
<sect2 id="faq-libdir-repmgr-error">
<title>What does this error mean: <literal>ERROR: could not access file "$libdir/repmgr"</literal>?</title>
<para>
It means the &repmgr; extension code is not installed in the
PostgreSQL application directory. This typically happens when using PostgreSQL
packages provided by a third-party vendor, which often have different
filesystem layouts.
</para>
<para>
Either use PostgreSQL packages provided by the community or 2ndQuadrant; if this
is not possible, contact your vendor for assistance.
</para>
</sect2>
<sect2 id="faq-old-packages">
<title>How can I obtain old versions of &repmgr; packages?</title>
<para>
See appendix <xref linkend="packages-old-versions"/> for details.
</para>
</sect2>
<sect2 id="faq-repmgr-required-for-replication">
<title>Is &repmgr; required for streaming replication?</title>
<para>
No.
</para>
<para>
&repmgr; (together with &repmgrd;) assists with
<emphasis>managing</emphasis> replication. It does not actually perform replication, which
is part of the core PostgreSQL functionality.
</para>
</sect2>
<sect2 id="faq-what-if-repmgr-uninstalled">
<title>Will replication stop working if &repmgr; is uninstalled?</title>
<para>
No. See preceding question.
</para>
</sect2>
<sect2 id="faq-version-mix">
<title>Does it matter if different &repmgr; versions are present in the replication cluster?</title>
<para>
Yes. If different &quot;major&quot; &repmgr; versions (e.g. 3.3.x and 4.1.x) are present,
&repmgr; (in particular &repmgrd;)
may not run, or run properly, or in the worst case (if different &repmgrd;
versions are running and there are differences in the failover implementation) break
your replication cluster.
</para>
<para>
If different &quot;minor&quot; &repmgr; versions (e.g. 4.1.1 and 4.1.6) are installed,
&repmgr; will function, but we strongly recommend always running the same version
to ensure there are no unexpected suprises, e.g. a newer version behaving slightly
differently to the older version.
</para>
<para>
See also <link linkend="faq-upgrade-repmgr">Should I upgrade &repmgr;?</link>.
</para>
</sect2>
<sect2 id="faq-upgrade-repmgr">
<title>Should I upgrade &repmgr;?</title>
<para>
Yes.
</para>
<para>
We don't release new versions for fun, you know. Upgrading may require a little effort,
but running an older &repmgr; version with bugs which have since been fixed may end up
costing you more effort. The same applies to PostgreSQL itself.
</para>
</sect2>
<sect2 id="faq-repmgr-conf-data-directory">
<title>Why do I need to specify the data directory location in repmgr.conf?</title>
<para>
In some circumstances &repmgr; may need to access a PostgreSQL data
directory while the PostgreSQL server is not running, e.g. to confirm
it shut down cleanly during a <link linkend="performing-switchover">switchover</link>.
</para>
<para>
Additionally, this provides support when using &repmgr; on PostgreSQL 9.6 and
earlier, where the <literal>repmgr</literal> user is not a superuser; in that
case the <literal>repmgr</literal> user will not be able to access the
<literal>data_directory</literal> configuration setting, access to which is restricted
to superusers.
</para>
<para>
In PostgreSQL 10 and later, non-superusers can be added to the
<ulink url="https://www.postgresql.org/docs/current/default-roles.html">default role</ulink>
<option>pg_read_all_settings</option> (or the meta-role <option>pg_monitor</option>)
which will enable them to read this setting.
</para>
</sect2>
<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 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
package naming schemes and/or file locations.
</para>
<para>
We cannot guarantee that &repmgr; packages will be compatible with these packages.
It may be possible to override package dependencies (e.g. <literal>rpm --nodeps</literal>
for CentOS-based systems or <literal>dpkg --force-depends</literal> for Debian-based systems).
</para>
</sect2>
</sect1>
<sect1 id="faq-repmgr" xreflabel="repmgr">
<title><command>repmgr</command></title>
<sect2 id="faq-register-existing-node" xreflabel="registering an existing node">
<title>Can I register an existing PostgreSQL server with repmgr?</title>
<para>
Yes, any existing PostgreSQL server which is part of the same replication
cluster can be registered with &repmgr;. There's no requirement for a
standby to have been cloned using &repmgr;.
</para>
</sect2>
<sect2 id="faq-repmgr-clone-other-source" >
<title>Can I use a standby not cloned by &repmgr; as a &repmgr; node?</title>
<para>
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 --recovery-conf-only</link></command>
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 <filename>recovery.conf</filename>, and what options can be set there?</title>
<para>
See section <link linkend="repmgr-standby-clone-recovery-conf">Customising recovery.conf</link>.
</para>
</sect2>
<sect2 id="faq-repmgr-failed-primary-standby" xreflabel="Reintegrate a failed primary as a standby">
<title>How can a failed primary be re-added as a standby?</title>
<para>
This is a two-stage process. First, the failed primary's data directory
must be re-synced with the current primary; secondly the failed primary
needs to be re-registered as a standby.
</para>
<para>
It's possible to use <command>pg_rewind</command> to re-synchronise the existing data
directory, which will usually be much
faster than re-cloning the server. However <command>pg_rewind</command> can only
be used if PostgreSQL either has <varname>wal_log_hints</varname> enabled, or
data checksums were enabled when the cluster was initialized.
</para>
<para>
Note that <command>pg_rewind</command> is available as part of the core PostgreSQL
distribution from PostgreSQL 9.5, and as a third-party utility for PostgreSQL 9.3 and 9.4.
</para>
<para>
&repmgr; provides the command <command>repmgr node rejoin</command> which can
optionally execute <command>pg_rewind</command>; see the <xref linkend="repmgr-node-rejoin"/>
documentation for details, in particular the section <xref linkend="repmgr-node-rejoin-pg-rewind"/>.
</para>
<para>
If <command>pg_rewind</command> cannot be used, then the data directory will need
to be re-cloned from scratch.
</para>
</sect2>
<sect2 id="faq-repmgr-check-configuration" xreflabel="Check PostgreSQL configuration">
<title>Is there an easy way to check my primary server is correctly configured for use with &repmgr;?</title>
<para>
Execute <command><link linkend="repmgr-standby-clone">repmgr standby clone</link></command>
with the <literal>--dry-run</literal> option; this will report any configuration problems
which need to be rectified.
</para>
</sect2>
<sect2 id="faq-repmgr-clone-skip-config-files" xreflabel="">
<title>When cloning a standby, how can I get &repmgr; to copy
<filename>postgresql.conf</filename> and <filename>pg_hba.conf</filename> from the PostgreSQL configuration
directory in <filename>/etc</filename>?</title>
<para>
Use the command line option <literal>--copy-external-config-files</literal>. For more details
see <xref linkend="repmgr-standby-clone-config-file-copying"/>.
</para>
</sect2>
<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>
No, the <literal>repmgr</literal> shared library is only needed when running &repmgrd;.
If you later decide to run &repmgrd;, you just need to add
<literal>shared_preload_libraries = 'repmgr'</literal> and restart PostgreSQL.
</para>
</sect2>
<sect2 id="faq-repmgr-permissions" xreflabel="Replication permission problems">
<title>I've provided replication permission for the <literal>repmgr</literal> user in <filename>pg_hba.conf</filename>
but <command>repmgr</command>/&repmgrd; complains it can't connect to the server... Why?</title>
<para>
<command>repmgr</command> and &repmgrd; need to be able to connect to the repmgr database
with a normal connection to query metadata. The <literal>replication</literal> connection
permission is for PostgreSQL's streaming replication (and doesn't necessarily need to be the <literal>repmgr</literal> user).
</para>
</sect2>
<sect2 id="faq-repmgr-clone-provide-primary-conninfo" xreflabel="Providing primary connection parameters">
<title>When cloning a standby, why do I need to provide the connection parameters
for the primary server on the command line, not in the configuration file?</title>
<para>
Cloning a standby is a one-time action; the role of the server being cloned
from could change, so fixing it in the configuration file would create
confusion. If &repmgr; needs to establish a connection to the primary
server, it can retrieve this from the <literal>repmgr.nodes</literal> table on the local
node, and if necessary scan the replication cluster until it locates the active primary.
</para>
</sect2>
<sect2 id="faq-repmgr-clone-waldir-xlogdir" xreflabel="Providing a custom WAL directory">
<title>When cloning a standby, how do I ensure the WAL files are placed in a custom directory?</title>
<para>
Provide the option <literal>--waldir</literal> (<literal>--xlogdir</literal> in PostgreSQL 9.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>
</sect2>
<sect2 id="faq-repmgr-events-no-fkey" xreflabel="No foreign key on node_id in repmgr.events">
<title>Why is there no foreign key on the <literal>node_id</literal> column in the <literal>repmgr.events</literal>
table?</title>
<para>
Under some circumstances event notifications can be generated for servers
which have not yet been registered; it's also useful to retain a record
of events which includes servers removed from the replication cluster
which no longer have an entry in the <literal>repmgr.nodes</literal> table.
</para>
</sect2>
<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 <filename>recovery.conf</filename> is parsed.
</para>
<para>
The escaping is performed by an internal PostgreSQL routine, which leaves strings consisting
of digits and alphabetical characters only as-is, but wraps everything else in pairs of single quotes,
even if the string does not contain any characters which need escaping.
</para>
</sect2>
</sect1>
<sect1 id="faq-repmgrd" xreflabel="repmgrd">
<title>&repmgrd;</title>
<sect2 id="faq-repmgrd-prevent-promotion" xreflabel="Prevent standby from being promoted to primary">
<title>How can I prevent a node from ever being promoted to primary?</title>
<para>
In <filename>repmgr.conf</filename>, set its priority to a value of <literal>0</literal>; apply the changed setting with
<command><link linkend="repmgr-standby-register">repmgr standby register --force</link></command>.
</para>
<para>
Additionally, if <varname>failover</varname> is set to <literal>manual</literal>, the node will never
be considered as a promotion candidate.
</para>
</sect2>
<sect2 id="faq-repmgrd-delayed-standby" xreflabel="Delayed standby support">
<title>Does &repmgrd; support delayed standbys?</title>
<para>
&repmgrd; can monitor delayed standbys - those set up with
<varname>recovery_min_apply_delay</varname> set to a non-zero value
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
by setting <varname>priority</varname> to <literal>0</literal> in
<filename>repmgr.conf</filename>.
</para>
<para>
Note that after registering a delayed standby, &repmgrd; will only start
once the metadata added in the primary node has been replicated.
</para>
</sect2>
<sect2 id="faq-repmgrd-logfile-rotate" xreflabel="repmgrd logfile rotation">
<title>How can I get &repmgrd; to rotate its logfile?</title>
<para>
Configure your system's <literal>logrotate</literal> service to do this; see <xref linkend="repmgrd-log-rotation"/>.
</para>
</sect2>
<sect2 id="faq-repmgrd-recloned-no-start" xreflabel="repmgrd not restarting after node cloned">
<title>I've recloned a failed primary as a standby, but &repmgrd; refuses to start?</title>
<para>
Check you registered the standby after recloning. If unregistered, the standby
cannot be considered as a promotion candidate even if <varname>failover</varname> is set to
<literal>automatic</literal>, which is probably not what you want. &repmgrd; will start if
<varname>failover</varname> is set to <literal>manual</literal> so the node's replication status can still
be monitored, if desired.
</para>
</sect2>
<sect2 id="faq-repmgrd-pg-bindir" xreflabel="repmgrd does not apply pg_bindir to promote_command or follow_command">
<title>
&repmgrd; ignores pg_bindir when executing <varname>promote_command</varname> or <varname>follow_command</varname>
</title>
<para>
<varname>promote_command</varname> or <varname>follow_command</varname> can be user-defined scripts,
so &repmgr; will not apply <option>pg_bindir</option> even if excuting &repmgr;. Always provide the full
path; see <xref linkend="repmgrd-automatic-failover-configuration"/> for more details.
</para>
</sect2>
<sect2 id="faq-repmgrd-startup-no-upstream" xreflabel="repmgrd does not start if upstream node is not running">
<title>
&repmgrd; aborts startup with the error "<literal>upstream node must be running before repmgrd can start</literal>"
</title>
<para>
&repmgrd; does this to avoid starting up on a replication cluster
which is not in a healthy state. If the upstream is unavailable, &repmgrd;
may initiate a failover immediately after starting up, which could have unintended side-effects,
particularly if &repmgrd; is not running on other nodes.
</para>
<para>
In particular, it's possible that the node's local copy of the <literal>repmgr.nodes</literal> copy
is out-of-date, which may lead to incorrect failover behaviour.
</para>
<para>
The onus is therefore on the adminstrator to manually set the cluster to a stable, healthy state before
starting &repmgrd;.
</para>
</sect2>
</sect1>
</appendix>

View File

@@ -1,11 +1,9 @@
<appendix id="appendix-packages" xreflabel="Package details">
<title>&repmgr; package details</title>
<indexterm>
<primary>packages</primary>
</indexterm>
<title>&repmgr; package details</title>
<para>
This section provides technical details about various &repmgr; binary
packages, such as location of the installed binaries and
@@ -122,7 +120,7 @@
<row>
<entry>Package name example:</entry>
<entry><filename>repmgr11-4.4.0-1.rhel7.x86_64</filename></entry>
<entry><filename>repmgr10-4.0.4-1.rhel7.x86_64</filename></entry>
</row>
<row>
@@ -132,12 +130,12 @@
<row>
<entry>Installation command:</entry>
<entry><literal>yum install repmgr11</literal></entry>
<entry><literal>yum install repmgr10</literal></entry>
</row>
<row>
<entry>Binary location:</entry>
<entry><filename>/usr/pgsql-11/bin</filename></entry>
<entry><filename>/usr/pgsql-10/bin</filename></entry>
</row>
<row>
@@ -147,22 +145,22 @@
<row>
<entry>Configuration file location:</entry>
<entry><filename>/etc/repmgr/11/repmgr.conf</filename></entry>
<entry><filename>/etc/repmgr/10/repmgr.conf</filename></entry>
</row>
<row>
<entry>Data directory:</entry>
<entry><filename>/var/lib/pgsql/11/data</filename></entry>
<entry><filename>/var/lib/pgsql/10/data</filename></entry>
</row>
<row>
<entry>repmgrd service command:</entry>
<entry><command>systemctl [start|stop|restart|reload] repmgr11</command></entry>
<entry><command>systemctl [start|stop|restart|reload] repmgr10</command></entry>
</row>
<row>
<entry>repmgrd service file location:</entry>
<entry><filename>/usr/lib/systemd/system/repmgr11.service</filename></entry>
<entry><filename>/usr/lib/systemd/system/repmgr10.service</filename></entry>
</row>
<row>
@@ -311,8 +309,8 @@
version number for your installation.
</para>
<para>
See also <xref linkend="repmgrd-configuration-debian-ubuntu"/> for some specifics related
to configuring the &repmgrd; daemon.
See also <xref linkend="repmgrd-configuration-debian-ubuntu"> for some specifics related
to configuring the <application>repmgrd</application> daemon.
</para>
<table id="debian-9-packages">
@@ -323,7 +321,7 @@
<row>
<entry>Package name example:</entry>
<entry><filename>postgresql-11-repmgr</filename></entry>
<entry><filename>postgresql-10-repmgr</filename></entry>
</row>
<row>
@@ -333,12 +331,12 @@
<row>
<entry>Installation command:</entry>
<entry><literal>apt-get install postgresql-11-repmgr</literal></entry>
<entry><literal>apt-get install postgresql-10-repmgr</literal></entry>
</row>
<row>
<entry>Binary location:</entry>
<entry><filename>/usr/lib/postgresql/11/bin</filename></entry>
<entry><filename>/usr/lib/postgresql/10/bin</filename></entry>
</row>
<row>
@@ -353,12 +351,12 @@
<row>
<entry>Data directory:</entry>
<entry><filename>/var/lib/postgresql/11/main</filename></entry>
<entry><filename>/var/lib/postgresql/10/main</filename></entry>
</row>
<row>
<entry>PostgreSQL service command:</entry>
<entry><command>systemctl [start|stop|restart|reload] postgresql@11-main</command></entry>
<entry><command>systemctl [start|stop|restart|reload] postgresql@10-main</command></entry>
</row>
@@ -386,7 +384,7 @@
it's recommended to execute <command>pg_ctlcluster</command> (as <literal>root</literal>,
either directly or via <command>sudo</command>), e.g.:
<programlisting>
<command>pg_ctlcluster 11 main [start|stop|restart|reload]</command></programlisting>
<command>pg_ctlcluster 10 main [start|stop|restart|reload]</command></programlisting>
</para>
<para>
For pre-<application>systemd</application> systems, <command>pg_ctlcluster</command>
@@ -488,7 +486,7 @@ repmgr96-4.1.1-0.0git320.g5113ab0.1.el7.x86_64.rpm</programlisting>
Old versions can be located with e.g.:
<programlisting>
yum --showduplicates list repmgr96</programlisting>
(substitute the appropriate package name; see <xref linkend="packages-centos"/>) and installed with:
(substitute the appropriate package name; see <xref linkend="packages-centos">) and installed with:
<programlisting>
yum install {package_name}-{version}</programlisting>
where <literal>{package_name}</literal> is the base package name (e.g. <literal>repmgr96</literal>)
@@ -552,13 +550,13 @@ repmgr96-4.1.1-0.0git320.g5113ab0.1.el7.x86_64.rpm</programlisting>
char package_conf_file[MAXPGPATH] = "";</programlisting>
</para>
<para>
See also: <xref linkend="configuration-file"/>
See also: <xref linkend="configuration-file">
</para>
</listitem>
<listitem>
<para>
PID file location: the default &repmgrd; PID file
PID file location: the default <application>repmgrd</application> PID file
location can be hard-coded by patching <varname>package_pid_file</varname>
in <filename>repmgrd.c</filename>:
<programlisting>
@@ -566,7 +564,7 @@ repmgr96-4.1.1-0.0git320.g5113ab0.1.el7.x86_64.rpm</programlisting>
char package_pid_file[MAXPGPATH] = "";</programlisting>
</para>
<para>
See also: <xref linkend="repmgrd-pid-file"/>
See also: <xref linkend="repmgrd-pid-file">
</para>
</listitem>

View File

@@ -1,11 +1,9 @@
<appendix id="appendix-support" xreflabel="repmgr support">
<title>&repmgr; support</title>
<indexterm>
<primary>support</primary>
</indexterm>
<title>&repmgr; support</title>
<para>
<ulink url="https://2ndquadrant.com/">2ndQuadrant</ulink> provides 24x7
production support for &repmgr; and other PostgreSQL
@@ -30,13 +28,12 @@
</important>
<sect1 id="appendix-support-reporting-issues" xreflabel="Reportins Issues">
<title>Reporting Issues</title>
<indexterm>
<primary>support</primary>
<secondary>reporting issues</secondary>
</indexterm>
<title>Reporting Issues</title>
<para>
When asking questions or reporting issues, it is extremely helpful if the following information is included:
@@ -51,7 +48,7 @@
<listitem>
<simpara>
How was &repmgr; installed? From source? From packages? If
How was &repmgr installed? From source? From packages? If
so from which repository?
</simpara>
</listitem>
@@ -83,7 +80,7 @@
the maximum level of logging output.
</para>
<para>
If issues are encountered with &repmgrd;,
If issues are encountered with <application>repmgrd</application>,
please provide relevant extracts from the &repmgr; log files
and if possible the PostgreSQL log itself. Please ensure these
logs do not contain any confidential data.

View File

@@ -2,8 +2,6 @@
<title>Cloning standbys</title>
<sect1 id="cloning-from-barman" xreflabel="Cloning from Barman">
<title>Cloning a standby from Barman</title>
<indexterm>
<primary>cloning</primary>
<secondary>from Barman</secondary>
@@ -13,8 +11,9 @@
<secondary>cloning a standby</secondary>
</indexterm>
<title>Cloning a standby from Barman</title>
<para>
<xref linkend="repmgr-standby-clone"/> can use
<xref linkend="repmgr-standby-clone"> can use
<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).
@@ -52,24 +51,6 @@
</itemizedlist>
</para>
<note>
<para>
Currently &repmgr;'s support for cloning from Barman is implemented by using
<productname>rsync</productname> to clone from the Barman server.
</para>
<para>
It is therefore not able to make use of Barman's parallel restore facility, which
is executed on the Barman server and clones to the target server.
</para>
<para>
Barman's parallel restore facility can be used by executing it manually on
the Barman server and integrating the resulting cloned standby using
<command><link linkend="repmgr-standby-clone">repmgr standby clone --recovery-conf-only</link></command>.
</para>
</note>
<sect2 id="cloning-from-barman-prerequisites">
<title>Prerequisites for cloning from Barman</title>
<para>
@@ -78,7 +59,8 @@
<itemizedlist spacing="compact" mark="bullet">
<listitem>
<para>
the Barman catalogue must include at least one valid backup for this server;
the <varname>barman_server</varname> setting in <filename>repmgr.conf</filename> is the same as the
server configured in Barman;
</para>
</listitem>
<listitem>
@@ -89,68 +71,19 @@
</listitem>
<listitem>
<para>
the <varname>barman_server</varname> setting in <filename>repmgr.conf</filename> is the same as the
server configured in Barman.
the <varname>restore_command</varname> setting in <filename>repmgr.conf</filename> is configured to
use a copy of the <command>barman-wal-restore</command> script shipped with the
<literal>barman-cli</literal> package (see section <xref linkend="cloning-from-barman-restore-command">
below).
</para>
</listitem>
<listitem>
<para>
the Barman catalogue includes at least one valid backup for this server.
</para>
</listitem>
</itemizedlist>
</para>
<para>
For example, assuming Barman is located on the host &quot;<literal>barmansrv</literal>&quot;
under the &quot;<literal>barman</literal>&quot; user account,
<filename>repmgr.conf</filename> should contain the following entries:
<programlisting>
barman_host='barman@barmansrv'
barman_server='somedb'</programlisting>
</para>
<note>
<para>
To use a non-default Barman configuration file on the Barman server,
specify this in <filename>repmgr.conf</filename> with <filename>barman_config</filename>:
<programlisting>
barman_config=/path/to/barman.conf</programlisting>
</para>
</note>
<para>
We also recommend configuring the <varname>restore_command</varname> setting in <filename>repmgr.conf</filename>
to use the <command>barman-wal-restore</command> script
(see section <xref linkend="cloning-from-barman-restore-command"/> below).
</para>
<tip>
<simpara>
If you have a non-default SSH configuration on the Barman
server, e.g. using a port other than 22, then you can set those
parameters in a dedicated Host section in <filename>~/.ssh/config</filename>
corresponding to the value of <varname>barman_host</varname> in
<filename>repmgr.conf</filename>. See the <literal>Host</literal>
section in <command>man 5 ssh_config</command> for more details.
</simpara>
</tip>
<para>
It's now possible to clone a standby from Barman, e.g.:
<programlisting>
$ repmgr -f /etc/repmgr.conf -h node1 -U repmgr -d repmgr standby clone
NOTICE: destination directory "/var/lib/postgresql/data" provided
INFO: connecting to Barman server to verify backup for "test_cluster"
INFO: checking and correcting permissions on existing directory "/var/lib/postgresql/data"
INFO: creating directory "/var/lib/postgresql/data/repmgr"...
INFO: connecting to Barman server to fetch server parameters
INFO: connecting to source node
DETAIL: current installation size is 30 MB
NOTICE: retrieving backup from Barman...
(...)
NOTICE: standby clone (from Barman) complete
NOTICE: you can now start your PostgreSQL server
HINT: for example: pg_ctl -D /var/lib/postgresql/data start</programlisting>
</para>
<note>
<simpara>
Barman support is automatically enabled if <varname>barman_server</varname>
@@ -160,16 +93,45 @@
command line option.
</simpara>
</note>
<tip>
<simpara>
If you have a non-default SSH configuration on the Barman
server, e.g. using a port other than 22, then you can set those
parameters in a dedicated Host section in <filename>~/.ssh/config</filename>
corresponding to the value of<varname>barman_host</varname> in
<filename>repmgr.conf</filename>. See the <literal>Host</literal>
section in <command>man 5 ssh_config</command> for more details.
</simpara>
</tip>
<para>
It's now possible to clone a standby from Barman, e.g.:
<programlisting>
NOTICE: using configuration file "/etc/repmgr.conf"
NOTICE: destination directory "/var/lib/postgresql/data" provided
INFO: connecting to Barman server to verify backup for test_cluster
INFO: checking and correcting permissions on existing directory "/var/lib/postgresql/data"
INFO: creating directory "/var/lib/postgresql/data/repmgr"...
INFO: connecting to Barman server to fetch server parameters
INFO: connecting to upstream node
INFO: connected to source node, checking its state
INFO: successfully connected to source node
DETAIL: current installation size is 29 MB
NOTICE: retrieving backup from Barman...
receiving file list ...
(...)
NOTICE: standby clone (from Barman) complete
NOTICE: you can now start your PostgreSQL server
HINT: for example: pg_ctl -D /var/lib/postgresql/data start</programlisting>
</para>
</sect2>
<sect2 id="cloning-from-barman-restore-command" xreflabel="Using Barman as a WAL file source">
<title>Using Barman as a WAL file source</title>
<indexterm>
<indexterm>
<primary>Barman</primary>
<secondary>fetching archived WAL</secondary>
</indexterm>
<title>Using Barman as a WAL file source</title>
<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
@@ -178,34 +140,39 @@
</para>
<para>
<command>barman-wal-restore</command> is a Python script provided as part of the <literal>barman-cli</literal>
package (Barman 2.0 ~ 2.7) or as part of the core Barman distribution (Barman 2.8 and later).
package (Barman 2.0 and later; for Barman 1.x the script is provided separately as
<command>barman-wal-restore.py</command>) which performs this function for Barman.
</para>
<para>
To use <command>barman-wal-restore</command> with &repmgr;,
assuming Barman is located on the host &quot;<literal>barmansrv</literal>&quot;
under the &quot;<literal>barman</literal>&quot; user account,
To use <command>barman-wal-restore</command> with &repmgr;
and assuming Barman is located on the <literal>barmansrv</literal> host
and that <command>barman-wal-restore</command> is located as an executable at
<filename>/usr/bin/barman-wal-restore</filename>,
<filename>repmgr.conf</filename> should include the following lines:
<programlisting>
barman_host='barman@barmansrv'
barman_server='somedb'
restore_command='/usr/bin/barman-wal-restore barmansrv somedb %f %p'</programlisting>
barman_host=barmansrv
barman_server=somedb
restore_command=/usr/bin/barman-wal-restore barmansrv somedb %f %p</programlisting>
</para>
<note>
<simpara>
<command>barman-wal-restore</command> supports command line switches to
control parallelism (<literal>--parallel=N</literal>) and compression
(<literal>--bzip2</literal>, <literal>--gzip</literal>).
control parallelism (<literal>--parallel=N</literal>) and compression (
<literal>--bzip2</literal>, <literal>--gzip</literal>).
</simpara>
</note>
<note>
<para>
To use a non-default Barman configuration file on the Barman server,
specify this in <filename>repmgr.conf</filename> with <filename>barman_config</filename>:
<programlisting>
barman_config=/path/to/barman.conf</programlisting>
</para>
</note>
</sect2>
</sect1>
<sect1 id="cloning-replication-slots" xreflabel="Cloning and replication slots">
<title>Cloning and replication slots</title>
<sect1 id="cloning-replication-slots" xreflabel="Cloning and replication slots">
<indexterm>
<primary>cloning</primary>
<secondary>replication slots</secondary>
@@ -215,6 +182,7 @@
<primary>replication slots</primary>
<secondary>cloning</secondary>
</indexterm>
<title>Cloning and replication slots</title>
<para>
Replication slots were introduced with PostgreSQL 9.4 and are designed to ensure
that any standby connected to the primary using a replication slot will always
@@ -276,20 +244,18 @@
<simpara>
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"/>
slot for each individual standby to reserve WAL. See section <xref linkend="cloning-from-barman">
for more details on using &repmgr; together with Barman.
</simpara>
</tip>
</sect1>
<sect1 id="cloning-cascading" xreflabel="Cloning and cascading replication">
<title>Cloning and cascading replication</title>
<indexterm>
<primary>cloning</primary>
<secondary>cascading replication</secondary>
</indexterm>
<title>Cloning and cascading replication</title>
<para>
Cascading replication, introduced with PostgreSQL 9.2, enables a standby server
to replicate from another standby server rather than directly from the primary,
@@ -310,7 +276,7 @@
</para>
<para>
To demonstrate cascading replication, first ensure you have a primary and standby
set up as shown in the <xref linkend="quickstart"/>.
set up as shown in the <xref linkend="quickstart">.
Then create an additional standby server with <filename>repmgr.conf</filename> looking
like this:
<programlisting>
@@ -373,11 +339,11 @@
</sect1>
<sect1 id="cloning-advanced" xreflabel="Advanced cloning options">
<title>Advanced cloning options</title>
<indexterm>
<primary>cloning</primary>
<secondary>advanced options</secondary>
</indexterm>
<title>Advanced cloning options</title>
<sect2 id="cloning-advanced-pg-basebackup-options" xreflabel="pg_basebackup options when cloning a standby">
<title>pg_basebackup options when cloning a standby</title>
@@ -399,7 +365,7 @@
<simpara>
If <application>Barman</application> is set up for the cluster, it's possible to
clone the standby directly from Barman, without any impact on the server the standby
is being cloned from. For more details see <xref linkend="cloning-from-barman"/>.
is being cloned from. For more details see <xref linkend="cloning-from-barman">.
</simpara>
</tip>
<para>
@@ -467,7 +433,7 @@
(but not <filename>~/.pgpass</filename>) and place it into the <varname>primary_conninfo</varname>
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"/>.
rewritten, e.g. <xref linkend="repmgr-standby-follow">.
</para>
<para>
It is of course also possible to include the password value in the <varname>conninfo</varname>
@@ -494,7 +460,7 @@
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"/>.
cloning a node or executing <xref linkend="repmgr-standby-follow">.
</para>
</sect2>
</sect1>

View File

@@ -1,6 +1,4 @@
<sect1 id="configuration-file-log-settings" xreflabel="log settings">
<title>Log settings</title>
<indexterm>
<primary>repmgr.conf</primary>
<secondary>log settings</secondary>
@@ -9,9 +7,10 @@
<primary>log settings</primary>
<secondary>configuration in repmgr.conf</secondary>
</indexterm>
<title>Log settings</title>
<para>
By default, &repmgr; and &repmgrd; write log output to
By default, &repmgr; and <application>repmgrd</application> write log output to
<literal>STDERR</literal>. An alternative log destination can be specified
(either a file or <literal>syslog</literal>).
</para>
@@ -25,7 +24,7 @@
<para>
This behaviour can be overriden with the command line option <option>--log-to-file</option>,
which will redirect all logging output to the configured log destination. This is recommended
when &repmgr; is executed by another application, particularly &repmgrd;,
when &repmgr; is executed by another application, particularly <application>repmgrd</application>,
to enable log output generated by the &repmgr; application to be stored for later reference.
</para>
</note>
@@ -33,11 +32,12 @@
<variablelist>
<varlistentry id="repmgr-conf-log-level" xreflabel="log_level">
<term><varname>log_level</varname> (<type>string</type>)</term>
<listitem>
<term><varname>log_level</varname> (<type>string</type>)
<indexterm>
<primary><varname>log_level</varname> configuration file parameter</primary>
</indexterm>
</term>
<listitem>
<para>
One of <option>DEBUG</option>, <option>INFO</option>, <option>NOTICE</option>,
<option>WARNING</option>, <option>ERROR</option>, <option>ALERT</option>, <option>CRIT</option>
@@ -76,11 +76,11 @@
</term>
<listitem>
<para>
If <xref linkend="repmgr-conf-log-facility"/> is set to <option>STDERR</option>, log output
If <xref linkend="repmgr-conf-log-facility"> is set to <option>STDERR</option>, log output
can be redirected to the specified file.
</para>
<para>
See <xref linkend="repmgrd-log-rotation"/> for information on configuring log rotation.
See <xref linkend="repmgrd-log-rotation"> for information on configuring log rotation.
</para>
</listitem>
</varlistentry>
@@ -93,12 +93,12 @@
</term>
<listitem>
<para>
This setting causes &repmgrd; to emit a status log
This setting causes <application>repmgrd</application> to emit a status log
line at the specified interval (in seconds, default <literal>300</literal>)
describing &repmgrd;'s current state, e.g.:
describing <application>repmgrd</application>'s current state, e.g.:
</para>
<programlisting>
[2018-07-12 00:47:32] [INFO] monitoring connection to upstream node "node1" (ID: 1)</programlisting>
[2018-07-12 00:47:32] [INFO] monitoring connection to upstream node "node1" (node ID: 1)</programlisting>
</listitem>
</varlistentry>

View File

@@ -1,124 +0,0 @@
<sect1 id="configuration-file-optional-settings" xreflabel="optional configuration file settings">
<title>Optional configuration file settings</title>
<indexterm>
<primary>repmgr.conf</primary>
<secondary>optional settings</secondary>
</indexterm>
<variablelist>
<varlistentry id="repmgr-conf-config-directory" xreflabel="config_directory">
<term><varname>config_directory</varname> (<type>string</type>)
<indexterm>
<primary><varname>config_directory</varname> configuration file parameter</primary>
</indexterm>
</term>
<listitem>
<para>
If PostgreSQL configuration files are located outside the data
directory, specify the directory where the main
<filename>postgresql.conf</filename> file is located.
</para>
<para>
This enables explicit provision of an external configuration file
directory, which if set will be passed to <command>pg_ctl</command> as the
<option>-D</option> parameter. Otherwise <command>pg_ctl</command> will
default to using the data directory, which will cause some operations
to fail if the configuration files are not present there.
</para>
<note>
<para>
This is implemented primarily for feature completeness and for
development/testing purposes. Users who have installed &repmgr; from
a package should <emphasis>not</emphasis> rely on to stop/start/restart PostgreSQL,
instead they should set the appropriate <option>service_..._command</option>
for their operating system. For more details see
<xref linkend="configuration-file-service-commands"/>.
</para>
</note>
</listitem>
</varlistentry>
<varlistentry id="repmgr-conf-replication-user" xreflabel="replication_user">
<term><varname>replication_user</varname> (<type>string</type>)
<indexterm>
<primary><varname>replication_user</varname> configuration file parameter</primary>
</indexterm>
</term>
<listitem>
<para>
PostgreSQL user to make replication connections with.
If not set defaults, to the user defined in <xref linkend="repmgr-conf-conninfo"/>.
</para>
</listitem>
</varlistentry>
<varlistentry id="repmgr-conf-replication-type" xreflabel="replication_type">
<term><varname>replication_type</varname> (<type>string</type>)
<indexterm>
<primary><varname>replication_type</varname> configuration file parameter</primary>
</indexterm>
</term>
<listitem>
<para>
Must be one of <literal>physical</literal> (for standard streaming replication)
or <literal>bdr</literal>.
</para>
<note>
<para>
Replication type <literal>bdr</literal> can only be used with BDR 2.x
</para>
<para>
BDR 3.x users should use <literal>physical</literal>.
</para>
</note>
</listitem>
</varlistentry>
<varlistentry id="repmgr-conf-location" xreflabel="location">
<term><varname>location</varname> (<type>string</type>)
<indexterm>
<primary><varname>location</varname> configuration file parameter</primary>
</indexterm>
</term>
<listitem>
<para>
An arbitrary string defining the location of the node; this
is used during failover to check visibility of the
current primary node.
</para>
<para>
For more details see <xref linkend="repmgrd-network-split"/>.
</para>
</listitem>
</varlistentry>
<varlistentry id="repmgr-conf-use-replication-slots" xreflabel="use_replication_slots">
<term><varname>use_replication_slots</varname> (<type>boolean</type>)
<indexterm>
<primary><varname>use_replication_slots</varname> configuration file parameter</primary>
</indexterm>
</term>
<listitem>
<para>
Whether to use physical replication slots.
</para>
<note>
<para>
When using replication slots,
<varname>max_replication_slots</varname> should be configured for
at least the number of standbys which will connect
to the primary.
</para>
</note>
</listitem>
</varlistentry>
</variablelist>
</sect1>

View File

@@ -1,12 +1,10 @@
<sect1 id="configuration-file-settings" xreflabel="required configuration file settings">
<title>Required configuration file settings</title>
<indexterm>
<primary>repmgr.conf</primary>
<secondary>required settings</secondary>
</indexterm>
<title>Required configuration file settings</title>
<para>
Each <filename>repmgr.conf</filename> file must contain the following parameters:
</para>
@@ -62,7 +60,7 @@
</para>
<para>
For details on conninfo strings, see section <ulink
url="https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING">Connection Strings</ulink>
url="https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING">Connection Strings</>
in the PosgreSQL documentation.
</para>
<para>
@@ -71,18 +69,18 @@
string to determine the length of time which elapses before a network
connection attempt is abandoned; for details see <ulink
url="https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNECT-CONNECT-TIMEOUT">
the PostgreSQL documentation</ulink>.
the PostgreSQL documentation</>.
</para>
</listitem>
</varlistentry>
<varlistentry id="repmgr-conf-data-directory" xreflabel="data_directory">
<term><varname>data_directory</varname> (<type>string</type>)</term>
<term><varname>data_directory</varname> (<type>string</type>)
<indexterm>
<primary><varname>data_directory</varname> configuration file parameter</primary>
</indexterm>
</term>
<listitem>
<indexterm>
<primary><varname>data_directory</varname> configuration file parameter</primary>
</indexterm>
<para>
The node's data directory. This is needed by repmgr
when performing operations when the PostgreSQL instance
@@ -96,6 +94,33 @@
</variablelist>
</para>
<para>
For a full list of annotated configuration items, see the file
<ulink url="https://raw.githubusercontent.com/2ndQuadrant/repmgr/master/repmgr.conf.sample">repmgr.conf.sample</ulink>.
</para>
<para>
For <application>repmgrd</application>-specific settings, see <xref linkend="repmgrd-configuration">.
</para>
<note>
<para>
The following parameters in the configuration file can be overridden with
command line options:
<itemizedlist>
<listitem>
<simpara>
<literal>-L/--log-level</literal> overrides <literal>log_level</literal> in
<filename>repmgr.conf</filename>
</simpara>
</listitem>
<listitem>
<simpara>
<literal>-b/--pg_bindir</literal> overrides <literal>pg_bindir</literal> in
<filename>repmgr.conf</filename>
</simpara>
</listitem>
</itemizedlist>
</para>
</note>
</sect1>

View File

@@ -1,6 +1,4 @@
<sect1 id="configuration-file-service-commands" xreflabel="service command settings">
<title>Service command settings</title>
<indexterm>
<primary>repmgr.conf</primary>
<secondary>service command settings</secondary>
@@ -9,9 +7,10 @@
<primary>service command settings</primary>
<secondary>configuration in repmgr.conf</secondary>
</indexterm>
<title>Service command settings</title>
<para>
In some circumstances, &repmgr; (and &repmgrd;) need to
In some circumstances, &repmgr; (and <application>repmgrd</application>) need to
be able to stop, start or restart PostgreSQL. &repmgr; commands which need to do this
include <link linkend="repmgr-standby-follow"><command>repmgr standby follow</command></link>,
<link linkend="repmgr-standby-switchover"><command>repmgr standby switchover</command></link> and
@@ -69,7 +68,7 @@
</para>
<para>
Do not confuse this with <varname>promote_command</varname>, which is used
by &repmgrd; to execute <xref linkend="repmgr-standby-promote"/>.
by <application>repmgrd</application> to execute <xref linkend="repmgr-standby-promote">.
</para>
</note>

View File

@@ -1,7 +1,4 @@
<sect1 id="configuration-file" xreflabel="configuration file">
<title>Configuration file</title>
<indexterm>
<primary>repmgr.conf</primary>
</indexterm>
@@ -11,27 +8,27 @@
<secondary>repmgr.conf</secondary>
</indexterm>
<title>Configuration file</title>
<para>
<application>repmgr</application> and &repmgrd;
<application>repmgr</application> and <application>repmgrd</application>
use a common configuration file, by default called
<filename>repmgr.conf</filename> (although any name can be used if explicitly specified).
<filename>repmgr.conf</filename> must contain a number of required parameters, including
the database connection string for the local node and the location
of its data directory; other values will be inferred from defaults if
not explicitly supplied. See section <xref linkend="configuration-file-settings"/>
not explicitly supplied. See section <xref linkend="configuration-file-settings">
for more details.
</para>
<sect2 id="configuration-file-format" xreflabel="configuration file format">
<title>Configuration file format</title>
<indexterm>
<primary>repmgr.conf</primary>
<secondary>format</secondary>
</indexterm>
<title>Configuration file format</title>
<para>
<filename>repmgr.conf</filename> is a plain text file with one parameter/value
@@ -41,10 +38,14 @@
Whitespace is insignificant (except within a quoted parameter value) and blank lines are ignored.
Hash marks (<literal>#</literal>) designate the remainder of the line as a comment.
Parameter values that are not simple identifiers or numbers should be single-quoted.
Note that single quote cannot be embedded in a parameter value.
</para>
<para>
To embed a single quote in a parameter value, write either two quotes (preferred) or backslash-quote.
</para>
<important>
<para>
&repmgr; will interpret double-quotes as being part of a string value; only use single quotes
to quote parameter values.
</para>
</important>
<para>
Example of a valid <filename>repmgr.conf</filename> file:
@@ -54,108 +55,20 @@
node_id=1
node_name= node1
conninfo ='host=node1 dbname=repmgr user=repmgr connect_timeout=2'
data_directory = '/var/lib/pgsql/12/data'</programlisting>
data_directory = /var/lib/pgsql/11/data</programlisting>
</para>
<note>
<para>
Beginning with <link linkend="release-5.0">repmgr 5.0</link>, configuration
file parsing has been tightened up and now matches the way PostgreSQL
itself parses configuration files.
</para>
<para>
This means <filename>repmgr.conf</filename> files used with earlier &repmgr;
versions may need slight modification before they can be used with &repmgr; 5
and later.
</para>
<para>
The main change is that &repmgr; requires most string values to be
enclosed in single quotes. For example, this was previously valid:
<programlisting>
conninfo=host=node1 user=repmgr dbname=repmgr connect_timeout=2</programlisting>
but must now be changed to:
<programlisting>
conninfo='host=node1 user=repmgr dbname=repmgr connect_timeout=2'</programlisting>
</para>
</note>
</sect2>
<sect2 id="configuration-file-items" xreflabel="configuration file items">
<title>Configuration file items</title>
<para>
The following sections document some sections of the configuration file:
<itemizedlist>
<listitem>
<simpara>
<xref linkend="configuration-file-settings"/>
</simpara>
</listitem>
<listitem>
<simpara>
<xref linkend="configuration-file-optional-settings"/>
</simpara>
</listitem>
<listitem>
<simpara>
<xref linkend="configuration-file-log-settings"/>
</simpara>
</listitem>
<listitem>
<simpara>
<xref linkend="configuration-file-service-commands"/>
</simpara>
</listitem>
</itemizedlist>
</para>
<para>
For a full list of annotated configuration items, see the file
<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"/>.
</para>
<note>
<para>
The following parameters in the configuration file can be overridden with
command line options:
<itemizedlist>
<listitem>
<simpara>
<literal>-L/--log-level</literal> overrides <literal>log_level</literal> in
<filename>repmgr.conf</filename>
</simpara>
</listitem>
<listitem>
<simpara>
<literal>-b/--pg_bindir</literal> overrides <literal>pg_bindir</literal> in
<filename>repmgr.conf</filename>
</simpara>
</listitem>
</itemizedlist>
</para>
</note>
</sect2>
<sect2 id="configuration-file-location" xreflabel="configuration file location">
<title>Configuration file location</title>
<indexterm>
<primary>repmgr.conf</primary>
<secondary>location</secondary>
</indexterm>
<title>Configuration file location</title>
<para>
The configuration file will be searched for in the following locations:
@@ -192,10 +105,10 @@ conninfo='host=node1 user=repmgr dbname=repmgr connect_timeout=2'</programlistin
<note>
<para>
If providing the configuration file location with <literal>-f/--config-file</literal>,
avoid using a relative path, particularly when executing <xref linkend="repmgr-primary-register"/>
and <xref linkend="repmgr-standby-register"/>, as &repmgr; stores the configuration file location
avoid using a relative path, particularly when executing <xref linkend="repmgr-primary-register">
and <xref linkend="repmgr-standby-register">, as &repmgr; stores the configuration file location
in the repmgr metadata for use when &repmgr; is executed remotely (e.g. during
<xref linkend="repmgr-standby-switchover"/>). &repmgr; will attempt to convert the
<xref linkend="repmgr-standby-switchover">). &repmgr; will attempt to convert the
a relative path into an absolute one, but this may not be the same as the path you
would explicitly provide (e.g. <filename>./repmgr.conf</filename> might be converted
to <filename>/path/to/./repmgr.conf</filename>, whereas you'd normally write

View File

@@ -2,8 +2,6 @@
<title>repmgr configuration</title>
<sect1 id="configuration-prerequisites" xreflabel="Prerequisites for configuration">
<title>Prerequisites for configuration</title>
<indexterm>
<primary>configuration</primary>
<secondary>prerequisites</secondary>
@@ -14,6 +12,7 @@
<secondary>ssh</secondary>
</indexterm>
<title>Prerequisites for configuration</title>
<para>
Following software must be installed on both servers:
<itemizedlist spacing="compact" mark="bullet">
@@ -63,8 +62,6 @@
</tip>
<sect2 id="configuration-postgresql" xreflabel="PostgreSQL configuration">
<title>PostgreSQL configuration for &repmgr;</title>
<indexterm>
<primary>configuration</primary>
<secondary>PostgreSQL</secondary>
@@ -74,6 +71,7 @@
<primary>PostgreSQL configuration</primary>
</indexterm>
<title>PostgreSQL configuration for &repmgr;</title>
<para>
The following PostgreSQL configuration parameters may need to be changed in order
for &repmgr; (and replication itself) to function correctly.
@@ -83,14 +81,13 @@
<varlistentry>
<indexterm>
<primary>hot_standby</primary>
<secondary>PostgreSQL configuration</secondary>
</indexterm>
<term><option>hot_standby</option></term>
<listitem>
<indexterm>
<primary>hot_standby</primary>
<secondary>PostgreSQL configuration</secondary>
</indexterm>
<para>
<option>hot_standby</option> must always be set to <literal>on</literal>, as &repmgr; needs
to be able to connect to each server it manages.
@@ -107,15 +104,13 @@
<varlistentry>
<indexterm>
<primary>wal_level</primary>
<secondary>PostgreSQL configuration</secondary>
</indexterm>
<term><option>wal_level</option></term>
<listitem>
<indexterm>
<primary>wal_level</primary>
<secondary>PostgreSQL configuration</secondary>
</indexterm>
<para>
<option>wal_level</option> must be one of <option>replica</option> or <option>logical</option>
(PostgreSQL 9.5 and earlier: one of <option>hot_standby</option> or <option>logical</option>).
@@ -128,15 +123,13 @@
<varlistentry>
<indexterm>
<primary>max_wal_senders</primary>
<secondary>PostgreSQL configuration</secondary>
</indexterm>
<term><option>max_wal_senders</option></term>
<listitem>
<indexterm>
<primary>max_wal_senders</primary>
<secondary>PostgreSQL configuration</secondary>
</indexterm>
<para>
<option>max_wal_senders</option> must be set to a value of <literal>2</literal> or greater.
In general you will need one WAL sender for each standby which will attach to the PostgreSQL
@@ -148,33 +141,21 @@
instances in the replication cluster which may potentially become a primary server or
(in cascading replication) the upstream server of a standby.
</para>
<para>
<para>
PostgreSQL documentation: <ulink url="https://www.postgresql.org/docs/current/runtime-config-replication.html#GUC-MAX-WAL-SENDERS">max_wal_senders</ulink>.
</para>
<note>
<para>
From <productname>PostgreSQL 12</productname>, <option>max_wal_senders</option>
<emphasis>must</emphasis> be set to the same or a higher value as the primary node
(at the time the node was cloned), otherwise the standby will refuse
to start (unless <option>hot_standby</option> is set to <literal>off</literal>, which
will prevent the node from accepting queries).
</para>
</note>
</listitem>
</varlistentry>
<varlistentry>
<indexterm>
<primary>max_replication_slots</primary>
<secondary>PostgreSQL configuration</secondary>
</indexterm>
<term><option>max_replication_slots</option></term>
<listitem>
<indexterm>
<primary>max_replication_slots</primary>
<secondary>PostgreSQL configuration</secondary>
</indexterm>
<para>
If you are intending to use replication slots, <option>max_replication_slots</option>
must be set to a non-zero value.
@@ -193,20 +174,19 @@
<varlistentry>
<indexterm>
<primary>wal_log_hints</primary>
<secondary>PostgreSQL configuration</secondary>
</indexterm>
<term><option>wal_log_hints</option></term>
<listitem>
<indexterm>
<primary>wal_log_hints</primary>
<secondary>PostgreSQL configuration</secondary>
</indexterm>
<para>If you are intending to use <application>pg_rewind</application>,
and the cluster was not initialised using data checksums, you may want to consider enabling
<option>wal_log_hints</option>.
</para>
<para>
For more details see <xref linkend="repmgr-node-rejoin-pg-rewind"/>.
For more details see <xref linkend="repmgr-node-rejoin-pg-rewind">.
</para>
<para>
PostgreSQL documentation: <ulink url="https://www.postgresql.org/docs/current/runtime-config-wal.html#GUC-WAL-LOG-HINTS">wal_log_hints</ulink>.
@@ -216,15 +196,13 @@
<varlistentry>
<indexterm>
<primary>archive_mode</primary>
<secondary>PostgreSQL configuration</secondary>
</indexterm>
<term><option>archive_mode</option></term>
<listitem>
<indexterm>
<primary>archive_mode</primary>
<secondary>PostgreSQL configuration</secondary>
</indexterm>
<para>
We suggest setting <option>archive_mode</option> to <literal>on</literal> (and
<option>archive_command</option> to <literal>/bin/true</literal>; see below)
@@ -247,15 +225,13 @@
<varlistentry>
<indexterm>
<primary>archive_command</primary>
<secondary>PostgreSQL configuration</secondary>
</indexterm>
<term><option>archive_command</option></term>
<listitem>
<indexterm>
<primary>archive_command</primary>
<secondary>PostgreSQL configuration</secondary>
</indexterm>
<para>
If you have set <option>archive_mode</option> to <literal>on</literal> but are not currently planning
to use WAL file archiving, set <option>archive_command</option> to a command which does nothing but returns
@@ -270,15 +246,13 @@
<varlistentry>
<indexterm>
<primary>wal_keep_segments</primary>
<secondary>PostgreSQL configuration</secondary>
</indexterm>
<term><option>wal_keep_segments</option></term>
<listitem>
<indexterm>
<primary>wal_keep_segments</primary>
<secondary>PostgreSQL configuration</secondary>
</indexterm>
<para>
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.
@@ -315,18 +289,16 @@
&configuration-file;
&configuration-file-required-settings;
&configuration-file-optional-settings;
&configuration-file-log-settings;
&configuration-file-service-commands;
<sect1 id="configuration-permissions" xreflabel="Database user permissions">
<title>repmgr database user permissions</title>
<indexterm>
<primary>configuration</primary>
<secondary>database user permissions</secondary>
</indexterm>
<title>repmgr database user permissions</title>
<para>
&repmgr; will create an extension database containing objects
for administering &repmgr; metadata. The user defined in the <varname>conninfo</varname>

View File

@@ -1,12 +1,12 @@
<chapter id="event-notifications" xreflabel="event notifications">
<title>Event Notifications</title>
<indexterm>
<primary>event notifications</primary>
</indexterm>
<title>Event Notifications</title>
<para>
Each time &repmgr; or &repmgrd; perform a significant event, a record
Each time &repmgr; or <application>repmgrd</application> perform a significant event, a record
of that event is written into the <literal>repmgr.events</literal> table together with
a timestamp, an indication of failure or success, and further details
if appropriate. This is useful for gaining an overview of events
@@ -27,7 +27,7 @@
(3 rows)</programlisting>
</para>
<para>
Alternatively, use <xref linkend="repmgr-cluster-event"/> to output a
Alternatively, use <xref linkend="repmgr-cluster-event"> to output a
formatted list of events.
</para>
<para>
@@ -91,7 +91,8 @@
may contain spaces, so should be quoted in the provided command
configuration, e.g.:
<programlisting>
event_notification_command='/path/to/some/script %n %e %s "%t" "%d"'</programlisting>
event_notification_command='/path/to/some/script %n %e %s "%t" "%d"'
</programlisting>
</para>
<para>
@@ -103,10 +104,10 @@
<term><option>%p</option></term>
<listitem>
<para>
node ID of the current primary (<xref linkend="repmgr-standby-register"/> and <xref linkend="repmgr-standby-follow"/>)
node ID of the current primary (<xref linkend="repmgr-standby-register"> and <xref linkend="repmgr-standby-follow">)
</para>
<para>
node ID of the demoted primary (<xref linkend="repmgr-standby-switchover"/> only)
node ID of the demoted primary (<xref linkend="repmgr-standby-switchover"> only)
</para>
</listitem>
</varlistentry>
@@ -115,7 +116,7 @@
<listitem>
<para>
<literal>conninfo</literal> string of the primary node
(<xref linkend="repmgr-standby-register"/> and <xref linkend="repmgr-standby-follow"/>)
(<xref linkend="repmgr-standby-register"> and <xref linkend="repmgr-standby-follow">)
</para>
<para>
<literal>conninfo</literal> string of the next available node
@@ -128,7 +129,7 @@
<term><option>%a</option></term>
<listitem>
<para>
name of the current primary node (<xref linkend="repmgr-standby-register"/> and <xref linkend="repmgr-standby-follow"/>)
name of the current primary node (<xref linkend="repmgr-standby-register"> and <xref linkend="repmgr-standby-follow">)
</para>
<para>
name of the next available node (<varname>bdr_failover</varname> and <varname>bdr_recovery</varname>)
@@ -146,10 +147,7 @@
<para>
By default, all notification types will be passed to the designated script;
the notification types can be filtered to explicitly named ones using the
<varname>event_notifications</varname> parameter, e.g.:
<programlisting>
event_notifications=primary_register,standby_register,witness_register</programlisting>
<varname>event_notifications</varname> parameter.
</para>
<para>
@@ -207,7 +205,7 @@
</para>
<para>
Events generated by &repmgrd; (streaming replication mode):
Events generated by <application>repmgrd</application> (streaming replication mode):
<itemizedlist spacing="compact" mark="bullet">
<listitem>
@@ -257,24 +255,11 @@
<simpara><literal>standby_recovery</literal></simpara>
</listitem>
<listitem>
<simpara><literal><link linkend="repmgrd-primary-child-disconnection-events">child_node_disconnect</link></literal></simpara>
</listitem>
<listitem>
<simpara><literal><link linkend="repmgrd-primary-child-disconnection-events">child_node_reconnect</link></literal></simpara>
</listitem>
<listitem>
<simpara><literal><link linkend="repmgrd-primary-child-disconnection-events">child_node_new_connect</link></literal></simpara>
</listitem>
<listitem>
<simpara><literal><link linkend="repmgrd-primary-child-disconnection-events">child_nodes_disconnect_command</link></literal></simpara>
</listitem>
</itemizedlist>
</para>
<para>
Events generated by &repmgrd; (BDR mode):
Events generated by <application>repmgrd</application> (BDR mode):
<itemizedlist spacing="compact" mark="bullet">
<listitem>
<simpara><literal>bdr_failover</literal></simpara>

90
doc/filelist.sgml Normal file
View File

@@ -0,0 +1,90 @@
<!-- doc/filelist.sgml -->
<!ENTITY legal SYSTEM "legal.sgml">
<!ENTITY bookindex SYSTEM "bookindex.sgml">
<!--
Some parts of the documentation are also source for some plain-text
files used during installation. To selectively ignore or include
some parts (e.g., external xref's) when generating these files we use
these parameter entities. See also standalone-install.sgml.
-->
<!ENTITY % standalone-ignore "INCLUDE">
<!ENTITY % standalone-include "IGNORE">
<!-- doc/filelist.sgml -->
<!--
By default, no index is included. Use -i include-index on the command line
to include it.
-->
<!ENTITY % include-index "IGNORE">
<!--
Create empty index element for processing by XSLT stylesheet.
-->
<!ENTITY % include-xslt-index "IGNORE">
<!--
Include external documentation sections
-->
<!ENTITY overview SYSTEM "overview.sgml">
<!ENTITY install SYSTEM "install.sgml">
<!ENTITY install-requirements SYSTEM "install-requirements.sgml">
<!ENTITY install-packages SYSTEM "install-packages.sgml">
<!ENTITY install-source SYSTEM "install-source.sgml">
<!ENTITY quickstart SYSTEM "quickstart.sgml">
<!ENTITY configuration SYSTEM "configuration.sgml">
<!ENTITY configuration-file SYSTEM "configuration-file.sgml">
<!ENTITY configuration-file-required-settings SYSTEM "configuration-file-required-settings.sgml">
<!ENTITY configuration-file-log-settings SYSTEM "configuration-file-log-settings.sgml">
<!ENTITY configuration-file-service-commands SYSTEM "configuration-file-service-commands.sgml">
<!ENTITY cloning-standbys SYSTEM "cloning-standbys.sgml">
<!ENTITY promoting-standby SYSTEM "promoting-standby.sgml">
<!ENTITY follow-new-primary SYSTEM "follow-new-primary.sgml">
<!ENTITY switchover SYSTEM "switchover.sgml">
<!ENTITY event-notifications SYSTEM "event-notifications.sgml">
<!ENTITY upgrading-repmgr SYSTEM "upgrading-repmgr.sgml">
<!ENTITY repmgrd-overview SYSTEM "repmgrd-overview.sgml">
<!ENTITY repmgrd-automatic-failover SYSTEM "repmgrd-automatic-failover.sgml">
<!ENTITY repmgrd-configuration SYSTEM "repmgrd-configuration.sgml">
<!ENTITY repmgrd-operation SYSTEM "repmgrd-operation.sgml">
<!ENTITY repmgrd-bdr SYSTEM "repmgrd-bdr.sgml">
<!ENTITY repmgr-primary-register SYSTEM "repmgr-primary-register.sgml">
<!ENTITY repmgr-primary-unregister SYSTEM "repmgr-primary-unregister.sgml">
<!ENTITY repmgr-standby-clone SYSTEM "repmgr-standby-clone.sgml">
<!ENTITY repmgr-standby-register SYSTEM "repmgr-standby-register.sgml">
<!ENTITY repmgr-standby-unregister SYSTEM "repmgr-standby-unregister.sgml">
<!ENTITY repmgr-standby-promote SYSTEM "repmgr-standby-promote.sgml">
<!ENTITY repmgr-standby-follow SYSTEM "repmgr-standby-follow.sgml">
<!ENTITY repmgr-standby-switchover SYSTEM "repmgr-standby-switchover.sgml">
<!ENTITY repmgr-witness-register SYSTEM "repmgr-witness-register.sgml">
<!ENTITY repmgr-witness-unregister SYSTEM "repmgr-witness-unregister.sgml">
<!ENTITY repmgr-node-status SYSTEM "repmgr-node-status.sgml">
<!ENTITY repmgr-node-check SYSTEM "repmgr-node-check.sgml">
<!ENTITY repmgr-node-rejoin SYSTEM "repmgr-node-rejoin.sgml">
<!ENTITY repmgr-node-service SYSTEM "repmgr-node-service.sgml">
<!ENTITY repmgr-cluster-show SYSTEM "repmgr-cluster-show.sgml">
<!ENTITY repmgr-cluster-matrix SYSTEM "repmgr-cluster-matrix.sgml">
<!ENTITY repmgr-cluster-crosscheck SYSTEM "repmgr-cluster-crosscheck.sgml">
<!ENTITY repmgr-cluster-event SYSTEM "repmgr-cluster-event.sgml">
<!ENTITY repmgr-cluster-cleanup SYSTEM "repmgr-cluster-cleanup.sgml">
<!ENTITY repmgr-daemon-status SYSTEM "repmgr-daemon-status.sgml">
<!ENTITY repmgr-daemon-start SYSTEM "repmgr-daemon-start.sgml">
<!ENTITY repmgr-daemon-stop SYSTEM "repmgr-daemon-stop.sgml">
<!ENTITY repmgr-daemon-pause SYSTEM "repmgr-daemon-pause.sgml">
<!ENTITY repmgr-daemon-unpause SYSTEM "repmgr-daemon-unpause.sgml">
<!ENTITY appendix-release-notes SYSTEM "appendix-release-notes.sgml">
<!ENTITY appendix-faq SYSTEM "appendix-faq.sgml">
<!ENTITY appendix-signatures SYSTEM "appendix-signatures.sgml">
<!ENTITY appendix-packages SYSTEM "appendix-packages.sgml">
<!ENTITY appendix-support SYSTEM "appendix-support.sgml">
<!ENTITY bookindex SYSTEM "bookindex.sgml">

View File

@@ -1,70 +0,0 @@
<!-- doc/filelist.xml -->
<!ENTITY legal SYSTEM "legal.xml">
<!ENTITY bookindex SYSTEM "bookindex.xml">
<!--
Include external documentation sections
-->
<!ENTITY overview SYSTEM "overview.xml">
<!ENTITY install SYSTEM "install.xml">
<!ENTITY install-requirements SYSTEM "install-requirements.xml">
<!ENTITY install-packages SYSTEM "install-packages.xml">
<!ENTITY install-source SYSTEM "install-source.xml">
<!ENTITY quickstart SYSTEM "quickstart.xml">
<!ENTITY configuration SYSTEM "configuration.xml">
<!ENTITY configuration-file SYSTEM "configuration-file.xml">
<!ENTITY configuration-file-required-settings SYSTEM "configuration-file-required-settings.xml">
<!ENTITY configuration-file-optional-settings SYSTEM "configuration-file-optional-settings.xml">
<!ENTITY configuration-file-log-settings SYSTEM "configuration-file-log-settings.xml">
<!ENTITY configuration-file-service-commands SYSTEM "configuration-file-service-commands.xml">
<!ENTITY cloning-standbys SYSTEM "cloning-standbys.xml">
<!ENTITY promoting-standby SYSTEM "promoting-standby.xml">
<!ENTITY follow-new-primary SYSTEM "follow-new-primary.xml">
<!ENTITY switchover SYSTEM "switchover.xml">
<!ENTITY event-notifications SYSTEM "event-notifications.xml">
<!ENTITY upgrading-repmgr SYSTEM "upgrading-repmgr.xml">
<!ENTITY repmgrd-overview SYSTEM "repmgrd-overview.xml">
<!ENTITY repmgrd-automatic-failover SYSTEM "repmgrd-automatic-failover.xml">
<!ENTITY repmgrd-configuration SYSTEM "repmgrd-configuration.xml">
<!ENTITY repmgrd-operation SYSTEM "repmgrd-operation.xml">
<!ENTITY repmgrd-bdr SYSTEM "repmgrd-bdr.xml">
<!ENTITY repmgr-primary-register SYSTEM "repmgr-primary-register.xml">
<!ENTITY repmgr-primary-unregister SYSTEM "repmgr-primary-unregister.xml">
<!ENTITY repmgr-standby-clone SYSTEM "repmgr-standby-clone.xml">
<!ENTITY repmgr-standby-register SYSTEM "repmgr-standby-register.xml">
<!ENTITY repmgr-standby-unregister SYSTEM "repmgr-standby-unregister.xml">
<!ENTITY repmgr-standby-promote SYSTEM "repmgr-standby-promote.xml">
<!ENTITY repmgr-standby-follow SYSTEM "repmgr-standby-follow.xml">
<!ENTITY repmgr-standby-switchover SYSTEM "repmgr-standby-switchover.xml">
<!ENTITY repmgr-witness-register SYSTEM "repmgr-witness-register.xml">
<!ENTITY repmgr-witness-unregister SYSTEM "repmgr-witness-unregister.xml">
<!ENTITY repmgr-node-status SYSTEM "repmgr-node-status.xml">
<!ENTITY repmgr-node-check SYSTEM "repmgr-node-check.xml">
<!ENTITY repmgr-node-rejoin SYSTEM "repmgr-node-rejoin.xml">
<!ENTITY repmgr-node-service SYSTEM "repmgr-node-service.xml">
<!ENTITY repmgr-cluster-show SYSTEM "repmgr-cluster-show.xml">
<!ENTITY repmgr-cluster-matrix SYSTEM "repmgr-cluster-matrix.xml">
<!ENTITY repmgr-cluster-crosscheck SYSTEM "repmgr-cluster-crosscheck.xml">
<!ENTITY repmgr-cluster-event SYSTEM "repmgr-cluster-event.xml">
<!ENTITY repmgr-cluster-cleanup SYSTEM "repmgr-cluster-cleanup.xml">
<!ENTITY repmgr-service-status SYSTEM "repmgr-service-status.xml">
<!ENTITY repmgr-service-pause SYSTEM "repmgr-service-pause.xml">
<!ENTITY repmgr-service-unpause SYSTEM "repmgr-service-unpause.xml">
<!ENTITY repmgr-daemon-start SYSTEM "repmgr-daemon-start.xml">
<!ENTITY repmgr-daemon-stop SYSTEM "repmgr-daemon-stop.xml">
<!ENTITY appendix-release-notes SYSTEM "appendix-release-notes.xml">
<!ENTITY appendix-faq SYSTEM "appendix-faq.xml">
<!ENTITY appendix-signatures SYSTEM "appendix-signatures.xml">
<!ENTITY appendix-packages SYSTEM "appendix-packages.xml">
<!ENTITY appendix-support SYSTEM "appendix-support.xml">
<!ENTITY bookindex SYSTEM "bookindex.xml">

View File

@@ -1,19 +1,18 @@
<chapter id="follow-new-primary">
<title>Following a new primary</title>
<indexterm>
<primary>Following a new primary</primary>
<seealso>repmgr standby follow</seealso>
</indexterm>
<title>Following a new primary</title>
<para>
Following the failure or removal of the replication cluster's existing primary
server, <xref linkend="repmgr-standby-follow"/> can be used to make &quot;orphaned&quot; standbys
server, <xref linkend="repmgr-standby-follow"> can be used to make 'orphaned' standbys
follow the new primary and catch up to its current state.
</para>
<para>
To demonstrate this, assuming a replication cluster in the same state as the
end of the preceding section (<xref linkend="promoting-standby"/>),
end of the preceding section (<xref linkend="promoting-standby">),
execute this:
<programlisting>
$ repmgr -f /etc/repmgr.conf standby follow

View File

@@ -13,13 +13,12 @@
<sect2 id="installation-packages-redhat" xreflabel="Installing from packages on RHEL, CentOS and Fedora">
<title>RedHat/CentOS/Fedora</title>
<indexterm>
<primary>installation</primary>
<secondary>on Red Hat/CentOS/Fedora etc.</secondary>
</indexterm>
<title>RedHat/CentOS/Fedora</title>
<para>
&repmgr; RPM packages for RedHat/CentOS variants and Fedora are available from the
<ulink url="https://2ndquadrant.com">2ndQuadrant</ulink>
@@ -42,16 +41,12 @@
customers, as the PostgreSQL filesystem layout may be different to the community RPMs.
Please contact your support vendor for assistance.
</para>
<para>
See also <link linkend="appendix-faq">FAQ</link> entry
<xref linkend="faq-third-party-packages"/>.
</para>
</note>
<para>
For more information on the package contents, including details of installation
paths and relevant <link linkend="configuration-file-service-commands">service commands</link>,
see the appendix section <xref linkend="packages-centos"/>.
see the appendix section <xref linkend="packages-centos">.
</para>
@@ -85,9 +80,9 @@
(this enables the 2ndQuadrant repository as a source of &repmgr; packages).
</para>
<para>
For example, for PostgreSQL 11 on CentOS, execute:
For example, for PostgreSQL 10 on CentOS, execute:
<programlisting>
curl https://dl.2ndquadrant.com/default/release/get/11/rpm | sudo bash</programlisting>
curl https://dl.2ndquadrant.com/default/release/get/10/rpm | sudo bash</programlisting>
</para>
<para>
@@ -103,16 +98,16 @@ curl https://dl.2ndquadrant.com/default/release/get/9.6/rpm | sudo bash</program
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>
2ndquadrant-dl-default-release-pg10/7/x86_64 2ndQuadrant packages (PG10) for 7 - x86_64 4
2ndquadrant-dl-default-release-pg10-debug/7/x86_64 2ndQuadrant packages (PG10) for 7 - x86_64 - Debug 3</programlisting>
</para>
</listitem>
<listitem>
<para>
Install the &repmgr; version appropriate for your PostgreSQL version (e.g. <literal>repmgr10</literal>):
Install the &repmgr version appropriate for your PostgreSQL version (e.g. <literal>repmgr10</literal>):
<programlisting>
sudo yum install repmgr11</programlisting>
sudo yum install repmgr10</programlisting>
</para>
<note>
<para>
@@ -157,23 +152,19 @@ yum search repmgr</programlisting>
To install a specific package version, execute <command>yum --showduplicates list</command>
for the package in question:
<programlisting>
[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
repmgr11.x86_64 4.4.0-1.rhel7 @pgdg11
Available Packages
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>
[root@localhost ~]# yum --showduplicates list repmgr10
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
* base: ftp.iij.ad.jp
* extras: ftp.iij.ad.jp
* updates: ftp.iij.ad.jp
Available Packages
repmgr10.x86_64 4.0.3-1.rhel7 pgdg10
repmgr10.x86_64 4.0.4-1.rhel7 pgdg10
repmgr10.x86_64 4.0.5-1.el7 2ndquadrant-repo-10</programlisting>
then append the appropriate version number to the package name with a hyphen, e.g.:
<programlisting>
[root@localhost ~]# yum install repmgr11-4.3-1.el7</programlisting>
[root@localhost ~]# yum install repmgr10-4.0.3-1.rhel7</programlisting>
</para>
<para>
@@ -190,13 +181,12 @@ repmgr11.x86_64 4.4-1.el7 2nd
<sect2 id="installation-packages-debian" xreflabel="Installing from packages on Debian or Ubuntu">
<title>Debian/Ubuntu</title>
<indexterm>
<primary>installation</primary>
<secondary>on Debian/Ubuntu etc.</secondary>
</indexterm>
<title>Debian/Ubuntu</title>
<para>.deb packages for &repmgr; are available from the
PostgreSQL Community APT repository (<ulink url="http://apt.postgresql.org/">http://apt.postgresql.org/</ulink>).
Instructions can be found in the APT section of the PostgreSQL Wiki
@@ -205,7 +195,7 @@ repmgr11.x86_64 4.4-1.el7 2nd
<para>
For more information on the package contents, including details of installation
paths and relevant <link linkend="configuration-file-service-commands">service commands</link>,
see the appendix section <xref linkend="packages-debian-ubuntu"/>.
see the appendix section <xref linkend="packages-debian-ubuntu">.
</para>
<sect3 id="installation-packages-debian-ubuntu-2ndq">
@@ -228,13 +218,13 @@ repmgr11.x86_64 4.4-1.el7 2nd
<itemizedlist>
<listitem>
<para>
<listitem>
<para>
Install the repository definition for your distribution and PostgreSQL version
(this enables the 2ndQuadrant 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.2ndquadrant.com/default/release/get/deb | sudo bash</programlisting>
</para>
curl https://dl.2ndquadrant.com/default/release/get/deb | sudo bash</programlisting>
</para>
<note>
<para>
This will automatically install the following additional packages, if not already present:
@@ -250,20 +240,20 @@ repmgr11.x86_64 4.4-1.el7 2nd
</note>
</listitem>
<listitem>
<para>
Install the &repmgr; version appropriate for your PostgreSQL version (e.g. <literal>repmgr11</literal>):
<listitem>
<para>
Install the &repmgr version appropriate for your PostgreSQL version (e.g. <literal>repmgr10</literal>):
<programlisting>
sudo apt-get install postgresql-11-repmgr</programlisting>
</para>
sudo apt-get install postgresql-10-repmgr</programlisting>
</para>
<note>
<para>
For packages for PostgreSQL 9.6 and earlier, the package name includes
a period between major and minor version numbers, e.g.
<literal>postgresql-9.6-repmgr</literal>.
For packages for PostgreSQL 9.6 and earlier, the package name includes
a period between major and minor version numbers, e.g.
<literal>postgresql-9.6-repmgr</literal>.
</para>
</note>
</listitem>
</listitem>
</itemizedlist>

View File

@@ -1,12 +1,11 @@
<sect1 id="install-requirements" xreflabel="installation requirements">
<title>Requirements for installing repmgr</title>
<indexterm>
<primary>installation</primary>
<secondary>requirements</secondary>
</indexterm>
<title>Requirements for installing repmgr</title>
<para>
repmgr is developed and tested on Linux and OS X, but should work on any
UNIX-like system supported by PostgreSQL itself. There is no support for
@@ -14,14 +13,14 @@
</para>
<para>
&repmgr; &repmgrversion; is compatible with all PostgreSQL versions from 9.3. See
&repmgr; 4.x 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>
<note>
<simpara>
If upgrading from &repmgr; 3.x, please see the section <xref linkend="upgrading-from-repmgr-3"/>.
If upgrading from &repmgr; 3.x, please see the section <xref linkend="upgrading-from-repmgr-3">.
</simpara>
</note>
@@ -39,21 +38,21 @@
<note>
<simpara>
The same &quot;major&quot; &repmgr; version (e.g. <literal>&repmgrversion;.x</literal>) <emphasis>must</emphasis>
The same &quot;major&quot; &repmgr; version (e.g. <literal>4.2.x</literal>) <emphasis>must</emphasis>
be installed on all node in the replication cluster. We strongly recommend keeping all
nodes on the same (preferably latest) &quot;minor&quot; &repmgr; version to minimize the risk
of incompatibilities.
</simpara>
<simpara>
If different &quot;major&quot; &repmgr; versions (e.g. 4.1.x and &repmgrversion;.x)
are installed on different nodes, in the best case &repmgr; (in particular &repmgrd;)
If different &quot;major&quot; &repmgr; versions (e.g. 3.3.x and 4.1.x)
are installed on different nodes, in the best case &repmgr; (in particular <application>repmgrd</application>)
will not run. In the worst case, you will end up with a broken cluster.
</simpara>
</note>
<para>
A dedicated system user for &repmgr; is <emphasis>not</emphasis> required; as many &repmgr; and
&repmgrd; actions require direct access to the PostgreSQL data directory,
<application>repmgrd</application> actions require direct access to the PostgreSQL data directory,
these commands should be executed by the <literal>postgres</literal> user.
</para>
@@ -73,8 +72,6 @@
<sect2 id="install-compatibility-matrix">
<title>&repmgr; compatibility matrix</title>
<indexterm>
<primary>repmgr</primary>
<secondary>compatibility matrix</secondary>
@@ -84,6 +81,7 @@
<primary>compatibility matrix</primary>
</indexterm>
<title>&repmgr; compatibility matrix</title>
<para>
The following table provides an overview of which &repmgr; version supports
which PostgreSQL version.
@@ -93,7 +91,7 @@
<table id="repmgr-compatibility-matrix">
<title>&repmgr; compatibility matrix</title>
<tgroup cols="3">
<tgroup cols="2">
<thead>
<row>
<entry>
@@ -109,25 +107,12 @@
</thead>
<tbody>
<row>
<entry>
&repmgr; 5.x
</entry>
<entry>
<link linkend="release-current">&repmgrversion;</link> (&releasedate;)
</entry>
<entry>
9.3, 9.4, 9.5, 9.6, 10, 11, 12
</entry>
</row>
<row>
<entry>
&repmgr; 4.x
</entry>
<entry>
<link linkend="release-4.4">4.4</link> (2019-06-27)
<link linkend="release-4.2">4.2</link> (2018-10-24)
</entry>
<entry>
9.3, 9.4, 9.5, 9.6, 10, 11
@@ -167,26 +152,11 @@
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. 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>
</sect2>
<sect2 id="install-postgresql-93-94">
<title>PostgreSQL 9.3 and 9.4 support</title>
<indexterm>
<primary>PostgreSQL 9.3</primary>
<secondary>repmgr support</secondary>
</indexterm>
<para>
Note that some &repmgr; functionality is not available in PostgreSQL 9.3 and 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">
@@ -205,22 +175,5 @@
</listitem>
</itemizedlist>
<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>)
and will no longer be updated with security or bugfixes.
</para>
<para>
PostgreSQL 9.4. is scheduled for its final release in February 2020
(see <ulink url="https://www.postgresql.org/support/versioning/">PostgreSQL Versioning Policy</ulink>).
</para>
<para>
We recommend that users of these versions migrate to a recent PostgreSQL version
as soon as possible.
</para>
</important>
</sect2>
</sect1>

View File

@@ -1,12 +1,11 @@
<sect1 id="installation-source" xreflabel="Installing from source code">
<indexterm>
<primary>installation</primary>
<secondary>from source</secondary>
</indexterm>
<title>Installing &repmgr; from source</title>
<indexterm>
<primary>installation</primary>
<secondary>from source</secondary>
</indexterm>
<sect2 id="installation-source-prereqs">
<title>Prerequisites for installing from source</title>
<para>
@@ -61,9 +60,6 @@ deb-src http://apt.postgresql.org/pub/repos/apt/ stretch-pgdg main</programlisti
<itemizedlist spacing="compact" mark="bullet">
<listitem>
<simpara><literal>flex</literal></simpara>
</listitem>
<listitem>
<simpara><literal>libedit-dev</literal></simpara>
</listitem>
@@ -118,9 +114,6 @@ deb-src http://apt.postgresql.org/pub/repos/apt/ stretch-pgdg main</programlisti
<itemizedlist spacing="compact" mark="bullet">
<listitem>
<simpara><literal>flex</literal></simpara>
</listitem>
<listitem>
<simpara><literal>libselinux-devel</literal></simpara>
</listitem>
@@ -183,8 +176,7 @@ deb-src http://apt.postgresql.org/pub/repos/apt/ stretch-pgdg main</programlisti
</para>
<para>
There are also tags for each <ulink url="https://github.com/2ndQuadrant/repmgr/releases">&repmgr; release</ulink>, e.g.
<literal><ulink url="https://github.com/2ndQuadrant/repmgr/releases/tag/v4.4.0">v4.4.0</ulink></literal>.
There are also tags for each &repmgr; release, e.g. <literal>v4.2.0</literal>.
</para>
<para>
@@ -208,7 +200,7 @@ deb-src http://apt.postgresql.org/pub/repos/apt/ stretch-pgdg main</programlisti
&repmgr; website along with a tarball checksum and a matching GnuPG
signature. See
<ulink url="http://repmgr.org/">http://repmgr.org/</ulink>
for the download information. See <xref linkend="appendix-signatures"/>
for the download information. See <xref linkend="appendix-signatures">
for information on verifying digital signatures.
</para>
@@ -216,11 +208,11 @@ deb-src http://apt.postgresql.org/pub/repos/apt/ stretch-pgdg main</programlisti
You will need to download the repmgr source, e.g. <filename>repmgr-4.0.tar.gz</filename>.
You may optionally verify the package checksums from the
<literal>.md5</literal> files and/or verify the GnuPG signatures
per <xref linkend="appendix-signatures"/>.
per <xref linkend="appendix-signatures">.
</para>
<para>
After you unpack the source code archives using <command>tar xf</command>
After you unpack the source code archives using <literal>tar xf</literal>
the installation process is the same as if you were installing from a git
clone.
</para>
@@ -235,7 +227,7 @@ deb-src http://apt.postgresql.org/pub/repos/apt/ stretch-pgdg main</programlisti
To installing &repmgr; from source, simply execute:
<programlisting>
./configure &amp;&amp; make install</programlisting>
./configure && make install</programlisting>
Ensure <command>pg_config</command> for the target PostgreSQL version is in
<varname>$PATH</varname>.
@@ -244,30 +236,16 @@ deb-src http://apt.postgresql.org/pub/repos/apt/ stretch-pgdg main</programlisti
<sect2 id="installation-build-repmgr-docs" xreflabel="Building repmgr documentation">
<sect2 id="installation-build-repmgr-docs">
<title>Building &repmgr; documentation</title>
<para>
The &repmgr; documentation is (like the main PostgreSQL project)
written in DocBook XML format. To build it locally as HTML, you'll need to
written in DocBook format. To build it locally as HTML, you'll need to
install the required packages as described in the
<ulink url="https://www.postgresql.org/docs/current/docguide-toolsets.html">PostgreSQL documentation</ulink>.
</para>
<para>
The minimum PostgreSQL version for building the &repmgr; documentation is
PostgreSQL 9.5.
</para>
<note>
<simpara>
In &repmgr; 4.3 and earlier, the documentation can only be built against
PostgreSQL 9.6 or earlier.
</simpara>
</note>
<para>
To build the documentation as HTML, execute:
<ulink url="https://www.postgresql.org/docs/9.6/docguide-toolsets.html">
PostgreSQL documentation</ulink> then execute:
<programlisting>
./configure &amp;&amp; make doc</programlisting>
./configure && make install-doc</programlisting>
</para>
<para>
The generated HTML files will be placed in the <filename>doc/html</filename>
@@ -275,20 +253,19 @@ deb-src http://apt.postgresql.org/pub/repos/apt/ stretch-pgdg main</programlisti
</para>
<para>
To build the documentation as a single HTML file, after configuring and building
the main &repmgr; source as described above, execute:
To build the documentation as a single HTML file, execute:
<programlisting>
./configure &amp;&amp; make doc-repmgr.html</programlisting>
cd doc/ && make repmgr.html</programlisting>
</para>
<para>
To build the documentation as a PDF file, after configuring and building
the main &repmgr; source as described above, execute:
<programlisting>
./configure &amp;&amp; make doc-repmgr-A4.pdf</programlisting>
</para>
<note>
<simpara>
Due to changes in PostgreSQL's documentation build system from PostgreSQL 10,
the documentation can currently only be built against PostgreSQL 9.6 or earlier.
This limitation will be fixed when time and resources permit.
</simpara>
</note>
</sect2>
</sect1>

View File

@@ -1,11 +1,10 @@
<chapter id="installation" xreflabel="Installation">
<title>Installation</title>
<indexterm>
<primary>installation</primary>
</indexterm>
<title>Installation</title>
<para>
&repmgr; can be installed from binary packages provided by your operating
system's packaging system, or from source.
@@ -19,7 +18,7 @@
only option if there are no packages for your operating system yet.
</para>
<para>
Before installing &repmgr; make sure you satisfy the <xref linkend="install-requirements"/>.
Before installing &repmgr; make sure you satisfy the <xref linkend="install-requirements">.
</para>
&install-requirements;

View File

@@ -1,4 +1,4 @@
<!-- doc/legal.xml -->
<!-- doc/legal.sgml -->
<date>2017</date>

View File

@@ -7,18 +7,18 @@
</para>
<sect1 id="repmgr-concepts" xreflabel="Concepts">
<title>Concepts</title>
<indexterm>
<primary>concepts</primary>
</indexterm>
<title>Concepts</title>
<para>
This guide assumes that you are familiar with PostgreSQL administration and
streaming replication concepts. For further details on streaming
replication, see the PostgreSQL documentation section on <ulink
url="https://www.postgresql.org/docs/current/warm-standby.html#STREAMING-REPLICATION">
streaming replication</ulink>.
url="https://www.postgresql.org/docs/current/interactive/warm-standby.html#STREAMING-REPLICATION">
streaming replication</>.
</para>
<para>
The following terms are used throughout the &repmgr; documentation.
@@ -58,7 +58,7 @@
<listitem>
<simpara>
This is the action which occurs if a primary server fails and a suitable standby
is promoted as the new primary. The &repmgrd; daemon supports automatic failover
is promoted as the new primary. The <application>repmgrd</application> daemon supports automatic failover
to minimise downtime.
</simpara>
</listitem>
@@ -107,7 +107,7 @@
promotes a (local) standby.
</para>
<para>
A witness server only needs to be created if &repmgrd;
A witness server only needs to be created if <application>repmgrd</application>
is in use.
</para>
</listitem>
@@ -198,7 +198,7 @@
</listitem>
<listitem>
<simpara><literal>repmgr.monitoring_history</literal>: historical standby monitoring information
written by &repmgrd;</simpara>
written by <application>repmgrd</application></simpara>
</listitem>
</itemizedlist>
</para>
@@ -214,7 +214,7 @@
name of the server's upstream node</simpara>
</listitem>
<listitem>
<simpara>repmgr.replication_status: when &repmgrd;'s monitoring is enabled, shows
<simpara>repmgr.replication_status: when <application>repmgrd</application>'s monitoring is enabled, shows
current monitoring status for each standby.</simpara>
</listitem>
</itemizedlist>

View File

@@ -1,13 +1,13 @@
<chapter id="promoting-standby" xreflabel="Promoting a standby">
<title>Promoting a standby server with repmgr</title>
<indexterm>
<primary>promoting a standby</primary>
<seealso>repmgr standby promote</seealso>
</indexterm>
<title>Promoting a standby server with repmgr</title>
<para>
If a primary server fails or needs to be removed from the replication cluster,
a new primary server must be designated, to ensure the cluster continues
to function correctly. This can be done with <xref linkend="repmgr-standby-promote"/>,
to function correctly. This can be done with <xref linkend="repmgr-standby-promote">,
which promotes the standby on the current server to primary.
</para>
@@ -31,7 +31,7 @@
At this point the replication cluster will be in a partially disabled state, with
both standbys accepting read-only connections while attempting to connect to the
stopped primary. Note that the &repmgr; metadata table will not yet have been updated;
executing <xref linkend="repmgr-cluster-show"/> will note the discrepancy:
executing <xref linkend="repmgr-cluster-show"> will note the discrepancy:
<programlisting>
$ repmgr -f /etc/repmgr.conf cluster show
ID | Name | Role | Status | Upstream | Location | Connection string
@@ -60,7 +60,7 @@
DETAIL: node 2 was successfully promoted to primary</programlisting>
</para>
<para>
Executing <xref linkend="repmgr-cluster-show"/> will show the current state; as there is now an
Executing <xref linkend="repmgr-cluster-show"> will show the current state; as there is now an
active primary, the previous warning will not be displayed:
<programlisting>
$ repmgr -f /etc/repmgr.conf cluster show
@@ -72,8 +72,8 @@
</para>
<para>
However the sole remaining standby (<literal>node3</literal>) is still trying to replicate from the failed
primary; <xref linkend="repmgr-standby-follow"/> must now be executed to rectify this situation
(see <xref linkend="follow-new-primary"/> for example).
primary; <xref linkend="repmgr-standby-follow"> must now be executed to rectify this situation
(see <xref linkend="follow-new-primary"> for example).
</para>
</chapter>

View File

@@ -17,7 +17,7 @@
<note>
<simpara>
To upgrade an existing &repmgr; 3.x installation, see section
<xref linkend="upgrading-from-repmgr-3"/>.
<xref linkend="upgrading-from-repmgr-3">.
</simpara>
</note>
@@ -139,7 +139,7 @@
<para>
Additionally, if you are intending to use <application>pg_rewind</application>,
and the cluster was not initialised using data checksums, you may want to consider enabling
<varname>wal_log_hints</varname>; for more details see <xref linkend="repmgr-node-rejoin-pg-rewind"/>.
<varname>wal_log_hints</varname>; for more details see <xref linkend="repmgr-node-rejoin-pg-rewind">.
</para>
<para>
See also the <link linkend="configuration-postgresql">PostgreSQL configuration</link> section in the
@@ -254,7 +254,7 @@
</para>
<programlisting>
node_id=1
node_name='node1'
node_name=node1
conninfo='host=node1 user=repmgr dbname=repmgr connect_timeout=2'
data_directory='/var/lib/postgresql/data'
</programlisting>
@@ -262,9 +262,10 @@
<para>
<filename>repmgr.conf</filename> should not be stored inside the PostgreSQL data directory,
as it could be overwritten when setting up or reinitialising the PostgreSQL
server. See sections <xref linkend="configuration"/> and <xref linkend="configuration-file"/>
server. See sections <xref linkend="configuration"> and <xref linkend="configuration-file">
for further details about <filename>repmgr.conf</filename>.
</para>
<note>
<para>
&repmgr; only uses <option>pg_bindir</option> when it executes
@@ -302,7 +303,7 @@
<para>
See the file
<ulink url="https://raw.githubusercontent.com/2ndQuadrant/repmgr/master/repmgr.conf.sample">repmgr.conf.sample</ulink>
<ulink url="https://raw.githubusercontent.com/2ndQuadrant/repmgr/master/repmgr.conf.sample">repmgr.conf.sample</>
for details of all available configuration parameters.
</para>
@@ -351,7 +352,7 @@
slot_name |
config_file | /etc/repmgr.conf</programlisting>
<para>
Each server in the replication cluster will have its own record. If &repmgrd;
Each server in the replication cluster will have its own record. If <application>repmgrd</application>
is in use, the fields <literal>upstream_node_id</literal>, <literal>active</literal> and
<literal>type</literal> will be updated when the node's status or role changes.
</para>
@@ -367,7 +368,7 @@
</para>
<programlisting>
node_id=2
node_name='node2'
node_name=node2
conninfo='host=node2 user=repmgr dbname=repmgr connect_timeout=2'
data_directory='/var/lib/postgresql/data'</programlisting>
<para>
@@ -477,8 +478,6 @@
latest_end_lsn | 0/7000538
latest_end_time | 2017-08-28 15:20:56.418735+09
slot_name |
sender_host | node1
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>recovery.conf</filename>
@@ -498,12 +497,11 @@
<para>
Check the node is registered by executing <command>repmgr cluster show</command> on the standby:
<programlisting>
$ repmgr -f /etc/repmgr.conf cluster show
ID | Name | Role | Status | Upstream | Location | Priority | Timeline | Connection string
----+-------+---------+-----------+----------+----------+----------+----------+--------------------------------------
1 | node1 | primary | * running | | default | 100 | 1 | host=node1 dbname=repmgr user=repmgr
2 | node2 | standby | running | node1 | default | 100 | 1 | host=node2 dbname=repmgr user=repmgr</programlisting>
$ repmgr -f /etc/repmgr.conf cluster show
ID | Name | Role | Status | Upstream | Location | Connection string
----+-------+---------+-----------+----------+----------+--------------------------------------
1 | node1 | primary | * running | | default | host=node1 dbname=repmgr user=repmgr
2 | node2 | standby | running | node1 | default | host=node2 dbname=repmgr user=repmgr</programlisting>
</para>
<para>
Both nodes are now registered with &repmgr; and the records have been copied to the standby server.

View File

@@ -38,7 +38,7 @@
<title>Notes</title>
<para>
Monitoring history will only be written if &repmgrd; is active, and
Monitoring history will only be written if <application>repmgrd</application> is active, and
<varname>monitoring_history</varname> is set to <literal>true</literal> in
<filename>repmgr.conf</filename>.
</para>
@@ -69,8 +69,8 @@
<refsect1>
<title>See also</title>
<para>
For more details see the sections <xref linkend="repmgrd-monitoring"/> and
<xref linkend="repmgrd-monitoring-configuration"/>.
For more details see the sections <xref linkend="repmgrd-monitoring"> and
<xref linkend="repmgrd-monitoring-configuration">.
</para>
</refsect1>

View File

@@ -16,9 +16,9 @@
<refsect1>
<title>Description</title>
<para>
<command>repmgr cluster crosscheck</command> is similar to <xref linkend="repmgr-cluster-matrix"/>,
<command>repmgr cluster crosscheck</command> is similar to <xref linkend="repmgr-cluster-matrix">,
but cross-checks connections between each combination of nodes. In "Example 3" in
<xref linkend="repmgr-cluster-matrix"/> we have no information about the state of <literal>node3</literal>.
<xref linkend="repmgr-cluster-matrix"> we have no information about the state of <literal>node3</literal>.
However by running <command>repmgr cluster crosscheck</command> it's possible to get a better
overview of the cluster situation:
<programlisting>

View File

@@ -40,12 +40,12 @@
<simpara><literal>--node-name</literal>: restrict entries to node with this name</simpara>
</listitem>
<listitem>
<simpara><literal>--event</literal>: filter specific event (see <xref linkend="event-notifications"/> for a full list)</simpara>
<simpara><literal>--event</literal>: filter specific event (see <xref linkend="event-notifications"> for a full list)</simpara>
</listitem>
</itemizedlist>
</para>
<para>
The &quot;Details&quot; column can be omitted by providing <literal>--compact</literal>.
The "Details" column can be omitted by providing <literal>--terse</literal>.
</para>
</refsect1>
@@ -71,9 +71,9 @@
<programlisting>
$ repmgr -f /etc/repmgr.conf cluster event --event=standby_register
Node ID | Name | Event | OK | Timestamp | Details
---------+-------+------------------+----+---------------------+-------------------------------------------------------
3 | node3 | standby_register | t | 2019-04-16 10:59:59 | standby registration succeeded; upstream node ID is 1
2 | node2 | standby_register | t | 2019-04-16 10:59:57 | standby registration succeeded; upstream node ID is 1</programlisting>
---------+-------+------------------+----+---------------------+--------------------------------
3 | node3 | standby_register | t | 2017-08-17 10:28:55 | standby registration succeeded
2 | node2 | standby_register | t | 2017-08-17 10:28:53 | standby registration succeeded</programlisting>
</para>
</refsect1>
</refentry>

View File

@@ -93,7 +93,7 @@
connection from <literal>node3</literal>.
</para>
<para>
In this case, the <xref linkend="repmgr-cluster-crosscheck"/> command will produce a more
In this case, the <xref linkend="repmgr-cluster-crosscheck"> command will produce a more
useful result.
</para>
</refsect1>

View File

@@ -22,13 +22,11 @@
directly and can be run on any node in the cluster; this is also useful when analyzing
connectivity from a particular node.
</para>
<para>
For PostgreSQL 9.6 and later, the output will also contain the node's current timeline ID.
</para>
<para>
Node availability is tested by connecting from the node where
<command>repmgr cluster show</command> is executed, and does not necessarily imply the node
is down. See <xref linkend="repmgr-cluster-matrix"/> and <xref linkend="repmgr-cluster-crosscheck"/> to get
is down. See <xref linkend="repmgr-cluster-matrix"> and <xref linkend="repmgr-cluster-crosscheck"> to get
better overviews of connections between nodes.
</para>
@@ -54,11 +52,11 @@
<programlisting>
$ repmgr -f /etc/repmgr.conf cluster show
ID | Name | Role | Status | Upstream | Location | Priority | Timeline | Connection string
ID | Name | Role | Status | Upstream | Location | Priority | Connection string
----+-------+---------+-----------+----------+----------+----------+-----------------------------------------
1 | node1 | primary | * running | | default | 100 | 1 | host=db_node1 dbname=repmgr user=repmgr
2 | node2 | standby | running | node1 | default | 100 | 1 | host=db_node2 dbname=repmgr user=repmgr
3 | node3 | standby | running | node1 | default | 100 | 1 | host=db_node3 dbname=repmgr user=repmgr</programlisting>
1 | node1 | primary | * running | | default | 100 | host=db_node1 dbname=repmgr user=repmgr
2 | node2 | standby | running | node1 | default | 100 | host=db_node2 dbname=repmgr user=repmgr
3 | node3 | standby | running | node1 | default | 100 | host=db_node3 dbname=repmgr user=repmgr</programlisting>
</para>
</refsect1>
<refsect1>
@@ -103,7 +101,7 @@
</para>
<tip>
<para>
Use <xref linkend="repmgr-cluster-matrix"/> and <xref linkend="repmgr-cluster-crosscheck"/>
Use <xref linkend="repmgr-cluster-matrix"> and <xref linkend="repmgr-cluster-crosscheck">
to diagnose connection issues across the whole replication cluster.
</para>
</tip>
@@ -233,7 +231,7 @@
<refsect1>
<title>See also</title>
<para>
<xref linkend="repmgr-node-status"/>, <xref linkend="repmgr-node-check"/>, <xref linkend="repmgr-service-status"/>
<xref linkend="repmgr-node-status">, <xref linkend="repmgr-node-check">, <xref linkend="repmgr-daemon-status">
</para>
</refsect1>

View File

@@ -1,6 +1,6 @@
<refentry id="repmgr-service-pause">
<refentry id="repmgr-daemon-pause">
<indexterm>
<primary>repmgr service pause</primary>
<primary>repmgr daemon pause</primary>
</indexterm>
<indexterm>
@@ -9,52 +9,43 @@
</indexterm>
<refmeta>
<refentrytitle>repmgr service pause</refentrytitle>
<refentrytitle>repmgr daemon pause</refentrytitle>
</refmeta>
<refnamediv>
<refname>repmgr service pause</refname>
<refpurpose>Instruct all &repmgrd; instances in the replication cluster to pause failover operations</refpurpose>
<refname>repmgr daemon pause</refname>
<refpurpose>Instruct all <application>repmgrd</application> instances in the replication cluster to pause failover operations</refpurpose>
</refnamediv>
<refsect1>
<title>Description</title>
<para>
This command can be run on any active node in the replication cluster to instruct all
running &repmgrd; instances to &quot;pause&quot; themselves, i.e. take no
running <application>repmgrd</application> instances to &quot;pause&quot; themselves, i.e. take no
action (such as promoting themselves or following a new primary) if a failover event is detected.
</para>
<para>
This functionality is useful for performing maintenance operations, such as switchovers
or upgrades, which might otherwise trigger a failover if &repmgrd;
or upgrades, which might otherwise trigger a failover if <application>repmgrd</application>
is running normally.
</para>
<note>
<para>
It's important to wait a few seconds after restarting PostgreSQL on any node before running
<command>repmgr service pause</command>, as the &repmgrd; instance
<command>repmgr daemon pause</command>, as the <application>repmgrd</application> instance
on the restarted node will take a second or two before it has updated its status.
</para>
</note>
<para>
<xref linkend="repmgr-service-unpause"/> will instruct all previously paused &repmgrd;
<xref linkend="repmgr-daemon-unpause"> will instruct all previously paused <application>repmgrd</application>
instances to resume normal failover operation.
</para>
</refsect1>
<refsect1>
<title>Prerequisites</title>
<para>
PostgreSQL must be accessible on all nodes (using the <varname>conninfo</varname> string shown by
<link linkend="repmgr-cluster-show"><command>repmgr cluster show</command></link>)
from the node where <command>repmgr service pause</command> is executed.
</para>
</refsect1>
<refsect1>
<title>Execution</title>
<para>
<command>repmgr service pause</command> can be executed on any active node in the
<command>repmgr daemon pause</command> can be executed on any active node in the
replication cluster. A valid <filename>repmgr.conf</filename> file is required.
It will have no effect on previously paused nodes.
</para>
@@ -64,7 +55,7 @@
<title>Example</title>
<para>
<programlisting>
$ repmgr -f /etc/repmgr.conf service pause
$ repmgr -f /etc/repmgr.conf daemon pause
NOTICE: node 1 (node1) paused
NOTICE: node 2 (node2) paused
NOTICE: node 3 (node3) paused</programlisting>
@@ -78,7 +69,7 @@ NOTICE: node 3 (node3) paused</programlisting>
<term><option>--dry-run</option></term>
<listitem>
<para>
Check if nodes are reachable but don't pause &repmgrd;.
Check if nodes are reachable but don't pause <application>repmgrd</application>.
</para>
</listitem>
</varlistentry>
@@ -88,7 +79,7 @@ NOTICE: node 3 (node3) paused</programlisting>
<refsect1>
<title>Exit codes</title>
<para>
One of the following exit codes will be emitted by <command>repmgr service unpause</command>:
One of the following exit codes will be emitted by <command>repmgr daemon unpause</command>:
</para>
<variablelist>
@@ -96,7 +87,7 @@ NOTICE: node 3 (node3) paused</programlisting>
<term><option>SUCCESS (0)</option></term>
<listitem>
<para>
&repmgrd; could be paused on all nodes.
<application>repmgrd</application> could be paused on all nodes.
</para>
</listitem>
</varlistentry>
@@ -105,7 +96,7 @@ NOTICE: node 3 (node3) paused</programlisting>
<term><option>ERR_REPMGRD_PAUSE (26)</option></term>
<listitem>
<para>
&repmgrd; could not be paused on one or mode nodes.
<application>repmgrd</application> could not be paused on one or mode nodes.
</para>
</listitem>
</varlistentry>
@@ -116,11 +107,7 @@ NOTICE: node 3 (node3) paused</programlisting>
<refsect1>
<title>See also</title>
<para>
<xref linkend="repmgr-service-unpause"/>,
<xref linkend="repmgr-service-status"/>,
<xref linkend="repmgrd-pausing"/>,
<xref linkend="repmgr-daemon-start"/>,
<xref linkend="repmgr-daemon-stop"/>
<xref linkend="repmgr-daemon-unpause">, <xref linkend="repmgr-daemon-status">
</para>
</refsect1>
</refentry>

View File

@@ -14,17 +14,17 @@
<refnamediv>
<refname>repmgr daemon start</refname>
<refpurpose>Start the &repmgrd; daemon on the local node</refpurpose>
<refpurpose>Start the <application>repmgrd</application> daemon</refpurpose>
</refnamediv>
<refsect1>
<title>Description</title>
<para>
This command starts the &repmgrd; service on the
This command starts the <application>repmgrd</application> daemon on the
local node.
</para>
<para>
By default, &repmgr; will wait for up to 15 seconds to confirm that &repmgrd;
By default, &repmgr; will wait for up to 15 seconds to confirm that <application>repmgrd</application>
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>
@@ -33,7 +33,7 @@
<para>
The <filename>repmgr.conf</filename> parameter <varname>repmgrd_service_start_command</varname>
must be set for <command>repmgr daemon start</command> to work; see section
<xref linkend="repmgr-daemon-start-configuration"/> for details.
<xref linkend="repmgr-daemon-start-configuration"> for details.
</para>
</important>
</refsect1>
@@ -50,7 +50,7 @@
<term><option>--dry-run</option></term>
<listitem>
<para>
Check prerequisites but don't actually attempt to start &repmgrd;.
Check prerequisites but don't actually attempt to start <application>repmgrd</application>.
</para>
<para>
This action will output the command which would be executed.
@@ -63,7 +63,7 @@
<term><option>--wait</option></term>
<listitem>
<para>
Wait for the specified number of seconds to confirm that &repmgrd;
Wait for the specified number of seconds to confirm that <application>repmgrd</application>
started successfully.
</para>
<para>
@@ -77,7 +77,7 @@
<term><option>--no-wait</option></term>
<listitem>
<para>
Don't wait to confirm that &repmgrd;
Don't wait to confirm that <application>repmgrd</application>
started successfully.
</para>
<para>
@@ -99,18 +99,17 @@
<variablelist>
<varlistentry>
<indexterm>
<primary>repmgrd_service_start_command</primary>
<secondary>with &quot;repmgr daemon start&quot;</secondary>
</indexterm>
<term><option>repmgrd_service_start_command</option></term>
<listitem>
<indexterm>
<primary>repmgrd_service_start_command</primary>
<secondary>with &quot;repmgr daemon start&quot;</secondary>
</indexterm>
<para>
<command>repmgr daemon start</command> will execute the command defined by the
<varname>repmgrd_service_start_command</varname> parameter in <filename>repmgr.conf</filename>.
This must be set to a shell command which will start &repmgrd;;
This must be set to a shell command which will start <application>repmgrd</application>;
if &repmgr; was installed from a package, this will be the service command defined by the
package. For more details see <link linkend="appendix-packages">Appendix: &repmgr; package details</link>.
</para>
@@ -118,7 +117,7 @@
<para>
If &repmgr; was installed from a system package, and you do not configure
<varname>repmgrd_service_start_command</varname> to an appropriate service command, this may
result in the system becoming confused about the state of the &repmgrd;
result in the system becoming confused about the state of the <application>repmgrd</application>
service; this is particularly the case with <literal>systemd</literal>.
</para>
</important>
@@ -140,12 +139,12 @@
<term><option>SUCCESS (0)</option></term>
<listitem>
<para>
The &repmgrd; start command (defined in
The <application>repmgrd</application> start command (defined in
<varname>repmgrd_service_start_command</varname>) was successfully executed.
</para>
<para>
If the <option>--wait</option> option was provided, &repmgr; will confirm that
&repmgrd; has actually started up.
<application>repmgrd</application> has actually started up.
</para>
</listitem>
</varlistentry>
@@ -168,10 +167,10 @@
&repmgr; was unable to connect to the local PostgreSQL node.
</para>
<para>
PostgreSQL must be running before &repmgrd;
PostgreSQL must be running before <application>repmgrd</application>
can be started. Additionally, unless the <option>--no-wait</option> option was
provided, &repmgr; needs to be able to connect to the local PostgreSQL node
to determine the state of &repmgrd;.
to determine the state of <application>repmgrd</application>.
</para>
</listitem>
</varlistentry>
@@ -181,11 +180,11 @@
<term><option>ERR_REPMGRD_SERVICE (27)</option></term>
<listitem>
<para>
The &repmgrd; start command (defined in
The <application>repmgrd</application> start command (defined in
<varname>repmgrd_service_start_command</varname>) was not successfully executed.
</para>
<para>
This can also mean that &repmgr; was unable to confirm whether &repmgrd;
This can also mean that &repmgr; was unable to confirm whether <application>repmgrd</application>
successfully started (unless the <option>--no-wait</option> option was provided).
</para>
</listitem>
@@ -197,11 +196,7 @@
<refsect1>
<title>See also</title>
<para>
<xref linkend="repmgr-daemon-stop"/>,
<xref linkend="repmgrd-daemon"/>,
<xref linkend="repmgr-service-status"/>,
<xref linkend="repmgr-service-pause"/>,
<xref linkend="repmgr-service-unpause"/>
<xref linkend="repmgr-daemon-stop">, <xref linkend="repmgr-daemon-status">, <xref linkend="repmgrd-daemon">
</para>
</refsect1>

View File

@@ -0,0 +1,186 @@
<refentry id="repmgr-daemon-status">
<indexterm>
<primary>repmgr daemon status</primary>
</indexterm>
<indexterm>
<primary>repmgrd</primary>
<secondary>displaying daemon status</secondary>
</indexterm>
<refmeta>
<refentrytitle>repmgr daemon status</refentrytitle>
</refmeta>
<refnamediv>
<refname>repmgr daemon status</refname>
<refpurpose>display information about the status of <application>repmgrd</application> on each node in the cluster</refpurpose>
</refnamediv>
<refsect1>
<title>Description</title>
<para>
This command provides an overview over all active nodes in the cluster and the state
of each node's <application>repmgrd</application> instance. It can be used to check
the result of <xref linkend="repmgr-daemon-pause"> and <xref linkend="repmgr-daemon-unpause">
operations.
</para>
</refsect1>
<refsect1>
<title>Execution</title>
<para>
<command>repmgr daemon status</command> can be executed on any active node in the
replication cluster. A valid <filename>repmgr.conf</filename> file is required.
</para>
<para>
If PostgreSQL is not running on a node, &repmgr; will not be able to determine the
status of that node's <application>repmgrd</application> instance.
</para>
<note>
<para>
After restarting PostgreSQL on any node, the <application>repmgrd</application> instance
will take a second or two before it is able to update its status. Until then,
<application>repmgrd</application> will be shown as not running.
</para>
</note>
</refsect1>
<refsect1>
<title>Examples</title>
<para>
<application>repmgrd</application> running normally on all nodes:
<programlisting>$ repmgr -f /etc/repmgr.conf daemon status
ID | Name | Role | Priority | Status | repmgrd | PID | Paused? | Upstream last seen
----+-------+---------+----------+---------+---------+-------+---------+--------------------
1 | node1 | primary | 100 | running | running | 71987 | no | n/a
2 | node2 | standby | 100 | running | running | 71996 | no | 1 second(s) ago
3 | node3 | standby | 100 | running | running | 72042 | no | 1 second(s) ago
</programlisting>
</para>
<para>
<application>repmgrd</application> paused on all nodes (using <xref linkend="repmgr-daemon-pause">):
<programlisting>$ repmgr -f /etc/repmgr.conf daemon status
ID | Name | Role | Priority | Status | repmgrd | PID | Paused? | Upstream last seen
----+-------+---------+----------+---------+---------+-------+---------+--------------------
1 | node1 | primary | 100 | running | running | 71987 | yes | n/a
2 | node2 | standby | 100 | running | running | 71996 | yes | 0 second(s) ago
3 | node3 | standby | 100 | running | running | 72042 | yes | 0 second(s) ago
</programlisting>
</para>
<para>
<application>repmgrd</application> not running on one node:
<programlisting>$ repmgr -f /etc/repmgr.conf daemon status
ID | Name | Role | Priority | Status | repmgrd | PID | Paused? | Upstream last seen
----+-------+---------+----------+---------+-------------+-------+---------+--------------------
1 | node1 | primary | 100 | running | running | 71987 | yes | n/a
2 | node2 | standby | 100 | running | not running | n/a | n/a | n/a
3 | node3 | standby | 100 | running | running | 72042 | yes | 0 second(s) ago</programlisting>
</para>
</refsect1>
<refsect1>
<title>Options</title>
<variablelist>
<varlistentry>
<term><option>--csv</option></term>
<listitem>
<para>
<command>repmgr daemon status</command> accepts an optional parameter <literal>--csv</literal>, which
outputs the replication cluster's status in a simple CSV format, suitable for
parsing by scripts, e.g.:
<programlisting>
$ repmgr -f /etc/repmgr.conf daemon status --csv
1,node1,primary,1,1,5722,1,100,-1
2,node2,standby,1,0,-1,1,100,1
3,node3,standby,1,1,5779,1,100,1</programlisting>
</para>
<para>
The columns have following meanings:
<itemizedlist spacing="compact" mark="bullet">
<listitem>
<simpara>
node ID
</simpara>
</listitem>
<listitem>
<simpara>
node name
</simpara>
</listitem>
<listitem>
<simpara>
node type (primary or standby)
</simpara>
</listitem>
<listitem>
<simpara>
PostgreSQL server running (1 = running, 0 = not running)
</simpara>
</listitem>
<listitem>
<simpara>
<application>repmgrd</application> running (1 = running, 0 = not running, -1 = unknown)
</simpara>
</listitem>
<listitem>
<simpara>
<application>repmgrd</application> PID (-1 if not running or status unknown)
</simpara>
</listitem>
<listitem>
<simpara>
<application>repmgrd</application> paused (1 = paused, 0 = not paused, -1 = unknown)
</simpara>
</listitem>
<listitem>
<simpara>
<application>repmgrd</application> node priority
</simpara>
</listitem>
<listitem>
<simpara>
interval in seconds since the node's upstream was last seen (this will be -1 if the value could not be retrieved, or the node is primary)
</simpara>
</listitem>
</itemizedlist>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--verbose</option></term>
<listitem>
<para>
Display the full text of any database connection error messages
</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>See also</title>
<para>
<xref linkend="repmgr-daemon-pause">, <xref linkend="repmgr-daemon-unpause">, <xref linkend="repmgr-cluster-show">
</para>
</refsect1>
</refentry>

View File

@@ -14,25 +14,25 @@
<refnamediv>
<refname>repmgr daemon stop</refname>
<refpurpose>Stop the &repmgrd; daemon on the local node</refpurpose>
<refpurpose>Stop the <application>repmgrd</application> daemon</refpurpose>
</refnamediv>
<refsect1>
<title>Description</title>
<para>
This command stops the &repmgrd; daemon on the
This command stops the <application>repmgrd</application> daemon on the
local node.
</para>
<para>
By default, &repmgr; will wait for up to 15 seconds to confirm that &repmgrd;
By default, &repmgr; will wait for up to 15 seconds to confirm that <application>repmgrd</application>
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>
<para>
If PostgreSQL is not running on the local node, under some circumstances &repmgr; may not
be able to confirm if &repmgrd; has actually stopped.
be able to confirm if <application>repmgrd</application> has actually stopped.
</para>
</note>
@@ -40,7 +40,7 @@
<para>
The <filename>repmgr.conf</filename> parameter <varname>repmgrd_service_stop_command</varname>
must be set for <command>repmgr daemon stop</command> to work; see section
<xref linkend="repmgr-daemon-stop-configuration"/> for details.
<xref linkend="repmgr-daemon-stop-configuration"> for details.
</para>
</important>
</refsect1>
@@ -50,7 +50,7 @@
<para>
<command>repmgr daemon stop</command> will execute the command defined by the
<varname>repmgrd_service_stop_command</varname> parameter in <filename>repmgr.conf</filename>.
This must be set to a shell command which will stop &repmgrd;;
This must be set to a shell command which will stop <application>repmgrd</application>;
if &repmgr; was installed from a package, this will be the service command defined by the
package. For more details see <link linkend="appendix-packages">Appendix: &repmgr; package details</link>.
</para>
@@ -59,7 +59,7 @@
<para>
If &repmgr; was installed from a system package, and you do not configure
<varname>repmgrd_service_stop_command</varname> to an appropriate service command, this may
result in the system becoming confused about the state of the &repmgrd;
result in the system becoming confused about the state of the <application>repmgrd</application>
service; this is particularly the case with <literal>systemd</literal>.
</para>
</important>
@@ -76,7 +76,7 @@
<term><option>--dry-run</option></term>
<listitem>
<para>
Check prerequisites but don't actually attempt to stop &repmgrd;.
Check prerequisites but don't actually attempt to stop <application>repmgrd</application>.
</para>
<para>
This action will output the command which would be executed.
@@ -89,7 +89,7 @@
<term><option>--wait</option></term>
<listitem>
<para>
Wait for the specified number of seconds to confirm that &repmgrd;
Wait for the specified number of seconds to confirm that <application>repmgrd</application>
stopped successfully.
</para>
<para>
@@ -103,7 +103,7 @@
<term><option>--no-wait</option></term>
<listitem>
<para>
Don't wait to confirm that &repmgrd;
Don't wait to confirm that <application>repmgrd</application>
stopped successfully.
</para>
<para>
@@ -124,18 +124,17 @@
<variablelist>
<varlistentry>
<indexterm>
<primary>repmgrd_service_stop_command</primary>
<secondary>with &quot;repmgr daemon stop&quot;</secondary>
</indexterm>
<term><option>repmgrd_service_stop_command</option></term>
<listitem>
<indexterm>
<primary>repmgrd_service_stop_command</primary>
<secondary>with &quot;repmgr daemon stop&quot;</secondary>
</indexterm>
<para>
<command>repmgr daemon stop</command> will execute the command defined by the
<varname>repmgrd_service_stop_command</varname> parameter in <filename>repmgr.conf</filename>.
This must be set to a shell command which will stop &repmgrd;;
This must be set to a shell command which will stop <application>repmgrd</application>;
if &repmgr; was installed from a package, this will be the service command defined by the
package. For more details see <link linkend="appendix-packages">Appendix: &repmgr; package details</link>.
</para>
@@ -143,7 +142,7 @@
<para>
If &repmgr; was installed from a system package, and you do not configure
<varname>repmgrd_service_stop_command</varname> to an appropriate service command, this may
result in the system becoming confused about the state of the &repmgrd;
result in the system becoming confused about the state of the <application>repmgrd</application>
service; this is particularly the case with <literal>systemd</literal>.
</para>
</important>
@@ -164,7 +163,7 @@
<term><option>SUCCESS (0)</option></term>
<listitem>
<para>
&repmgrd; could be stopped.
<application>repmgrd</application> could be stopped.
</para>
</listitem>
</varlistentry>
@@ -183,7 +182,7 @@
<term><option>ERR_REPMGRD_SERVICE (27)</option></term>
<listitem>
<para>
&repmgrd; could not be stopped.
<application>repmgrd</application> could not be stopped.
</para>
</listitem>
</varlistentry>
@@ -194,11 +193,7 @@
<refsect1>
<title>See also</title>
<para>
<xref linkend="repmgr-daemon-start"/>,
<xref linkend="repmgrd-daemon"/>,
<xref linkend="repmgr-service-status"/>,
<xref linkend="repmgr-service-pause"/>,
<xref linkend="repmgr-service-unpause"/>
<xref linkend="repmgr-daemon-start">, <xref linkend="repmgr-daemon-status">, <xref linkend="repmgrd-daemon">
</para>
</refsect1>

View File

@@ -1,6 +1,6 @@
<refentry id="repmgr-service-unpause">
<refentry id="repmgr-daemon-unpause">
<indexterm>
<primary>repmgr service unpause</primary>
<primary>repmgr daemon unpause</primary>
</indexterm>
<indexterm>
@@ -8,47 +8,39 @@
<secondary>unpausing</secondary>
</indexterm>
<refmeta>
<refentrytitle>repmgr service unpause</refentrytitle>
<refentrytitle>repmgr daemon unpause</refentrytitle>
</refmeta>
<refnamediv>
<refname>repmgr service unpause</refname>
<refpurpose>Instruct all &repmgrd; instances in the replication cluster to resume failover operations</refpurpose>
<refname>repmgr daemon unpause</refname>
<refpurpose>Instruct all <application>repmgrd</application> instances in the replication cluster to resume failover operations</refpurpose>
</refnamediv>
<refsect1>
<title>Description</title>
<para>
This command can be run on any active node in the replication cluster to instruct all
running &repmgrd; instances to &quot;unpause&quot;
(following a previous execution of <xref linkend="repmgr-service-pause"/>)
running <application>repmgrd</application> instances to &quot;unpause&quot;
(following a previous execution of <xref linkend="repmgr-daemon-pause">)
and resume normal failover/monitoring operation.
</para>
<note>
<para>
It's important to wait a few seconds after restarting PostgreSQL on any node before running
<command>repmgr service pause</command>, as the &repmgrd; instance
<command>repmgr daemon pause</command>, as the <application>repmgrd</application> instance
on the restarted node will take a second or two before it has updated its status.
</para>
</note>
</refsect1>
<refsect1>
<title>Prerequisites</title>
<para>
PostgreSQL must be accessible on all nodes (using the <varname>conninfo</varname> string shown by
<link linkend="repmgr-cluster-show"><command>repmgr cluster show</command></link>)
from the node where <command>repmgr service pause</command> is executed.
</para>
</refsect1>
<refsect1>
<title>Execution</title>
<para>
<command>repmgr service unpause</command> can be executed on any active node in the
<command>repmgr daemon unpause</command> can be executed on any active node in the
replication cluster. A valid <filename>repmgr.conf</filename> file is required.
It will have no effect on nodes which are not already paused.
</para>
@@ -58,7 +50,7 @@
<title>Example</title>
<para>
<programlisting>
$ repmgr -f /etc/repmgr.conf service unpause
$ repmgr -f /etc/repmgr.conf daemon unpause
NOTICE: node 1 (node1) unpaused
NOTICE: node 2 (node2) unpaused
NOTICE: node 3 (node3) unpaused</programlisting>
@@ -72,7 +64,7 @@ NOTICE: node 3 (node3) unpaused</programlisting>
<term><option>--dry-run</option></term>
<listitem>
<para>
Check if nodes are reachable but don't unpause &repmgrd;.
Check if nodes are reachable but don't unpause <application>repmgrd</application>.
</para>
</listitem>
</varlistentry>
@@ -82,7 +74,7 @@ NOTICE: node 3 (node3) unpaused</programlisting>
<refsect1>
<title>Exit codes</title>
<para>
One of the following exit codes will be emitted by <command>repmgr service unpause</command>:
One of the following exit codes will be emitted by <command>repmgr daemon unpause</command>:
</para>
<variablelist>
@@ -90,7 +82,7 @@ NOTICE: node 3 (node3) unpaused</programlisting>
<term><option>SUCCESS (0)</option></term>
<listitem>
<para>
&repmgrd; could be unpaused on all nodes.
<application>repmgrd</application> could be unpaused on all nodes.
</para>
</listitem>
</varlistentry>
@@ -99,7 +91,7 @@ NOTICE: node 3 (node3) unpaused</programlisting>
<term><option>ERR_REPMGRD_PAUSE (26)</option></term>
<listitem>
<para>
&repmgrd; could not be unpaused on one or mode nodes.
<application>repmgrd</application> could not be unpaused on one or mode nodes.
</para>
</listitem>
</varlistentry>
@@ -110,11 +102,7 @@ NOTICE: node 3 (node3) unpaused</programlisting>
<refsect1>
<title>See also</title>
<para>
<xref linkend="repmgr-service-pause"/>,
<xref linkend="repmgr-service-status"/>,
<xref linkend="repmgrd-pausing"/>,
<xref linkend="repmgr-daemon-start"/>,
<xref linkend="repmgr-daemon-stop"/>
<xref linkend="repmgr-daemon-pause">, <xref linkend="repmgr-daemon-status">
</para>
</refsect1>
</refentry>

View File

@@ -203,7 +203,7 @@
<refsect1>
<title>See also</title>
<para>
<xref linkend="repmgr-node-status"/>, <xref linkend="repmgr-cluster-show"/>
<xref linkend="repmgr-node-status">, <xref linkend="repmgr-cluster-show">
</para>
</refsect1>

View File

@@ -26,10 +26,10 @@
<tip>
<para>
If the node is running and needs to be attached to the current primary, use
<xref linkend="repmgr-standby-follow"/>.
<xref linkend="repmgr-standby-follow">.
</para>
<para>
Note <xref linkend="repmgr-standby-follow"/> can only be used for standbys which have not diverged
Note <xref linkend="repmgr-standby-follow"> can only be used for standbys which have not diverged
from the rest of the cluster.
</para>
</tip>
@@ -230,13 +230,12 @@
<refsect1 id="repmgr-node-rejoin-pg-rewind" xreflabel="Using pg_rewind">
<title>Using <command>pg_rewind</command></title>
<indexterm>
<primary>pg_rewind</primary>
<secondary>using with "repmgr node rejoin"</secondary>
</indexterm>
<title>Using <command>pg_rewind</command></title>
<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.
@@ -322,7 +321,7 @@
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.
will succeed. See also section <xref linkend="repmgr-node-rejoin-caveats"> below.
</para>
</note>
@@ -345,18 +344,17 @@
<refsect1 id="repmgr-node-rejoin-caveats" xreflabel="Caveats">
<title>Caveats when using <command>repmgr node rejoin</command></title>
<indexterm>
<primary>repmgr node rejoin</primary>
<secondary>caveats</secondary>
</indexterm>
<primary>repmgr node rejoin</primary>
<secondary>caveats</secondary>
</indexterm>
<title>Caveats when using <command>repmgr node rejoin</command></title>
<para>
<command>repmgr node rejoin</command> attempts to determine whether it will succeed by
comparing the timelines and relative WAL positions of the local node (rejoin candidate) and primary
(rejoin target). This is particularly important if planning to use <application>pg_rewind</application>,
which currently (as of PostgreSQL 12) may appear to succeed (or indicate there is no action
which currently (as of PostgreSQL 11) may appear to succeed (or indicate there is no action
needed) but potentially allow an impossible action, such as trying to rejoin a standby to a
primary which is behind the standby. &repmgr; will prevent this situation from occurring.
</para>
@@ -383,7 +381,7 @@
<refsect1>
<title>See also</title>
<para>
<xref linkend="repmgr-standby-follow"/>
<xref linkend="repmgr-standby-follow">
</para>
</refsect1>
</refentry>

View File

@@ -114,38 +114,38 @@
<para>
See what action would be taken for a restart:
<programlisting>
[postgres@node1 ~]$ repmgr -f /etc/repmgr/12/repmgr.conf node service --action=restart --checkpoint --dry-run
[postgres@node1 ~]$ repmgr -f /etc/repmgr/11/repmgr.conf node service --action=restart --checkpoint --dry-run
INFO: a CHECKPOINT would be issued here
INFO: would execute server command "sudo service postgresql-12 restart"</programlisting>
INFO: would execute server command "sudo service postgresql-11 restart"</programlisting>
</para>
<para>
Restart the PostgreSQL instance:
<programlisting>
[postgres@node1 ~]$ repmgr -f /etc/repmgr/12/repmgr.conf node service --action=restart --checkpoint
[postgres@node1 ~]$ repmgr -f /etc/repmgr/11/repmgr.conf node service --action=restart --checkpoint
NOTICE: issuing CHECKPOINT
DETAIL: executing server command "sudo service postgresql-12 restart"
Redirecting to /bin/systemctl restart postgresql-12.service</programlisting>
DETAIL: executing server command "sudo service postgresql-11 restart"
Redirecting to /bin/systemctl restart postgresql-11.service</programlisting>
</para>
<para>
List all commands:
<programlisting>
[postgres@node1 ~]$ repmgr -f /etc/repmgr/12/repmgr.conf node service --list-actions
[postgres@node1 ~]$ repmgr -f /etc/repmgr/11/repmgr.conf node service --list-actions
Following commands would be executed for each action:
start: "sudo service postgresql-12 start"
stop: "sudo service postgresql-12 stop"
restart: "sudo service postgresql-12 restart"
reload: "sudo service postgresql-12 reload"
promote: "/usr/pgsql-12/bin/pg_ctl -w -D '/var/lib/pgsql/12/data' promote"</programlisting>
start: "sudo service postgresql-11 start"
stop: "sudo service postgresql-11 stop"
restart: "sudo service postgresql-11 restart"
reload: "sudo service postgresql-11 reload"
promote: "/usr/pgsql-11/bin/pg_ctl -w -D '/var/lib/pgsql/11/data' promote"</programlisting>
</para>
<para>
List a single command:
<programlisting>
[postgres@node1 ~]$ repmgr -f /etc/repmgr/12/repmgr.conf node service --list-actions --action=promote
/usr/pgsql-12/bin/pg_ctl -w -D '/var/lib/pgsql/12/data' promote </programlisting>
[postgres@node1 ~]$ repmgr -f /etc/repmgr/11/repmgr.conf node service --list-actions --action=promote
/usr/pgsql-11/bin/pg_ctl -w -D '/var/lib/pgsql/11/data' promote </programlisting>
</para>
</refsect1>
</refentry>

View File

@@ -84,7 +84,7 @@
<refsect1>
<title>See also</title>
<para>
See <xref linkend="repmgr-node-check"/> to diagnose issues and <xref linkend="repmgr-cluster-show"/>
See <xref linkend="repmgr-node-check"> to diagnose issues and <xref linkend="repmgr-cluster-show">
for an overview of all nodes in the cluster.
</para>
</refsect1>

View File

@@ -38,25 +38,23 @@
Execute with the <option>--dry-run</option> option to check what would happen without
actually registering the primary.
</para>
<para>
<command>repmgr master register</command> can be used as an alias for
<command>repmgr primary register</command>.
</para>
<note>
<para>
If providing the configuration file location with <option>-f/--config-file</option>,
avoid using a relative path, as &repmgr; stores the configuration file location
in the repmgr metadata for use when &repmgr; is executed remotely (e.g. during
<xref linkend="repmgr-standby-switchover"/>). &repmgr; will attempt to convert the
<xref linkend="repmgr-standby-switchover">). &repmgr; will attempt to convert the
a relative path into an absolute one, but this may not be the same as the path you
would explicitly provide (e.g. <filename>./repmgr.conf</filename> might be converted
to <filename>/path/to/./repmgr.conf</filename>, whereas you'd normally write
<filename>/path/to/repmgr.conf</filename>).
</para>
</note>
<para>
<command>repmgr master register</command> can be used as an alias for
<command>repmgr primary register</command>.
</para>
</refsect1>
<refsect1>

View File

@@ -1,215 +0,0 @@
<refentry id="repmgr-service-status">
<indexterm>
<primary>repmgr service status</primary>
</indexterm>
<indexterm>
<primary>repmgrd</primary>
<secondary>displaying service status</secondary>
</indexterm>
<refmeta>
<refentrytitle>repmgr service status</refentrytitle>
</refmeta>
<refnamediv>
<refname>repmgr service status</refname>
<refpurpose>display information about the status of &repmgrd; on each node in the cluster</refpurpose>
</refnamediv>
<refsect1>
<title>Description</title>
<para>
This command provides an overview over all active nodes in the cluster and the state
of each node's &repmgrd; instance. It can be used to check
the result of <xref linkend="repmgr-service-pause"/> and <xref linkend="repmgr-service-unpause"/>
operations.
</para>
</refsect1>
<refsect1>
<title>Prerequisites</title>
<para>
PostgreSQL should be accessible on all nodes (using the <varname>conninfo</varname> string shown by
<link linkend="repmgr-cluster-show"><command>repmgr cluster show</command></link>)
from the node where <command>repmgr service status</command> is executed.
</para>
</refsect1>
<refsect1>
<title>Execution</title>
<para>
<command>repmgr service status</command> can be executed on any active node in the
replication cluster. A valid <filename>repmgr.conf</filename> file is required.
</para>
<para>
If a node is not accessible, or PostgreSQL itself is not running on the node,
&repmgr; will not be able to determine the status of that node's &repmgrd; instance,
and &quot;<literal>n/a</literal>&quot; will be displayed in the node's <literal>repmgrd</literal>
column.
</para>
<note>
<para>
After restarting PostgreSQL on any node, the &repmgrd; instance
will take a second or two before it is able to update its status. Until then,
&repmgrd; will be shown as not running.
</para>
</note>
</refsect1>
<refsect1>
<title>Examples</title>
<para>
&repmgrd; running normally on all nodes:
<programlisting>$ repmgr -f /etc/repmgr.conf service status
ID | Name | Role | Status | Upstream | repmgrd | PID | Paused? | Upstream last seen
----+-------+---------+-----------+----------+---------+-------+---------+--------------------
1 | node1 | primary | * running | | running | 96563 | no | n/a
2 | node2 | standby | running | node1 | running | 96572 | no | 1 second(s) ago
3 | node3 | standby | running | node1 | running | 96584 | no | 0 second(s) ago</programlisting>
</para>
<para>
&repmgrd; paused on all nodes (using <xref linkend="repmgr-service-pause"/>):
<programlisting>$ repmgr -f /etc/repmgr.conf service status
ID | Name | Role | Status | Upstream | repmgrd | PID | Paused? | Upstream last seen
----+-------+---------+-----------+----------+---------+-------+---------+--------------------
1 | node1 | primary | * running | | running | 96563 | yes | n/a
2 | node2 | standby | running | node1 | running | 96572 | yes | 1 second(s) ago
3 | node3 | standby | running | node1 | running | 96584 | yes | 0 second(s) ago</programlisting>
</para>
<para>
&repmgrd; not running on one node:
<programlisting>$ repmgr -f /etc/repmgr.conf service status
ID | Name | Role | Status | Upstream | repmgrd | PID | Paused? | Upstream last seen
----+-------+---------+-----------+----------+-------------+-------+---------+--------------------
1 | node1 | primary | * running | | running | 96563 | yes | n/a
2 | node2 | standby | running | node1 | not running | n/a | n/a | n/a
3 | node3 | standby | running | node1 | running | 96584 | yes | 0 second(s) ago</programlisting>
</para>
</refsect1>
<refsect1>
<title>Options</title>
<variablelist>
<varlistentry>
<term><option>--csv</option></term>
<listitem>
<para>
<command>repmgr service status</command> accepts an optional parameter <literal>--csv</literal>, which
outputs the replication cluster's status in a simple CSV format, suitable for
parsing by scripts, e.g.:
<programlisting>
$ repmgr -f /etc/repmgr.conf service status --csv
1,node1,primary,1,1,5722,1,100,-1,default
2,node2,standby,1,0,-1,1,100,1,default
3,node3,standby,1,1,5779,1,100,1,default</programlisting>
</para>
<para>
The columns have following meanings:
<itemizedlist spacing="compact" mark="bullet">
<listitem>
<simpara>
node ID
</simpara>
</listitem>
<listitem>
<simpara>
node name
</simpara>
</listitem>
<listitem>
<simpara>
node type (primary or standby)
</simpara>
</listitem>
<listitem>
<simpara>
PostgreSQL server running (1 = running, 0 = not running)
</simpara>
</listitem>
<listitem>
<simpara>
&repmgrd; running (1 = running, 0 = not running, -1 = unknown)
</simpara>
</listitem>
<listitem>
<simpara>
&repmgrd; PID (-1 if not running or status unknown)
</simpara>
</listitem>
<listitem>
<simpara>
&repmgrd; paused (1 = paused, 0 = not paused, -1 = unknown)
</simpara>
</listitem>
<listitem>
<simpara>
&repmgrd; node priority
</simpara>
</listitem>
<listitem>
<simpara>
interval in seconds since the node's upstream was last seen (this will be -1 if the value could not be retrieved, or the node is primary)
</simpara>
</listitem>
<listitem>
<simpara>
node location
</simpara>
</listitem>
</itemizedlist>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--detail</option></term>
<listitem>
<para>
Display additional information (<literal>location</literal>, <literal>priority</literal>)
about the &repmgr; configuration.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--verbose</option></term>
<listitem>
<para>
Display the full text of any database connection error messages.
</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>See also</title>
<para>
<xref linkend="repmgr-service-pause"/>,
<xref linkend="repmgr-service-unpause"/>,
<xref linkend="repmgr-cluster-show"/>,
<xref linkend="repmgrd-pausing"/>,
<xref linkend="repmgr-daemon-start"/>,
<xref linkend="repmgr-daemon-stop"/>
</para>
</refsect1>
</refentry>

View File

@@ -18,7 +18,7 @@
<para>
<command>repmgr standby clone</command> clones a PostgreSQL node from another
PostgreSQL node, typically the primary, but optionally from any other node in
the cluster or from Barman. It creates the replication configuration required
the cluster or from Barman. It creates the <filename>recovery.conf</filename> file required
to attach the cloned node to the primary node (or another standby, if cascading replication
is in use).
</para>
@@ -85,20 +85,14 @@
</refsect1>
<refsect1 id="repmgr-standby-clone-recovery-conf">
<title>Customising replication configuration</title>
<indexterm>
<indexterm>
<primary>recovery.conf</primary>
<secondary>customising with &quot;repmgr standby clone&quot;</secondary>
</indexterm>
<indexterm>
<primary>replication configuration</primary>
<secondary>customising with &quot;repmgr standby clone&quot;</secondary>
</indexterm>
</indexterm>
<title>Customising recovery.conf</title>
<para>
By default, &repmgr; will create a minimal replication configuration
By default, &repmgr; will create a minimal <filename>recovery.conf</filename>
containing following parameters:
</para>
@@ -124,7 +118,7 @@
<para>
The following additional parameters can be specified in <filename>repmgr.conf</filename>
for inclusion in the replication configuration:
for inclusion in <filename>recovery.conf</filename>:
</para>
<itemizedlist spacing="compact" mark="bullet">
@@ -148,7 +142,7 @@
We recommend using <ulink url="https://www.pgbarman.org/">Barman</ulink> to manage
WAL file archiving. For more details on combining &repmgr; and <application>Barman</application>,
in particular using <varname>restore_command</varname> to configure Barman as a backup source of
WAL files, see <xref linkend="cloning-from-barman"/>.
WAL files, see <xref linkend="cloning-from-barman">.
</para>
</note>
@@ -160,7 +154,7 @@
When initially cloning a standby, you will need to ensure
that all required WAL files remain available while the cloning is taking
place. To ensure this happens when using the default <command>pg_basebackup</command> method,
&repmgr; will set <command>pg_basebackup</command>'s <literal>--wal-method</literal>
&repmgr; will set <command>pg_basebackup</command>'s <literal>--xlog-method</literal>
parameter to <literal>stream</literal>,
which will ensure all WAL files generated during the cloning process are
streamed in parallel with the main backup. Note that this requires two
@@ -170,10 +164,10 @@
</para>
<para>
To override this behaviour, in <filename>repmgr.conf</filename> set
<command>pg_basebackup</command>'s <literal>--wal-method</literal>
<command>pg_basebackup</command>'s <literal>--xlog-method</literal>
parameter to <literal>fetch</literal>:
<programlisting>
pg_basebackup_options='--wal-method=fetch'</programlisting>
pg_basebackup_options='--xlog-method=fetch'</programlisting>
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">
@@ -182,8 +176,9 @@
<note>
<simpara>
If using PostgreSQL 9.6 or earlier, replace <literal>--wal-method</literal>
with <literal>--xlog-method</literal>.
From PostgreSQL 10, <command>pg_basebackup</command>'s
<literal>--xlog-method</literal> parameter has been renamed to
<literal>--wal-method</literal>.
</simpara>
</note>
</refsect1>
@@ -191,57 +186,43 @@
<refsect1 id="repmgr-standby-create-recovery-conf">
<title>Using a standby cloned by another method</title>
<indexterm>
<primary>recovery.conf</primary>
<secondary>generating for a standby cloned by another method</secondary>
</indexterm>
<indexterm>
<primary>replication configuration</primary>
<secondary>generating for a standby cloned by another method</secondary>
</indexterm>
<title>Using a standby cloned by another method</title>
<para>
&repmgr; supports standbys cloned by another method (e.g. using <application>barman</application>'s
<command><ulink url="https://docs.pgbarman.org/#recover">barman recover</ulink></command> command).
<command><ulink url="http://docs.pgbarman.org/release/2.5/#recover">barman recover</ulink></command> command).
</para>
<para>
To integrate the standby as a &repmgr; node, once the standby has been cloned,
ensure the <filename>repmgr.conf</filename>
file is created for the node, and that it has been registered using
<command><link linkend="repmgr-standby-register">repmgr standby register</link></command>.
</para>
<tip>
<para>
To register a standby which is not running, execute
<link linkend="repmgr-standby-register">repmgr standby register --force</link>
and provide the connection details for the primary.
</para>
<para>
See <xref linkend="repmgr-standby-register-inactive-node"/> for more details.
</para>
</tip>
<para>
Then execute the command <command>repmgr standby clone --recovery-conf-only</command>.
This will create the <filename>recovery.conf</filename> file needed to attach
the node to its upstream (in PostgreSQL 12 and later: append replication configuration
to <filename>postgresql.auto.conf</filename>), and will also create a replication slot on the
the node to its upstream, and will also create a replication slot on the
upstream node if required.
</para>
<para>
Note that the upstream node must be running. In PostgreSQL 11 and earlier, an existing
Note that the upstream node must be running. An existing
<filename>recovery.conf</filename> will not be overwritten unless the
<option>-F/--force</option> option is provided.
</para>
<para>
Execute <command>repmgr standby clone --recovery-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.
to check the prerequisites for creating the <filename>recovery.conf</filename> file,
and display the contents of the file without actually creating it.
</para>
<note>
<para>
<option>--recovery-conf-only</option> was introduced in &repmgr; <link linkend="release-4.0.4">4.0.4</link>.
</para>
</note>
</refsect1>
<refsect1>
@@ -267,8 +248,8 @@
</para>
<para>
If <option>--recovery-conf-only</option> specified, the contents of
the generated recovery configuration will be displayed
but not written.
the generated <filename>recovery.conf</filename> file will be displayed
but the file itself not written.
</para>
</listitem>
</varlistentry>
@@ -315,16 +296,8 @@
<term><option> --recovery-conf-only</option></term>
<listitem>
<para>
Create recovery configuration for a previously cloned instance.
Create <filename>recovery.conf</filename> file for a previously cloned instance. &repmgr 4.0.4 and later.
</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>
@@ -352,13 +325,9 @@
<term><option>--upstream-conninfo</option></term>
<listitem>
<para>
<literal>primary_conninfo</literal> value to include in the recovery configuration
<literal>primary_conninfo</literal> value to write in recovery.conf
when the intended upstream server does not yet exist.
</para>
<para>
Note that &repmgr; may modify the provided value, in particular to set the
correct <literal>application_name</literal>.
</para>
</listitem>
</varlistentry>
@@ -392,7 +361,7 @@
<refsect1>
<title>See also</title>
<para>
See <xref linkend="cloning-standbys"/> for details about various aspects of cloning.
See <xref linkend="cloning-standbys"> for details about various aspects of cloning.
</para>
</refsect1>
</refentry>

View File

@@ -20,54 +20,49 @@
(&quot;follow target&quot;). Typically this will be the primary, but this
command can also be used to attach the standby to another standby.
</para>
<para>
This command requires a valid <filename>repmgr.conf</filename> file for the standby,
either specified explicitly with <literal>-f/--config-file</literal> or located in a
This command requires a valid
<filename>repmgr.conf</filename> file for the standby, either specified
explicitly with <literal>-f/--config-file</literal> or located in a
default location; no additional arguments are required.
</para>
<para>The standby node (&quot;follow candidate&quot;) <emphasis>must</emphasis>
be running. If the new upstream (&quot;follow target&quot;) is not the primary,
the cluster primary <emphasis>must</emphasis> be running and accessible from the
standby node.
</para>
<tip>
<para>
To re-add an inactive node to the replication cluster, use
<xref linkend="repmgr-node-rejoin"/>.
</para>
</tip>
<para>
By default &repmgr; will attempt to attach the standby to the current primary.
If <option>--upstream-node-id</option> is provided, &repmgr; will attempt
to attach the standby to the specified node, which can be another standby.
</para>
<para>
By default &repmgr; will attempt to attach the standby to the current primary.
If <option>--upstream-node-id</option> is provided, &repmgr; will attempt
to attach the standby to the specified node, which can be another standby.
This command will force a restart of the standby server, which must be
running.
</para>
<para>
This command will force a restart of PostgreSQL on the standby node.
</para>
<para>
<command>repmgr standby follow</command> will wait up to
<varname>standby_follow_timeout</varname> seconds (default: <literal>30</literal>)
to verify the standby has actually connected to the new upstream node.
</para>
<note>
<tip>
<para>
If <option>recovery_min_apply_delay</option> is set for the standby, it
will not attach to the new upstream node until it has replayed available
WAL.
To re-add an inactive node to the replication cluster, use
<xref linkend="repmgr-node-rejoin">.
</para>
<para>
Conversely, if the standby is attached to an upstream standby
which has <option>recovery_min_apply_delay</option> set, the upstream
standby's replay state may actually be behind that of its new downstream node.
</para>
</note>
</tip>
<para>
<command>repmgr standby follow</command> will wait up to
<varname>standby_follow_timeout</varname> seconds (default: <literal>30</literal>)
to verify the standby has actually connected to the new upstream node.
</para>
<note>
<para>
If <option>recovery_min_apply_delay</option> is set for the standby, it
will not attach to the new upstream node until it has replayed available
WAL.
</para>
<para>
Conversely, if the standby is attached to an upstream standby
which has <option>recovery_min_apply_delay</option> set, the upstream
standby's replay state may actually be behind that of its new downstream node.
</para>
</note>
</refsect1>
@@ -127,9 +122,9 @@
If not provided, &repmgr; will attempt to follow the current primary node.
</para>
<para>
Note that when using &repmgrd;, <option>--upstream-node-id</option>
Note that when using <application>repmgrd</application>, <option>--upstream-node-id</option>
should always be configured;
see <link linkend="repmgrd-automatic-failover-configuration">Automatic failover configuration</link>
see <link linkend="repmgrd-automatic-failover-configuration">Automatic failover configuration</link>
for details.
</para>
</listitem>
@@ -171,7 +166,7 @@
be possible to follow the new upstream node, and &repmgr; will emit an error
message like this:
<programlisting>
ERROR: this node cannot attach to follow target node &quot;node3&quot; (ID 3)
ERROR: this node cannot attach to follow target node 3
DETAIL: follow target server's timeline 2 forked off current database system timeline 1 before current recovery point 0/6108880</programlisting>
</para>
<para>
@@ -257,7 +252,7 @@ DETAIL: follow target server's timeline 2 forked off current database system tim
<refsect1>
<title>See also</title>
<para>
<xref linkend="repmgr-node-rejoin"/>
<xref linkend="repmgr-node-rejoin">
</para>
</refsect1>
</refentry>

View File

@@ -17,51 +17,18 @@
<para>
Promotes a standby to a primary if the current primary has failed. This
command requires a valid <filename>repmgr.conf</filename> file for the standby, either
specified explicitly with <literal>-f/--config-file</literal> or located in a
specified explicitly with <literal>-f/--config-file</literal> or located in a
default location; no additional arguments are required.
</para>
<important>
<para>
If &repmgrd; is active, you must execute
<command><link linkend="repmgr-service-pause">repmgr service pause</link></command>
(&repmgr; 4.2 - 4.4: <command><link linkend="repmgr-service-pause">repmgr service pause</link></command>)
to temporarily disable &repmgrd; while making any changes
to the replication cluster.
</para>
</important>
<para>
If the standby promotion succeeds, the server will not need to be
restarted. However any other standbys will need to follow the new primary,
and will need to be restarted to do this.
restarted. However any other standbys will need to follow the new server,
by using <xref linkend="repmgr-standby-follow">; if <application>repmgrd</application>
is active, it will handle this automatically.
</para>
<para>
Beginning with <link linkend="release-4.4">repmgr 4.4</link>,
the option <option>--siblings-follow</option> can be used to have
all other standbys (and a witness server, if in use)
follow the new primary.
</para>
<note>
<para>
If using &repmgrd;, when invoking
<command>repmgr standby promote</command> (either directly via
the <option>promote_command</option>, or in a script called
via <option>promote_command</option>), <option>--siblings-follow</option>
<emphasis>must not</emphasis> be included as a
command line option for <command>repmgr standby promote</command>.
</para>
</note>
<para>
In <link linkend="release-4.3">repmgr 4.3</link> and earlier,
<command><link linkend="repmgr-standby-follow">repmgr standby follow</link></command>
must be executed on each standby individually.
</para>
<para>
&repmgr; will wait for up to <varname>promote_check_timeout</varname> seconds
(default: <literal>60</literal>) to verify that the standby has been promoted, and will
Note that &repmgr; will wait for up to <varname>promote_check_timeout</varname> seconds
(default: 60 seconds) to verify that the standby has been promoted, and will
check the promotion every <varname>promote_check_interval</varname> seconds (default: 1 second).
Both values can be defined in <filename>repmgr.conf</filename>.
</para>
@@ -105,36 +72,13 @@
<title>Options</title>
<variablelist>
<varlistentry>
<term><option>--dry-run</option></term>
<listitem>
<para>
Check if this node can be promoted, but don't carry out the promotion.
Check if this node can be promoted, but don't carry out the promotion
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--siblings-follow</option></term>
<listitem>
<para>
Have all sibling nodes (nodes formerly attached to the same upstream
node as the promotion candidate) follow this node after it has been promoted.
</para>
<para>
Note that a witness server, if in use, is also
counted as a &quot;sibling node&quot; as it needs to be instructed to
synchronise its metadata with the new primary.
</para>
<important>
<para>
Do <emphasis>not</emphasis> provide this option when configuring
&repmgrd;'s <option>promote_command</option>.
</para>
</important>
</listitem>
</varlistentry>
</variablelist>
</refsect1>

View File

@@ -17,7 +17,7 @@
<para>
<command>repmgr standby register</command> adds a standby's information to
the &repmgr; metadata. This command needs to be executed to enable
promote/follow operations and to allow &repmgrd; to work with the node.
promote/follow operations and to allow <application>repmgrd</application> to work with the node.
An existing standby can be registered using this command. Execute with the
<literal>--dry-run</literal> option to check what would happen without actually registering the
standby.
@@ -28,7 +28,7 @@
If providing the configuration file location with <literal>-f/--config-file</literal>,
avoid using a relative path, as &repmgr; stores the configuration file location
in the repmgr metadata for use when &repmgr; is executed remotely (e.g. during
<xref linkend="repmgr-standby-switchover"/>). &repmgr; will attempt to convert the
<xref linkend="repmgr-standby-switchover">). &repmgr; will attempt to convert the
a relative path into an absolute one, but this may not be the same as the path you
would explicitly provide (e.g. <filename>./repmgr.conf</filename> might be converted
to <filename>/path/to/./repmgr.conf</filename>, whereas you'd normally write
@@ -59,7 +59,7 @@
<para>
Depending on your environment and workload, it may take some time for the standby's node record
to propagate from the primary to the standby. Some actions (such as starting
&repmgrd;) require that the standby's node record
<application>repmgrd</application>) require that the standby's node record
is present and up-to-date to function correctly.
</para>
<para>
@@ -75,22 +75,10 @@
<para>
Under some circumstances you may wish to register a standby which is not
yet running; this can be the case when using provisioning tools to create
a complex replication cluster, or if the node was not cloned by &repmgr;.
</para>
<para>
In this case, by using the <option>-F/--force</option>
a complex replication cluster. In this case, by using the <option>-F/--force</option>
option and providing the connection parameters to the primary server,
the standby can be registered even if it has not yet been started.
the standby can be registered.
</para>
<tip>
<para>
Connection parameters can either be provided either as a <literal>conninfo</literal> string
(e.g. <option>-d 'host=node1 user=repmgr'</option> or as individual connection parameters
(<option>-h/--host</option>, <option>-d/--dbname</option>,
<option>-U/--user</option>, <option>-p/--port</option> etc.).
</para>
</tip>
<para>
Similarly, with cascading replication it may be necessary to register
a standby whose upstream node has not yet been registered - in this case,
@@ -108,11 +96,9 @@
<title>Registering a node not cloned by repmgr</title>
<para>
If you've cloned a standby using another method (e.g. <application>barman</application>'s
<command><ulink url="https://docs.pgbarman.org/#recover">barman recover</ulink></command>
command), register the node as detailed in section
<xref linkend="repmgr-standby-register-inactive-node"/> then execute
<command>barman recover</command> command), first execute
<link linkend="repmgr-standby-create-recovery-conf">repmgr standby clone --recovery-conf-only</link>
to generate the appropriate replication configuration.
to add the <filename>recovery.conf</filename> file, then register the standby as usual.
</para>
</refsect1>
@@ -133,7 +119,7 @@
<varlistentry>
<term><option>-F</option>/<option>--force</option></term>
<term><option>-F</option><option>--force</option></term>
<listitem>
<para>
Overwrite an existing node record

View File

@@ -26,9 +26,7 @@
these to follow the new primary if the option <literal>--siblings-follow</literal>
is specified. This requires a passwordless SSH connection between the promotion
candidate (new primary) and the nodes attached to the demotion candidate
(existing primary). Note that a witness server, if in use, is also
counted as a &quot;sibling node&quot; as it needs to be instructed to
synchronise its metadata with the new primary.
(existing primary).
</para>
<note>
<para>
@@ -44,18 +42,18 @@
</note>
<para>
For more details on performing a switchover, including preparation and configuration,
see section <xref linkend="performing-switchover"/>.
see section <xref linkend="performing-switchover">.
</para>
<note>
<para>
From <link linkend="release-4.2">repmgr 4.2</link>, &repmgr; will instruct any running
&repmgrd; instances to pause operations while the switchover
is being carried out, to prevent &repmgrd; from
unintentionally promoting a node. For more details, see <xref linkend="repmgrd-pausing"/>.
<application>repmgrd</application> instances to pause operations while the switchover
is being carried out, to prevent <application>repmgrd</application> from
unintentionally promoting a node. For more details, see <xref linkend="repmgrd-pausing">.
</para>
<para>
Users of &repmgr; versions prior to 4.2 should ensure that &repmgrd;
Users of &repmgr; versions prior to 4.2 should ensure that <application>repmgrd</application>
is not running on any nodes while a switchover is being executed.
</para>
</note>
@@ -117,7 +115,7 @@
(and the prerequisites for using <application>pg_rewind</application> are met).
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"/>.
provide its full path. For more details see also <xref linkend="switchover-pg-rewind">.
</para>
</listitem>
</varlistentry>
@@ -136,30 +134,12 @@
<term><option>--repmgrd-no-pause</option></term>
<listitem>
<para>
Don't pause &repmgrd; while executing a switchover.
Don't pause <application>repmgrd</application> while executing a switchover.
</para>
<para>
This option should not be used unless you take steps by other means
to ensure &repmgrd; is paused or not
to ensure <application>repmgrd</application> is paused or not
running on all nodes.
</para>
<para>
This option cannot be used together with <option>--repmgrd-force-unpause</option>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--repmgrd-force-unpause</option></term>
<listitem>
<para>
Always unpause all &repmgrd; instances after executing a switchover. This will ensure that
any &repmgrd; instances which were paused before the switchover will be
unpaused.
</para>
<para>
This option cannot be used together with <option>--repmgrd-no-pause</option>.
</para>
</listitem>
</varlistentry>
@@ -199,14 +179,13 @@
<variablelist>
<varlistentry>
<indexterm>
<primary>replication_lag_critical</primary>
<secondary>with &quot;repmgr standby switchover&quot;</secondary>
</indexterm>
<term><option>replication_lag_critical</option></term>
<listitem>
<indexterm>
<primary>replication_lag_critical</primary>
<secondary>with &quot;repmgr standby switchover&quot;</secondary>
</indexterm>
<para>
If replication lag (in seconds) on the standby exceeds this value, the
switchover will be aborted (unless the <literal>-F/--force</literal> option
@@ -216,14 +195,13 @@
</varlistentry>
<varlistentry>
<indexterm>
<primary>shutdown_check_timeout</primary>
<secondary>with &quot;repmgr standby switchover&quot;</secondary>
</indexterm>
<term><option>shutdown_check_timeout</option></term>
<listitem>
<indexterm>
<primary>shutdown_check_timeout</primary>
<secondary>with &quot;repmgr standby switchover&quot;</secondary>
</indexterm>
<para>
The maximum number of seconds to wait for the
demotion candidate (current primary) to shut down, before aborting the switchover.
@@ -245,13 +223,13 @@
<varlistentry>
<indexterm>
<primary>wal_receive_check_timeout</primary>
<secondary>with &quot;repmgr standby switchover&quot;</secondary>
</indexterm>
<term><option>wal_receive_check_timeout</option></term>
<listitem>
<indexterm>
<primary>wal_receive_check_timeout</primary>
<secondary>with &quot;repmgr standby switchover&quot;</secondary>
</indexterm>
<para>
After the primary has shut down, the maximum number of seconds to wait for the
walreceiver on the standby to flush WAL to disk before comparing WAL receive location
@@ -262,14 +240,13 @@
<varlistentry>
<indexterm>
<primary>standby_reconnect_timeout</primary>
<secondary>with &quot;repmgr standby switchover&quot;</secondary>
</indexterm>
<term><option>standby_reconnect_timeout</option></term>
<listitem>
<indexterm>
<primary>standby_reconnect_timeout</primary>
<secondary>with &quot;repmgr standby switchover&quot;</secondary>
</indexterm>
<para>
The maximum number of seconds to attempt to wait for the demotion candidate (former primary)
to reconnect to the promoted primary (default: 60 seconds)
@@ -282,16 +259,14 @@
</listitem>
</varlistentry>
<varlistentry>
<varlistentry>
<indexterm>
<primary>node_rejoin_timeout</primary>
<secondary>with &quot;repmgr standby switchover&quot;</secondary>
</indexterm>
<term><option>node_rejoin_timeout</option></term>
<listitem>
<indexterm>
<primary>node_rejoin_timeout</primary>
<secondary>with &quot;repmgr standby switchover&quot;</secondary>
</indexterm>
<para>
maximum number of seconds to attempt to wait for the demotion candidate (former primary)
to reconnect to the promoted primary (default: 60 seconds)
@@ -385,10 +360,10 @@
<refsect1>
<title>See also</title>
<para>
<xref linkend="repmgr-standby-follow"/>, <xref linkend="repmgr-node-rejoin"/>
<xref linkend="repmgr-standby-follow">, <xref linkend="repmgr-node-rejoin">
</para>
<para>
For more details on performing a switchover operation, see the section <xref linkend="performing-switchover"/>.
For more details on performing a switchover operation, see the section <xref linkend="performing-switchover">.
</para>
</refsect1>

View File

@@ -20,7 +20,7 @@
record to the &repmgr; metadata, and if necessary initialises the witness
node by installing the &repmgr; extension and copying the &repmgr; metadata
to the witness server. This command needs to be executed to enable
use of the witness server with &repmgrd;.
use of the witness server with <application>repmgrd</application>.
</para>
<para>
When executing <command>repmgr witness register</command>, database connection

View File

@@ -1,12 +1,11 @@
<!-- doc/repmgr.xml -->
<!-- doc/src/sgml/postgres.sgml -->
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"
[
<!ENTITY % version SYSTEM "version.xml">
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V4.2//EN" [
<!ENTITY % version SYSTEM "version.sgml">
%version;
<!ENTITY % filelist SYSTEM "filelist.xml">
<!ENTITY % filelist SYSTEM "filelist.sgml">
%filelist;
<!ENTITY repmgr "<productname>repmgr</productname>">
@@ -26,7 +25,7 @@
<abstract>
<para>
This is the official documentation of &repmgr; &repmgrversion; for
use with PostgreSQL 9.3 - PostgreSQL 12.
use with PostgreSQL 9.3 - PostgreSQL 11.
</para>
<para>
&repmgr; is being continually developed and we strongly recommend using the
@@ -39,7 +38,7 @@
<para>
&repmgr; is developed by
<ulink url="https://2ndquadrant.com">2ndQuadrant</ulink>
along with contributions from other individuals and organisations.
along with contributions from other individuals and companies.
Contributions from the community are appreciated and welcome - get
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>.
@@ -51,7 +50,7 @@
&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.
Other companies as well as individual developers are welcome to participate in the efforts.
</para>
</abstract>
@@ -116,11 +115,11 @@
&repmgr-cluster-crosscheck;
&repmgr-cluster-event;
&repmgr-cluster-cleanup;
&repmgr-service-status;
&repmgr-service-pause;
&repmgr-service-unpause;
&repmgr-daemon-status;
&repmgr-daemon-start;
&repmgr-daemon-stop;
&repmgr-daemon-pause;
&repmgr-daemon-unpause;
</part>
&appendix-release-notes;
@@ -129,6 +128,7 @@
&appendix-packages;
&appendix-support;
<index id="bookindex"></index>
<![%include-index;[&bookindex;]]>
<![%include-xslt-index;[<index id="bookindex"></index>]]>
</book>

View File

@@ -0,0 +1,297 @@
<chapter id="repmgrd-automatic-failover" xreflabel="Automatic failover with repmgrd">
<indexterm>
<primary>repmgrd</primary>
<secondary>automatic failover</secondary>
</indexterm>
<title>Automatic failover with repmgrd</title>
<para>
<application>repmgrd</application> is a management and monitoring daemon which runs
on each node in a replication cluster. It can automate actions such as
failover and updating standbys to follow the new primary, as well as
providing monitoring information about the state of each standby.
</para>
<sect1 id="repmgrd-witness-server" xreflabel="Using a witness server with repmgrd">
<indexterm>
<primary>repmgrd</primary>
<secondary>witness server</secondary>
</indexterm>
<indexterm>
<primary>witness server</primary>
<secondary>repmgrd</secondary>
</indexterm>
<title>Using a witness server</title>
<para>
A <xref linkend="witness-server"> is a normal PostgreSQL instance which
is not part of the streaming replication cluster; its purpose is, if a
failover situation occurs, to provide proof that it is the primary server
itself which is unavailable, rather than e.g. a network split between
different physical locations.
</para>
<para>
A typical use case for a witness server is a two-node streaming replication
setup, where the primary and standby are in different locations (data centres).
By creating a witness server in the same location (data centre) as the primary,
if the primary becomes unavailable it's possible for the standby to decide whether
it can promote itself without risking a "split brain" scenario: if it can't see either the
witness or the primary server, it's likely there's a network-level interruption
and it should not promote itself. If it can see the witness but not the primary,
this proves there is no network interruption and the primary itself is unavailable,
and it can therefore promote itself (and ideally take action to fence the
former primary).
</para>
<note>
<para>
<emphasis>Never</emphasis> install a witness server on the same physical host
as another node in the replication cluster managed by &repmgr; - it's essential
the witness is not affected in any way by failure of another node.
</para>
</note>
<para>
For more complex replication scenarios,e.g. with multiple datacentres, it may
be preferable to use location-based failover, which ensures that only nodes
in the same location as the primary will ever be promotion candidates;
see <xref linkend="repmgrd-network-split"> for more details.
</para>
<note>
<simpara>
A witness server will only be useful if <application>repmgrd</application>
is in use.
</simpara>
</note>
<sect2 id="creating-witness-server">
<title>Creating a witness server</title>
<para>
To create a witness server, set up a normal PostgreSQL instance on a server
in the same physical location as the cluster's primary server.
</para>
<para>
This instance should <emphasis>not</emphasis> be on the same physical host as the primary server,
as otherwise if the primary server fails due to hardware issues, the witness
server will be lost too.
</para>
<note>
<simpara>
&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">.
</para>
<para>
Register the witness server with <xref linkend="repmgr-witness-register">.
This will create the &repmgr; extension on the witness server, and make
a copy of the &repmgr; metadata.
</para>
<note>
<simpara>
As the witness server is not part of the replication cluster, further
changes to the &repmgr; metadata will be synchronised by
<application>repmgrd</application>.
</simpara>
</note>
<para>
Once the witness server has been configured, <application>repmgrd</application>
should be started.
</para>
<para>
To unregister a witness server, use <xref linkend="repmgr-witness-unregister">.
</para>
</sect2>
</sect1>
<sect1 id="repmgrd-network-split" xreflabel="Handling network splits with repmgrd">
<indexterm>
<primary>repmgrd</primary>
<secondary>network splits</secondary>
</indexterm>
<indexterm>
<primary>network splits</primary>
</indexterm>
<title>Handling network splits with repmgrd</title>
<para>
A common pattern for replication cluster setups is to spread servers over
more than one datacentre. This can provide benefits such as geographically-
distributed read replicas and DR (disaster recovery capability). However
this also means there is a risk of disconnection at network level between
datacentre locations, which would result in a split-brain scenario if
servers in a secondary data centre were no longer able to see the primary
in the main data centre and promoted a standby among themselves.
</para>
<para>
&repmgr; enables provision of &quot;<xref linkend="witness-server">&quot; to
artificially create a quorum of servers in a particular location, ensuring
that nodes in another location will not elect a new primary if they
are unable to see the majority of nodes. However this approach does not
scale well, particularly with more complex replication setups, e.g.
where the majority of nodes are located outside of the primary datacentre.
It also means the <literal>witness</literal> node needs to be managed as an
extra PostgreSQL instance outside of the main replication cluster, which
adds administrative and programming complexity.
</para>
<para>
<literal>repmgr4</literal> introduces the concept of <literal>location</literal>:
each node is associated with an arbitrary location string (default is
<literal>default</literal>); this is set in <filename>repmgr.conf</filename>, e.g.:
<programlisting>
node_id=1
node_name=node1
conninfo='host=node1 user=repmgr dbname=repmgr connect_timeout=2'
data_directory='/var/lib/postgresql/data'
location='dc1'</programlisting>
</para>
<para>
In a failover situation, <application>repmgrd</application> will check if any servers in the
same location as the current primary node are visible. If not, <application>repmgrd</application>
will assume a network interruption and not promote any node in any
other location (it will however enter <link linkend="repmgrd-degraded-monitoring">degraded monitoring</link>
mode until a primary becomes visible).
</para>
</sect1>
<sect1 id="repmgrd-standby-disconnection-on-failover" xreflabel="Standby disconnection on failover">
<indexterm>
<primary>repmgrd</primary>
<secondary>standby disconnection on failover</secondary>
</indexterm>
<indexterm>
<primary>standby disconnection on failover</primary>
</indexterm>
<title>Standby disconnection on failover</title>
<para>
If <option>standby_disconnect_on_failover</option> is set to <literal>true</literal> in
<filename>repmgr.conf</filename>, in a failover situation <application>repmgrd</application> will forcibly disconnect
the local node's WAL receiver before making a failover decision.
</para>
<note>
<para>
<option>standby_disconnect_on_failover</option> is available from PostgreSQL 9.5 and later.
Additionally this requires that the <literal>repmgr</literal> database user is a superuser.
</para>
</note>
<para>
By doing this, it's possible to ensure that, at the point the failover decision is made, no nodes
are receiving data from the primary and their LSN location will be static.
</para>
<important>
<para>
<option>standby_disconnect_on_failover</option> <emphasis>must</emphasis> be set to the same value on
all nodes.
</para>
</important>
<para>
Note that when using <option>standby_disconnect_on_failover</option> there will be a delay of 5 seconds
plus however many seconds it takes to confirm the WAL receiver is disconnected before
<application>repmgrd</application> proceeds with the failover decision.
</para>
<para>
Following the failover operation, no matter what the outcome, each node will reconnect its WAL receiver.
</para>
</sect1>
<sect1 id="repmgrd-failover-validation" xreflabel="Failover validation">
<indexterm>
<primary>repmgrd</primary>
<secondary>failover validation</secondary>
</indexterm>
<indexterm>
<primary>failover validation</primary>
</indexterm>
<title>Failover validation</title>
<para>
From <link linkend="release-4.3">repmgr 4.3</link>, &repmgr; makes it possible to provide a script
to <application>repmgrd</application> which, in a failover situation,
will be executed by the promotion candidate (the node which has been selected
to be the new primary) to confirm whether the node should actually be promoted.
</para>
<para>
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 %a</programlisting>
</para>
<para>
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.
Any other value will result in the promotion being aborted and the election rerun.
There is a pause of <option>election_rerun_interval</option> seconds before the election is rerun.
</para>
<para>
Sample <application>repmgrd</application> log file output during which the failover validation
script rejects the proposed promotion candidate:
<programlisting>
[2019-03-13 21:01:30] [INFO] visible nodes: 2; total nodes: 2; no nodes have seen the primary within the last 4 seconds
[2019-03-13 21:01:30] [NOTICE] promotion candidate is "node2" (ID: 2)
[2019-03-13 21:01:30] [NOTICE] executing "failover_validation_command"
[2019-03-13 21:01:30] [DETAIL] /usr/local/bin/failover-validation.sh 2
[2019-03-13 21:01:30] [INFO] output returned by failover validation command:
Node ID: 2
[2019-03-13 21:01:30] [NOTICE] failover validation command returned a non-zero value: "1"
[2019-03-13 21:01:30] [NOTICE] promotion candidate election will be rerun
[2019-03-13 21:01:30] [INFO] 1 followers to notify
[2019-03-13 21:01:30] [NOTICE] notifying node "node3" (node ID: 3) to rerun promotion candidate selection
INFO: node 3 received notification to rerun promotion candidate election
[2019-03-13 21:01:30] [NOTICE] rerunning election after 15 seconds ("election_rerun_interval")</programlisting>
</para>
</sect1>
<sect1 id="cascading-replication" xreflabel="Cascading replication">
<indexterm>
<primary>repmgrd</primary>
<secondary>cascading replication</secondary>
</indexterm>
<indexterm>
<primary>cascading replication</primary>
<secondary>repmgrd</secondary>
</indexterm>
<title>repmgrd and cascading replication</title>
<para>
Cascading replication - where a standby can connect to an upstream node and not
the primary server itself - was introduced in PostgreSQL 9.2. &repmgr; and
<application>repmgrd</application> support cascading replication by keeping track of the relationship
between standby servers - each node record is stored with the node id of its
upstream ("parent") server (except of course the primary server).
</para>
<para>
In a failover situation where the primary node fails and a top-level standby
is promoted, a standby connected to another standby will not be affected
and continue working as normal (even if the upstream standby it's connected
to becomes the primary node). If however the node's direct upstream fails,
the &quot;cascaded standby&quot; will attempt to reconnect to that node's parent
(unless <varname>failover</varname> is set to <literal>manual</literal> in
<filename>repmgr.conf</filename>).
</para>
</sect1>
</chapter>

View File

@@ -1,933 +0,0 @@
<chapter id="repmgrd-automatic-failover" xreflabel="Automatic failover with repmgrd">
<title>Automatic failover with repmgrd</title>
<indexterm>
<primary>repmgrd</primary>
<secondary>automatic failover</secondary>
</indexterm>
<para>
&repmgrd; is a management and monitoring daemon which runs
on each node in a replication cluster. It can automate actions such as
failover and updating standbys to follow the new primary, as well as
providing monitoring information about the state of each standby.
</para>
<sect1 id="repmgrd-witness-server" xreflabel="Using a witness server with repmgrd">
<title>Using a witness server</title>
<indexterm>
<primary>repmgrd</primary>
<secondary>witness server</secondary>
</indexterm>
<indexterm>
<primary>witness server</primary>
<secondary>repmgrd</secondary>
</indexterm>
<para>
A <xref linkend="witness-server"/> is a normal PostgreSQL instance which
is not part of the streaming replication cluster; its purpose is, if a
failover situation occurs, to provide proof that it is the primary server
itself which is unavailable, rather than e.g. a network split between
different physical locations.
</para>
<para>
A typical use case for a witness server is a two-node streaming replication
setup, where the primary and standby are in different locations (data centres).
By creating a witness server in the same location (data centre) as the primary,
if the primary becomes unavailable it's possible for the standby to decide whether
it can promote itself without risking a "split brain" scenario: if it can't see either the
witness or the primary server, it's likely there's a network-level interruption
and it should not promote itself. If it can see the witness but not the primary,
this proves there is no network interruption and the primary itself is unavailable,
and it can therefore promote itself (and ideally take action to fence the
former primary).
</para>
<note>
<para>
<emphasis>Never</emphasis> install a witness server on the same physical host
as another node in the replication cluster managed by &repmgr; - it's essential
the witness is not affected in any way by failure of another node.
</para>
</note>
<para>
For more complex replication scenarios, e.g. with multiple datacentres, it may
be preferable to use location-based failover, which ensures that only nodes
in the same location as the primary will ever be promotion candidates;
see <xref linkend="repmgrd-network-split"/> for more details.
</para>
<note>
<simpara>
A witness server will only be useful if &repmgrd;
is in use.
</simpara>
</note>
<sect2 id="creating-witness-server">
<title>Creating a witness server</title>
<para>
To create a witness server, set up a normal PostgreSQL instance on a server
in the same physical location as the cluster's primary server.
</para>
<para>
This instance should <emphasis>not</emphasis> be on the same physical host as the primary server,
as otherwise if the primary server fails due to hardware issues, the witness
server will be lost too.
</para>
<note>
<simpara>
&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"/>.
</para>
<para>
Register the witness server with <xref linkend="repmgr-witness-register"/>.
This will create the &repmgr; extension on the witness server, and make
a copy of the &repmgr; metadata.
</para>
<note>
<simpara>
As the witness server is not part of the replication cluster, further
changes to the &repmgr; metadata will be synchronised by
&repmgrd;.
</simpara>
</note>
<para>
Once the witness server has been configured, &repmgrd;
should be started.
</para>
<para>
To unregister a witness server, use <xref linkend="repmgr-witness-unregister"/>.
</para>
</sect2>
</sect1>
<sect1 id="repmgrd-network-split" xreflabel="Handling network splits with repmgrd">
<title>Handling network splits with repmgrd</title>
<indexterm>
<primary>repmgrd</primary>
<secondary>network splits</secondary>
</indexterm>
<indexterm>
<primary>network splits</primary>
</indexterm>
<para>
A common pattern for replication cluster setups is to spread servers over
more than one datacentre. This can provide benefits such as geographically-
distributed read replicas and DR (disaster recovery capability). However
this also means there is a risk of disconnection at network level between
datacentre locations, which would result in a split-brain scenario if
servers in a secondary data centre were no longer able to see the primary
in the main data centre and promoted a standby among themselves.
</para>
<para>
&repmgr; enables provision of &quot;<xref linkend="witness-server"/>&quot; to
artificially create a quorum of servers in a particular location, ensuring
that nodes in another location will not elect a new primary if they
are unable to see the majority of nodes. However this approach does not
scale well, particularly with more complex replication setups, e.g.
where the majority of nodes are located outside of the primary datacentre.
It also means the <literal>witness</literal> node needs to be managed as an
extra PostgreSQL instance outside of the main replication cluster, which
adds administrative and programming complexity.
</para>
<para>
<literal>repmgr4</literal> introduces the concept of <literal>location</literal>:
each node is associated with an arbitrary location string (default is
<literal>default</literal>); this is set in <filename>repmgr.conf</filename>, e.g.:
<programlisting>
node_id=1
node_name=node1
conninfo='host=node1 user=repmgr dbname=repmgr connect_timeout=2'
data_directory='/var/lib/postgresql/data'
location='dc1'</programlisting>
</para>
<para>
In a failover situation, &repmgrd; will check if any servers in the
same location as the current primary node are visible. If not, &repmgrd;
will assume a network interruption and not promote any node in any
other location (it will however enter <link linkend="repmgrd-degraded-monitoring">degraded monitoring</link>
mode until a primary becomes visible).
</para>
</sect1>
<sect1 id="repmgrd-primary-visibility-consensus" xreflabel="Primary visibility consensus">
<title>Primary visibility consensus</title>
<indexterm>
<primary>repmgrd</primary>
<secondary>primary visibility consensus</secondary>
</indexterm>
<indexterm>
<primary>primary_visibility_consensus</primary>
</indexterm>
<para>
In more complex replication setups, particularly where replication occurs between
multiple datacentres, it's possible that some but not all standbys get cut off from the
primary (but not from the other standbys).
</para>
<para>
In this situation, normally it's not desirable for any of the standbys which have been
cut off to initiate a failover, as the primary is still functioning and standbys are
connected. Beginning with <link linkend="release-4.4">&repmgr; 4.4</link>
it is now possible for the affected standbys to build a consensus about whether
the primary is still available to some standbys (&quot;primary visibility consensus&quot;).
This is done by polling each standby for the time it last saw the primary;
if any have seen the primary very recently, it's reasonable
to infer that the primary is still available and a failover should not be started.
</para>
<para>
The time the primary was last seen by each node can be checked by executing
<link linkend="repmgr-service-status"><command>repmgr service status</command></link>
(&repmgr; 4.2 - 4.4: <link linkend="repmgr-service-status"><command>repmgr daemon status</command></link>)
which includes this in its output, e.g.:
<programlisting>$ repmgr -f /etc/repmgr.conf service status
ID | Name | Role | Status | Upstream | repmgrd | PID | Paused? | Upstream last seen
----+-------+---------+-----------+----------+---------+-------+---------+--------------------
1 | node1 | primary | * running | | running | 96563 | no | n/a
2 | node2 | standby | running | node1 | running | 96572 | no | 1 second(s) ago
3 | node3 | standby | running | node1 | running | 96584 | no | 0 second(s) ago</programlisting>
</para>
<para>
To enable this functionality, in <filename>repmgr.conf</filename> set:
<programlisting>
primary_visibility_consensus=true</programlisting>
</para>
<note>
<para>
<option>primary_visibility_consensus</option> <emphasis>must</emphasis> be set to
<literal>true</literal> on all nodes for it to be effective.
</para>
</note>
<para>
The following sample &repmgrd; log output demonstrates the behaviour in a situation
where one of three standbys is no longer able to connect to the primary, but <emphasis>can</emphasis>
connect to the two other standbys (&quot;sibling nodes&quot;):
<programlisting>
[2019-05-17 05:36:12] [WARNING] unable to reconnect to node 1 after 3 attempts
[2019-05-17 05:36:12] [INFO] 2 active sibling nodes registered
[2019-05-17 05:36:12] [INFO] local node's last receive lsn: 0/7006E58
[2019-05-17 05:36:12] [INFO] checking state of sibling node "node3" (ID: 3)
[2019-05-17 05:36:12] [INFO] node "node3" (ID: 3) reports its upstream is node 1, last seen 1 second(s) ago
[2019-05-17 05:36:12] [NOTICE] node 3 last saw primary node 1 second(s) ago, considering primary still visible
[2019-05-17 05:36:12] [INFO] last receive LSN for sibling node "node3" (ID: 3) is: 0/7006E58
[2019-05-17 05:36:12] [INFO] node "node3" (ID: 3) has same LSN as current candidate "node2" (ID: 2)
[2019-05-17 05:36:12] [INFO] checking state of sibling node "node4" (ID: 4)
[2019-05-17 05:36:12] [INFO] node "node4" (ID: 4) reports its upstream is node 1, last seen 0 second(s) ago
[2019-05-17 05:36:12] [NOTICE] node 4 last saw primary node 0 second(s) ago, considering primary still visible
[2019-05-17 05:36:12] [INFO] last receive LSN for sibling node "node4" (ID: 4) is: 0/7006E58
[2019-05-17 05:36:12] [INFO] node "node4" (ID: 4) has same LSN as current candidate "node2" (ID: 2)
[2019-05-17 05:36:12] [INFO] 2 nodes can see the primary
[2019-05-17 05:36:12] [DETAIL] following nodes can see the primary:
- node "node3" (ID: 3): 1 second(s) ago
- node "node4" (ID: 4): 0 second(s) ago
[2019-05-17 05:36:12] [NOTICE] cancelling failover as some nodes can still see the primary
[2019-05-17 05:36:12] [NOTICE] election cancelled
[2019-05-17 05:36:14] [INFO] node "node2" (ID: 2) monitoring upstream node "node1" (ID: 1) in degraded state</programlisting>
In this situation it will cancel the failover and enter degraded monitoring node,
waiting for the primary to reappear.
</para>
</sect1>
<sect1 id="repmgrd-standby-disconnection-on-failover" xreflabel="Standby disconnection on failover">
<title>Standby disconnection on failover</title>
<indexterm>
<primary>repmgrd</primary>
<secondary>standby disconnection on failover</secondary>
</indexterm>
<indexterm>
<primary>standby disconnection on failover</primary>
</indexterm>
<para>
If <option>standby_disconnect_on_failover</option> is set to <literal>true</literal> in
<filename>repmgr.conf</filename>, in a failover situation &repmgrd; will forcibly disconnect
the local node's WAL receiver, and wait for the WAL receiver on all sibling nodes to be
disconnected, before making a failover decision.
</para>
<note>
<para>
<option>standby_disconnect_on_failover</option> is available with PostgreSQL 9.5 and later.
Additionally this requires that the <literal>repmgr</literal> database user is a superuser.
</para>
</note>
<para>
By doing this, it's possible to ensure that, at the point the failover decision is made, no nodes
are receiving data from the primary and their LSN location will be static.
</para>
<important>
<para>
<option>standby_disconnect_on_failover</option> <emphasis>must</emphasis> be set to the same value on
all nodes.
</para>
</important>
<para>
Note that when using <option>standby_disconnect_on_failover</option> there will be a delay of 5 seconds
plus however many seconds it takes to confirm the WAL receiver is disconnected before
&repmgrd; proceeds with the failover decision.
</para>
<para>
&repmgrd; will wait up to <option>sibling_nodes_disconnect_timeout</option> seconds (default:
<literal>30</literal>) to confirm that the WAL receiver on all sibling nodes hase been
disconnected before proceding with the failover operation. If the timeout is reached, the
failover operation will go ahead anyway.
</para>
<para>
Following the failover operation, no matter what the outcome, each node will reconnect its WAL receiver.
</para>
<para>
If using <option>standby_disconnect_on_failover</option>, we recommend that the
<option>primary_visibility_consensus</option> option is also used.
</para>
</sect1>
<sect1 id="repmgrd-failover-validation" xreflabel="Failover validation">
<title>Failover validation</title>
<indexterm>
<primary>repmgrd</primary>
<secondary>failover validation</secondary>
</indexterm>
<indexterm>
<primary>failover validation</primary>
</indexterm>
<para>
From <link linkend="release-4.3">repmgr 4.3</link>, &repmgr; makes it possible to provide a script
to &repmgrd; which, in a failover situation,
will be executed by the promotion candidate (the node which has been selected
to be the new primary) to confirm whether the node should actually be promoted.
</para>
<para>
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 %a</programlisting>
</para>
<para>
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.
Any other value will result in the promotion being aborted and the election rerun.
There is a pause of <option>election_rerun_interval</option> seconds before the election is rerun.
</para>
<para>
Sample &repmgrd; log file output during which the failover validation
script rejects the proposed promotion candidate:
<programlisting>
[2019-03-13 21:01:30] [INFO] visible nodes: 2; total nodes: 2; no nodes have seen the primary within the last 4 seconds
[2019-03-13 21:01:30] [NOTICE] promotion candidate is "node2" (ID: 2)
[2019-03-13 21:01:30] [NOTICE] executing "failover_validation_command"
[2019-03-13 21:01:30] [DETAIL] /usr/local/bin/failover-validation.sh 2
[2019-03-13 21:01:30] [INFO] output returned by failover validation command:
Node ID: 2
[2019-03-13 21:01:30] [NOTICE] failover validation command returned a non-zero value: "1"
[2019-03-13 21:01:30] [NOTICE] promotion candidate election will be rerun
[2019-03-13 21:01:30] [INFO] 1 followers to notify
[2019-03-13 21:01:30] [NOTICE] notifying node "node3" (ID: 3) to rerun promotion candidate selection
INFO: node 3 received notification to rerun promotion candidate election
[2019-03-13 21:01:30] [NOTICE] rerunning election after 15 seconds ("election_rerun_interval")</programlisting>
</para>
</sect1>
<sect1 id="cascading-replication" xreflabel="Cascading replication">
<title>repmgrd and cascading replication</title>
<indexterm>
<primary>repmgrd</primary>
<secondary>cascading replication</secondary>
</indexterm>
<indexterm>
<primary>cascading replication</primary>
<secondary>repmgrd</secondary>
</indexterm>
<para>
Cascading replication - where a standby can connect to an upstream node and not
the primary server itself - was introduced in PostgreSQL 9.2. &repmgr; and
&repmgrd; support cascading replication by keeping track of the relationship
between standby servers - each node record is stored with the node id of its
upstream ("parent") server (except of course the primary server).
</para>
<para>
In a failover situation where the primary node fails and a top-level standby
is promoted, a standby connected to another standby will not be affected
and continue working as normal (even if the upstream standby it's connected
to becomes the primary node). If however the node's direct upstream fails,
the &quot;cascaded standby&quot; will attempt to reconnect to that node's parent
(unless <varname>failover</varname> is set to <literal>manual</literal> in
<filename>repmgr.conf</filename>).
</para>
</sect1>
<sect1 id="repmgrd-primary-child-disconnection" xreflabel="Monitoring standby disconnections on the primary">
<title>Monitoring standby disconnections on the primary node</title>
<indexterm>
<primary>repmgrd</primary>
<secondary>standby disconnection</secondary>
</indexterm>
<indexterm>
<primary>repmgrd</primary>
<secondary>child node disconnection</secondary>
</indexterm>
<note>
<para>
This functionality is available in <link linkend="release-4.4">&repmgr; 4.4</link> and later.
</para>
</note>
<para>
When running on the primary node, &repmgrd; can
monitor connections and in particular disconnections by its attached
child nodes (standbys, and if in use, the witness server), and optionally
execute a custom command if certain criteria are met (such as the number of
attached nodes falling to zero following a failover to a new primary); this
command can be used for example to &quot;fence&quot; the node and ensure it
is isolated from any applications attempting to access the replication cluster.
</para>
<note>
<para>
Currently &repmgrd; can only detect disconnections
of streaming replication standbys and cannot determine whether a standby
has disconnected and fallen back to archive recovery.
</para>
<para>
See section <link linkend="repmgrd-primary-child-disconnection-caveats">caveats</link> below.
</para>
</note>
<sect2 id="repmgrd-primary-child-disconnection-monitoring-process">
<title>Standby disconnections monitoring process and criteria</title>
<para>
&repmgrd; monitors attached child nodes and decides
whether to invoke the user-defined command based on the following process
and criteria:
<itemizedlist>
<listitem>
<para>
Every few seconds (defined by the configuration parameter <varname>child_nodes_check_interval</varname>;
default: <literal>5</literal> seconds, a value of <literal>0</literal> disables this altogether), &repmgrd; queries
the <literal>pg_stat_replication</literal> system view and compares
the nodes present there against the list of nodes registered with &repmgr; which
should be attached to the primary.
</para>
<para>
If a witness server is in use, &repmgrd; connects to it and checks which upstream node
it is following.
</para>
</listitem>
<listitem>
<para>
If a child node (standby) is no longer present in <literal>pg_stat_replication</literal>,
&repmgrd; notes the time it detected the node's absence, and additionally generates a
<literal>child_node_disconnect</literal> event.
</para>
<para>
If a witness server is in use, and it is no longer following the primary, or not
reachable at all, &repmgrd; notes the time it detected the node's absence, and additionally generates a
<literal>child_node_disconnect</literal> event.
</para>
</listitem>
<listitem>
<para>
If a child node (standby) which was absent from <literal>pg_stat_replication</literal> reappears,
&repmgrd; clears the time it detected the node's absence, and additionally generates a
<literal>child_node_reconnect</literal> event.
</para>
<para>
If a witness server is in use, which was previously not reachable or not following the
primary node, has become reachable and is following the primary node, &repmgrd; clears the
time it detected the node's absence, and additionally generates a
<literal>child_node_reconnect</literal> event.
</para>
</listitem>
<listitem>
<para>
If an entirely new child node (standby or witness) is detected, &repmgrd; adds it to its internal list
and additionally generates a <literal>child_node_new_connect</literal> event.
</para>
</listitem>
<listitem>
<para>
If the <varname>child_nodes_disconnect_command</varname> parameter is set in
<filename>repmgr.conf</filename>, &repmgrd; will then loop through all child nodes.
If it determines that insufficient child nodes are connected, and a
minimum of <varname>child_nodes_disconnect_timeout</varname> seconds (default: <literal>30</literal>)
has elapsed since the last node became disconnected, &repmgrd; will then execute the
<varname>child_nodes_disconnect_command</varname> script.
</para>
<para>
By default, the <varname>child_nodes_disconnect_command</varname> will only be executed
if all child nodes are disconnected. If <varname>child_nodes_connected_min_count</varname>
is set, the <varname>child_nodes_disconnect_command</varname> script will be triggered
if the number of connected child nodes falls below the specified value (e.g.
if set to <literal>2</literal>, the script will be triggered if only one child node
is connected). Alternatively, if <varname>child_nodes_disconnect_min_count</varname>
and more than that number of child nodes disconnects, the script will be triggered.
</para>
<note>
<para>
By default, a witness node, if in use, will <emphasis>not</emphasis> be counted as a
child node for the purposes of determining whether to execute
<varname>child_nodes_disconnect_command</varname>.
</para>
<para>
To enable the witness node to be counted as a child node, set
<varname>child_nodes_connected_include_witness</varname> in <filename>repmgr.conf</filename>
to <literal>true</literal>
(and <link linkend="repmgrd-reloading-configuration">reload the configuration</link> if &repmgrd;
is running).
</para>
</note>
</listitem>
<listitem>
<para>
Note that child nodes which are not attached when &repmgrd;
starts will <emphasis>not</emphasis> be considered as missing, as &repmgrd;
cannot know why they are not attached.
</para>
</listitem>
</itemizedlist>
</para>
</sect2>
<sect2 id="repmgrd-primary-child-disconnection-example">
<title>Standby disconnections monitoring process example</title>
<para>
This example shows typical &repmgrd; log output from a three-node cluster
(primary and two child nodes), with <varname>child_nodes_connected_min_count</varname>
set to <literal>2</literal>.
</para>
<para>
&repmgrd; on the primary has started up, while two child
nodes are being provisioned:
<programlisting>
[2019-04-24 15:25:33] [INFO] monitoring primary node "node1" (ID: 1) in normal state
[2019-04-24 15:25:35] [NOTICE] new node "node2" (ID: 2) has connected
[2019-04-24 15:25:35] [NOTICE] 1 (of 1) child nodes are connected, but at least 2 child nodes required
[2019-04-24 15:25:35] [INFO] no child nodes have detached since repmgrd startup
(...)
[2019-04-24 15:25:44] [NOTICE] new node "node3" (ID: 3) has connected
[2019-04-24 15:25:46] [INFO] monitoring primary node "node1" (ID: 1) in normal state
(...)</programlisting>
</para>
<para>
One of the child nodes has disconnected; &repmgrd;
is now waiting <varname>child_nodes_disconnect_timeout</varname> seconds
before executing <varname>child_nodes_disconnect_command</varname>:
<programlisting>
[2019-04-24 15:28:11] [INFO] monitoring primary node "node1" (ID: 1) in normal state
[2019-04-24 15:28:17] [INFO] monitoring primary node "node1" (ID: 1) in normal state
[2019-04-24 15:28:19] [NOTICE] node "node3" (ID: 3) has disconnected
[2019-04-24 15:28:19] [NOTICE] 1 (of 2) child nodes are connected, but at least 2 child nodes required
[2019-04-24 15:28:19] [INFO] most recently detached child node was 3 (ca. 0 seconds ago), not triggering "child_nodes_disconnect_command"
[2019-04-24 15:28:19] [DETAIL] "child_nodes_disconnect_timeout" set To 30 seconds
(...)</programlisting>
</para>
<para>
<varname>child_nodes_disconnect_command</varname> is executed once:
<programlisting>
[2019-04-24 15:28:49] [INFO] most recently detached child node was 3 (ca. 30 seconds ago), triggering "child_nodes_disconnect_command"
[2019-04-24 15:28:49] [INFO] "child_nodes_disconnect_command" is:
"/usr/bin/fence-all-the-things.sh"
[2019-04-24 15:28:51] [NOTICE] 1 (of 2) child nodes are connected, but at least 2 child nodes required
[2019-04-24 15:28:51] [INFO] "child_nodes_disconnect_command" was previously executed, taking no action</programlisting>
</para>
</sect2>
<sect2 id="repmgrd-primary-child-disconnection-caveats">
<title>Standby disconnections monitoring caveats</title>
<para>
The follwing caveats should be considered if you are intending to use this functionality.
</para>
<para>
<itemizedlist mark="bullet">
<listitem>
<para>
If a child node is configured to use archive recovery, it's possible that
the child node will disconnect from the primary node and fall back to
archive recovery. In this case &repmgrd;
will nevertheless register a node disconnection.
</para>
</listitem>
<listitem>
<para>
&repmgr; relies on <varname>application_name</varname> in the child node's
<varname>primary_conninfo</varname> string to be the same as the node name
defined in the node's <filename>repmgr.conf</filename> file. Furthermore,
this <varname>application_name</varname> must be unique across the replication
cluster.
</para>
<para>
If a custom <varname>application_name</varname> is used, or the
<varname>application_name</varname> is not unique across the replication
cluster, &repmgr; will not be able to reliably monitor child node connections.
</para>
</listitem>
</itemizedlist>
</para>
</sect2>
<sect2 id="repmgrd-primary-child-disconnection-configuration">
<title>Standby disconnections monitoring process configuration</title>
<para>
The following parameters, set in <filename>repmgr.conf</filename>,
control how child node disconnection monitoring operates.
</para>
<variablelist>
<varlistentry>
<term><varname>child_nodes_check_interval</varname></term>
<listitem>
<indexterm>
<primary>child_nodes_check_interval</primary>
<secondary>child node disconnection monitoring</secondary>
</indexterm>
<para>
Interval (in seconds) after which &repmgrd; queries the
<literal>pg_stat_replication</literal> system view and compares the nodes present
there against the list of nodes registered with repmgr which should be attached to the primary.
</para>
<para>
Default is <literal>5</literal> seconds, a value of <literal>0</literal> disables this check
altogether.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>child_nodes_disconnect_command</varname></term>
<listitem>
<indexterm>
<primary>child_nodes_disconnect_command</primary>
<secondary>child node disconnection monitoring</secondary>
</indexterm>
<para>
User-definable script to be executed when &repmgrd;
determines that an insufficient number of child nodes are connected. By default
the script is executed when no child nodes are executed, but the execution
threshold can be modified by setting one of <varname>child_nodes_connected_min_count</varname>
or<varname>child_nodes_disconnect_min_count</varname> (see below).
</para>
<para>
The <varname>child_nodes_disconnect_command</varname> script can be
any user-defined script or program. It <emphasis>must</emphasis> be able
to be executed by the system user under which the PostgreSQL server itself
runs (usually <literal>postgres</literal>).
</para>
<note>
<para>
If <varname>child_nodes_disconnect_command</varname> is not set, no action
will be taken.
</para>
</note>
<para>
If specified, the following format placeholder will be substituted when
executing <varname>child_nodes_disconnect_command</varname>:
</para>
<variablelist>
<varlistentry>
<term><option>%p</option></term>
<listitem>
<para>
ID of the node executing the <varname>child_nodes_disconnect_command</varname> script.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
The <varname>child_nodes_disconnect_command</varname> script will only be executed once
while the criteria for its execution are met. If the criteria for its execution are no longer
met (i.e. some child nodes have reconnected), it will be executed again if
the criteria for its execution are met again.
</para>
<para>
The <varname>child_nodes_disconnect_command</varname> script will not be executed if
&repmgrd; is <link linkend="repmgrd-pausing">paused</link>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>child_nodes_disconnect_timeout</varname></term>
<listitem>
<indexterm>
<primary>child_nodes_disconnect_timeout</primary>
<secondary>child node disconnection monitoring</secondary>
</indexterm>
<para>
If &repmgrd; determines that an insufficient number of
child nodes are connected, it will wait for the specified number of seconds
to execute the <varname>child_nodes_disconnect_command</varname>.
</para>
<para>
Default: <literal>30</literal> seconds.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>child_nodes_connected_min_count</varname></term>
<listitem>
<indexterm>
<primary>child_nodes_connected_min_count</primary>
<secondary>child node disconnection monitoring</secondary>
</indexterm>
<para>
If the number of child nodes connected falls below the number specified in
this parameter, the <varname>child_nodes_disconnect_command</varname> script
will be executed.
</para>
<para>
For example, if <varname>child_nodes_connected_min_count</varname> is set
to <literal>2</literal>, the <varname>child_nodes_disconnect_command</varname>
script will be executed if one or no child nodes are connected.
</para>
<para>
Note that <varname>child_nodes_connected_min_count</varname> overrides any value
set in <varname>child_nodes_disconnect_min_count</varname>.
</para>
<para>
If neither of <varname>child_nodes_connected_min_count</varname> or
<varname>child_nodes_disconnect_min_count</varname> are set,
the <varname>child_nodes_disconnect_command</varname> script
will be executed when no child nodes are connected.
</para>
<para>
A witness node, if in use, will not be counted as a child node unless
<varname>child_nodes_connected_include_witness</varname> is set to <literal>true</literal>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>child_nodes_disconnect_min_count</varname></term>
<listitem>
<indexterm>
<primary>child_nodes_disconnect_min_count</primary>
<secondary>child node disconnection monitoring</secondary>
</indexterm>
<para>
If the number of disconnected child nodes exceeds the number specified in
this parameter, the <varname>child_nodes_disconnect_command</varname> script
will be executed.
</para>
<para>
For example, if <varname>child_nodes_disconnect_min_count</varname> is set
to <literal>2</literal>, the <varname>child_nodes_disconnect_command</varname>
script will be executed if more than two child nodes are disconnected.
</para>
<para>
Note that any value set in <varname>child_nodes_disconnect_min_count</varname>
will be overriden by <varname>child_nodes_connected_min_count</varname>.
</para>
<para>
If neither of <varname>child_nodes_connected_min_count</varname> or
<varname>child_nodes_disconnect_min_count</varname> are set,
the <varname>child_nodes_disconnect_command</varname> script
will be executed when no child nodes are connected.
</para>
<para>
A witness node, if in use, will not be counted as a child node unless
<varname>child_nodes_connected_include_witness</varname> is set to <literal>true</literal>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>child_nodes_connected_include_witness</varname></term>
<listitem>
<indexterm>
<primary>child_nodes_connected_include_witness</primary>
<secondary>child node disconnection monitoring</secondary>
</indexterm>
<para>
Whether to count the witness node (if in use) as a child node when
determining whether to execute <varname>child_nodes_disconnect_command</varname>.
</para>
<para>
Default to <literal>false</literal>.
</para>
</listitem>
</varlistentry>
</variablelist>
</sect2>
<sect2 id="repmgrd-primary-child-disconnection-events">
<title>Standby disconnections monitoring process event notifications</title>
<para>
The following <link linkend="event-notifications">event notifications</link> may be generated:
</para>
<variablelist>
<varlistentry>
<term><varname>child_node_disconnect</varname></term>
<listitem>
<indexterm>
<primary>child_node_disconnect</primary>
<secondary>event notification</secondary>
</indexterm>
<para>
This event is generated after &repmgrd;
detects that a child node is no longer streaming from the primary node.
</para>
<para>
Example:
<programlisting>
$ repmgr cluster event --event=child_node_disconnect
Node ID | Name | Event | OK | Timestamp | Details
---------+-------+-----------------------+----+---------------------+--------------------------------------------
1 | node1 | child_node_disconnect | t | 2019-04-24 12:41:36 | node "node3" (ID: 3) has disconnected</programlisting>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>child_node_reconnect</varname></term>
<listitem>
<indexterm>
<primary>child_node_reconnect</primary>
<secondary>event notification</secondary>
</indexterm>
<para>
This event is generated after &repmgrd;
detects that a child node has resumed streaming from the primary node.
</para>
<para>
Example:
<programlisting>
$ repmgr cluster event --event=child_node_reconnect
Node ID | Name | Event | OK | Timestamp | Details
---------+-------+----------------------+----+---------------------+------------------------------------------------------------
1 | node1 | child_node_reconnect | t | 2019-04-24 12:42:19 | node "node3" (ID: 3) has reconnected after 42 seconds</programlisting>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>child_node_new_connect</varname></term>
<listitem>
<indexterm>
<primary>child_node_new_connect</primary>
<secondary>event notification</secondary>
</indexterm>
<para>
This event is generated after &repmgrd;
detects that a new child node has been registered with &repmgr; and has
connected to the primary.
</para>
<para>
Example:
<programlisting>
$ repmgr cluster event --event=child_node_new_connect
Node ID | Name | Event | OK | Timestamp | Details
---------+-------+------------------------+----+---------------------+---------------------------------------------
1 | node1 | child_node_new_connect | t | 2019-04-24 12:41:30 | new node "node3" (ID: 3) has connected</programlisting>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>child_nodes_disconnect_command</varname></term>
<listitem>
<indexterm>
<primary>child_nodes_disconnect_command</primary>
<secondary>event notification</secondary>
</indexterm>
<para>
This event is generated after &repmgrd; detects
that sufficient child nodes have been disconnected for a sufficient amount
of time to trigger execution of the <varname>child_nodes_disconnect_command</varname>.
</para>
<para>
Example:
<programlisting>
$ repmgr cluster event --event=child_nodes_disconnect_command
Node ID | Name | Event | OK | Timestamp | Details
---------+-------+--------------------------------+----+---------------------+--------------------------------------------------------
1 | node1 | child_nodes_disconnect_command | t | 2019-04-24 13:08:17 | "child_nodes_disconnect_command" successfully executed</programlisting>
</para>
</listitem>
</varlistentry>
</variablelist>
</sect2>
</sect1>
</chapter>

View File

@@ -1,6 +1,4 @@
<chapter id="repmgrd-bdr">
<title>BDR failover with repmgrd</title>
<indexterm>
<primary>repmgrd</primary>
<secondary>BDR</secondary>
@@ -10,6 +8,7 @@
<primary>BDR</primary>
</indexterm>
<title>BDR failover with repmgrd</title>
<para>
&repmgr; 4.x provides support for monitoring a pair of BDR 2.x nodes and taking action in
case one of the nodes fails.
@@ -25,10 +24,10 @@
<para>
In contrast to streaming replication, there's no concept of "promoting" a new
primary node with BDR. Instead, "failover" involves monitoring both nodes
with &repmgrd; and redirecting queries from the failed node to the remaining
with <application>repmgrd</application> and redirecting queries from the failed node to the remaining
active node. This can be done by using an
<link linkend="event-notifications">event notification</link> script
which is called by &repmgrd; to dynamically
which is called by <application>repmgrd</application> to dynamically
reconfigure a proxy server/connection pooler such as <application>PgBouncer</application>.
</para>
@@ -61,7 +60,7 @@
<para>
Application database connections *must* be passed through a proxy server/
connection pooler such as <application>PgBouncer</application>, and it must be possible to dynamically
reconfigure that from &repmgrd;. The example demonstrated in this document
reconfigure that from <application>repmgrd</application>. The example demonstrated in this document
will use <application>PgBouncer</application>
</para>
<para>
@@ -95,7 +94,7 @@
# Event notification configuration
event_notifications=bdr_failover
event_notification_command='/path/to/bdr-pgbouncer.sh %n %e %s "%c" "%a" >> /tmp/bdr-failover.log 2>&amp;1'
event_notification_command='/path/to/bdr-pgbouncer.sh %n %e %s "%c" "%a" >> /tmp/bdr-failover.log 2>&1'
# repmgrd options
monitor_interval_secs=5
@@ -121,7 +120,7 @@
<simpara>
<varname>event_notification_command</varname> is the script which does the actual "heavy lifting"
of reconfiguring the proxy server/ connection pooler. It is fully
user-definable; see section <xref linkend="bdr-event-notification-command"/> for a reference
user-definable; see section <xref linkend="bdr-event-notification-command"> for a reference
implementation.
</simpara>
</note>
@@ -159,7 +158,7 @@
</important>
<para>
At this point the meta data for both nodes has been created; executing
<xref linkend="repmgr-cluster-show"/> (on either node) should produce output like this:
<xref linkend="repmgr-cluster-show"> (on either node) should produce output like this:
<programlisting>
$ repmgr -f /etc/repmgr.conf cluster show
ID | Name | Role | Status | Upstream | Location | Connection string
@@ -169,7 +168,7 @@
</para>
<para>
Additionally it's possible to display log of significant events; executing
<xref linkend="repmgr-cluster-event"/> (on either node) should produce output like this:
<xref linkend="repmgr-cluster-event"> (on either node) should produce output like this:
<programlisting>
$ repmgr -f /etc/repmgr.conf cluster event
Node ID | Event | OK | Timestamp | Details
@@ -297,7 +296,7 @@
</listitem>
<listitem>
<simpara>recreates the <application>PgBouncer</application> configuration file on each
node using the information provided by &repmgrd;
node using the information provided by <application>repmgrd</application>
(primarily the <varname>conninfo</varname> string) to configure
<application>PgBouncer</application></simpara>
</listitem>
@@ -319,21 +318,21 @@
<title>Node monitoring and failover</title>
<para>
At the intervals specified by <varname>monitor_interval_secs</varname>
in <filename>repmgr.conf</filename>, &repmgrd;
in <filename>repmgr.conf</filename>, <application>repmgrd</application>
will ping each node to check if it's available. If a node isn't available,
&repmgrd; will enter failover mode and check <varname>reconnect_attempts</varname>
<application>repmgrd</application> will enter failover mode and check <varname>reconnect_attempts</varname>
times at intervals of <varname>reconnect_interval</varname> to confirm the node is definitely unreachable.
This buffer period is necessary to avoid false positives caused by transient
network outages.
</para>
<para>
If the node is still unavailable, &repmgrd; will enter failover mode and execute
If the node is still unavailable, <application>repmgrd</application> will enter failover mode and execute
the script defined in <varname>event_notification_command</varname>; an entry will be logged
in the <literal>repmgr.events</literal> table and &repmgrd; will
in the <literal>repmgr.events</literal> table and <application>repmgrd</application> will
(unless otherwise configured) resume monitoring of the node in "degraded" mode until it reappears.
</para>
<para>
&repmgrd; logfile output during a failover event will look something like this
<application>repmgrd</application> logfile output during a failover event will look something like this
on one node (usually the node which has failed, here <literal>node2</literal>):
<programlisting>
...
@@ -389,8 +388,8 @@
</para>
<para>
This assumes only the PostgreSQL instance on <literal>node2</literal> has failed. In this case the
&repmgrd; instance running on <literal>node2</literal> has performed the failover. However if
the entire server becomes unavailable, &repmgrd; on <literal>node1</literal> will perform
<application>repmgrd</application> instance running on <literal>node2</literal> has performed the failover. However if
the entire server becomes unavailable, <application>repmgrd</application> on <literal>node1</literal> will perform
the failover.
</para>
</sect1>
@@ -405,7 +404,7 @@
</para>
<para>
If the failed node comes back up and connects correctly, output similar to this
will be visible in the &repmgrd; log:
will be visible in the <application>repmgrd</application> log:
<programlisting>
[2017-07-27 21:25:30] [DETAIL] monitoring node "node2" (ID: 2) in degraded mode
[2017-07-27 21:25:46] [INFO] monitoring BDR replication status on node "node2" (ID: 2)
@@ -418,10 +417,10 @@
<sect1 id="bdr-complete-shutdown" xreflabel="Shutdown of both nodes">
<title>Shutdown of both nodes</title>
<para>
If both PostgreSQL instances are shut down, &repmgrd; will try and handle the
If both PostgreSQL instances are shut down, <application>repmgrd</application> will try and handle the
situation as gracefully as possible, though with no failover candidates available
there's not much it can do. Should this case ever occur, we recommend shutting
down &repmgrd; on both nodes and restarting it once the PostgreSQL instances
down <application>repmgrd</application> on both nodes and restarting it once the PostgreSQL instances
are running properly.
</para>
</sect1>

View File

@@ -1,20 +1,20 @@
<chapter id="repmgrd-configuration">
<title>repmgrd setup and configuration</title>
<indexterm>
<primary>repmgrd</primary>
<secondary>configuration</secondary>
</indexterm>
<title>repmgrd setup and configuration</title>
<para>
&repmgrd; is a daemon process which runs on each PostgreSQL node,
<application>repmgrd</application> is a daemon which runs on each PostgreSQL node,
monitoring the local node, and (unless it's the primary node) the upstream server
(the primary server or with cascading replication, another standby) which it's
connected to.
</para>
<para>
&repmgrd; can be configured to provide failover
<application>repmgrd</application> can be configured to provide failover
capability in case the primary upstream node becomes unreachable, and/or
provide monitoring data to the &repmgr; metadatabase.
</para>
@@ -23,7 +23,7 @@
<title>repmgrd configuration</title>
<para>
To use &repmgrd;, its associated function library <emphasis>must</emphasis> be
To use <application>repmgrd</application>, its associated function library <emphasis>must</emphasis> be
included via <filename>postgresql.conf</filename> with:
<programlisting>
@@ -35,115 +35,112 @@
</para>
<para>
The following configuraton options apply to &repmgrd; in all circumstances:
The following configuraton options apply to <application>repmgrd</application> in all circumstances:
</para>
<variablelist>
<varlistentry>
<term><option>monitor_interval_secs</option></term>
<listitem>
<indexterm>
<varlistentry>
<indexterm>
<primary>monitor_interval_secs</primary>
</indexterm>
<term><option>monitor_interval_secs</option></term>
<listitem>
<para>
The interval (in seconds, default: <literal>2</literal>) to check the availability of the upstream node.
</para>
</listitem>
<para>
The interval (in seconds, default: <literal>2</literal>) to check the availability of the upstream node.
</para>
</listitem>
</varlistentry>
</varlistentry>
<varlistentry id="connection-check-type">
<varlistentry id="connection-check-type">
<term><option>connection_check_type</option></term>
<listitem>
<indexterm>
<primary>connection_check_type</primary>
</indexterm>
<para>
The option <option>connection_check_type</option> is used to select the method
&repmgrd; uses to determine whether the upstream node is available.
</para>
<para>
Possible values are:
<itemizedlist spacing="compact" mark="bullet">
<listitem>
<term><option>connection_check_type</option></term>
<listitem>
<para>
The option <option>connection_check_type</option> is used to select the method
<application>repmgrd</application> uses to determine whether the upstream node is available.
</para>
<para>
Possible values are:
<itemizedlist spacing="compact" mark="bullet">
<listitem>
<simpara>
<literal>ping</literal> (default) - uses <command>PQping()</command> to
determine server availability
</simpara>
</listitem>
<listitem>
<simpara>
<literal>connection</literal> - determines server availability
by attempting to make a new connection to the upstream node
</simpara>
</listitem>
<listitem>
<simpara>
<literal>query</literal> - determines server availability
by executing an SQL statement on the node via the existing connection
</simpara>
</listitem>
</listitem>
<listitem>
<simpara>
<literal>connection</literal> - determines server availability
by attempt ingto make a new connection to the upstream node
</simpara>
</listitem>
<listitem>
<simpara>
<literal>query</literal> - determines server availability
by executing an SQL statement on the node via the existing connection
</simpara>
</listitem>
</itemizedlist>
</para>
</listitem>
</varlistentry>
</itemizedlist>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>reconnect_attempts</option></term>
<listitem>
<indexterm>
<varlistentry>
<indexterm>
<primary>reconnect_attempts</primary>
</indexterm>
<para>
The number of attempts (default: <literal>6</literal>) will be made to reconnect to an unreachable
upstream node before initiating a failover.
</para>
<para>
There will be an interval of <option>reconnect_interval</option> seconds between each reconnection
attempt.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>reconnect_interval</option></term>
<listitem>
<indexterm>
<term><option>reconnect_attempts</option></term>
<listitem>
<para>
The number of attempts (default: <literal>6</literal>) will be made to reconnect to an unreachable
upstream node before initiating a failover.
</para>
<para>
There will be an interval of <option>reconnect_interval</option> seconds between each reconnection
attempt.
</para>
</listitem>
</varlistentry>
<varlistentry>
<indexterm>
<primary>reconnect_interval</primary>
</indexterm>
<para>
Interval (in seconds, default: <literal>10</literal>) between attempts to reconnect to an unreachable
upstream node.
</para>
<para>
<term><option>reconnect_interval</option></term>
<listitem>
<para>
Interval (in seconds, default: <literal>10</literal>) between attempts to reconnect to an unreachable
upstream node.
</para>
<para>
The number of reconnection attempts is defined by the parameter <option>reconnect_attempts</option>.
</para>
</listitem>
</varlistentry>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>degraded_monitoring_timeout</option></term>
<listitem>
<varlistentry>
<indexterm>
<primary>degraded_monitoring_timeout</primary>
</indexterm>
<para>
Interval (in seconds) after which &repmgrd; will terminate if
either of the servers (local node and or upstream node) being monitored is no longer available
(<link linkend="repmgrd-degraded-monitoring">degraded monitoring mode</link>).
</para>
<para>
<literal>-1</literal> (default) disables this timeout completely.
</para>
</listitem>
</varlistentry>
<term><option>degraded_monitoring_timeout</option></term>
<listitem>
<para>
Interval (in seconds) after which <application>repmgrd</application> will terminate if
either of the servers (local node and or upstream node) being monitored is no longer available
(<link linkend="repmgrd-degraded-monitoring">degraded monitoring mode</link>).
</para>
<para>
<literal>-1</literal> (default) disables this timeout completely.
</para>
</listitem>
</varlistentry>
</variablelist>
@@ -155,7 +152,7 @@
<title>Required configuration for automatic failover</title>
<para>
The following &repmgrd; options <emphasis>must</emphasis> be set in
The following <application>repmgrd</application> options <emphasis>must</emphasis> be set in
<filename>repmgr.conf</filename>:
<itemizedlist spacing="compact" mark="bullet">
@@ -185,18 +182,17 @@
<variablelist>
<varlistentry>
<indexterm>
<primary>failover</primary>
</indexterm>
<term><option>failover</option></term>
<listitem>
<indexterm>
<primary>failover</primary>
</indexterm>
<para>
<option>failover</option> can be one of <literal>automatic</literal> or <literal>manual</literal>.
</para>
<note>
<para>
If <option>failover</option> is set to <literal>manual</literal>, &repmgrd;
If <option>failover</option> is set to <literal>manual</literal>, <application>repmgrd</application>
will not take any action if a failover situation is detected, and the node may need to
be modified manually (e.g. by executing <command><link linkend="repmgr-standby-follow">repmgr standby follow</link></command>).
</para>
@@ -206,33 +202,20 @@
</varlistentry>
<varlistentry>
<indexterm>
<primary>promote_command</primary>
</indexterm>
<term><option>promote_command</option></term>
<listitem>
<indexterm>
<primary>promote_command</primary>
</indexterm>
<para>
The program or script defined in <option>promote_command</option> will be executed
in a failover situation when &repmgrd; determines that
in a failover situation when <application>repmgrd</application> determines that
the current node is to become the new primary node.
</para>
<para>
Normally <option>promote_command</option> is set as &repmgr;'s
<command><link linkend="repmgr-standby-promote">repmgr standby promote</link></command> command.
</para>
<note>
<para>
When invoking <command>repmgr standby promote</command> (either directly via
the <option>promote_command</option>, or in a script called
via <option>promote_command</option>), <option>--siblings-follow</option>
<emphasis>must not</emphasis> be included as a
command line option for <command>repmgr standby promote</command>.
</para>
</note>
<para>
It is also possible to provide a shell script to e.g. perform user-defined tasks
before promoting the current node. In this case the script <emphasis>must</emphasis>
@@ -248,8 +231,8 @@
<para>
Note that the <literal>--log-to-file</literal> option will cause
output generated by the &repmgr; command, when executed by &repmgrd;,
to be logged to the same destination configured to receive log output for &repmgrd;.
output generated by the &repmgr; command, when executed by <application>repmgrd</application>,
to be logged to the same destination configured to receive log output for <application>repmgrd</application>.
</para>
<note>
<para>
@@ -262,15 +245,14 @@
</varlistentry>
<varlistentry>
<indexterm>
<primary>follow_command</primary>
</indexterm>
<term><option>follow_command</option></term>
<listitem>
<indexterm>
<primary>follow_command</primary>
</indexterm>
<para>
The program or script defined in <option>follow_command</option> will be executed
in a failover situation when &repmgrd; determines that
in a failover situation when <application>repmgrd</application> determines that
the current node is to follow the new primary node.
</para>
<para>
@@ -281,7 +263,7 @@
The <option>follow_command</option> parameter
should provide the <literal>--upstream-node-id=%n</literal>
option to <command>repmgr standby follow</command>; the <literal>%n</literal> will be replaced by
&repmgrd; with the ID of the new primary node. If this is not provided,
<application>repmgrd</application> with the ID of the new primary node. If this is not provided,
<command>repmgr standby follow</command> will attempt to determine the new primary by itself, but if the
original primary comes back online after the new primary is promoted, there is a risk that
<command>repmgr standby follow</command> will result in the node continuing to follow
@@ -302,8 +284,8 @@
<para>
Note that the <literal>--log-to-file</literal> option will cause
output generated by the &repmgr; command, when executed by &repmgrd;,
to be logged to the same destination configured to receive log output for &repmgrd;.
output generated by the &repmgr; command, when executed by <application>repmgrd</application>,
to be logged to the same destination configured to receive log output for <application>repmgrd</application>.
</para>
<note>
<para>
@@ -330,12 +312,11 @@
<variablelist>
<varlistentry>
<indexterm>
<primary>priority</primary>
</indexterm>
<term><option>priority</option></term>
<listitem>
<indexterm>
<primary>priority</primary>
</indexterm>
<para>
Indicates a preferred priority (default: <literal>100</literal>) for promoting nodes;
a value of zero prevents the node being promoted to primary.
@@ -349,15 +330,14 @@
</varlistentry>
<varlistentry>
<indexterm>
<primary>failover_validation_command</primary>
</indexterm>
<term><option>failover_validation_command</option></term>
<listitem>
<indexterm>
<primary>failover_validation_command</primary>
</indexterm>
<para>
User-defined script to execute for an external mechanism to validate the failover
decision made by &repmgrd;.
decision made by <application>repmgrd</application>.
</para>
<note>
<para>
@@ -384,36 +364,13 @@
</listitem>
</varlistentry>
<varlistentry>
<term><option>primary_visibility_consensus</option></term>
<listitem>
<indexterm>
<primary>primary_visibility_consensus</primary>
</indexterm>
<para>
If <literal>true</literal>, only continue with failover if no standbys have seen
the primary node recently.
</para>
<note>
<para>
This option <emphasis>must</emphasis> be identically configured
on all nodes.
</para>
</note>
</listitem>
</varlistentry>
<varlistentry>
<indexterm>
<primary>standby_disconnect_on_failover</primary>
</indexterm>
<term><option>standby_disconnect_on_failover</option></term>
<listitem>
<indexterm>
<primary>standby_disconnect_on_failover</primary>
</indexterm>
<para>
In a failover situation, disconnect the local node's WAL receiver.
</para>
@@ -430,7 +387,7 @@
for this option.
</para>
<para>
&repmgrd; will refuse to start if this option is set
<application>repmgrd</application> will refuse to start if this option is set
but either of these prerequisites is not met.
</para>
</note>
@@ -451,12 +408,11 @@
<variablelist>
<varlistentry>
<indexterm>
<primary>election_rerun_interval</primary>
</indexterm>
<term><option>election_rerun_interval</option></term>
<listitem>
<indexterm>
<primary>election_rerun_interval</primary>
</indexterm>
<para>
If <option>failover_validation_command</option> is set, and the command returns
an error, pause the specified amount of seconds (default: 15) before rerunning the election.
@@ -466,12 +422,11 @@
<varlistentry>
<indexterm>
<primary>sibling_nodes_disconnect_timeout</primary>
</indexterm>
<term><option>sibling_nodes_disconnect_timeout</option></term>
<listitem>
<indexterm>
<primary>sibling_nodes_disconnect_timeout</primary>
</indexterm>
<para>
If <option>standby_disconnect_on_failover</option> is <literal>true</literal>, the
maximum length of time (in seconds, default: <literal>30</literal>)
@@ -487,40 +442,37 @@
</sect2>
<sect2 id="postgresql-service-configuration">
<title>PostgreSQL service configuration</title>
<indexterm>
<primary>repmgrd</primary>
<secondary>PostgreSQL service configuration</secondary>
</indexterm>
<title>PostgreSQL service configuration</title>
<para>
If using automatic failover, currently &repmgrd; will need to execute
If using automatic failover, currently <application>repmgrd</application> will need to execute
<link linkend="repmgr-standby-follow"><command>repmgr standby follow</command></link>
to restart PostgreSQL on standbys to have them follow a new primary.
</para>
<para>
To ensure this happens smoothly, it's essential to provide the appropriate system/service restart
command appropriate to your operating system via <varname>service_restart_command</varname>
in <filename>repmgr.conf</filename>. If you don't do this, &repmgrd;
in <filename>repmgr.conf</filename>. If you don't do this, <application>repmgrd</application>
will default to using <command>pg_ctl</command>, which can result in unexpected problems,
particularly on <application>systemd</application>-based systems.
</para>
<para>
For more details, see <xref linkend="configuration-file-service-commands"/>.
For more details, see <xref linkend="configuration-file-service-commands">.
</para>
</sect2>
<sect2 id="repmgrd-service-configuration">
<title>repmgrd service configuration</title>
<indexterm>
<primary>repmgrd</primary>
<secondary>repmgrd service configuration</secondary>
</indexterm>
<title>repmgrd service configuration</title>
<para>
If you are intending to use the <link linkend="repmgr-daemon-start"><command>repmgr daemon start</command></link>
and <link linkend="repmgr-daemon-stop"><command>repmgr daemon stop</command></link>
commands, the following
and <link linkend="repmgr-daemon-stop"><command>repmgr daemon stop</command></link> commands, the following
parameters <emphasis>must</emphasis> be set in <filename>repmgr.conf</filename>:
<itemizedlist spacing="compact" mark="bullet">
@@ -536,10 +488,10 @@
</para>
<para>
Example (for &repmgr; with PostgreSQL 12 on CentOS 7):
Example (for &repmgr; with PostgreSQL 11 on CentOS 7):
<programlisting>
repmgrd_service_start_command='sudo systemctl repmgr12 start'
repmgrd_service_stop_command='sudo systemctl repmgr12 stop'
repmgrd_service_start_command='sudo systemctl repmgr11 start'
repmgrd_service_stop_command='sudo systemctl repmgr11 stop'
</programlisting>
</para>
<para>
@@ -549,12 +501,11 @@ repmgrd_service_stop_command='sudo systemctl repmgr12 stop'
<sect2 id="repmgrd-monitoring-configuration" xreflabel="repmgrd monitoring configuration">
<title>Monitoring configuration</title>
<indexterm>
<primary>repmgrd</primary>
<secondary>monitoring configuration</secondary>
</indexterm>
<title>Monitoring configuration</title>
<para>
To enable monitoring, set:
<programlisting>
@@ -566,33 +517,32 @@ 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 more details on monitoring, see <xref linkend="repmgrd-monitoring">.
</para>
</sect2>
<sect2 id="repmgrd-reloading-configuration" xreflabel="reloading repmgrd configuration">
<title>Applying configuration changes to repmgrd</title>
<sect2 id="repmgrd-reloading-configuration"xreflabel="reloading repmgrd configuration">
<indexterm>
<primary>repmgrd</primary>
<secondary>applying configuration changes</secondary>
</indexterm>
<title>Applying configuration changes to repmgrd</title>
<para>
To apply configuration file changes to a running &repmgrd;
daemon, execute the operating system's &repmgrd; service reload command
(see <xref linkend="appendix-packages"/> for examples),
To apply configuration file changes to a running <application>repmgrd</application>
daemon, execute the operating system's <application>repmgrd</application> service reload command
(see <xref linkend="appendix-packages"> for examples),
or for instances which were manually started, execute <command>kill -HUP</command>, e.g.
<command>kill -HUP `cat /tmp/repmgrd.pid`</command>.
</para>
<tip>
<para>
Check the &repmgrd; log to see what changes were
Check the <application>repmgrd</application> log to see what changes were
applied, or if any issues were encountered when reloading the configuration.
</para>
</tip>
<para>
Note that only the following subset of configuration file parameters can be changed on a
running &repmgrd; daemon:
running <application>repmgrd</application> daemon:
</para>
<itemizedlist spacing="compact" mark="bullet">
@@ -614,41 +564,6 @@ repmgrd_service_stop_command='sudo systemctl repmgr12 stop'
</simpara>
</listitem>
<listitem>
<simpara>
<varname>child_nodes_check_interval</varname>
</simpara>
</listitem>
<listitem>
<simpara>
<varname>child_nodes_connected_include_witness</varname>
</simpara>
</listitem>
<listitem>
<simpara>
<varname>child_nodes_connected_min_count</varname>
</simpara>
</listitem>
<listitem>
<simpara>
<varname>child_nodes_disconnect_command</varname>
</simpara>
</listitem>
<listitem>
<simpara>
<varname>child_nodes_disconnect_min_count</varname>
</simpara>
</listitem>
<listitem>
<simpara>
<varname>child_nodes_disconnect_timeout</varname>
</simpara>
</listitem>
<listitem>
<simpara>
@@ -740,12 +655,6 @@ repmgrd_service_stop_command='sudo systemctl repmgr12 stop'
</simpara>
</listitem>
<listitem>
<simpara>
<varname>primary_visibility_consensus</varname>
</simpara>
</listitem>
<listitem>
<simpara>
<varname>promote_command</varname>
@@ -834,7 +743,7 @@ repmgrd_service_stop_command='sudo systemctl repmgr12 stop'
<note>
<para>
After executing <command><link linkend="repmgr-standby-register">repmgr standby register --force</link></command>,
&repmgrd; <emphasis>must</emphasis> be restarted for the changes to take effect.
<application>repmgrd</application> <emphasis>must</emphasis> be restarted for the changes to take effect.
</para>
</note>
@@ -843,25 +752,24 @@ repmgrd_service_stop_command='sudo systemctl repmgr12 stop'
</sect1>
<sect1 id="repmgrd-daemon" xreflabel="repmgrd daemon">
<title>repmgrd daemon</title>
<indexterm>
<primary>repmgrd</primary>
<secondary>starting and stopping</secondary>
</indexterm>
<title>repmgrd daemon</title>
<para>
If installed from a package, the &repmgrd; can be started
If installed from a package, the <application>repmgrd</application> can be started
via the operating system's service command, e.g. in <application>systemd</application>
using <command>systemctl</command>.
</para>
<para>
See appendix <xref linkend="appendix-packages"/> for details of service commands
See appendix <xref linkend="appendix-packages"> for details of service commands
for different distributions.
</para>
<para>
The commands <link linkend="repmgr-daemon-start"><command>repmgr daemon start</command></link> and
<link linkend="repmgr-daemon-stop"><command>repmgr daemon stop</command></link> can be used
as convenience wrappers to start and stop &repmgrd; on the local node.
as convenience wrappers to start and stop <application>repmgrd</application>.
</para>
<important>
<para>
@@ -873,15 +781,13 @@ repmgrd_service_stop_command='sudo systemctl repmgr12 stop'
</para>
</important>
<para>
&repmgrd; can be started manually like this:
<application>repmgrd</application> can be started manually like this:
<programlisting>
repmgrd -f /etc/repmgr.conf --pid-file /tmp/repmgrd.pid</programlisting>
and stopped with <command>kill `cat /tmp/repmgrd.pid`</command>. Adjust paths as appropriate.
</para>
<sect2 id="repmgrd-pid-file" xreflabel="repmgrd's PID file">
<title>repmgrd's PID file</title>
<indexterm>
<primary>repmgrd</primary>
<secondary>PID file</secondary>
@@ -890,8 +796,9 @@ repmgrd_service_stop_command='sudo systemctl repmgr12 stop'
<primary>PID file</primary>
<secondary>repmgrd</secondary>
</indexterm>
<title>repmgrd's PID file</title>
<para>
&repmgrd; will generate a PID file by default.
<application>repmgrd</application> will generate a PID file by default.
</para>
<note>
<simpara>
@@ -911,12 +818,12 @@ repmgrd_service_stop_command='sudo systemctl repmgr12 stop'
<option>--pid-file</option> may be deprecated in future releases.
</para>
<para>
If a PID file location was specified by the package maintainer, &repmgrd;
If a PID file location was specified by the package maintainer, <application>repmgrd</application>
will use that. This only applies if &repmgr; was installed from a package and the package
maintainer has specified the PID file location.
</para>
<para>
If none of the above apply, &repmgrd; will create a PID file
If none of the above apply, <application>repmgrd</application> will create a PID file
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>
@@ -925,17 +832,15 @@ repmgrd_service_stop_command='sudo systemctl repmgr12 stop'
<option>--no-pid-file</option>.
</para>
<para>
To see which PID file &repmgrd; would use, execute &repmgrd;
with the option <option>--show-pid-file</option>. &repmgrd;
To see which PID file <application>repmgrd</application> would use, execute <application>repmgrd</application>
with the option <option>--show-pid-file</option>. <application>repmgrd</application>
will not start if this option is provided. Note that the value shown is the
file &repmgrd; would use next time it starts, and is
file <application>repmgrd</application> would use next time it starts, and is
not necessarily the PID file currently in use.
</para>
</sect2>
<sect2 id="repmgrd-configuration-debian-ubuntu">
<title>repmgrd daemon configuration on Debian/Ubuntu</title>
<indexterm>
<primary>repmgrd</primary>
<secondary>Debian/Ubuntu and daemon configuration</secondary>
@@ -945,9 +850,11 @@ repmgrd_service_stop_command='sudo systemctl repmgr12 stop'
<secondary>repmgrd daemon configuration</secondary>
</indexterm>
<title>repmgrd daemon configuration on Debian/Ubuntu</title>
<para>
If &repmgr; was installed from Debian/Ubuntu packages, additional configuration
is required before &repmgrd; is started as a daemon.
is required before <application>repmgrd</application> is started as a daemon.
</para>
<para>
This is done via the file <filename>/etc/default/repmgrd</filename>, which by default
@@ -981,17 +888,17 @@ REPMGRD_OPTS="--daemonize=false"
</para>
<tip>
<para>
See <xref linkend="packages-debian-ubuntu"/> for details of the Debian/Ubuntu packages and
See <xref linkend="packages-debian-ubuntu"> for details of the Debian/Ubuntu packages and
typical file locations (including <filename>repmgr.conf</filename>).
</para>
</tip>
<para>
From &repmgrd; 4.1, ensure <varname>REPMGRD_OPTS</varname> includes
From <application>repmgrd</application> 4.1, ensure <varname>REPMGRD_OPTS</varname> includes
<option>--daemonize=false</option>, as daemonization is handled by the service command.
</para>
<para>
If using <application>systemd</application>, you may need to execute <command>systemctl daemon-reload</command>.
Also, if you attempted to start &repmgrd; using <command>systemctl start repmgrd</command>,
Also, if you attempted to start <application>repmgrd</application> using <command>systemctl start repmgrd</command>,
you'll need to execute <command>systemctl stop repmgrd</command>. Because that's how <application>systemd</application>
rolls.
</para>
@@ -1025,9 +932,7 @@ REPMGRD_OPTS="--daemonize=false"
<sect1 id="repmgrd-log-rotation">
<title>repmgrd log rotation</title>
<sect1 id="repmgrd-log-rotation">
<indexterm>
<primary>log rotation</primary>
<secondary>repmgrd</secondary>
@@ -1038,8 +943,9 @@ REPMGRD_OPTS="--daemonize=false"
<secondary>log rotation</secondary>
</indexterm>
<title>repmgrd log rotation</title>
<para>
To ensure the current &repmgrd; logfile
To ensure the current <application>repmgrd</application> logfile
(specified in <filename>repmgr.conf</filename> with the parameter
<option>log_file</option>) does not grow indefinitely, configure your
system's <command>logrotate</command> to regularly rotate it.

View File

@@ -1,14 +1,13 @@
<chapter id="repmgrd-operation" xreflabel="repmgrd operation">
<title>repmgrd operation</title>
<indexterm>
<primary>repmgrd</primary>
<secondary>operation</secondary>
</indexterm>
<sect1 id="repmgrd-pausing" xreflabel="pausing the repmgrd service">
<title>repmgrd operation</title>
<title>Pausing the repmgrd service</title>
<sect1 id="repmgrd-pausing">
<indexterm>
<primary>repmgrd</primary>
@@ -19,44 +18,45 @@
<primary>pausing repmgrd</primary>
</indexterm>
<title>Pausing repmgrd</title>
<para>
In normal operation, &repmgrd; monitors the state of the
In normal operation, <application>repmgrd</application> monitors the state of the
PostgreSQL node it is running on, and will take appropriate action if problems
are detected, e.g. (if so configured) promote the node to primary, if the existing
primary has been determined as failed.
</para>
<para>
However, &repmgrd; is unable to distinguish between
However, <application>repmgrd</application> is unable to distinguish between
planned outages (such as performing a <link linkend="performing-switchover">switchover</link>
or installing PostgreSQL maintenance released), and an actual server outage. In versions prior to
&repmgr; 4.2 it was necessary to stop &repmgrd; on all nodes (or at least
on all nodes where &repmgrd; is
&repmgr; 4.2 it was necessary to stop <application>repmgrd</application> on all nodes (or at least
on all nodes where <application>repmgrd</application> is
<link linkend="repmgrd-automatic-failover">configured for automatic failover</link>)
to prevent &repmgrd; from making unintentional changes to the
to prevent <application>repmgrd</application> from making unintentional changes to the
replication cluster.
</para>
<para>
From <link linkend="release-4.2">&repmgr; 4.2</link>, &repmgrd;
From <link linkend="release-4.2">&repmgr; 4.2</link>, <application>repmgrd</application>
can now be &quot;paused&quot;, i.e. instructed not to take any action such as performing a failover.
This can be done from any node in the cluster, removing the need to stop/restart
each &repmgrd; individually.
each <application>repmgrd</application> individually.
</para>
<note>
<para>
For major PostgreSQL upgrades, e.g. from PostgreSQL 11 to PostgreSQL 12,
&repmgrd; should be shut down completely and only started up
For major PostgreSQL upgrades, e.g. from PostgreSQL 10 to PostgreSQL 11,
<application>repmgrd</application> should be shut down completely and only started up
once the &repmgr; packages for the new PostgreSQL major version have been installed.
</para>
</note>
<sect2 id="repmgrd-pausing-prerequisites">
<title>Prerequisites for pausing &repmgrd;</title>
<title>Prerequisites for pausing <application>repmgrd</application></title>
<para>
In order to be able to pause/unpause &repmgrd;, following
In order to be able to pause/unpause <application>repmgrd</application>, following
prerequisites must be met:
<itemizedlist spacing="compact" mark="bullet">
@@ -86,23 +86,19 @@
</sect2>
<sect2 id="repmgrd-pausing-execution">
<title>Pausing/unpausing &repmgrd;</title>
<title>Pausing/unpausing <application>repmgrd</application></title>
<para>
To pause &repmgrd;, execute <link linkend="repmgr-service-pause"><command>repmgr service pause</command></link>
(&repmgr; 4.2 - 4.4: <link linkend="repmgr-service-pause"><command>repmgr daemon pause</command></link>),
e.g.:
To pause <application>repmgrd</application>, execute <link linkend="repmgr-daemon-pause"><command>repmgr daemon pause</command></link>, e.g.:
<programlisting>
$ repmgr -f /etc/repmgr.conf service pause
$ repmgr -f /etc/repmgr.conf daemon pause
NOTICE: node 1 (node1) paused
NOTICE: node 2 (node2) paused
NOTICE: node 3 (node3) paused</programlisting>
</para>
<para>
The state of &repmgrd; on each node can be checked with
<link linkend="repmgr-service-status"><command>repmgr service status</command></link>
(&repmgr; 4.2 - 4.4: <link linkend="repmgr-service-status"><command>repmgr daemon status</command></link>),
e.g.:
<programlisting>$ repmgr -f /etc/repmgr.conf service status
The state of <application>repmgrd</application> on each node can be checked with
<link linkend="repmgr-daemon-status"><command>repmgr daemon status</command></link>, e.g.:
<programlisting>$ repmgr -f /etc/repmgr.conf daemon status
ID | Name | Role | Status | repmgrd | PID | Paused?
----+-------+---------+---------+---------+------+---------
1 | node1 | primary | running | running | 7851 | yes
@@ -112,41 +108,38 @@ NOTICE: node 3 (node3) paused</programlisting>
<note>
<para>
If executing a switchover with <link linkend="repmgr-standby-switchover"><command>repmgr standby switchover</command></link>,
&repmgr; will automatically pause/unpause the &repmgrd; service as part of the switchover process.
If executing a switchover with <link linkend="repmgr-standby-switchover"><command>repmgr standby switchover</command></link>,
&repmgr; will automatically pause/unpause <application>repmgrd</application> as part of the switchover process.
</para>
</note>
<para>
If the primary (in this example, <literal>node1</literal>) is stopped, &repmgrd;
If the primary (in this example, <literal>node1</literal>) is stopped, <application>repmgrd</application>
running on one of the standbys (here: <literal>node2</literal>) will react like this:
<programlisting>
[2019-08-28 12:22:21] [WARNING] unable to connect to upstream node "node1" (node ID: 1)
[2019-08-28 12:22:21] [INFO] checking state of node 1, 1 of 5 attempts
[2019-08-28 12:22:21] [INFO] sleeping 1 seconds until next reconnection attempt
[2018-09-20 12:22:21] [WARNING] unable to connect to upstream node "node1" (node ID: 1)
[2018-09-20 12:22:21] [INFO] checking state of node 1, 1 of 5 attempts
[2018-09-20 12:22:21] [INFO] sleeping 1 seconds until next reconnection attempt
...
[2019-08-28 12:22:24] [INFO] sleeping 1 seconds until next reconnection attempt
[2019-08-28 12:22:25] [INFO] checking state of node 1, 5 of 5 attempts
[2019-08-28 12:22:25] [WARNING] unable to reconnect to node 1 after 5 attempts
[2019-08-28 12:22:25] [NOTICE] node is paused
[2019-08-28 12:22:33] [INFO] node "node2" (ID: 2) monitoring upstream node "node1" (node ID: 1) in degraded state
[2019-08-28 12:22:33] [DETAIL] repmgrd paused by administrator
[2019-08-28 12:22:33] [HINT] execute "repmgr service unpause" to resume normal failover mode</programlisting>
[2018-09-20 12:22:24] [INFO] sleeping 1 seconds until next reconnection attempt
[2018-09-20 12:22:25] [INFO] checking state of node 1, 5 of 5 attempts
[2018-09-20 12:22:25] [WARNING] unable to reconnect to node 1 after 5 attempts
[2018-09-20 12:22:25] [NOTICE] node is paused
[2018-09-20 12:22:33] [INFO] node "node2" (node ID: 2) monitoring upstream node "node1" (node ID: 1) in degraded state
[2018-09-20 12:22:33] [DETAIL] repmgrd paused by administrator
[2018-09-20 12:22:33] [HINT] execute "repmgr daemon unpause" to resume normal failover mode</programlisting>
</para>
<para>
If the primary becomes available again (e.g. following a software upgrade), &repmgrd;
If the primary becomes available again (e.g. following a software upgrade), <application>repmgrd</application>
will automatically reconnect, e.g.:
<programlisting>
[2019-08-28 12:25:41] [NOTICE] reconnected to upstream node 1 after 8 seconds, resuming monitoring</programlisting>
[2018-09-20 13:12:41] [NOTICE] reconnected to upstream node 1 after 8 seconds, resuming monitoring</programlisting>
</para>
<para>
To unpause the &repmgrd; service, execute
<link linkend="repmgr-service-unpause"><command>repmgr service unpause</command></link>
((&repmgr; 4.2 - 4.4: <link linkend="repmgr-service-unpause"><command>repmgr daemon unpause</command></link>),
e.g.:
To unpause <application>repmgrd</application>, execute <link linkend="repmgr-daemon-unpause"><command>repmgr daemon unpause</command></link>, e.g.:
<programlisting>
$ repmgr -f /etc/repmgr.conf service unpause
$ repmgr -f /etc/repmgr.conf daemon unpause
NOTICE: node 1 (node1) unpaused
NOTICE: node 2 (node2) unpaused
NOTICE: node 3 (node3) unpaused</programlisting>
@@ -154,61 +147,54 @@ NOTICE: node 3 (node3) unpaused</programlisting>
<note>
<para>
If the previous primary is no longer accessible when &repmgrd;
If the previous primary is no longer accessible when <application>repmgrd</application>
is unpaused, no failover action will be taken. Instead, a new primary must be manually promoted using
<link linkend="repmgr-standby-promote"><command>repmgr standby promote</command></link>,
and any standbys attached to the new primary with
<link linkend="repmgr-standby-follow"><command>repmgr standby follow</command></link>.
and any standbys attached to the new primary with
<link linkend="repmgr-standby-follow"><command>repmgr standby follow</command></link>.
</para>
<para>
This is to prevent execution of <link linkend="repmgr-service-unpause"><command>repmgr service unpause</command></link>
This is to prevent <link linkend="repmgr-daemon-unpause"><command>repmgr daemon unpause</command></link>
resulting in the automatic promotion of a new primary, which may be a problem particularly
in larger clusters, where &repmgrd; could select a different promotion
in larger clusters, where <application>repmgrd</application> could select a different promotion
candidate to the one intended by the administrator.
</para>
</note>
</sect2>
<sect2 id="repmgrd-pausing-details">
<title>Details on the &repmgrd; pausing mechanism</title>
<title>Details on the <application>repmgrd</application> pausing mechanism</title>
<para>
The pause state of each node will be stored over a PostgreSQL restart.
</para>
<para>
<link linkend="repmgr-service-pause"><command>repmgr service pause</command></link> and
<link linkend="repmgr-service-unpause"><command>repmgr service unpause</command></link> can be
executed even if &repmgrd; is not running; in this case,
&repmgrd; will start up in whichever pause state has been set.
</para>
<para>
<link linkend="repmgr-daemon-pause"><command>repmgr daemon pause</command></link> and
<link linkend="repmgr-daemon-unpause"><command>repmgr daemon unpause</command></link> can be
executed even if <application>repmgrd</application> is not running; in this case,
<application>repmgrd</application> will start up in whichever pause state has been set.
</para>
<note>
<para>
<link linkend="repmgr-service-pause"><command>repmgr service pause</command></link> and
<link linkend="repmgr-service-unpause"><command>repmgr service unpause</command></link>
<emphasis>do not</emphasis> start/stop &repmgrd;.
</para>
<para>
The commands <link linkend="repmgr-daemon-start"><command>repmgr daemon start</command></link>
and <link linkend="repmgr-daemon-stop"><command>repmgr daemon stop</command></link>
(<link linkend="repmgrd-service-configuration">if correctly configured</link>) can be used to start/stop
&repmgrd; on individual nodes.
<link linkend="repmgr-daemon-pause"><command>repmgr daemon pause</command></link> and
<link linkend="repmgr-daemon-unpause"><command>repmgr daemon unpause</command></link>
<emphasis>do not</emphasis> stop/start <application>repmgrd</application>.
</para>
</note>
</sect2>
</sect1>
<sect1 id="repmgrd-wal-replay-pause">
<title>repmgrd and paused WAL replay</title>
<indexterm>
<primary>repmgrd</primary>
<secondary>paused WAL replay</secondary>
</indexterm>
<title>repmgrd and paused WAL replay</title>
<para>
If WAL replay has been paused (using <command>pg_wal_replay_pause()</command>,
on PostgreSQL 9.6 and earlier <command>pg_xlog_replay_pause()</command>),
in a failover situation &repmgrd; will
in a failover situation <application>repmgrd</application> will
automatically resume WAL replay.
</para>
<para>
@@ -228,8 +214,6 @@ NOTICE: node 3 (node3) unpaused</programlisting>
</sect1>
<sect1 id="repmgrd-degraded-monitoring" xreflabel="repmgrd degraded monitoring">
<title>"degraded monitoring" mode</title>
<indexterm>
<primary>repmgrd</primary>
<secondary>degraded monitoring</secondary>
@@ -239,10 +223,11 @@ NOTICE: node 3 (node3) unpaused</programlisting>
<primary>degraded monitoring</primary>
</indexterm>
<title>"degraded monitoring" mode</title>
<para>
In certain circumstances, &repmgrd; is not able to fulfill its primary mission
In certain circumstances, <application>repmgrd</application> is not able to fulfill its primary mission
of monitoring the node's upstream server. In these cases it enters &quot;degraded monitoring&quot;
mode, where &repmgrd; remains active but is waiting for the situation
mode, where <application>repmgrd</application> remains active but is waiting for the situation
to be resolved.
</para>
<para>
@@ -283,8 +268,8 @@ NOTICE: node 3 (node3) unpaused</programlisting>
Example output in a situation where there is only one standby with <literal>failover=manual</literal>,
and the primary node is unavailable (but is later restarted):
<programlisting>
[2017-08-29 10:59:19] [INFO] node "node2" (ID: 2) monitoring upstream node "node1" (ID: 1) in normal state (automatic failover disabled)
[2017-08-29 10:59:33] [WARNING] unable to connect to upstream node "node1" (ID: 1)
[2017-08-29 10:59:19] [INFO] node "node2" (node ID: 2) monitoring upstream node "node1" (node ID: 1) in normal state (automatic failover disabled)
[2017-08-29 10:59:33] [WARNING] unable to connect to upstream node "node1" (node ID: 1)
[2017-08-29 10:59:33] [INFO] checking state of node 1, 1 of 5 attempts
[2017-08-29 10:59:33] [INFO] sleeping 1 seconds until next reconnection attempt
(...)
@@ -293,21 +278,21 @@ NOTICE: node 3 (node3) unpaused</programlisting>
[2017-08-29 10:59:37] [NOTICE] this node is not configured for automatic failover so will not be considered as promotion candidate
[2017-08-29 10:59:37] [NOTICE] no other nodes are available as promotion candidate
[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 10:59:37] [INFO] node "node2" (node ID: 2) monitoring upstream node "node1" (node ID: 1) in degraded state (automatic failover disabled)
[2017-08-29 10:59:53] [INFO] node "node2" (node ID: 2) monitoring upstream node "node1" (node ID: 1) in degraded state (automatic failover disabled)
[2017-08-29 11:00:45] [NOTICE] reconnected to upstream node 1 after 68 seconds, resuming monitoring
[2017-08-29 11:00:57] [INFO] node "node2" (ID: 2) monitoring upstream node "node1" (ID: 1) in normal state (automatic failover disabled)</programlisting>
[2017-08-29 11:00:57] [INFO] node "node2" (node ID: 2) monitoring upstream node "node1" (node ID: 1) in normal state (automatic failover disabled)</programlisting>
</para>
<para>
By default, <literal>repmgrd</literal> will continue in degraded monitoring mode indefinitely.
However a timeout (in seconds) can be set with <varname>degraded_monitoring_timeout</varname>,
after which &repmgrd; will terminate.
after which <application>repmgrd</application> will terminate.
</para>
<note>
<para>
If &repmgrd; is monitoring a primary mode which has been stopped
If <application>repmgrd</application> is monitoring a primary mode which has been stopped
and manually restarted as a standby attached to a new primary, it will automatically detect
the status change and update the node record to reflect the node's new status
as an active standby. It will then resume monitoring the node as a standby.
@@ -317,7 +302,6 @@ NOTICE: node 3 (node3) unpaused</programlisting>
<sect1 id="repmgrd-monitoring" xreflabel="Storing monitoring data">
<title>Storing monitoring data</title>
<indexterm>
<primary>repmgrd</primary>
<secondary>monitoring</secondary>
@@ -327,8 +311,9 @@ NOTICE: node 3 (node3) unpaused</programlisting>
<secondary>with repmgrd</secondary>
</indexterm>
<title>Storing monitoring data</title>
<para>
When &repmgrd; is running with the option <literal>monitoring_history=true</literal>,
When <application>repmgrd</application> is running with the option <literal>monitoring_history=true</literal>,
it will constantly write standby node status information to the
<varname>monitoring_history</varname> table, providing a near-real time
overview of replication status on all nodes
@@ -361,12 +346,12 @@ NOTICE: node 3 (node3) unpaused</programlisting>
<para>
As this can generate a large amount of monitoring data in the table
<literal>repmgr.monitoring_history</literal>. it's advisable to regularly
purge historical data using the <xref linkend="repmgr-cluster-cleanup"/>
purge historical data using the <xref linkend="repmgr-cluster-cleanup">
command; use the <literal>-k/--keep-history</literal> option to
specify how many day's worth of data should be retained.
</para>
<para>
It's possible to use &repmgrd; to run in monitoring
It's possible to use <application>repmgrd</application> to run in monitoring
mode only (without automatic failover capability) for some or all
nodes by setting <literal>failover=manual</literal> in the node's
<filename>repmgr.conf</filename> file. In the event of the node's upstream failing,

View File

@@ -1,24 +1,24 @@
<chapter id="repmgrd-overview" xreflabel="repmgrd overview">
<title>repmgrd overview</title>
<indexterm>
<primary>repmgrd</primary>
<secondary>overview</secondary>
</indexterm>
<title>repmgrd overview</title>
<para>
&repmgrd; (&quot;<literal>replication manager daemon</literal>&quot;)
<application>repmgrd</application> (&quot;<literal>replication manager daemon</literal>&quot;)
is a management and monitoring daemon which runs
on each node in a replication cluster. It can automate actions such as
failover and updating standbys to follow the new primary, as well as
providing monitoring information about the state of each standby.
</para>
<para>
&repmgrd; is designed to be straightforward to set up
<application>repmgrd</application> is designed to be straightforward to set up
and does not require additional external infrastructure.
</para>
<para>
Functionality provided by &repmgrd; includes:
Functionality provided by <application>repmgrd</application> includes:
<itemizedlist spacing="compact" mark="bullet">
<listitem>
@@ -38,7 +38,7 @@
<simpara>
ability to <link linkend="repmgrd-pausing">pause repmgrd</link>
operation on all nodes with a
<link linkend="repmgr-service-pause"><command>single command</command></link>
<link linkend="repmgr-daemon-pause"><command>single command</command></link>
</simpara>
</listitem>
@@ -93,28 +93,28 @@
<tip>
<para>
See section <link linkend="repmgrd-automatic-failover-configuration">Required configuration for automatic failover</link>
for an example of minimal <filename>repmgr.conf</filename> file settings suitable for use with &repmgrd;.
for an example of minimal <filename>repmgr.conf</filename> file settings suitable for use with <application>repmgrd</application>.
</para>
</tip>
<para>
Start &repmgrd; on each standby and verify that it's running by examining the
Start <application>repmgrd</application> on each standby and verify that it's running by examining the
log output, which at log level <literal>INFO</literal> will look like this:
<programlisting>
[2019-08-15 07:14:42] [NOTICE] repmgrd (repmgrd 5.0) starting up
[2019-08-15 07:14:42] [INFO] connecting to database "host=node2 dbname=repmgr user=repmgr connect_timeout=2"
INFO: set_repmgrd_pid(): provided pidfile is /var/run/repmgr/repmgrd-12.pid
[2019-08-15 07:14:42] [NOTICE] starting monitoring of node "node2" (ID: 2)
[2019-08-15 07:14:42] [INFO] monitoring connection to upstream node "node1" (ID: 1)</programlisting>
[2019-03-15 06:32:05] [NOTICE] repmgrd (repmgrd 4.3) starting up
[2019-03-15 06:32:05] [INFO] connecting to database "host=node2 dbname=repmgr user=repmgr connect_timeout=2"
INFO: set_repmgrd_pid(): provided pidfile is /var/run/repmgr/repmgrd-11.pid
[2019-03-15 06:32:05] [NOTICE] starting monitoring of node "node2" (ID: 2)
[2019-03-15 06:32:05] [INFO] monitoring connection to upstream node "node1" (node ID: 1)</programlisting>
</para>
<para>
Each &repmgrd; should also have recorded its successful startup as an event:
Each <application>repmgrd</application> should also have recorded its successful startup as an event:
<programlisting>
$ repmgr -f /etc/repmgr.conf cluster event --event=repmgrd_start
Node ID | Name | Event | OK | Timestamp | Details
---------+-------+---------------+----+---------------------+--------------------------------------------------------
3 | node3 | repmgrd_start | t | 2019-08-15 07:14:42 | monitoring connection to upstream node "node1" (ID: 1)
2 | node2 | repmgrd_start | t | 2019-08-15 07:14:41 | monitoring connection to upstream node "node1" (ID: 1)
1 | node1 | repmgrd_start | t | 2019-08-15 07:14:39 | monitoring cluster primary "node1" (ID: 1)</programlisting>
---------+-------+---------------+----+---------------------+-------------------------------------------------------------
3 | node3 | repmgrd_start | t | 2019-03-14 04:17:30 | monitoring connection to upstream node "node1" (node ID: 1)
2 | node2 | repmgrd_start | t | 2019-03-14 04:11:47 | monitoring connection to upstream node "node1" (node ID: 1)
1 | node1 | repmgrd_start | t | 2019-03-14 04:04:31 | monitoring cluster primary "node1" (node ID: 1)</programlisting>
</para>
<para>
Now stop the current primary server with e.g.:
@@ -123,38 +123,38 @@
</para>
<para>
This will force the primary to shut down straight away, aborting all processes
and transactions. This will cause a flurry of activity in the &repmgrd; log
files as each &repmgrd; detects the failure of the primary and a failover
and transactions. This will cause a flurry of activity in the <application>repmgrd</application> log
files as each <application>repmgrd</application> detects the failure of the primary and a failover
decision is made. This is an extract from the log of a standby server (<literal>node2</literal>)
which has promoted to new primary after failure of the original primary (<literal>node1</literal>).
<programlisting>
[2019-08-15 07:27:50] [WARNING] unable to connect to upstream node "node1" (ID: 1)
[2019-08-15 07:27:50] [INFO] checking state of node 1, 1 of 3 attempts
[2019-08-15 07:27:50] [INFO] sleeping 5 seconds until next reconnection attempt
[2019-08-15 07:27:55] [INFO] checking state of node 1, 2 of 3 attempts
[2019-08-15 07:27:55] [INFO] sleeping 5 seconds until next reconnection attempt
[2019-08-15 07:28:00] [INFO] checking state of node 1, 3 of 3 attempts
[2019-08-15 07:28:00] [WARNING] unable to reconnect to node 1 after 3 attempts
[2019-08-15 07:28:00] [INFO] primary and this node have the same location ("default")
[2019-08-15 07:28:00] [INFO] local node's last receive lsn: 0/900CBF8
[2019-08-15 07:28:00] [INFO] node 3 last saw primary node 12 second(s) ago
[2019-08-15 07:28:00] [INFO] last receive LSN for sibling node "node3" (ID: 3) is: 0/900CBF8
[2019-08-15 07:28:00] [INFO] node "node3" (ID: 3) has same LSN as current candidate "node2" (ID: 2)
[2019-08-15 07:28:00] [INFO] visible nodes: 2; total nodes: 2; no nodes have seen the primary within the last 4 seconds
[2019-08-15 07:28:00] [NOTICE] promotion candidate is "node2" (ID: 2)
[2019-08-15 07:28:00] [NOTICE] this node is the winner, will now promote itself and inform other nodes
[2019-08-15 07:28:00] [INFO] promote_command is:
"/usr/pgsql-12/bin/repmgr -f /etc/repmgr/12/repmgr.conf standby promote"
[2019-03-15 06:37:50] [WARNING] unable to connect to upstream node "node1" (node ID: 1)
[2019-03-15 06:37:50] [INFO] checking state of node 1, 1 of 3 attempts
[2019-03-15 06:37:50] [INFO] sleeping 5 seconds until next reconnection attempt
[2019-03-15 06:37:55] [INFO] checking state of node 1, 2 of 3 attempts
[2019-03-15 06:37:55] [INFO] sleeping 5 seconds until next reconnection attempt
[2019-03-15 06:38:00] [INFO] checking state of node 1, 3 of 3 attempts
[2019-03-15 06:38:00] [WARNING] unable to reconnect to node 1 after 3 attempts
[2019-03-15 06:38:00] [INFO] primary and this node have the same location ("default")
[2019-03-15 06:38:00] [INFO] local node's last receive lsn: 0/900CBF8
[2019-03-15 06:38:00] [INFO] node 3 last saw primary node 12 second(s) ago
[2019-03-15 06:38:00] [INFO] last receive LSN for sibling node "node3" (ID: 3) is: 0/900CBF8
[2019-03-15 06:38:00] [INFO] node "node3" (ID: 3) has same LSN as current candidate "node2" (ID: 2)
[2019-03-15 06:38:00] [INFO] visible nodes: 2; total nodes: 2; no nodes have seen the primary within the last 4 seconds
[2019-03-15 06:38:00] [NOTICE] promotion candidate is "node2" (ID: 2)
[2019-03-15 06:38:00] [NOTICE] this node is the winner, will now promote itself and inform other nodes
[2019-03-15 06:38:00] [INFO] promote_command is:
"/usr/pgsql-11/bin/repmgr -f /etc/repmgr/11/repmgr.conf standby promote"
NOTICE: promoting standby to primary
DETAIL: promoting server "node2" (ID: 2) using "/usr/pgsql-12/bin/pg_ctl -w -D '/var/lib/pgsql/12/data' promote"
DETAIL: promoting server "node2" (ID: 2) using "/usr/pgsql-11/bin/pg_ctl -w -D '/var/lib/pgsql/11/data' promote"
NOTICE: waiting up to 60 seconds (parameter "promote_check_timeout") for promotion to complete
NOTICE: STANDBY PROMOTE successful
DETAIL: server "node2" (ID: 2) was successfully promoted to primary
[2019-08-15 07:28:01] [INFO] 3 followers to notify
[2019-08-15 07:28:01] [NOTICE] notifying node "node3" (ID: 3) to follow node 2
[2019-03-15 06:38:01] [INFO] 3 followers to notify
[2019-03-15 06:38:01] [NOTICE] notifying node "node3" (node ID: 3) to follow node 2
INFO: node 3 received notification to follow node 2
[2019-08-15 07:28:01] [INFO] switching to primary monitoring mode
[2019-08-15 07:28:01] [NOTICE] monitoring cluster primary "node2" (ID: 2)</programlisting>
[2019-03-15 06:38:01] [INFO] switching to primary monitoring mode
[2019-03-15 06:38:01] [NOTICE] monitoring cluster primary "node2" (node ID: 2)</programlisting>
</para>
<para>
The cluster status will now look like this, with the original primary (<literal>node1</literal>)
@@ -176,11 +176,11 @@
$ repmgr -f /etc/repmgr.conf cluster event
Node ID | Name | Event | OK | Timestamp | Details
---------+-------+----------------------------+----+---------------------+-------------------------------------------------------------
3 | node3 | repmgrd_failover_follow | t | 2019-08-15 07:38:03 | node 3 now following new upstream node 2
3 | node3 | standby_follow | t | 2019-08-15 07:38:02 | standby attached to upstream node "node2" (ID: 2)
2 | node2 | repmgrd_reload | t | 2019-08-15 07:38:01 | monitoring cluster primary "node2" (ID: 2)
2 | node2 | repmgrd_failover_promote | t | 2019-08-15 07:38:01 | node 2 promoted to primary; old primary 1 marked as failed
2 | node2 | standby_promote | t | 2019-08-15 07:38:01 | server "node2" (ID: 2) was successfully promoted to primary</programlisting>
3 | node3 | repmgrd_failover_follow | t | 2019-03-15 06:38:03 | node 3 now following new upstream node 2
3 | node3 | standby_follow | t | 2019-03-15 06:38:02 | standby attached to upstream node "node2" (node ID: 2)
2 | node2 | repmgrd_reload | t | 2019-03-15 06:38:01 | monitoring cluster primary "node2" (node ID: 2)
2 | node2 | repmgrd_failover_promote | t | 2019-03-15 06:38:01 | node 2 promoted to primary; old primary 1 marked as failed
2 | node2 | standby_promote | t | 2019-03-15 06:38:01 | server "node2" (ID: 2) was successfully promoted to primary</programlisting>
</para>
</sect1>

View File

@@ -1,89 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<!--
This file contains XSLT stylesheet customizations that are common to
all output formats (HTML, HTML Help, XSL-FO, etc.).
-->
<xsl:include href="stylesheet-speedup-common.xsl" />
<!-- Parameters -->
<!--
<xsl:param name="draft.mode">
<xsl:choose>
<xsl:when test="contains($repmgr.version, 'devel')">yes</xsl:when>
<xsl:otherwise>no</xsl:otherwise>
</xsl:choose>
</xsl:param>
-->
<xsl:param name="show.comments">
<xsl:choose>
<xsl:when test="contains($repmgr.version, 'devel')">1</xsl:when>
<xsl:otherwise>0</xsl:otherwise>
</xsl:choose>
</xsl:param>
<xsl:param name="callout.graphics" select="'0'"></xsl:param>
<xsl:param name="toc.section.depth">2</xsl:param>
<xsl:param name="linenumbering.extension" select="'0'"></xsl:param>
<xsl:param name="section.autolabel" select="1"></xsl:param>
<xsl:param name="section.label.includes.component.label" select="1"></xsl:param>
<xsl:param name="refentry.generate.name" select="0"></xsl:param>
<xsl:param name="refentry.generate.title" select="1"></xsl:param>
<xsl:param name="refentry.xref.manvolnum" select="0"/>
<xsl:param name="formal.procedures" select="0"></xsl:param>
<xsl:param name="generate.consistent.ids" select="1"/>
<xsl:param name="punct.honorific" select="''"></xsl:param>
<xsl:param name="variablelist.term.break.after">1</xsl:param>
<xsl:param name="variablelist.term.separator"></xsl:param>
<xsl:param name="xref.with.number.and.title" select="0"></xsl:param>
<!-- Change display of some elements -->
<xsl:template match="productname">
<xsl:call-template name="inline.charseq"/>
</xsl:template>
<xsl:template match="structfield">
<xsl:call-template name="inline.monoseq"/>
</xsl:template>
<xsl:template match="structname">
<xsl:call-template name="inline.monoseq"/>
</xsl:template>
<xsl:template match="symbol">
<xsl:call-template name="inline.monoseq"/>
</xsl:template>
<xsl:template match="systemitem">
<xsl:call-template name="inline.charseq"/>
</xsl:template>
<xsl:template match="token">
<xsl:call-template name="inline.monoseq"/>
</xsl:template>
<xsl:template match="type">
<xsl:call-template name="inline.monoseq"/>
</xsl:template>
<xsl:template match="programlisting/emphasis">
<xsl:call-template name="inline.boldseq"/>
</xsl:template>
<!-- Special support for Tcl synopses -->
<xsl:template match="optional[@role='tcl']">
<xsl:text>?</xsl:text>
<xsl:call-template name="inline.charseq"/>
<xsl:text>?</xsl:text>
</xsl:template>
</xsl:stylesheet>

View File

@@ -1,97 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0"
xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:import href="http://docbook.sourceforge.net/release/xsl/current/fo/docbook.xsl"/>
<xsl:include href="stylesheet-common.xsl" />
<xsl:param name="fop1.extensions" select="1"></xsl:param>
<xsl:param name="tablecolumns.extension" select="0"></xsl:param>
<xsl:param name="toc.max.depth">3</xsl:param>
<xsl:param name="ulink.footnotes" select="1"></xsl:param>
<xsl:param name="use.extensions" select="1"></xsl:param>
<xsl:param name="variablelist.as.blocks" select="1"></xsl:param>
<xsl:attribute-set name="monospace.verbatim.properties"
use-attribute-sets="verbatim.properties monospace.properties">
<xsl:attribute name="wrap-option">wrap</xsl:attribute>
</xsl:attribute-set>
<xsl:attribute-set name="nongraphical.admonition.properties">
<xsl:attribute name="border-style">solid</xsl:attribute>
<xsl:attribute name="border-width">1pt</xsl:attribute>
<xsl:attribute name="border-color">black</xsl:attribute>
<xsl:attribute name="padding-start">12pt</xsl:attribute>
<xsl:attribute name="padding-end">12pt</xsl:attribute>
<xsl:attribute name="padding-top">6pt</xsl:attribute>
<xsl:attribute name="padding-bottom">6pt</xsl:attribute>
</xsl:attribute-set>
<xsl:attribute-set name="admonition.title.properties">
<xsl:attribute name="text-align">center</xsl:attribute>
</xsl:attribute-set>
<!-- fix missing space after vertical simplelist
https://github.com/docbook/xslt10-stylesheets/issues/31 -->
<xsl:attribute-set name="normal.para.spacing">
<xsl:attribute name="space-after.optimum">1em</xsl:attribute>
<xsl:attribute name="space-after.minimum">0.8em</xsl:attribute>
<xsl:attribute name="space-after.maximum">1.2em</xsl:attribute>
</xsl:attribute-set>
<!-- Change display of some elements -->
<xsl:template match="command">
<xsl:call-template name="inline.monoseq"/>
</xsl:template>
<xsl:template match="confgroup" mode="bibliography.mode">
<fo:inline>
<xsl:apply-templates select="conftitle/text()" mode="bibliography.mode"/>
<xsl:text>, </xsl:text>
<xsl:apply-templates select="confdates/text()" mode="bibliography.mode"/>
<xsl:value-of select="$biblioentry.item.separator"/>
</fo:inline>
</xsl:template>
<xsl:template match="isbn" mode="bibliography.mode">
<fo:inline>
<xsl:text>ISBN </xsl:text>
<xsl:apply-templates mode="bibliography.mode"/>
<xsl:value-of select="$biblioentry.item.separator"/>
</fo:inline>
</xsl:template>
<!-- bug fix from <https://sourceforge.net/p/docbook/bugs/1360/#831b> -->
<xsl:template match="varlistentry/term" mode="xref-to">
<xsl:param name="verbose" select="1"/>
<xsl:apply-templates mode="no.anchor.mode"/>
</xsl:template>
<!-- include refsects in PDF bookmarks
(https://github.com/docbook/xslt10-stylesheets/issues/46) -->
<xsl:template match="refsect1|refsect2|refsect3"
mode="bookmark">
<xsl:variable name="id">
<xsl:call-template name="object.id"/>
</xsl:variable>
<xsl:variable name="bookmark-label">
<xsl:apply-templates select="." mode="object.title.markup"/>
</xsl:variable>
<fo:bookmark internal-destination="{$id}">
<xsl:attribute name="starting-state">
<xsl:value-of select="$bookmarks.state"/>
</xsl:attribute>
<fo:bookmark-title>
<xsl:value-of select="normalize-space($bookmark-label)"/>
</fo:bookmark-title>
<xsl:apply-templates select="*" mode="bookmark"/>
</fo:bookmark>
</xsl:template>
</xsl:stylesheet>

View File

@@ -1,292 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xsl:stylesheet [
<!ENTITY % common.entities SYSTEM "http://docbook.sourceforge.net/release/xsl/current/common/entities.ent">
%common.entities;
]>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<!--
This file contains XSLT stylesheet customizations that are common to
all HTML output variants (chunked and single-page).
-->
<!-- Parameters -->
<xsl:param name="make.valid.html" select="1"></xsl:param>
<xsl:param name="generate.id.attributes" select="1"></xsl:param>
<xsl:param name="make.graphic.viewport" select="0"/>
<xsl:param name="link.mailto.url">pgsql-docs@lists.postgresql.org</xsl:param>
<xsl:param name="toc.max.depth">2</xsl:param>
<!-- Change display of some elements -->
<xsl:template match="command">
<xsl:call-template name="inline.monoseq"/>
</xsl:template>
<xsl:template match="confgroup" mode="bibliography.mode">
<span>
<xsl:call-template name="common.html.attributes"/>
<xsl:call-template name="id.attribute"/>
<xsl:apply-templates select="conftitle/text()" mode="bibliography.mode"/>
<xsl:text>, </xsl:text>
<xsl:apply-templates select="confdates/text()" mode="bibliography.mode"/>
<xsl:copy-of select="$biblioentry.item.separator"/>
</span>
</xsl:template>
<xsl:template match="isbn" mode="bibliography.mode">
<span>
<xsl:call-template name="common.html.attributes"/>
<xsl:call-template name="id.attribute"/>
<xsl:text>ISBN </xsl:text>
<xsl:apply-templates mode="bibliography.mode"/>
<xsl:copy-of select="$biblioentry.item.separator"/>
</span>
</xsl:template>
<!-- table of contents configuration -->
<xsl:param name="generate.toc">
appendix toc,title
article/appendix nop
article toc,title
book toc,title
chapter toc,title
part toc,title
preface toc,title
qandadiv toc
qandaset toc
reference toc,title
sect1 toc
sect2 toc
sect3 toc
sect4 toc
sect5 toc
section toc
set toc,title
</xsl:param>
<xsl:param name="generate.section.toc.level" select="1"></xsl:param>
<!-- include refentry under sect1 in tocs -->
<xsl:template match="sect1" mode="toc">
<xsl:param name="toc-context" select="."/>
<xsl:call-template name="subtoc">
<xsl:with-param name="toc-context" select="$toc-context"/>
<xsl:with-param name="nodes" select="sect2|refentry
|bridgehead[$bridgehead.in.toc != 0]"/>
</xsl:call-template>
</xsl:template>
<!-- Put index "quicklinks" (A | B | C | ...) at the top of the bookindex page. -->
<!-- from html/autoidx.xsl -->
<xsl:template name="generate-basic-index">
<xsl:param name="scope" select="NOTANODE"/>
<xsl:variable name="role">
<xsl:if test="$index.on.role != 0">
<xsl:value-of select="@role"/>
</xsl:if>
</xsl:variable>
<xsl:variable name="type">
<xsl:if test="$index.on.type != 0">
<xsl:value-of select="@type"/>
</xsl:if>
</xsl:variable>
<xsl:variable name="terms"
select="//indexterm
[count(.|key('letter',
translate(substring(&primary;, 1, 1),
&lowercase;,
&uppercase;))
[&scope;][1]) = 1
and not(@class = 'endofrange')]"/>
<xsl:variable name="alphabetical"
select="$terms[contains(concat(&lowercase;, &uppercase;),
substring(&primary;, 1, 1))]"/>
<xsl:variable name="others" select="$terms[not(contains(concat(&lowercase;,
&uppercase;),
substring(&primary;, 1, 1)))]"/>
<div class="index">
<!-- pgsql-docs: begin added stuff -->
<p class="indexdiv-quicklinks">
<a href="#indexdiv-Symbols">
<xsl:call-template name="gentext">
<xsl:with-param name="key" select="'index symbols'"/>
</xsl:call-template>
</a>
<xsl:apply-templates select="$alphabetical[count(.|key('letter',
translate(substring(&primary;, 1, 1),
&lowercase;,&uppercase;))[&scope;][1]) = 1]"
mode="index-div-quicklinks">
<xsl:with-param name="position" select="position()"/>
<xsl:with-param name="scope" select="$scope"/>
<xsl:with-param name="role" select="$role"/>
<xsl:with-param name="type" select="$type"/>
<xsl:sort select="translate(&primary;, &lowercase;, &uppercase;)"/>
</xsl:apply-templates>
</p>
<!-- pgsql-docs: end added stuff -->
<xsl:if test="$others">
<xsl:choose>
<xsl:when test="normalize-space($type) != '' and
$others[@type = $type][count(.|key('primary', &primary;)[&scope;][1]) = 1]">
<!-- pgsql-docs: added id attribute here for linking to it -->
<div class="indexdiv" id="indexdiv-Symbols">
<h3>
<xsl:call-template name="gentext">
<xsl:with-param name="key" select="'index symbols'"/>
</xsl:call-template>
</h3>
<dl>
<xsl:apply-templates select="$others[count(.|key('primary', &primary;)[&scope;][1]) = 1]"
mode="index-symbol-div">
<xsl:with-param name="position" select="position()"/>
<xsl:with-param name="scope" select="$scope"/>
<xsl:with-param name="role" select="$role"/>
<xsl:with-param name="type" select="$type"/>
<xsl:sort select="translate(&primary;, &lowercase;, &uppercase;)"/>
</xsl:apply-templates>
</dl>
</div>
</xsl:when>
<xsl:when test="normalize-space($type) != ''">
<!-- Output nothing, as there isn't a match for $other using this $type -->
</xsl:when>
<xsl:otherwise>
<!-- pgsql-docs: added id attribute here for linking to it -->
<div class="indexdiv" id="indexdiv-Symbols">
<h3>
<xsl:call-template name="gentext">
<xsl:with-param name="key" select="'index symbols'"/>
</xsl:call-template>
</h3>
<dl>
<xsl:apply-templates select="$others[count(.|key('primary',
&primary;)[&scope;][1]) = 1]"
mode="index-symbol-div">
<xsl:with-param name="position" select="position()"/>
<xsl:with-param name="scope" select="$scope"/>
<xsl:with-param name="role" select="$role"/>
<xsl:with-param name="type" select="$type"/>
<xsl:sort select="translate(&primary;, &lowercase;, &uppercase;)"/>
</xsl:apply-templates>
</dl>
</div>
</xsl:otherwise>
</xsl:choose>
</xsl:if>
<xsl:apply-templates select="$alphabetical[count(.|key('letter',
translate(substring(&primary;, 1, 1),
&lowercase;,&uppercase;))[&scope;][1]) = 1]"
mode="index-div-basic">
<xsl:with-param name="position" select="position()"/>
<xsl:with-param name="scope" select="$scope"/>
<xsl:with-param name="role" select="$role"/>
<xsl:with-param name="type" select="$type"/>
<xsl:sort select="translate(&primary;, &lowercase;, &uppercase;)"/>
</xsl:apply-templates>
</div>
</xsl:template>
<xsl:template match="indexterm" mode="index-div-basic">
<xsl:param name="scope" select="."/>
<xsl:param name="role" select="''"/>
<xsl:param name="type" select="''"/>
<xsl:variable name="key"
select="translate(substring(&primary;, 1, 1),
&lowercase;,&uppercase;)"/>
<xsl:if test="key('letter', $key)[&scope;]
[count(.|key('primary', &primary;)[&scope;][1]) = 1]">
<div class="indexdiv">
<!-- pgsql-docs: added id attribute here for linking to it -->
<xsl:attribute name="id">
<xsl:value-of select="concat('indexdiv-', $key)"/>
</xsl:attribute>
<xsl:if test="contains(concat(&lowercase;, &uppercase;), $key)">
<h3>
<xsl:value-of select="translate($key, &lowercase;, &uppercase;)"/>
</h3>
</xsl:if>
<dl>
<xsl:apply-templates select="key('letter', $key)[&scope;]
[count(.|key('primary', &primary;)
[&scope;][1])=1]"
mode="index-primary">
<xsl:with-param name="position" select="position()"/>
<xsl:with-param name="scope" select="$scope"/>
<xsl:with-param name="role" select="$role"/>
<xsl:with-param name="type" select="$type"/>
<xsl:sort select="translate(&primary;, &lowercase;, &uppercase;)"/>
</xsl:apply-templates>
</dl>
</div>
</xsl:if>
</xsl:template>
<!-- pgsql-docs -->
<xsl:template match="indexterm" mode="index-div-quicklinks">
<xsl:param name="scope" select="."/>
<xsl:param name="role" select="''"/>
<xsl:param name="type" select="''"/>
<xsl:variable name="key"
select="translate(substring(&primary;, 1, 1),
&lowercase;,&uppercase;)"/>
<xsl:if test="key('letter', $key)[&scope;]
[count(.|key('primary', &primary;)[&scope;][1]) = 1]">
<xsl:if test="contains(concat(&lowercase;, &uppercase;), $key)">
|
<a>
<xsl:attribute name="href">
<xsl:value-of select="concat('#indexdiv-', $key)"/>
</xsl:attribute>
<xsl:value-of select="translate($key, &lowercase;, &uppercase;)"/>
</a>
</xsl:if>
</xsl:if>
</xsl:template>
<!-- upper case HTML anchors for backward compatibility -->
<xsl:template name="object.id">
<xsl:param name="object" select="."/>
<xsl:choose>
<xsl:when test="$object/@id">
<xsl:value-of select="translate($object/@id, &lowercase;, &uppercase;)"/>
</xsl:when>
<xsl:when test="$object/@xml:id">
<xsl:value-of select="$object/@xml:id"/>
</xsl:when>
<xsl:when test="$generate.consistent.ids != 0">
<!-- Make $object the current node -->
<xsl:for-each select="$object">
<xsl:text>id-</xsl:text>
<xsl:number level="multiple" count="*"/>
</xsl:for-each>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="generate-id($object)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>

View File

@@ -1,23 +0,0 @@
<?xml version='1.0'?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version='1.0'
xmlns="http://www.w3.org/TR/xhtml1/transitional"
exclude-result-prefixes="#default">
<xsl:import href="http://docbook.sourceforge.net/release/xsl/current/xhtml/docbook.xsl"/>
<xsl:include href="stylesheet-common.xsl" />
<xsl:include href="stylesheet-html-common.xsl" />
<xsl:include href="stylesheet-speedup-xhtml.xsl" />
<!-- embed SVG images into output file -->
<xsl:template match="imagedata[@format='SVG']">
<xsl:variable name="filename">
<xsl:call-template name="mediaobject.filename">
<xsl:with-param name="object" select=".."/>
</xsl:call-template>
</xsl:variable>
<xsl:copy-of select="document($filename)"/>
</xsl:template>
</xsl:stylesheet>

View File

@@ -1,100 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version='1.0'>
<!-- Performance-optimized versions of some upstream templates from common/
directory -->
<!-- from common/labels.xsl -->
<xsl:template match="chapter" mode="label.markup">
<xsl:choose>
<xsl:when test="@label">
<xsl:value-of select="@label"/>
</xsl:when>
<xsl:when test="string($chapter.autolabel) != 0">
<xsl:if test="$component.label.includes.part.label != 0 and
ancestor::part">
<xsl:variable name="part.label">
<xsl:apply-templates select="ancestor::part"
mode="label.markup"/>
</xsl:variable>
<xsl:if test="$part.label != ''">
<xsl:value-of select="$part.label"/>
<xsl:apply-templates select="ancestor::part"
mode="intralabel.punctuation">
<xsl:with-param name="object" select="."/>
</xsl:apply-templates>
</xsl:if>
</xsl:if>
<xsl:variable name="format">
<xsl:call-template name="autolabel.format">
<xsl:with-param name="format" select="$chapter.autolabel"/>
</xsl:call-template>
</xsl:variable>
<xsl:choose>
<xsl:when test="$label.from.part != 0 and ancestor::part">
<xsl:number from="part" count="chapter" format="{$format}" level="any"/>
</xsl:when>
<xsl:otherwise>
<!-- Optimization for pgsql-docs: When counting to get label for
this chapter, preceding chapters can only be our siblings or
children of a preceding part, so only count those instead of
scanning the entire node tree. -->
<!-- <xsl:number from="book" count="chapter" format="{$format}" level="any"/> -->
<xsl:number value="count(../preceding-sibling::part/chapter) + count(preceding-sibling::chapter) + 1" format="{$format}"/>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
</xsl:choose>
</xsl:template>
<xsl:template match="appendix" mode="label.markup">
<xsl:choose>
<xsl:when test="@label">
<xsl:value-of select="@label"/>
</xsl:when>
<xsl:when test="string($appendix.autolabel) != 0">
<xsl:if test="$component.label.includes.part.label != 0 and
ancestor::part">
<xsl:variable name="part.label">
<xsl:apply-templates select="ancestor::part"
mode="label.markup"/>
</xsl:variable>
<xsl:if test="$part.label != ''">
<xsl:value-of select="$part.label"/>
<xsl:apply-templates select="ancestor::part"
mode="intralabel.punctuation">
<xsl:with-param name="object" select="."/>
</xsl:apply-templates>
</xsl:if>
</xsl:if>
<xsl:variable name="format">
<xsl:call-template name="autolabel.format">
<xsl:with-param name="format" select="$appendix.autolabel"/>
</xsl:call-template>
</xsl:variable>
<xsl:choose>
<xsl:when test="$label.from.part != 0 and ancestor::part">
<xsl:number from="part" count="appendix" format="{$format}" level="any"/>
</xsl:when>
<xsl:otherwise>
<!-- Optimization for pgsql-docs: When counting to get label for
this appendix, preceding appendixes can only be our siblings or
children of a preceding part, so only count those instead of
scanning the entire node tree. -->
<!-- <xsl:number from="book|article" count="appendix" format="{$format}" level="any"/> -->
<xsl:number value="count(../preceding-sibling::part/appendix) + count(preceding-sibling::appendix) + 1" format="{$format}"/>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
</xsl:choose>
</xsl:template>
<!-- from common/l10n.xsl -->
<!-- Just hardcode the language for the whole document, to make it faster. -->
<xsl:template name="l10n.language">en</xsl:template>
</xsl:stylesheet>

View File

@@ -1,345 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://www.w3.org/1999/xhtml"
version='1.0'>
<!-- Performance-optimized versions of some upstream templates from xhtml/
directory -->
<!-- from xhtml/autoidx.xsl -->
<xsl:template match="indexterm" mode="reference">
<xsl:param name="scope" select="."/>
<xsl:param name="role" select="''"/>
<xsl:param name="type" select="''"/>
<xsl:param name="position"/>
<xsl:param name="separator" select="''"/>
<xsl:variable name="term.separator">
<xsl:call-template name="index.separator">
<xsl:with-param name="key" select="'index.term.separator'"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="number.separator">
<xsl:call-template name="index.separator">
<xsl:with-param name="key" select="'index.number.separator'"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="range.separator">
<xsl:call-template name="index.separator">
<xsl:with-param name="key" select="'index.range.separator'"/>
</xsl:call-template>
</xsl:variable>
<xsl:choose>
<xsl:when test="$separator != ''">
<xsl:value-of select="$separator"/>
</xsl:when>
<xsl:when test="$position = 1">
<xsl:value-of select="$term.separator"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$number.separator"/>
</xsl:otherwise>
</xsl:choose>
<xsl:choose>
<xsl:when test="@zone and string(@zone)">
<xsl:call-template name="reference">
<xsl:with-param name="zones" select="normalize-space(@zone)"/>
<xsl:with-param name="position" select="position()"/>
<xsl:with-param name="scope" select="$scope"/>
<xsl:with-param name="role" select="$role"/>
<xsl:with-param name="type" select="$type"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<a>
<xsl:apply-templates select="." mode="class.attribute"/>
<xsl:variable name="title">
<xsl:choose>
<xsl:when test="$index.prefer.titleabbrev != 0">
<xsl:apply-templates select="(ancestor-or-self::set|ancestor-or-self::book|ancestor-or-self::part|ancestor-or-self::reference|ancestor-or-self::partintro|ancestor-or-self::chapter|ancestor-or-self::appendix|ancestor-or-self::preface|ancestor-or-self::article|ancestor-or-self::section|ancestor-or-self::sect1|ancestor-or-self::sect2|ancestor-or-self::sect3|ancestor-or-self::sect4|ancestor-or-self::sect5|ancestor-or-self::refentry|ancestor-or-self::refsect1|ancestor-or-self::refsect2|ancestor-or-self::refsect3|ancestor-or-self::simplesect|ancestor-or-self::bibliography|ancestor-or-self::glossary|ancestor-or-self::index|ancestor-or-self::webpage|ancestor-or-self::topic)[last()]" mode="titleabbrev.markup"/>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="(ancestor-or-self::set|ancestor-or-self::book|ancestor-or-self::part|ancestor-or-self::reference|ancestor-or-self::partintro|ancestor-or-self::chapter|ancestor-or-self::appendix|ancestor-or-self::preface|ancestor-or-self::article|ancestor-or-self::section|ancestor-or-self::sect1|ancestor-or-self::sect2|ancestor-or-self::sect3|ancestor-or-self::sect4|ancestor-or-self::sect5|ancestor-or-self::refentry|ancestor-or-self::refsect1|ancestor-or-self::refsect2|ancestor-or-self::refsect3|ancestor-or-self::simplesect|ancestor-or-self::bibliography|ancestor-or-self::glossary|ancestor-or-self::index|ancestor-or-self::webpage|ancestor-or-self::topic)[last()]" mode="title.markup"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:attribute name="href">
<xsl:choose>
<xsl:when test="$index.links.to.section = 1">
<xsl:call-template name="href.target">
<xsl:with-param name="object" select="(ancestor-or-self::set|ancestor-or-self::book|ancestor-or-self::part|ancestor-or-self::reference|ancestor-or-self::partintro|ancestor-or-self::chapter|ancestor-or-self::appendix|ancestor-or-self::preface|ancestor-or-self::article|ancestor-or-self::section|ancestor-or-self::sect1|ancestor-or-self::sect2|ancestor-or-self::sect3|ancestor-or-self::sect4|ancestor-or-self::sect5|ancestor-or-self::refentry|ancestor-or-self::refsect1|ancestor-or-self::refsect2|ancestor-or-self::refsect3|ancestor-or-self::simplesect|ancestor-or-self::bibliography|ancestor-or-self::glossary|ancestor-or-self::index|ancestor-or-self::webpage|ancestor-or-self::topic)[last()]"/>
<!-- Optimization for pgsql-docs: We only have an index as a
child of book, so look that up directly instead of
scanning the entire node tree. Also, don't look for
setindex. -->
<!-- <xsl:with-param name="context" select="(//index[count(ancestor::node()|$scope) = count(ancestor::node()) and ($role = @role or $type = @type or (string-length($role) = 0 and string-length($type) = 0))] | //setindex[count(ancestor::node()|$scope) = count(ancestor::node()) and ($role = @role or $type = @type or (string-length($role) = 0 and string-length($type) = 0))])[1]"/> -->
<xsl:with-param name="context" select="(/book/index[count(ancestor::node()|$scope) = count(ancestor::node()) and ($role = @role or $type = @type or (string-length($role) = 0 and string-length($type) = 0))])[1]"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="href.target">
<xsl:with-param name="object" select="."/>
<xsl:with-param name="context" select="(//index[count(ancestor::node()|$scope) = count(ancestor::node()) and ($role = @role or $type = @type or (string-length($role) = 0 and string-length($type) = 0))] | //setindex[count(ancestor::node()|$scope) = count(ancestor::node()) and ($role = @role or $type = @type or (string-length($role) = 0 and string-length($type) = 0))])[1]"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
<xsl:value-of select="$title"/> <!-- text only -->
</a>
<xsl:variable name="id" select="(@id|@xml:id)[1]"/>
<xsl:if test="key('endofrange', $id)[count(ancestor::node()|$scope) = count(ancestor::node()) and ($role = @role or $type = @type or (string-length($role) = 0 and string-length($type) = 0))]">
<xsl:apply-templates select="key('endofrange', $id)[count(ancestor::node()|$scope) = count(ancestor::node()) and ($role = @role or $type = @type or (string-length($role) = 0 and string-length($type) = 0))][last()]" mode="reference">
<xsl:with-param name="position" select="position()"/>
<xsl:with-param name="scope" select="$scope"/>
<xsl:with-param name="role" select="$role"/>
<xsl:with-param name="type" select="$type"/>
<xsl:with-param name="separator" select="$range.separator"/>
</xsl:apply-templates>
</xsl:if>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="reference">
<xsl:param name="scope" select="."/>
<xsl:param name="role" select="''"/>
<xsl:param name="type" select="''"/>
<xsl:param name="zones"/>
<xsl:choose>
<xsl:when test="contains($zones, ' ')">
<xsl:variable name="zone" select="substring-before($zones, ' ')"/>
<xsl:variable name="target" select="key('sections', $zone)"/>
<a>
<xsl:apply-templates select="." mode="class.attribute"/>
<!-- Optimization for pgsql-docs: this call adds nothing but fails with docbook-xsl 1.76 -->
<!-- <xsl:call-template name="id.attribute"/> -->
<xsl:attribute name="href">
<xsl:call-template name="href.target">
<xsl:with-param name="object" select="$target[1]"/>
<xsl:with-param name="context" select="//index[count(ancestor::node()|$scope) = count(ancestor::node()) and ($role = @role or $type = @type or (string-length($role) = 0 and string-length($type) = 0))][1]"/>
</xsl:call-template>
</xsl:attribute>
<xsl:apply-templates select="$target[1]" mode="index-title-content"/>
</a>
<xsl:text>, </xsl:text>
<xsl:call-template name="reference">
<xsl:with-param name="zones" select="substring-after($zones, ' ')"/>
<xsl:with-param name="position" select="position()"/>
<xsl:with-param name="scope" select="$scope"/>
<xsl:with-param name="role" select="$role"/>
<xsl:with-param name="type" select="$type"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="zone" select="$zones"/>
<xsl:variable name="target" select="key('sections', $zone)"/>
<a>
<xsl:apply-templates select="." mode="class.attribute"/>
<!-- Optimization for pgsql-docs: this call adds nothing but fails with docbook-xsl 1.76 -->
<!-- <xsl:call-template name="id.attribute"/> -->
<xsl:attribute name="href">
<xsl:call-template name="href.target">
<xsl:with-param name="object" select="$target[1]"/>
<!-- Optimization for pgsql-docs: Only look for index under book
instead of searching the whole node tree. -->
<!-- <xsl:with-param name="context" select="//index[count(ancestor::node()|$scope) = count(ancestor::node()) and ($role = @role or $type = @type or (string-length($role) = 0 and string-length($type) = 0))][1]"/> -->
<xsl:with-param name="context" select="/book/index[count(ancestor::node()|$scope) = count(ancestor::node()) and ($role = @role or $type = @type or (string-length($role) = 0 and string-length($type) = 0))][1]"/>
</xsl:call-template>
</xsl:attribute>
<xsl:apply-templates select="$target[1]" mode="index-title-content"/>
</a>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!-- from xhtml/chunk-common.xsl -->
<xsl:template name="chunk-all-sections">
<xsl:param name="content">
<xsl:apply-imports/>
</xsl:param>
<!-- Optimization for pgsql-docs: Since we set a fixed $chunk.section.depth,
we can do away with a bunch of complicated XPath searches for the
previous and next sections at various levels. -->
<xsl:if test="$chunk.section.depth != 1">
<xsl:message terminate="yes">
<xsl:text>Error: If you change $chunk.section.depth, then you must update the performance-optimized chunk-all-sections-template.</xsl:text>
</xsl:message>
</xsl:if>
<xsl:variable name="prev"
select="(preceding::book[1]
|preceding::preface[1]
|preceding::chapter[1]
|preceding::appendix[1]
|preceding::part[1]
|preceding::reference[1]
|preceding::refentry[1]
|preceding::colophon[1]
|preceding::article[1]
|preceding::topic[1]
|preceding::bibliography[parent::article or parent::book or parent::part][1]
|preceding::glossary[parent::article or parent::book or parent::part][1]
|preceding::index[$generate.index != 0]
[parent::article or parent::book or parent::part][1]
|preceding::setindex[$generate.index != 0][1]
|ancestor::set
|ancestor::book[1]
|ancestor::preface[1]
|ancestor::chapter[1]
|ancestor::appendix[1]
|ancestor::part[1]
|ancestor::reference[1]
|ancestor::article[1]
|ancestor::topic[1]
|preceding::sect1[1]
|ancestor::sect1[1])[last()]"/>
<xsl:variable name="next"
select="(following::book[1]
|following::preface[1]
|following::chapter[1]
|following::appendix[1]
|following::part[1]
|following::reference[1]
|following::refentry[1]
|following::colophon[1]
|following::bibliography[parent::article or parent::book or parent::part][1]
|following::glossary[parent::article or parent::book or parent::part][1]
|following::index[$generate.index != 0]
[parent::article or parent::book][1]
|following::article[1]
|following::topic[1]
|following::setindex[$generate.index != 0][1]
|descendant::book[1]
|descendant::preface[1]
|descendant::chapter[1]
|descendant::appendix[1]
|descendant::article[1]
|descendant::topic[1]
|descendant::bibliography[parent::article or parent::book][1]
|descendant::glossary[parent::article or parent::book or parent::part][1]
|descendant::index[$generate.index != 0]
[parent::article or parent::book][1]
|descendant::colophon[1]
|descendant::setindex[$generate.index != 0][1]
|descendant::part[1]
|descendant::reference[1]
|descendant::refentry[1]
|following::sect1[1]
|descendant::sect1[1])[1]"/>
<xsl:call-template name="process-chunk">
<xsl:with-param name="prev" select="$prev"/>
<xsl:with-param name="next" select="$next"/>
<xsl:with-param name="content" select="$content"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="href.target">
<xsl:param name="context" select="."/>
<xsl:param name="object" select="."/>
<xsl:param name="toc-context" select="."/>
<!-- Optimization for pgsql-docs: Remove support for dbhtml processing
instruction here -->
<xsl:variable name="href.to.uri">
<xsl:call-template name="href.target.uri">
<xsl:with-param name="object" select="$object"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="href.from.uri">
<xsl:choose>
<xsl:when test="not($toc-context = .)">
<xsl:call-template name="href.target.uri">
<xsl:with-param name="object" select="$toc-context"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="href.target.uri">
<xsl:with-param name="object" select="$context"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="href.to">
<xsl:value-of select="$href.to.uri"/>
</xsl:variable>
<xsl:variable name="href.from">
<xsl:call-template name="trim.common.uri.paths">
<xsl:with-param name="uriA" select="$href.to.uri"/>
<xsl:with-param name="uriB" select="$href.from.uri"/>
<xsl:with-param name="return" select="'B'"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="depth">
<xsl:call-template name="count.uri.path.depth">
<xsl:with-param name="filename" select="$href.from"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="href">
<xsl:call-template name="copy-string">
<xsl:with-param name="string" select="'../'"/>
<xsl:with-param name="count" select="$depth"/>
</xsl:call-template>
<xsl:value-of select="$href.to"/>
</xsl:variable>
<xsl:value-of select="$href"/>
</xsl:template>
<xsl:template name="html.head">
<xsl:param name="prev" select="/foo"/>
<xsl:param name="next" select="/foo"/>
<!-- Optimization for pgsql-docs: Cut out a bunch of things we don't need
here, including an expensive //legalnotice search. -->
<head>
<xsl:call-template name="system.head.content"/>
<xsl:call-template name="head.content"/>
<xsl:if test="$prev">
<link rel="prev">
<xsl:attribute name="href">
<xsl:call-template name="href.target">
<xsl:with-param name="object" select="$prev"/>
</xsl:call-template>
</xsl:attribute>
<xsl:attribute name="title">
<xsl:apply-templates select="$prev" mode="object.title.markup.textonly"/>
</xsl:attribute>
</link>
</xsl:if>
<xsl:if test="$next">
<link rel="next">
<xsl:attribute name="href">
<xsl:call-template name="href.target">
<xsl:with-param name="object" select="$next"/>
</xsl:call-template>
</xsl:attribute>
<xsl:attribute name="title">
<xsl:apply-templates select="$next" mode="object.title.markup.textonly"/>
</xsl:attribute>
</link>
</xsl:if>
<xsl:call-template name="user.head.content"/>
</head>
</xsl:template>
</xsl:stylesheet>

View File

@@ -1,471 +1,96 @@
/* PostgreSQL.org Documentation Style */
/* doc/src/sgml/stylesheet.css */
@import 'website-docs.css';
/* color scheme similar to www.postgresql.org */
/* requires global.css, table.css and text.css to be loaded before this file! */
body {
font-family: verdana, sans-serif;
font-size: 76%;
background: url("/resources/background.png") repeat-x scroll left top transparent;
padding: 15px 4%;
margin: 0;
BODY {
color: #000000;
background: #FFFFFF;
font-family: verdana, sans-serif;
}
/* monospace font size fix */
pre, code, kbd, samp, tt {
font-family: monospace,monospace;
font-size: 1em;
}
div.NAVHEADER table {
margin-left: 0;
}
/* Container Definitions */
#docContainerWrap {
text-align: center; /* Win IE5 */
}
#docContainer {
margin: 0 auto;
width: 90%;
padding-bottom: 2em;
display: block;
text-align: left; /* Win IE5 */
}
#docHeader {
background-image: url("/media/img/docs/bg_hdr.png");
height: 83px;
margin: 0px;
padding: 0px;
display: block;
}
#docHeaderLogo {
position: relative;
width: 206px;
height: 83px;
border: 0px;
padding: 0px;
margin: 0 0 0 20px;
}
#docHeaderLogo img {
border: 0px;
}
#docNavSearchContainer {
padding-bottom: 2px;
}
#docNav, #docVersions {
position: relative;
text-align: left;
margin-left: 10px;
margin-top: 5px;
color: #666;
font-size: 0.95em;
}
#docSearch {
position: relative;
text-align: right;
padding: 0;
margin: 0;
color: #666;
}
#docTextSize {
text-align: right;
white-space: nowrap;
margin-top: 7px;
font-size: 0.95em;
}
#docSearch form {
position: relative;
top: 5px;
right: 0;
margin: 0; /* need for IE 5.5 OSX */
text-align: right; /* need for IE 5.5 OSX */
white-space: nowrap; /* for Opera */
}
#docSearch form label {
color: #666;
font-size: 0.95em;
}
#docSearch form input {
font-size: 0.95em;
}
#docSearch form #submit {
font-size: 0.95em;
background: #7A7A7A;
color: #fff;
border: 1px solid #7A7A7A;
padding: 1px 4px;
}
#docSearch form #q {
width: 170px;
font-size: 0.95em;
border: 1px solid #7A7A7A;
background: #E1E1E1;
color: #000000;
padding: 2px;
}
.frmDocSearch {
padding: 0;
margin: 0;
display: inline;
}
.inpDocSearch {
padding: 0;
margin: 0;
color: #000;
}
#docContent {
position: relative;
margin-left: 10px;
margin-right: 10px;
margin-top: 40px;
}
#docFooter {
position: relative;
font-size: 0.9em;
color: #666;
line-height: 1.3em;
margin-left: 10px;
margin-right: 10px;
}
#docComments {
margin-top: 10px;
}
#docClear {
clear: both;
margin: 0;
padding: 0;
}
/* Heading Definitions */
h1, h2, h3 {
font-weight: bold;
margin-top: 2ex;
color: #444;
}
h1 {
font-size: 1.4em;
}
h2 {
font-size: 1.2em !important;
}
h3 {
font-size: 1.1em;
}
h1 a:hover,
h2 a:hover,
h3 a:hover,
h4 a:hover {
color: #444;
text-decoration: none;
}
/* Text Styles */
div.SECT2 {
margin-top: 4ex;
}
div.SECT3 {
margin-top: 3ex;
margin-left: 3ex;
}
.txtCurrentLocation {
font-weight: bold;
}
A:link { color:#0066A2; }
A:visited { color:#004E66; }
A:active { color:#0066A2; }
A:hover { color:#000000; }
p, ol, ul, li {
line-height: 1.5em;
H1 {
font-size: 1.4em;
font-weight: bold;
margin-top: 0em;
margin-bottom: 0em;
color: #EC5800;
}
.txtCommentsWrap {
border: 2px solid #F5F5F5;
width: 100%;
H2 {
font-size: 1.2em;
margin: 1.2em 0em 1.2em 0em;
font-weight: bold;
color: #666;
}
.txtCommentsContent {
background: #F5F5F5;
padding: 3px;
H3 {
font-size: 1.1em;
margin: 1.2em 0em 1.2em 0em;
font-weight: bold;
color: #666;
}
.txtCommentsPoster {
float: left;
H4 {
font-size: 0.95em;
margin: 1.2em 0em 1.2em 0em;
font-weight: normal;
color: #666;
}
.txtCommentsDate {
float: right;
H5 {
font-size: 0.9em;
margin: 1.2em 0em 1.2em 0em;
font-weight: normal;
}
.txtCommentsComment {
padding: 3px;
H6 {
font-size: 0.85em;
margin: 1.2em 0em 1.2em 0em;
font-weight: normal;
}
#docContainer pre code,
#docContainer pre tt,
#docContainer pre pre,
#docContainer tt tt,
#docContainer tt code,
#docContainer tt pre {
font-size: 1em;
}
/* center some titles */
pre.LITERALLAYOUT,
.SCREEN,
.SYNOPSIS,
.PROGRAMLISTING,
.REFSYNOPSISDIV p,
table.CAUTION,
table.WARNING,
blockquote.NOTE,
blockquote.TIP,
table.CALSTABLE {
-moz-box-shadow: 3px 3px 5px #DFDFDF;
-webkit-box-shadow: 3px 3px 5px #DFDFDF;
-khtml-box-shadow: 3px 3px 5px #DFDFDF;
-o-box-shadow: 3px 3px 5px #DFDFDF;
box-shadow: 3px 3px 5px #DFDFDF;
.BOOK .TITLE, .BOOK .CORPAUTHOR, .BOOK .COPYRIGHT {
text-align: center;
}
pre.LITERALLAYOUT,
.SCREEN,
.SYNOPSIS,
.PROGRAMLISTING,
.REFSYNOPSISDIV p,
table.CAUTION,
table.WARNING,
blockquote.NOTE,
blockquote.TIP {
color: black;
border-width: 1px;
border-style: solid;
padding: 2ex;
margin: 2ex 0 2ex 2ex;
overflow: auto;
-moz-border-radius: 8px;
-webkit-border-radius: 8px;
-khtml-border-radius: 8px;
border-radius: 8px;
}
/* decoration for formal examples */
pre.LITERALLAYOUT,
pre.SYNOPSIS,
pre.PROGRAMLISTING,
.REFSYNOPSISDIV p,
.SCREEN {
border-color: #CFCFCF;
background-color: #F7F7F7;
DIV.EXAMPLE {
padding-left: 15px;
border-style: solid;
border-width: 0px;
border-left-width: 2px;
border-color: black;
margin: 0.5ex;
}
blockquote.NOTE,
blockquote.TIP {
border-color: #DBDBCC;
background-color: #EEEEDD;
padding: 14px;
width: 572px;
}
/* less dense spacing of TOC */
blockquote.NOTE,
blockquote.TIP,
table.CAUTION,
table.WARNING {
margin: 4ex auto;
.BOOK .TOC DL DT {
padding-top: 1.5ex;
padding-bottom: 1.5ex;
}
blockquote.NOTE p,
blockquote.TIP p {
margin: 0;
.BOOK .TOC DL DL DT {
padding-top: 0ex;
padding-bottom: 0ex;
}
blockquote.NOTE pre,
blockquote.NOTE code,
blockquote.TIP pre,
blockquote.TIP code {
margin-left: 0;
margin-right: 0;
-moz-box-shadow: none;
-webkit-box-shadow: none;
-khtml-box-shadow: none;
-o-box-shadow: none;
box-shadow: none;
}
/* miscellaneous */
.emphasis,
.c2 {
font-weight: bold;
PRE.LITERALLAYOUT, .SCREEN, .SYNOPSIS, .PROGRAMLISTING {
margin-left: 4ex;
}
.REPLACEABLE {
font-style: italic;
}
/* Table Styles */
table {
margin-left: 2ex;
}
table.CALSTABLE td,
table.CALSTABLE th,
table.CAUTION td,
table.CAUTION th,
table.WARNING td,
table.WARNING th {
border-style: solid;
}
table.CALSTABLE,
table.CAUTION,
table.WARNING {
border-spacing: 0;
border-collapse: collapse;
}
table.CALSTABLE
{
margin: 2ex 0 2ex 2ex;
background-color: #E0ECEF;
border: 2px solid #A7C6DF;
}
table.CALSTABLE tr:hover td
{
background-color: #EFEFEF;
}
table.CALSTABLE td {
background-color: #FFF;
}
table.CALSTABLE td,
table.CALSTABLE th {
border: 1px solid #A7C6DF;
padding: 0.5ex 0.5ex;
}
table.CAUTION,
table.WARNING {
border-collapse: separate;
display: block;
padding: 0;
max-width: 600px;
}
table.CAUTION {
background-color: #F5F5DC;
border-color: #DEDFA7;
}
table.WARNING {
background-color: #FFD7D7;
border-color: #DF421E;
}
.COMMENT { color: red; }
table.CAUTION td,
table.CAUTION th,
table.WARNING td,
table.WARNING th {
border-width: 0;
padding-left: 2ex;
padding-right: 2ex;
}
table.CAUTION td,
table.CAUTION th {
border-color: #F3E4D5
}
table.WARNING td,
table.WARNING th {
border-color: #FFD7D7;
}
td.c1,
td.c2,
td.c3,
td.c4,
td.c5,
td.c6 {
font-size: 1.1em;
font-weight: bold;
border-bottom: 0px solid #FFEFEF;
padding: 1ex 2ex 0;
}
/* Link Styles */
#docNav a {
font-weight: bold;
}
a:link,
a:visited,
a:active,
a:hover {
text-decoration: underline;
}
a:link,
a:active {
color:#0066A2;
}
a:visited {
color:#004E66;
}
a:hover {
color:#000000;
}
#docFooter a:link,
#docFooter a:visited,
#docFooter a:active {
color:#666;
}
#docContainer code.FUNCTION tt {
font-size: 1em;
}
div.header {
color: #444;
margin-top: 5px;
}
div.footer {
text-align: center;
background-image: url("/resources/footerl.png"), url("/resources/footerr.png"), url("/resources/footerc.png");
background-position: left top, right top, center top;
background-repeat: no-repeat, no-repeat, repeat-x;
padding-top: 45px;
}
img {
border-style: none;
}
VAR { font-family: monospace; font-style: italic; }
/* Konqueror's standard style for ACRONYM is italic. */
ACRONYM { font-style: inherit; }

View File

@@ -1,174 +0,0 @@
<?xml version='1.0'?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version='1.0'
xmlns="http://www.w3.org/TR/xhtml1/transitional"
exclude-result-prefixes="#default">
<xsl:import href="http://docbook.sourceforge.net/release/xsl/current/xhtml/chunk.xsl"/>
<xsl:include href="stylesheet-common.xsl" />
<xsl:include href="stylesheet-html-common.xsl" />
<xsl:include href="stylesheet-speedup-xhtml.xsl" />
<!-- Parameters -->
<xsl:param name="base.dir" select="'html/'"></xsl:param>
<xsl:param name="use.id.as.filename" select="'1'"></xsl:param>
<xsl:param name="generate.legalnotice.link" select="1"></xsl:param>
<xsl:param name="chunk.first.sections" select="1"/>
<xsl:param name="chunk.quietly" select="1"></xsl:param>
<xsl:param name="admon.style"></xsl:param> <!-- handled by CSS stylesheet -->
<xsl:param name="website.stylesheet" select="0"/>
<xsl:param name="html.stylesheet">
<xsl:choose>
<xsl:when test="$website.stylesheet = 0">stylesheet.css</xsl:when>
<xsl:otherwise>https://www.postgresql.org/media/css/docs.css</xsl:otherwise>
</xsl:choose>
</xsl:param>
<!-- strip directory name from image filerefs -->
<xsl:template match="imagedata/@fileref">
<xsl:value-of select="substring-after(., '/')"/>
</xsl:template>
<!--
Customization of header
- add Up and Home links
- add tool tips to links
(overrides html/chunk-common.xsl)
-->
<xsl:template name="header.navigation">
<xsl:param name="prev" select="/foo"/>
<xsl:param name="next" select="/foo"/>
<xsl:param name="nav.context"/>
<xsl:variable name="home" select="/*[1]"/>
<xsl:variable name="up" select="parent::*"/>
<xsl:variable name="row1" select="$navig.showtitles != 0"/>
<xsl:variable name="row2" select="count($prev) &gt; 0
or (count($up) &gt; 0
and generate-id($up) != generate-id($home)
and $navig.showtitles != 0)
or count($next) &gt; 0"/>
<xsl:if test="$suppress.navigation = '0' and $suppress.header.navigation = '0'">
<div class="navheader">
<xsl:if test="$row1 or $row2">
<table width="100%" summary="Navigation header">
<xsl:if test="$row1">
<tr>
<th colspan="5" align="center">
<xsl:apply-templates select="." mode="object.title.markup"/>
</th>
</tr>
</xsl:if>
<xsl:if test="$row2">
<tr>
<td width="10%" align="{$direction.align.start}">
<xsl:if test="count($prev)>0">
<a accesskey="p">
<xsl:attribute name="href">
<xsl:call-template name="href.target">
<xsl:with-param name="object" select="$prev"/>
</xsl:call-template>
</xsl:attribute>
<xsl:attribute name="title">
<xsl:apply-templates select="$prev" mode="object.title.markup"/>
</xsl:attribute>
<xsl:call-template name="navig.content">
<xsl:with-param name="direction" select="'prev'"/>
</xsl:call-template>
</a>
</xsl:if>
<xsl:text>&#160;</xsl:text>
</td>
<td width="10%" align="{$direction.align.start}">
<xsl:choose>
<xsl:when test="count($up)&gt;0
and generate-id($up) != generate-id($home)">
<a accesskey="u">
<xsl:attribute name="href">
<xsl:call-template name="href.target">
<xsl:with-param name="object" select="$up"/>
</xsl:call-template>
</xsl:attribute>
<xsl:attribute name="title">
<xsl:apply-templates select="$up" mode="object.title.markup"/>
</xsl:attribute>
<xsl:call-template name="navig.content">
<xsl:with-param name="direction" select="'up'"/>
</xsl:call-template>
</a>
</xsl:when>
<xsl:otherwise>&#160;</xsl:otherwise>
</xsl:choose>
</td>
<th width="60%" align="center">
<xsl:choose>
<xsl:when test="count($up) > 0
and generate-id($up) != generate-id($home)
and $navig.showtitles != 0">
<xsl:apply-templates select="$up" mode="object.title.markup"/>
</xsl:when>
<xsl:otherwise>&#160;</xsl:otherwise>
</xsl:choose>
</th>
<td width="10%" align="{$direction.align.end}">
<xsl:choose>
<xsl:when test="$home != . or $nav.context = 'toc'">
<a accesskey="h">
<xsl:attribute name="href">
<xsl:call-template name="href.target">
<xsl:with-param name="object" select="$home"/>
</xsl:call-template>
</xsl:attribute>
<xsl:attribute name="title">
<xsl:apply-templates select="$home" mode="object.title.markup"/>
</xsl:attribute>
<xsl:call-template name="navig.content">
<xsl:with-param name="direction" select="'home'"/>
</xsl:call-template>
</a>
<xsl:if test="$chunk.tocs.and.lots != 0 and $nav.context != 'toc'">
<xsl:text>&#160;|&#160;</xsl:text>
</xsl:if>
</xsl:when>
<xsl:otherwise>&#160;</xsl:otherwise>
</xsl:choose>
</td>
<td width="10%" align="{$direction.align.end}">
<xsl:text>&#160;</xsl:text>
<xsl:if test="count($next)>0">
<a accesskey="n">
<xsl:attribute name="href">
<xsl:call-template name="href.target">
<xsl:with-param name="object" select="$next"/>
</xsl:call-template>
</xsl:attribute>
<xsl:attribute name="title">
<xsl:apply-templates select="$next" mode="object.title.markup"/>
</xsl:attribute>
<xsl:call-template name="navig.content">
<xsl:with-param name="direction" select="'next'"/>
</xsl:call-template>
</a>
</xsl:if>
</td>
</tr>
</xsl:if>
</table>
</xsl:if>
<xsl:if test="$header.rule != 0">
<hr/>
</xsl:if>
</div>
</xsl:if>
</xsl:template>
</xsl:stylesheet>

View File

@@ -1,10 +1,10 @@
<chapter id="performing-switchover" xreflabel="Performing a switchover with repmgr">
<title>Performing a switchover with repmgr</title>
<indexterm>
<primary>switchover</primary>
</indexterm>
<title>Performing a switchover with repmgr</title>
<para>
A typical use-case for replication is a combination of primary and standby
server, with the standby serving as a backup which can easily be activated
@@ -15,7 +15,7 @@
<para>
In some cases however it's desirable to promote the standby in a planned
way, e.g. so maintenance can be performed on the primary; this kind of switchover
is supported by the <xref linkend="repmgr-standby-switchover"/> command.
is supported by the <xref linkend="repmgr-standby-switchover"> command.
</para>
<para>
<command>repmgr standby switchover</command> differs from other &repmgr;
@@ -44,18 +44,17 @@
and capturing all output to assist troubleshooting any problems.
</simpara>
<simpara>
Please also read carefully the sections <xref linkend="preparing-for-switchover"/> and
<xref linkend="switchover-caveats"/> below.
Please also read carefully the sections <xref linkend="preparing-for-switchover"> and
<xref linkend="switchover-caveats"> below.
</simpara>
</note>
<sect1 id="preparing-for-switchover" xreflabel="Preparing for switchover">
<title>Preparing for switchover</title>
<indexterm>
<primary>switchover</primary>
<secondary>preparation</secondary>
</indexterm>
<title>Preparing for switchover</title>
<para>
As mentioned in the previous section, success of the switchover operation depends on
@@ -115,7 +114,7 @@
server.
</para>
<para>
For more details, see <xref linkend="configuration-file-service-commands"/>.
For more details, see <xref linkend="configuration-file-service-commands">.
</para>
</important>
@@ -160,12 +159,12 @@
<note>
<para>
From <link linkend="release-4.2">repmgr 4.2</link>, &repmgr; will instruct any running
&repmgrd; instances to pause operations while the switchover
is being carried out, to prevent &repmgrd; from
unintentionally promoting a node. For more details, see <xref linkend="repmgrd-pausing"/>.
<application>repmgrd</application> instances to pause operations while the switchover
is being carried out, to prevent <application>repmgrd</application> from
unintentionally promoting a node. For more details, see <xref linkend="repmgrd-pausing">.
</para>
<para>
Users of &repmgr; versions prior to 4.2 should ensure that &repmgrd;
Users of &repmgr; versions prior to 4.2 should ensure that <application>repmgrd</application>
is not running on any nodes while a switchover is being executed.
</para>
</note>
@@ -205,19 +204,18 @@
<note>
<simpara>
See <xref linkend="repmgr-standby-switchover"/> for a full list of available
See <xref linkend="repmgr-standby-switchover"> for a full list of available
command line options and <filename>repmgr.conf</filename> settings relevant
to performing a switchover.
</simpara>
</note>
<sect2 id="switchover-pg-rewind" xreflabel="Switchover and pg_rewind">
<title>Switchover and pg_rewind</title>
<sect2 id="switchover-pg-rewind" xreflabel="Switchover and pg_rewind">
<indexterm>
<primary>pg_rewind</primary>
<secondary>using with "repmgr standby switchover"</secondary>
</indexterm>
<title>Switchover and pg_rewind</title>
<para>
If the demotion candidate does not shut down smoothly or cleanly, there's a risk it
will have a slightly divergent timeline and will not be able to attach to the new
@@ -260,12 +258,11 @@
</sect1>
<sect1 id="switchover-execution" xreflabel="Executing the switchover command">
<title>Executing the switchover command</title>
<indexterm>
<primary>switchover</primary>
<secondary>execution</secondary>
</indexterm>
<title>Executing the switchover command</title>
<para>
To demonstrate switchover, we will assume a replication cluster with a
primary (<literal>node1</literal>) and one standby (<literal>node2</literal>);
@@ -316,15 +313,13 @@
</programlisting>
</para>
<para>
If &repmgrd; is in use, it's worth double-checking that
all nodes are unpaused by executing
<command><link linkend="repmgr-service-status">repmgr service status</link></command>
(&repmgr; 4.2 - 4.4: <command><link linkend="repmgr-service-status">repmgr daemon status</link></command>).
If <application>repmgrd</application> is in use, it's worth double-checking that
all nodes are unpaused by executing <command><link linkend="repmgr-daemon-status">repmgr-daemon-status</link></command>.
</para>
<note>
<para>
Users of &repmgr; versions prior to 4.2 will need to manually restart &repmgrd;
Users of &repmgr; versions prior to 4.2 will need to manually restart <application>repmgrd</application>
on all nodes after the switchover is completed.
</para>
</note>
@@ -333,11 +328,11 @@
<sect1 id="switchover-caveats" xreflabel="Caveats">
<title>Caveats</title>
<indexterm>
<primary>switchover</primary>
<secondary>caveats</secondary>
</indexterm>
<title>Caveats</title>
<para>
<itemizedlist spacing="compact" mark="bullet">
<listitem>
@@ -362,12 +357,11 @@
</sect1>
<sect1 id="switchover-troubleshooting" xreflabel="Troubleshooting">
<title>Troubleshooting switchover issues</title>
<indexterm>
<primary>switchover</primary>
<secondary>troubleshooting</secondary>
</indexterm>
<title>Troubleshooting switchover issues</title>
<para>
As <link linkend="performing-switchover">emphasised previously</link>, performing a switchover

View File

@@ -1,10 +1,10 @@
<chapter id="upgrading-repmgr" xreflabel="Upgrading repmgr">
<title>Upgrading repmgr</title>
<indexterm>
<primary>upgrading</primary>
</indexterm>
<title>Upgrading repmgr</title>
<para>
&repmgr; is updated regularly with minor releases (e.g. 4.0.1 to 4.0.2)
@@ -13,19 +13,18 @@
</para>
<sect1 id="upgrading-repmgr-extension" xreflabel="Upgrading repmgr 4.x and later">
<title>Upgrading repmgr 4.x and later</title>
<indexterm>
<primary>upgrading</primary>
<secondary>repmgr 4.x and later</secondary>
</indexterm>
<title>Upgrading repmgr 4.x and later</title>
<para>
From version 4, &repmgr; consists of three elements:
<itemizedlist spacing="compact" mark="bullet">
<listitem>
<simpara>
the <application>repmgr</application> and &repmgrd; executables
the <application>repmgr</application> and <application>repmgrd</application> executables
</simpara>
</listitem>
@@ -38,7 +37,7 @@
<listitem>
<simpara>
the shared library module used by &repmgrd; which
the shared library module used by <application>repmgrd</application> which
is resident in the PostgreSQL backend
</simpara>
</listitem>
@@ -46,8 +45,8 @@
</para>
<para>
With <emphasis>minor releases</emphasis>, usually changes are only made to the <application>repmgr</application>
and &repmgrd; executables. In this case, the upgrade is quite straightforward,
and is simply a case of installing the new version, and restarting &repmgrd;
and <application>repmgrd</application> executables. In this case, the upgrade is quite straightforward,
and is simply a case of installing the new version, and restarting <application>repmgrd</application>
(if running).
</para>
@@ -64,12 +63,11 @@
</important>
<sect2 id="upgrading-minor-version" xreflabel="Upgrading a minor version release">
<title>Upgrading a minor version release</title>
<indexterm>
<primary>upgrading</primary>
<secondary>minor release</secondary>
</indexterm>
<title>Upgrading a minor version release</title>
<para>
The process for installing minor version upgrades is quite straightforward:
@@ -84,7 +82,7 @@
<listitem>
<simpara>
restart &repmgrd; on all nodes where it is running
restart <application>repmgrd</application> on all nodes where it is running
</simpara>
</listitem>
@@ -95,7 +93,7 @@
<note>
<para>
Some packaging systems (e.g. <link linkend="packages-debian-ubuntu">Debian/Ubuntu</link>
may restart &repmgrd; as part of the package upgrade process.
may restart <application>repmgrd</application> as part of the package upgrade process.
</para>
</note>
@@ -120,17 +118,15 @@
</sect2>
<sect2 id="upgrading-major-version" xreflabel="Upgrading a major version release">
<title>Upgrading a major version release</title>
<indexterm>
<primary>upgrading</primary>
<secondary>major release</secondary>
</indexterm>
<title>Upgrading a major version release</title>
<para>
&quot;major version&quot; upgrades need to be planned more carefully, as they may include
changes to the &repmgr; metadata (which need to be propagated from the primary to all
standbys) and/or changes to the shared object file used by &repmgrd;
standbys) and/or changes to the shared object file used by <application>repmgrd</application>
(which require a PostgreSQL restart).
</para>
<para>
@@ -142,14 +138,14 @@
<listitem>
<simpara>
Stop &repmgrd; (if in use) on all nodes where it is running.
Stop <application>repmgrd</application> (if in use) on all nodes where it is running.
</simpara>
</listitem>
<listitem>
<simpara>
Disable the &repmgrd; service on all nodes where it is in use;
this is to prevent packages from prematurely restarting &repmgrd;.
Disable the <application>repmgrd</application> service on all nodes where it is in use;
this is to prevent packages from prematurely restarting <application>repmgrd</application>.
</simpara>
</listitem>
@@ -171,12 +167,12 @@ systemctl daemon-reload</programlisting>
<listitem>
<simpara>
If the &repmgr; shared library module has been updated (check the <link linkend="appendix-release-notes">release notes</link>!),
restart PostgreSQL, then &repmgrd; (if in use) on each node,
restart PostgreSQL, then <application>repmgrd</application> (if in use) on each node,
The order in which this is applied to individual nodes is not critical,
and it's also fine to restart PostgreSQL on all nodes first before starting &repmgrd;.
and it's also fine to restart PostgreSQL on all nodes first before starting <application>repmgrd</application>.
</simpara>
<simpara>
Note that if the upgrade requires a PostgreSQL restart, &repmgrd;
Note that if the upgrade requires a PostgreSQL restart, <application>repmgrd</application>
will only function correctly once all nodes have been restarted.
</simpara>
</listitem>
@@ -192,7 +188,7 @@ ALTER EXTENSION repmgr UPDATE</programlisting>
<listitem>
<simpara>
Reenable the &repmgrd; service on all nodes where it is in use, and
Reenable the <application>repmgrd</application> service on all nodes where it is in use, and
ensure it is running.
</simpara>
</listitem>
@@ -209,24 +205,19 @@ ALTER EXTENSION repmgr UPDATE</programlisting>
</sect2>
<sect2 id="upgrading-check-repmgrd" xreflabel="Checking repmgrd status after an upgrade">
<title>Checking repmgrd status after an upgrade</title>
<indexterm>
<primary>upgrading</primary>
<secondary>checking repmgrd status</secondary>
</indexterm>
<title>Checking repmgrd status after an upgrade</title>
<para>
From <link linkend="release-4.2">repmgr 4.2</link>, once the upgrade is complete, execute the
<command><link linkend="repmgr-service-status">repmgr service status</link></command>
(&repmgr; 4.2 - 4.4: <command><link linkend="repmgr-service-status">repmgr daemon status</link></command>)
command (on any node) to show an overview of the status of &repmgrd; on all nodes.
From <link linkend="release-4.2">repmgr 4.2</link>, once the upgrade is complete, execute the <command><link linkend="repmgr-daemon-status">repmgr daemon status</link></command>
command (on any node) to show an overview of the status of <application>repmgrd</application> on all nodes.
</para>
</sect2>
</sect1>
<sect1 id="upgrading-and-pg-upgrade" xreflabel="pg_upgrade and repmgr">
<title>pg_upgrade and repmgr</title>
<indexterm>
<primary>upgrading</primary>
<secondary>pg_upgrade</secondary>
@@ -234,6 +225,7 @@ ALTER EXTENSION repmgr UPDATE</programlisting>
<indexterm>
<primary>pg_upgrade</primary>
</indexterm>
<title>pg_upgrade and repmgr</title>
<para>
<application>pg_upgrade</application> requires that if any functions are
@@ -265,7 +257,7 @@ ALTER EXTENSION repmgr UPDATE</programlisting>
<tip>
<para>
Use <command><link linkend="repmgr-node-check">repmgr node check</link></command>
to determine which replication slots need to be recreated.
to determine which replacation slots need to be recreated.
</para>
</tip>
@@ -273,13 +265,12 @@ ALTER EXTENSION repmgr UPDATE</programlisting>
<sect1 id="upgrading-from-repmgr-3" xreflabel="Upgrading from repmgr 3.x">
<title>Upgrading from repmgr 3.x</title>
<indexterm>
<primary>upgrading</primary>
<secondary>from repmgr 3.x</secondary>
</indexterm>
<title>Upgrading from repmgr 3.x</title>
<para>
The upgrade process consists of two steps:
<orderedlist>
@@ -341,7 +332,7 @@ ALTER EXTENSION repmgr UPDATE</programlisting>
</listitem>
<listitem>
<simpara><varname>monitoring_history</varname>: this replaces the
&repmgrd; command line option
<application>repmgrd</application> command line option
<literal>--monitoring-history</literal></simpara>
</listitem>
</itemizedlist>
@@ -392,7 +383,7 @@ ALTER EXTENSION repmgr UPDATE</programlisting>
to the server configured in Barman (in &repmgr; 3, the deprecated
<literal>cluster</literal> parameter was used for this);
the physical Barman hostname is configured with
<literal>barman_host</literal> (see <xref linkend="cloning-from-barman-prerequisites"/>
<literal>barman_host</literal> (see <xref linkend="cloning-from-barman-prerequisites">
for details).
</para>
</note>
@@ -419,13 +410,13 @@ ALTER EXTENSION repmgr UPDATE</programlisting>
<programlisting>
$ ./convert-config.pl /etc/repmgr.conf
node_id=2
node_name='node2'
conninfo='host=node2 dbname=repmgr user=repmgr connect_timeout=2'
node_name=node2
conninfo=host=node2 dbname=repmgr user=repmgr connect_timeout=2
pg_ctl_options='-l /var/log/postgres/startup.log'
rsync_options='--exclude=postgresql.local.conf --archive'
log_level='INFO'
pg_basebackup_options='--no-slot'
data_directory=''</programlisting>
rsync_options=--exclude=postgresql.local.conf --archive
log_level=INFO
pg_basebackup_options=--no-slot
data_directory=</programlisting>
</para>
<para>
The converted file is printed to <literal>STDOUT</literal> and the original file is not
@@ -434,14 +425,15 @@ 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.
is a required parameter in repmgr4 and which <emphasis>must</emphasis>
be provided.
</para>
</sect3>
</sect2>
<sect2>
<title>Upgrading the repmgr schema</title>
<para>
Ensure &repmgrd; is not running, or any cron jobs which execute the
Ensure <application>repmgrd</application> is not running, or any cron jobs which execute the
<command>repmgr</command> binary.
</para>
<para>
@@ -507,7 +499,7 @@ ALTER EXTENSION repmgr UPDATE</programlisting>
</para>
<para>
Check the data is updated as expected by examining the <structname>repmgr.nodes</structname>
table; restart &repmgrd; if required.
table; restart <application>repmgrd</application> if required.
</para>
<para>
The original <literal>repmgr_$cluster</literal> schema can be dropped at any time.

View File

@@ -1,20 +1,21 @@
/* PostgreSQL.org Documentation Style */
/*
* Documentation generated by XSL stylesheets has lower-case class
* names, older documentation generated by DSSSL stylesheets has
* upper-case class names, so we need to support both for a while. In
* some cases, the elements and classes differ further between the two
* stylesheets.
*/
/* requires global.css, table.css and text.css to be loaded before this file! */
body {
font-family: verdana, sans-serif;
font-size: 76%;
background: url("/resources/background.png") repeat-x scroll left top transparent;
padding: 15px 4%;
margin: 0;
}
.navheader table,
.NAVHEADER table {
/* monospace font size fix */
pre, code, kbd, samp, tt {
font-family: monospace,monospace;
font-size: 1em;
}
div.NAVHEADER table {
margin-left: 0;
}
@@ -98,7 +99,7 @@ body {
#docSearch form input {
font-size: 0.95em;
}
#docSearch form #submit {
font-size: 0.95em;
background: #7A7A7A;
@@ -106,7 +107,7 @@ body {
border: 1px solid #7A7A7A;
padding: 1px 4px;
}
#docSearch form #q {
width: 170px;
font-size: 0.95em;
@@ -137,9 +138,9 @@ body {
#docFooter {
position: relative;
font-size: 0.9em;
color: #666;
line-height: 1.3em;
font-size: 0.9em;
color: #666;
line-height: 1.3em;
margin-left: 10px;
margin-right: 10px;
}
@@ -159,6 +160,7 @@ body {
h1, h2, h3 {
font-weight: bold;
margin-top: 2ex;
color: #444;
}
h1 {
@@ -173,35 +175,20 @@ h3 {
font-size: 1.1em;
}
h1 a:hover {
color: #EC5800;
text-decoration: none;
}
h1 a:hover,
h2 a:hover,
h3 a:hover,
h4 a:hover {
color: #666666;
color: #444;
text-decoration: none;
}
/*
* Change color of h2 chunk titles in XSL build. (In DSSSL build,
* these will be h1, which is already handled elsewhere.)
*/
.titlepage h2.title,
.refnamediv h2 {
color: #EC5800;
}
/* Text Styles */
div.sect2,
div.SECT2 {
margin-top: 4ex;
}
div.sect3,
div.SECT3 {
margin-top: 3ex;
margin-left: 3ex;
@@ -216,7 +203,7 @@ p, ol, ul, li {
}
.txtCommentsWrap {
border: 2px solid #F5F5F5;
border: 2px solid #F5F5F5;
width: 100%;
}
@@ -246,17 +233,6 @@ p, ol, ul, li {
font-size: 1em;
}
pre.literallayout,
.screen,
.synopsis,
.programlisting,
.refsynopsisdiv p,
.caution,
.warning,
.note,
.tip,
.table table,
.informaltable table,
pre.LITERALLAYOUT,
.SCREEN,
.SYNOPSIS,
@@ -274,15 +250,6 @@ table.CALSTABLE {
box-shadow: 3px 3px 5px #DFDFDF;
}
pre.literallayout,
.screen,
.synopsis,
.programlisting,
.refsynopsisdiv p,
.caution,
.warning,
.note,
.tip,
pre.LITERALLAYOUT,
.SCREEN,
.SYNOPSIS,
@@ -304,11 +271,6 @@ blockquote.TIP {
border-radius: 8px;
}
pre.literallayout,
pre.synopsis,
pre.programlisting,
.refsynopsisdiv p,
.screen,
pre.LITERALLAYOUT,
pre.SYNOPSIS,
pre.PROGRAMLISTING,
@@ -318,8 +280,6 @@ pre.PROGRAMLISTING,
background-color: #F7F7F7;
}
.note,
.tip,
blockquote.NOTE,
blockquote.TIP {
border-color: #DBDBCC;
@@ -328,10 +288,6 @@ blockquote.TIP {
width: 572px;
}
.note,
.tip,
.caution,
.warning,
blockquote.NOTE,
blockquote.TIP,
table.CAUTION,
@@ -339,17 +295,11 @@ table.WARNING {
margin: 4ex auto;
}
.note p,
.tip p,
blockquote.NOTE p,
blockquote.TIP p {
margin: 0;
}
.note pre,
.note code,
.tip pre,
.tip code,
blockquote.NOTE pre,
blockquote.NOTE code,
blockquote.TIP pre,
@@ -363,24 +313,11 @@ blockquote.TIP code {
box-shadow: none;
}
.caution,
.warning {
max-width: 600px;
}
.tip h3,
.note h3,
.caution h3,
.warning h3 {
text-align: center;
}
.emphasis,
.c2 {
font-weight: bold;
}
.replaceable,
.REPLACEABLE {
font-style: italic;
}
@@ -391,10 +328,6 @@ table {
margin-left: 2ex;
}
.table table td,
.table table th,
.informaltable table td,
.informaltable table th,
table.CALSTABLE td,
table.CALSTABLE th,
table.CAUTION td,
@@ -404,8 +337,6 @@ table.WARNING th {
border-style: solid;
}
.table table,
.informaltable table,
table.CALSTABLE,
table.CAUTION,
table.WARNING {
@@ -413,8 +344,6 @@ table.WARNING {
border-collapse: collapse;
}
.table table,
.informaltable table,
table.CALSTABLE
{
margin: 2ex 0 2ex 2ex;
@@ -422,23 +351,15 @@ table.CALSTABLE
border: 2px solid #A7C6DF;
}
.table table tr:hover td,
.informaltable table tr:hover td,
table.CALSTABLE tr:hover td
{
background-color: #EFEFEF;
}
.table table td,
.informaltable table td,
table.CALSTABLE td {
background-color: #FFF;
}
.table table td,
.table table th,
.informaltable table td,
.informaltable table th,
table.CALSTABLE td,
table.CALSTABLE th {
border: 1px solid #A7C6DF;
@@ -453,13 +374,11 @@ table.WARNING {
max-width: 600px;
}
.caution,
table.CAUTION {
background-color: #F5F5DC;
border-color: #DEDFA7;
}
.warning,
table.WARNING {
background-color: #FFD7D7;
border-color: #DF421E;
@@ -528,7 +447,23 @@ a:hover {
color:#666;
}
#docContainer code.function tt,
#docContainer code.FUNCTION tt {
font-size: 1em;
}
div.header {
color: #444;
margin-top: 5px;
}
div.footer {
text-align: center;
background-image: url("/resources/footerl.png"), url("/resources/footerr.png"), url("/resources/footerc.png");
background-position: left top, right top, center top;
background-repeat: no-repeat, no-repeat, repeat-x;
padding-top: 45px;
}
img {
border-style: none;
}

View File

@@ -78,6 +78,8 @@ CREATE VIEW repmgr.show_nodes AS
LEFT JOIN repmgr.nodes un
ON un.node_id = n.upstream_node_id;
/* XXX update upgrade scripts! */
CREATE TABLE repmgr.voting_term (
term INT NOT NULL
);

View File

@@ -78,6 +78,8 @@ CREATE VIEW repmgr.show_nodes AS
LEFT JOIN repmgr.nodes un
ON un.node_id = n.upstream_node_id;
/* XXX update upgrade scripts! */
CREATE TABLE repmgr.voting_term (
term INT NOT NULL
);

View File

@@ -78,6 +78,8 @@ CREATE VIEW repmgr.show_nodes AS
LEFT JOIN repmgr.nodes un
ON un.node_id = n.upstream_node_id;
/* XXX update upgrade scripts! */
CREATE TABLE repmgr.voting_term (
term INT NOT NULL
);

View File

@@ -1,19 +0,0 @@
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
\echo Use "CREATE EXTENSION repmgr" to load this file. \quit
DROP FUNCTION set_upstream_last_seen();
CREATE FUNCTION set_upstream_last_seen(INT)
RETURNS VOID
AS 'MODULE_PATHNAME', 'set_upstream_last_seen'
LANGUAGE C STRICT;
CREATE FUNCTION get_upstream_node_id()
RETURNS INT
AS 'MODULE_PATHNAME', 'get_upstream_node_id'
LANGUAGE C STRICT;
CREATE FUNCTION set_upstream_node_id(INT)
RETURNS VOID
AS 'MODULE_PATHNAME', 'set_upstream_node_id'
LANGUAGE C STRICT;

View File

@@ -78,6 +78,8 @@ CREATE VIEW repmgr.show_nodes AS
LEFT JOIN repmgr.nodes un
ON un.node_id = n.upstream_node_id;
/* XXX update upgrade scripts! */
CREATE TABLE repmgr.voting_term (
term INT NOT NULL
);

View File

@@ -1,5 +0,0 @@
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
\echo Use "CREATE EXTENSION repmgr" to load this file. \quit
ALTER FUNCTION set_repmgrd_pid(INT, TEXT) RETURNS NULL ON NULL INPUT;

View File

@@ -1,224 +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
);
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
);
DO $repmgr$
DECLARE
DECLARE server_version_num INT;
BEGIN
SELECT setting
FROM pg_catalog.pg_settings
WHERE name = 'server_version_num'
INTO server_version_num;
IF server_version_num >= 90400 THEN
EXECUTE $repmgr_func$
CREATE TABLE repmgr.monitoring_history (
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
)
$repmgr_func$;
ELSE
EXECUTE $repmgr_func$
CREATE TABLE repmgr.monitoring_history (
primary_node_id INTEGER NOT NULL,
standby_node_id INTEGER NOT NULL,
last_monitor_time TIMESTAMP WITH TIME ZONE NOT NULL,
last_apply_time TIMESTAMP WITH TIME ZONE,
last_wal_primary_location TEXT NOT NULL,
last_wal_standby_location TEXT,
replication_lag BIGINT NOT NULL,
apply_lag BIGINT NOT NULL
)
$repmgr_func$;
END IF;
END$repmgr$;
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;
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 am_bdr_failover_handler(INT)
RETURNS BOOL
AS 'MODULE_PATHNAME', 'am_bdr_failover_handler'
LANGUAGE C STRICT;
CREATE FUNCTION unset_bdr_failover_handler()
RETURNS VOID
AS 'MODULE_PATHNAME', 'unset_bdr_failover_handler'
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 STRICT;
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
);

View File

@@ -1,224 +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
);
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
);
DO $repmgr$
DECLARE
DECLARE server_version_num INT;
BEGIN
SELECT setting
FROM pg_catalog.pg_settings
WHERE name = 'server_version_num'
INTO server_version_num;
IF server_version_num >= 90400 THEN
EXECUTE $repmgr_func$
CREATE TABLE repmgr.monitoring_history (
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
)
$repmgr_func$;
ELSE
EXECUTE $repmgr_func$
CREATE TABLE repmgr.monitoring_history (
primary_node_id INTEGER NOT NULL,
standby_node_id INTEGER NOT NULL,
last_monitor_time TIMESTAMP WITH TIME ZONE NOT NULL,
last_apply_time TIMESTAMP WITH TIME ZONE,
last_wal_primary_location TEXT NOT NULL,
last_wal_standby_location TEXT,
replication_lag BIGINT NOT NULL,
apply_lag BIGINT NOT NULL
)
$repmgr_func$;
END IF;
END$repmgr$;
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;
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 am_bdr_failover_handler(INT)
RETURNS BOOL
AS 'MODULE_PATHNAME', 'am_bdr_failover_handler'
LANGUAGE C STRICT;
CREATE FUNCTION unset_bdr_failover_handler()
RETURNS VOID
AS 'MODULE_PATHNAME', 'unset_bdr_failover_handler'
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
);

View File

@@ -24,7 +24,7 @@
#include "repmgr-client-global.h"
#include "repmgr-action-cluster.h"
#define SHOW_HEADER_COUNT 9
#define SHOW_HEADER_COUNT 8
typedef enum
{
@@ -35,7 +35,6 @@ typedef enum
SHOW_UPSTREAM_NAME,
SHOW_LOCATION,
SHOW_PRIORITY,
SHOW_TIMELINE_ID,
SHOW_CONNINFO
} ShowHeader;
@@ -65,7 +64,6 @@ static void cube_set_node_status(t_node_status_cube **cube, int n, int node_id,
* CLUSTER SHOW
*
* Parameters:
* --compact
* --csv
*/
void
@@ -114,15 +112,9 @@ do_cluster_show(void)
strncpy(headers_show[SHOW_LOCATION].title, _("Location"), MAXLEN);
if (runtime_options.compact == true)
{
strncpy(headers_show[SHOW_PRIORITY].title, _("Prio."), MAXLEN);
strncpy(headers_show[SHOW_TIMELINE_ID].title, _("TLI"), MAXLEN);
}
else
{
strncpy(headers_show[SHOW_PRIORITY].title, _("Priority"), MAXLEN);
strncpy(headers_show[SHOW_TIMELINE_ID].title, _("Timeline"), MAXLEN);
}
strncpy(headers_show[SHOW_CONNINFO].title, _("Connection string"), MAXLEN);
@@ -135,16 +127,6 @@ do_cluster_show(void)
{
headers_show[i].display = true;
/* Don't display timeline on pre-9.6 clusters */
if (i == SHOW_TIMELINE_ID)
{
if (PQserverVersion(conn) < 90600)
{
headers_show[i].display = false;
}
}
/* if --compact provided, don't display conninfo */
if (runtime_options.compact == true)
{
if (i == SHOW_CONNINFO)
@@ -153,38 +135,34 @@ do_cluster_show(void)
}
}
if (headers_show[i].display == true)
{
headers_show[i].max_length = strlen(headers_show[i].title);
}
}
/*
* TODO: count nodes marked as "? unreachable" and add a hint about
* the other cluster commands for better determining whether
* unreachable.
*/
for (cell = nodes.head; cell; cell = cell->next)
{
PQExpBufferData node_status;
PQExpBufferData upstream;
PQExpBufferData details;
PQExpBufferData buf;
cell->node_info->replication_info = palloc0(sizeof(ReplInfo));
if (cell->node_info->replication_info == NULL)
{
log_error(_("unable to allocate memory"));
exit(ERR_INTERNAL);
}
init_replication_info(cell->node_info->replication_info);
cell->node_info->conn = establish_db_connection_quiet(cell->node_info->conninfo);
if (PQstatus(cell->node_info->conn) != CONNECTION_OK)
if (PQstatus(cell->node_info->conn) == CONNECTION_OK)
{
cell->node_info->node_status = NODE_STATUS_UP;
cell->node_info->recovery_type = get_recovery_type(cell->node_info->conn);
}
else
{
/* check if node is reachable, but just not letting us in */
if (is_server_available_quiet(cell->node_info->conninfo))
cell->node_info->node_status = NODE_STATUS_REJECTED;
else
cell->node_info->node_status = NODE_STATUS_DOWN;
cell->node_info->recovery_type = RECTYPE_UNKNOWN;
connection_error_found = true;
if (runtime_options.verbose)
@@ -203,25 +181,235 @@ do_cluster_show(void)
cell->node_info->node_name, cell->node_info->node_id);
}
}
else
initPQExpBuffer(&details);
/*
* TODO: count nodes marked as "? unreachable" and add a hint about
* the other cluster commands for better determining whether
* unreachable.
*/
switch (cell->node_info->type)
{
/* NOP on pre-9.6 servers */
cell->node_info->replication_info->timeline_id = get_node_timeline(cell->node_info->conn);
case PRIMARY:
{
/* node is reachable */
if (cell->node_info->node_status == NODE_STATUS_UP)
{
if (cell->node_info->active == true)
{
switch (cell->node_info->recovery_type)
{
case RECTYPE_PRIMARY:
appendPQExpBufferStr(&details, "* running");
break;
case RECTYPE_STANDBY:
appendPQExpBufferStr(&details, "! running as standby");
item_list_append_format(&warnings,
"node \"%s\" (ID: %i) is registered as primary but running as standby",
cell->node_info->node_name, cell->node_info->node_id);
break;
case RECTYPE_UNKNOWN:
appendPQExpBufferStr(&details, "! unknown");
item_list_append_format(&warnings,
"node \"%s\" (ID: %i) has unknown replication status",
cell->node_info->node_name, cell->node_info->node_id);
break;
}
}
else
{
if (cell->node_info->recovery_type == RECTYPE_PRIMARY)
{
appendPQExpBufferStr(&details, "! running");
item_list_append_format(&warnings,
"node \"%s\" (ID: %i) is running but the repmgr node record is inactive",
cell->node_info->node_name, cell->node_info->node_id);
}
else
{
appendPQExpBufferStr(&details, "! running as standby");
item_list_append_format(&warnings,
"node \"%s\" (ID: %i) is registered as an inactive primary but running as standby",
cell->node_info->node_name, cell->node_info->node_id);
}
}
}
/* node is up but cannot connect */
else if (cell->node_info->node_status == NODE_STATUS_REJECTED)
{
if (cell->node_info->active == true)
{
appendPQExpBufferStr(&details, "? running");
}
else
{
appendPQExpBufferStr(&details, "! running");
error_found = true;
}
}
/* node is unreachable */
else
{
/* node is unreachable but marked active */
if (cell->node_info->active == true)
{
appendPQExpBufferStr(&details, "? unreachable");
item_list_append_format(&warnings,
"node \"%s\" (ID: %i) is registered as an active primary but is unreachable",
cell->node_info->node_name, cell->node_info->node_id);
}
/* node is unreachable and marked as inactive */
else
{
appendPQExpBufferStr(&details, "- failed");
error_found = true;
}
}
}
break;
case STANDBY:
{
/* node is reachable */
if (cell->node_info->node_status == NODE_STATUS_UP)
{
if (cell->node_info->active == true)
{
switch (cell->node_info->recovery_type)
{
case RECTYPE_STANDBY:
appendPQExpBufferStr(&details, " running");
break;
case RECTYPE_PRIMARY:
appendPQExpBufferStr(&details, "! running as primary");
item_list_append_format(&warnings,
"node \"%s\" (ID: %i) is registered as standby but running as primary",
cell->node_info->node_name, cell->node_info->node_id);
break;
case RECTYPE_UNKNOWN:
appendPQExpBufferStr(&details, "! unknown");
item_list_append_format(
&warnings,
"node \"%s\" (ID: %i) has unknown replication status",
cell->node_info->node_name, cell->node_info->node_id);
break;
}
}
else
{
if (cell->node_info->recovery_type == RECTYPE_STANDBY)
{
appendPQExpBufferStr(&details, "! running");
item_list_append_format(&warnings,
"node \"%s\" (ID: %i) is running but the repmgr node record is inactive",
cell->node_info->node_name, cell->node_info->node_id);
}
else
{
appendPQExpBufferStr(&details, "! running as primary");
item_list_append_format(&warnings,
"node \"%s\" (ID: %i) is running as primary but the repmgr node record is inactive",
cell->node_info->node_name, cell->node_info->node_id);
}
}
/* warn about issue with paused WAL replay */
if (is_wal_replay_paused(cell->node_info->conn, true))
{
item_list_append_format(&warnings,
_("WAL replay is paused on node \"%s\" (ID: %i) with WAL replay pending; this node cannot be manually promoted until WAL replay is resumed"),
cell->node_info->node_name, cell->node_info->node_id);
}
}
/* node is up but cannot connect */
else if (cell->node_info->node_status == NODE_STATUS_REJECTED)
{
if (cell->node_info->active == true)
{
appendPQExpBufferStr(&details, "? running");
}
else
{
appendPQExpBufferStr(&details, "! running");
error_found = true;
}
}
/* node is unreachable */
else
{
/* node is unreachable but marked active */
if (cell->node_info->active == true)
{
appendPQExpBufferStr(&details, "? unreachable");
item_list_append_format(&warnings,
"node \"%s\" (ID: %i) is registered as an active standby but is unreachable",
cell->node_info->node_name, cell->node_info->node_id);
}
else
{
appendPQExpBufferStr(&details, "- failed");
error_found = true;
}
}
}
break;
case WITNESS:
case BDR:
{
/* node is reachable */
if (cell->node_info->node_status == NODE_STATUS_UP)
{
if (cell->node_info->active == true)
{
appendPQExpBufferStr(&details, "* running");
}
else
{
appendPQExpBufferStr(&details, "! running");
error_found = true;
}
}
/* node is up but cannot connect */
else if (cell->node_info->node_status == NODE_STATUS_REJECTED)
{
if (cell->node_info->active == true)
{
appendPQExpBufferStr(&details, "? rejected");
}
else
{
appendPQExpBufferStr(&details, "! failed");
error_found = true;
}
}
/* node is unreachable */
else
{
if (cell->node_info->active == true)
{
appendPQExpBufferStr(&details, "? unreachable");
}
else
{
appendPQExpBufferStr(&details, "- failed");
error_found = true;
}
}
}
break;
case UNKNOWN:
{
/* this should never happen */
appendPQExpBufferStr(&details, "? unknown node type");
error_found = true;
}
break;
}
initPQExpBuffer(&node_status);
initPQExpBuffer(&upstream);
if (format_node_status(cell->node_info, &node_status, &upstream, &warnings) == true)
error_found = true;
snprintf(cell->node_info->details, sizeof(cell->node_info->details),
"%s", node_status.data);
snprintf(cell->node_info->upstream_node_name, sizeof(cell->node_info->upstream_node_name),
"%s", upstream.data);
termPQExpBuffer(&node_status);
termPQExpBuffer(&upstream);
strncpy(cell->node_info->details, details.data, MAXLEN);
termPQExpBuffer(&details);
PQfinish(cell->node_info->conn);
cell->node_info->conn = NULL;
@@ -234,7 +422,6 @@ do_cluster_show(void)
headers_show[SHOW_ROLE].cur_length = strlen(get_node_type_string(cell->node_info->type));
headers_show[SHOW_NAME].cur_length = strlen(cell->node_info->node_name);
headers_show[SHOW_STATUS].cur_length = strlen(cell->node_info->details);
headers_show[SHOW_UPSTREAM_NAME].cur_length = strlen(cell->node_info->upstream_node_name);
initPQExpBuffer(&buf);
@@ -244,18 +431,7 @@ do_cluster_show(void)
headers_show[SHOW_LOCATION].cur_length = strlen(cell->node_info->location);
if (cell->node_info->replication_info->timeline_id == UNKNOWN_TIMELINE_ID)
{
/* display "?" */
headers_show[SHOW_PRIORITY].cur_length = 1;
}
else
{
initPQExpBuffer(&buf);
appendPQExpBuffer(&buf, "%i", cell->node_info->replication_info->timeline_id);
headers_show[SHOW_PRIORITY].cur_length = strlen(buf.data);
termPQExpBuffer(&buf);
}
headers_show[SHOW_CONNINFO].cur_length = strlen(cell->node_info->conninfo);
@@ -320,14 +496,6 @@ do_cluster_show(void)
printf("| %-*s ", headers_show[SHOW_LOCATION].max_length, cell->node_info->location);
printf("| %-*i ", headers_show[SHOW_PRIORITY].max_length, cell->node_info->priority);
if (headers_show[SHOW_TIMELINE_ID].display == true)
{
if (cell->node_info->replication_info->timeline_id == UNKNOWN_TIMELINE_ID)
printf("| %-*c ", headers_show[SHOW_TIMELINE_ID].max_length, '?');
else
printf("| %-*i ", headers_show[SHOW_TIMELINE_ID].max_length, (int)cell->node_info->replication_info->timeline_id);
}
if (headers_show[SHOW_CONNINFO].display == true)
{
printf("| %-*s", headers_show[SHOW_CONNINFO].max_length, cell->node_info->conninfo);
@@ -382,7 +550,6 @@ do_cluster_show(void)
* --node-[id|name]
* --event
* --csv
* --compact
*/
void
@@ -428,11 +595,11 @@ do_cluster_event(void)
strncpy(headers_event[EV_DETAILS].title, _("Details"), MAXLEN);
/*
* If --compact or --csv provided, simply omit the "Details" column.
* If --terse or --csv provided, simply omit the "Details" column.
* In --csv mode we'd need to quote/escape the contents "Details" column,
* which is doable but which will remain a TODO for now.
*/
if (runtime_options.compact == true || runtime_options.output_mode == OM_CSV)
if (runtime_options.terse == true || runtime_options.output_mode == OM_CSV)
column_count --;
for (i = 0; i < column_count; i++)
@@ -987,19 +1154,7 @@ build_cluster_matrix(t_node_matrix_rec ***matrix_rec_dest, int *name_length, Ite
make_remote_repmgr_path(&command, cell->node_info);
appendPQExpBufferStr(&command,
" cluster show --csv --terse");
/*
* Usually we'll want NOTICE as the log level, but if the user
* explicitly provided one with --log-level, that will be passed
* in the remote repmgr invocation.
*/
if (runtime_options.log_level[0] == '\0')
{
appendPQExpBufferStr(&command,
" -L NOTICE");
}
appendPQExpBufferChar(&command, '"');
" cluster show --csv -L NOTICE --terse\"");
log_verbose(LOG_DEBUG, "build_cluster_matrix(): executing:\n %s", command.data);
@@ -1187,18 +1342,7 @@ build_cluster_crosscheck(t_node_status_cube ***dest_cube, int *name_length, Item
make_remote_repmgr_path(&command, cell->node_info);
appendPQExpBufferStr(&command,
" cluster matrix --csv --terse");
/*
* Usually we'll want NOTICE as the log level, but if the user
* explicitly provided one with --log-level, that will be passed
* in the remote repmgr invocation.
*/
if (runtime_options.log_level[0] == '\0')
{
appendPQExpBufferStr(&command,
" -L NOTICE");
}
" cluster matrix --csv -L NOTICE --terse");
initPQExpBuffer(&command_output);
@@ -1486,7 +1630,6 @@ do_cluster_help(void)
printf(_(" --event filter specific event\n"));
printf(_(" --node-id restrict entries to node with this ID\n"));
printf(_(" --node-name restrict entries to node with this name\n"));
printf(_(" --compact omit \"Details\" column"));
printf(_(" --csv emit output as CSV\n"));
puts("");

View File

@@ -26,9 +26,439 @@
#include "repmgr-client-global.h"
#include "repmgr-action-daemon.h"
#define REPMGR_SERVICE_STOP_START_WAIT 15
#define REPMGR_SERVICE_STATUS_START_HINT _("use \"repmgr service status\" to confirm that repmgrd was successfully started")
#define REPMGR_SERVICE_STATUS_STOP_HINT _("use \"repmgr service status\" to confirm that repmgrd was successfully stopped")
#define REPMGR_DAEMON_STOP_START_WAIT 15
#define REPMGR_DAEMON_STATUS_START_HINT _("use \"repmgr daemon status\" to confirm that repmgrd was successfully started")
#define REPMGR_DAEMON_STATUS_STOP_HINT _("use \"repmgr daemon status\" to confirm that repmgrd was successfully stopped")
/*
* Possibly also show:
* - repmgrd start time?
* - repmgrd mode
* - priority
* - whether promotion candidate (due to zero priority/different location)
*/
typedef enum
{
STATUS_ID = 0,
STATUS_NAME,
STATUS_ROLE,
STATUS_PRIORITY,
STATUS_PG,
STATUS_RUNNING,
STATUS_PID,
STATUS_PAUSED,
STATUS_UPSTREAM_LAST_SEEN
} StatusHeader;
#define STATUS_HEADER_COUNT 9
struct ColHeader headers_status[STATUS_HEADER_COUNT];
static void fetch_node_records(PGconn *conn, NodeInfoList *node_list);
static void _do_repmgr_pause(bool pause);
void
do_daemon_status(void)
{
PGconn *conn = NULL;
NodeInfoList nodes = T_NODE_INFO_LIST_INITIALIZER;
NodeInfoListCell *cell = NULL;
int i;
RepmgrdInfo **repmgrd_info;
ItemList warnings = {NULL, NULL};
bool connection_error_found = false;
/* Connect to local database to obtain cluster connection data */
log_verbose(LOG_INFO, _("connecting to database"));
if (strlen(config_file_options.conninfo))
conn = establish_db_connection(config_file_options.conninfo, true);
else
conn = establish_db_connection_by_params(&source_conninfo, true);
fetch_node_records(conn, &nodes);
repmgrd_info = (RepmgrdInfo **) pg_malloc0(sizeof(RepmgrdInfo *) * nodes.node_count);
if (repmgrd_info == NULL)
{
log_error(_("unable to allocate memory"));
exit(ERR_OUT_OF_MEMORY);
}
strncpy(headers_status[STATUS_ID].title, _("ID"), MAXLEN);
strncpy(headers_status[STATUS_NAME].title, _("Name"), MAXLEN);
strncpy(headers_status[STATUS_ROLE].title, _("Role"), MAXLEN);
if (runtime_options.compact == true)
strncpy(headers_status[STATUS_PRIORITY].title, _("Prio."), MAXLEN);
else
strncpy(headers_status[STATUS_PRIORITY].title, _("Priority"), MAXLEN);
strncpy(headers_status[STATUS_PG].title, _("Status"), MAXLEN);
strncpy(headers_status[STATUS_RUNNING].title, _("repmgrd"), MAXLEN);
strncpy(headers_status[STATUS_PID].title, _("PID"), MAXLEN);
strncpy(headers_status[STATUS_PAUSED].title, _("Paused?"), MAXLEN);
if (runtime_options.compact == true)
strncpy(headers_status[STATUS_UPSTREAM_LAST_SEEN].title, _("Upstr. last"), MAXLEN);
else
strncpy(headers_status[STATUS_UPSTREAM_LAST_SEEN].title, _("Upstream last seen"), MAXLEN);
for (i = 0; i < STATUS_HEADER_COUNT; i++)
{
headers_status[i].max_length = strlen(headers_status[i].title);
headers_status[i].display = true;
}
i = 0;
for (cell = nodes.head; cell; cell = cell->next)
{
int j;
PQExpBufferData buf;
repmgrd_info[i] = pg_malloc0(sizeof(RepmgrdInfo));
repmgrd_info[i]->node_id = cell->node_info->node_id;
repmgrd_info[i]->pid = UNKNOWN_PID;
repmgrd_info[i]->recovery_type = RECTYPE_UNKNOWN;
repmgrd_info[i]->paused = false;
repmgrd_info[i]->running = false;
repmgrd_info[i]->pg_running = true;
repmgrd_info[i]->wal_paused_pending_wal = false;
repmgrd_info[i]->upstream_last_seen = -1;
cell->node_info->conn = establish_db_connection_quiet(cell->node_info->conninfo);
if (PQstatus(cell->node_info->conn) != CONNECTION_OK)
{
connection_error_found = true;
if (runtime_options.verbose)
{
char error[MAXLEN];
strncpy(error, PQerrorMessage(cell->node_info->conn), MAXLEN);
item_list_append_format(&warnings,
"when attempting to connect to node \"%s\" (ID: %i), following error encountered :\n\"%s\"",
cell->node_info->node_name, cell->node_info->node_id, trim(error));
}
else
{
item_list_append_format(&warnings,
"unable to connect to node \"%s\" (ID: %i)",
cell->node_info->node_name, cell->node_info->node_id);
}
repmgrd_info[i]->pg_running = false;
maxlen_snprintf(repmgrd_info[i]->pg_running_text, "%s", _("not running"));
maxlen_snprintf(repmgrd_info[i]->repmgrd_running, "%s", _("n/a"));
maxlen_snprintf(repmgrd_info[i]->pid_text, "%s", _("n/a"));
}
else
{
maxlen_snprintf(repmgrd_info[i]->pg_running_text, "%s", _("running"));
repmgrd_info[i]->pid = repmgrd_get_pid(cell->node_info->conn);
repmgrd_info[i]->running = repmgrd_is_running(cell->node_info->conn);
if (repmgrd_info[i]->running == true)
{
maxlen_snprintf(repmgrd_info[i]->repmgrd_running, "%s", _("running"));
}
else
{
maxlen_snprintf(repmgrd_info[i]->repmgrd_running, "%s", _("not running"));
}
if (repmgrd_info[i]->pid == UNKNOWN_PID)
{
maxlen_snprintf(repmgrd_info[i]->pid_text, "%s", _("n/a"));
}
else
{
maxlen_snprintf(repmgrd_info[i]->pid_text, "%i", repmgrd_info[i]->pid);
}
repmgrd_info[i]->paused = repmgrd_is_paused(cell->node_info->conn);
repmgrd_info[i]->recovery_type = get_recovery_type(cell->node_info->conn);
if (repmgrd_info[i]->recovery_type == RECTYPE_STANDBY)
{
repmgrd_info[i]->wal_paused_pending_wal = is_wal_replay_paused(cell->node_info->conn, true);
if (repmgrd_info[i]->wal_paused_pending_wal == true)
{
item_list_append_format(&warnings,
_("WAL replay is paused on node \"%s\" (ID: %i) with WAL replay pending; this node cannot be manually promoted until WAL replay is resumed"),
cell->node_info->node_name, cell->node_info->node_id);
}
}
repmgrd_info[i]->upstream_last_seen = get_upstream_last_seen(cell->node_info->conn, cell->node_info->type);
if (repmgrd_info[i]->upstream_last_seen < 0)
{
maxlen_snprintf(repmgrd_info[i]->upstream_last_seen_text, "%s", _("n/a"));
}
else
{
if (runtime_options.compact == true)
{
maxlen_snprintf(repmgrd_info[i]->upstream_last_seen_text, _("%i sec(s) ago"), repmgrd_info[i]->upstream_last_seen);
}
else
{
maxlen_snprintf(repmgrd_info[i]->upstream_last_seen_text, _("%i second(s) ago"), repmgrd_info[i]->upstream_last_seen);
}
}
PQfinish(cell->node_info->conn);
}
headers_status[STATUS_NAME].cur_length = strlen(cell->node_info->node_name);
headers_status[STATUS_ROLE].cur_length = strlen(get_node_type_string(cell->node_info->type));
initPQExpBuffer(&buf);
appendPQExpBuffer(&buf, "%i", cell->node_info->priority);
headers_status[STATUS_PRIORITY].cur_length = strlen(buf.data);
termPQExpBuffer(&buf);
headers_status[STATUS_PID].cur_length = strlen(repmgrd_info[i]->pid_text);
headers_status[STATUS_RUNNING].cur_length = strlen(repmgrd_info[i]->repmgrd_running);
headers_status[STATUS_PG].cur_length = strlen(repmgrd_info[i]->pg_running_text);
headers_status[STATUS_UPSTREAM_LAST_SEEN].cur_length = strlen(repmgrd_info[i]->upstream_last_seen_text);
for (j = 0; j < STATUS_HEADER_COUNT; j++)
{
if (headers_status[j].cur_length > headers_status[j].max_length)
{
headers_status[j].max_length = headers_status[j].cur_length;
}
}
i++;
}
/* Print column header row (text mode only) */
if (runtime_options.output_mode == OM_TEXT)
{
print_status_header(STATUS_HEADER_COUNT, headers_status);
}
i = 0;
for (cell = nodes.head; cell; cell = cell->next)
{
if (runtime_options.output_mode == OM_CSV)
{
int running = repmgrd_info[i]->running ? 1 : 0;
int paused = repmgrd_info[i]->paused ? 1 : 0;
/* If PostgreSQL is not running, repmgrd status is unknown */
if (repmgrd_info[i]->pg_running == false)
{
running = -1;
paused = -1;
}
printf("%i,%s,%s,%i,%i,%i,%i,%i,%i\n",
cell->node_info->node_id,
cell->node_info->node_name,
get_node_type_string(cell->node_info->type),
repmgrd_info[i]->pg_running ? 1 : 0,
running,
repmgrd_info[i]->pid,
paused,
cell->node_info->priority,
repmgrd_info[i]->pid == UNKNOWN_PID
? -1
: repmgrd_info[i]->upstream_last_seen);
}
else
{
printf(" %-*i ", headers_status[STATUS_ID].max_length, cell->node_info->node_id);
printf("| %-*s ", headers_status[STATUS_NAME].max_length, cell->node_info->node_name);
printf("| %-*s ", headers_status[STATUS_ROLE].max_length, get_node_type_string(cell->node_info->type));
printf("| %-*i ", headers_status[STATUS_PRIORITY].max_length, cell->node_info->priority);
printf("| %-*s ", headers_status[STATUS_PG].max_length, repmgrd_info[i]->pg_running_text);
printf("| %-*s ", headers_status[STATUS_RUNNING].max_length, repmgrd_info[i]->repmgrd_running);
printf("| %-*s ", headers_status[STATUS_PID].max_length, repmgrd_info[i]->pid_text);
if (repmgrd_info[i]->pid == UNKNOWN_PID)
{
printf("| %-*s ", headers_status[STATUS_PAUSED].max_length, _("n/a"));
printf("| %-*s ", headers_status[STATUS_UPSTREAM_LAST_SEEN].max_length, _("n/a"));
}
else
{
printf("| %-*s ", headers_status[STATUS_PAUSED].max_length, repmgrd_info[i]->paused ? _("yes") : _("no"));
printf("| %-*s ", headers_status[STATUS_UPSTREAM_LAST_SEEN].max_length, repmgrd_info[i]->upstream_last_seen_text);
}
printf("\n");
}
pfree(repmgrd_info[i]);
i++;
}
pfree(repmgrd_info);
/* emit any warnings */
if (warnings.head != NULL && runtime_options.terse == false && runtime_options.output_mode != OM_CSV)
{
ItemListCell *cell = NULL;
printf(_("\nWARNING: following issues were detected\n"));
for (cell = warnings.head; cell; cell = cell->next)
{
printf(_(" - %s\n"), cell->string);
}
if (runtime_options.verbose == false && connection_error_found == true)
{
log_hint(_("execute with --verbose option to see connection error messages"));
}
}
}
void
do_daemon_pause(void)
{
_do_repmgr_pause(true);
}
void
do_daemon_unpause(void)
{
_do_repmgr_pause(false);
}
static void
_do_repmgr_pause(bool pause)
{
PGconn *conn = NULL;
NodeInfoList nodes = T_NODE_INFO_LIST_INITIALIZER;
NodeInfoListCell *cell = NULL;
int i;
int error_nodes = 0;
/* Connect to local database to obtain cluster connection data */
log_verbose(LOG_INFO, _("connecting to database"));
if (strlen(config_file_options.conninfo))
conn = establish_db_connection(config_file_options.conninfo, true);
else
conn = establish_db_connection_by_params(&source_conninfo, true);
fetch_node_records(conn, &nodes);
i = 0;
for (cell = nodes.head; cell; cell = cell->next)
{
log_verbose(LOG_DEBUG, "pausing node %i (%s)",
cell->node_info->node_id,
cell->node_info->node_name);
cell->node_info->conn = establish_db_connection_quiet(cell->node_info->conninfo);
if (PQstatus(cell->node_info->conn) != CONNECTION_OK)
{
log_warning(_("unable to connect to node %i"),
cell->node_info->node_id);
error_nodes++;
}
else
{
if (runtime_options.dry_run == true)
{
if (pause == true)
{
log_info(_("would pause node %i (%s) "),
cell->node_info->node_id,
cell->node_info->node_name);
}
else
{
log_info(_("would unpause node %i (%s) "),
cell->node_info->node_id,
cell->node_info->node_name);
}
}
else
{
bool success = repmgrd_pause(cell->node_info->conn, pause);
if (success == false)
error_nodes++;
log_notice(_("node %i (%s) %s"),
cell->node_info->node_id,
cell->node_info->node_name,
success == true
? pause == true ? "paused" : "unpaused"
: pause == true ? "not paused" : "not unpaused");
}
PQfinish(cell->node_info->conn);
}
i++;
}
if (error_nodes > 0)
{
if (pause == true)
{
log_error(_("unable to pause %i node(s)"), error_nodes);
}
else
{
log_error(_("unable to unpause %i node(s)"), error_nodes);
}
log_hint(_("execute \"repmgr daemon status\" to view current status"));
exit(ERR_REPMGRD_PAUSE);
}
exit(SUCCESS);
}
void
fetch_node_records(PGconn *conn, NodeInfoList *node_list)
{
bool success = get_all_node_records(conn, node_list);
if (success == false)
{
/* get_all_node_records() will display any error message */
PQfinish(conn);
exit(ERR_BAD_CONFIG);
}
if (node_list->node_count == 0)
{
log_error(_("no node records were found"));
log_hint(_("ensure at least one node is registered"));
PQfinish(conn);
exit(ERR_BAD_CONFIG);
}
}
void
do_daemon_start(void)
@@ -114,12 +544,12 @@ do_daemon_start(void)
if (runtime_options.no_wait == true || runtime_options.wait == 0)
{
log_hint(REPMGR_SERVICE_STATUS_START_HINT);
log_hint(REPMGR_DAEMON_STATUS_START_HINT);
}
else
{
int i = 0;
int timeout = REPMGR_SERVICE_STOP_START_WAIT;
int timeout = REPMGR_DAEMON_STOP_START_WAIT;
if (runtime_options.wait_provided)
timeout = runtime_options.wait;
@@ -129,7 +559,7 @@ do_daemon_start(void)
if (PQstatus(conn) != CONNECTION_OK)
{
log_notice(_("unable to connect to local node"));
log_hint(REPMGR_SERVICE_STATUS_START_HINT);
log_hint(REPMGR_DAEMON_STATUS_START_HINT);
exit(ERR_DB_CONN);
}
@@ -147,7 +577,7 @@ do_daemon_start(void)
PQfinish(conn);
log_error(_("repmgrd does not appear to have started after %i seconds"),
timeout);
log_hint(REPMGR_SERVICE_STATUS_START_HINT);
log_hint(REPMGR_DAEMON_STATUS_START_HINT);
exit(ERR_REPMGRD_SERVICE);
}
@@ -243,12 +673,12 @@ void do_daemon_stop(void)
if (runtime_options.no_wait == true || runtime_options.wait == 0)
{
if (have_db_connection == true)
log_hint(REPMGR_SERVICE_STATUS_STOP_HINT);
log_hint(REPMGR_DAEMON_STATUS_STOP_HINT);
}
else
{
int i = 0;
int timeout = REPMGR_SERVICE_STOP_START_WAIT;
int timeout = REPMGR_DAEMON_STOP_START_WAIT;
/*
*
*/
@@ -263,7 +693,7 @@ void do_daemon_stop(void)
log_warning(_("unable to determine repmgrd PID"));
if (have_db_connection == true)
log_hint(REPMGR_SERVICE_STATUS_STOP_HINT);
log_hint(REPMGR_DAEMON_STATUS_STOP_HINT);
exit(ERR_REPMGRD_SERVICE);
}
@@ -295,7 +725,7 @@ void do_daemon_stop(void)
timeout);
if (have_db_connection == true)
log_hint(REPMGR_SERVICE_STATUS_START_HINT);
log_hint(REPMGR_DAEMON_STATUS_START_HINT);
exit(ERR_REPMGRD_SERVICE);
}
@@ -314,29 +744,52 @@ void do_daemon_help(void)
print_help_header();
printf(_("Usage:\n"));
printf(_(" %s [OPTIONS] daemon status\n"), progname());
printf(_(" %s [OPTIONS] daemon pause\n"), progname());
printf(_(" %s [OPTIONS] daemon unpause\n"), progname());
printf(_(" %s [OPTIONS] daemon start\n"), progname());
printf(_(" %s [OPTIONS] daemon stop\n"), progname());
puts("");
printf(_("DAEMON STATUS\n"));
puts("");
printf(_(" \"daemon status\" shows the status of repmgrd on each node in the cluster\n"));
puts("");
printf(_(" --csv emit output as CSV\n"));
printf(_(" --verbose show text of database connection error messages\n"));
puts("");
printf(_("DAEMON START\n"));
puts("");
printf(_(" \"daemon start\" attempts to start repmgrd on the local node\n"));
printf(_(" \"daemon start\" attempts to start repmgrd\n"));
puts("");
printf(_(" --dry-run check prerequisites but don't start repmgrd\n"));
printf(_(" -w/--wait wait for repmgrd to start (default: %i seconds)\n"), REPMGR_SERVICE_STOP_START_WAIT);
printf(_(" -w/--wait wait for repmgrd to start (default: %i seconds)\n"), REPMGR_DAEMON_STOP_START_WAIT);
printf(_(" --no-wait don't wait for repmgrd to start\n"));
puts("");
printf(_("DAEMON STOP\n"));
puts("");
printf(_(" \"daemon stop\" attempts to stop repmgrd on the local node\n"));
printf(_(" \"daemon stop\" attempts to stop repmgrd\n"));
puts("");
printf(_(" --dry-run check prerequisites but don't stop repmgrd\n"));
printf(_(" -w/--wait wait for repmgrd to stop (default: %i seconds)\n"), REPMGR_SERVICE_STOP_START_WAIT);
printf(_(" -w/--wait wait for repmgrd to stop (default: %i seconds)\n"), REPMGR_DAEMON_STOP_START_WAIT);
printf(_(" --no-wait don't wait for repmgrd to stop\n"));
puts("");
printf(_("DAEMON PAUSE\n"));
puts("");
printf(_(" \"daemon pause\" instructs repmgrd on each node to pause failover detection\n"));
puts("");
printf(_(" --dry-run check if nodes are reachable but don't pause repmgrd\n"));
puts("");
printf(_("DAEMON UNPAUSE\n"));
puts("");
printf(_(" \"daemon unpause\" instructs repmgrd on each node to resume failover detection\n"));
puts("");
printf(_(" --dry-run check if nodes are reachable but don't unpause repmgrd\n"));
puts("");
puts("");
}

View File

@@ -19,6 +19,10 @@
#ifndef _REPMGR_ACTION_DAEMON_H_
#define _REPMGR_ACTION_DAEMON_H_
extern void do_daemon_status(void);
extern void do_daemon_pause(void);
extern void do_daemon_unpause(void);
extern void do_daemon_start(void);
extern void do_daemon_stop(void);

View File

@@ -294,7 +294,7 @@ do_node_status(void)
continue;
}
if (is_downstream_node_attached(conn, node_cell->node_info->node_name) != NODE_ATTACHED)
if (is_downstream_node_attached(conn, node_cell->node_info->node_name) == false)
{
missing_nodes_count++;
item_list_append_format(&missing_nodes,
@@ -1166,7 +1166,7 @@ do_node_check_downstream(PGconn *conn, OutputMode mode, CheckStatusList *list_ou
continue;
}
if (is_downstream_node_attached(conn, cell->node_info->node_name) != NODE_ATTACHED)
if (is_downstream_node_attached(conn, cell->node_info->node_name) == false)
{
missing_nodes_count++;
item_list_append_format(&missing_nodes,
@@ -1833,7 +1833,7 @@ do_node_check_data_directory(PGconn *conn, OutputMode mode, t_node_info *node_in
* a superuser connection
*/
if (connection_has_pg_settings(conn) == true)
if (is_superuser_connection(conn, NULL) == true)
{
/* we expect to have a database connection */
if (get_pg_setting(conn, "data_directory", actual_data_directory) == false)
@@ -1878,7 +1878,7 @@ do_node_check_data_directory(PGconn *conn, OutputMode mode, t_node_info *node_in
/* XXX add -S/--superuser option */
if (PQserverVersion(conn) >= 100000)
{
log_hint(_("add the \"%s\" user to group \"pg_read_all_settings\" or \"pg_monitor\""),
log_hint(_("add the \"%s\" user to group \"pg_read_all_settings\""),
PQuser(conn));
}
}
@@ -2222,7 +2222,7 @@ do_node_rejoin(void)
{
RecoveryType upstream_recovery_type = get_recovery_type(upstream_conn);
log_error(_("unable to connect to current registered primary \"%s\" (ID: %i)"),
log_error(_("unable to connect to current registered primary \"%s\" (node ID: %i)"),
primary_node_record.node_name,
primary_node_record.node_id);
log_detail(_("registered primary node conninfo is: \"%s\""),
@@ -2562,10 +2562,9 @@ do_node_rejoin(void)
for (; i < config_file_options.node_rejoin_timeout; i++)
{
NodeAttached node_attached = is_downstream_node_attached(primary_conn,
config_file_options.node_name);
success = is_downstream_node_attached(primary_conn, config_file_options.node_name);
if (node_attached == NODE_ATTACHED)
if (success == true)
{
log_verbose(LOG_INFO, _("node %i has attached to its upstream node"),
config_file_options.node_id);
@@ -2613,9 +2612,7 @@ do_node_rejoin(void)
else
{
/* -W/--no-wait provided - check once */
NodeAttached node_attached = is_downstream_node_attached(primary_conn, config_file_options.node_name);
if (node_attached == NODE_ATTACHED)
success = true;
success = is_downstream_node_attached(primary_conn, config_file_options.node_name);
}
/*
@@ -2857,7 +2854,7 @@ _do_node_archive_config(void)
{
int filename_len = j - i;
if (filename_len >= MAXPGPATH)
if (filename_len > MAXPGPATH)
filename_len = MAXPGPATH - 1;
strncpy(filenamebuf, runtime_options.config_files + i, filename_len);

View File

@@ -113,7 +113,7 @@ do_primary_register(void)
{
if (get_recovery_type(primary_conn) == RECTYPE_PRIMARY)
{
log_error(_("there is already an active registered primary (ID: %i) in this cluster"),
log_error(_("there is already an active registered primary (node ID: %i) in this cluster"),
current_primary_id);
log_detail(_("a streaming replication cluster can have only one primary node"));
@@ -223,12 +223,12 @@ do_primary_register(void)
if (record_status == RECORD_FOUND)
{
log_notice(_("primary node record (ID: %i) updated"),
log_notice(_("primary node record (id: %i) updated"),
config_file_options.node_id);
}
else
{
log_notice(_("primary node record (ID: %i) registered"),
log_notice(_("primary node record (id: %i) registered"),
config_file_options.node_id);
}
@@ -274,7 +274,7 @@ do_primary_unregister(void)
if (get_primary_node_record(local_conn, &primary_node_info) == true)
{
log_detail(_("current primary registered as node \"%s\" (ID: %i, conninfo: \"%s\")"),
log_detail(_("current primary registered as node %s (id: %i, conninfo: \"%s\")"),
primary_node_info.node_name,
primary_node_info.node_id,
primary_node_info.conninfo);
@@ -316,7 +316,7 @@ do_primary_unregister(void)
if (target_node_info_ptr->type == WITNESS)
{
log_error(_("node \"%s\" (ID: %i) is a witness server, unable to unregister"),
log_error(_("node %s (id: %i) is a witness server, unable to unregister"),
target_node_info_ptr->node_name,
target_node_info_ptr->node_id);
if (target_node_info_ptr->type == STANDBY)
@@ -357,7 +357,7 @@ do_primary_unregister(void)
for (cell = downstream_nodes.head; cell; cell = cell->next)
{
appendPQExpBuffer(&detail,
" %s (ID: %i)\n",
" %s (id: %i)\n",
cell->node_info->node_name,
cell->node_info->node_id);
}
@@ -377,7 +377,7 @@ do_primary_unregister(void)
{
if (target_node_info_ptr->type != PRIMARY)
{
log_error(_("node \"%s\" (ID: %i) is not a primary, unable to unregister"),
log_error(_("node %s (id: %i) is not a primary, unable to unregister"),
target_node_info_ptr->node_name,
target_node_info_ptr->node_id);
if (target_node_info_ptr->type == STANDBY)
@@ -404,7 +404,7 @@ do_primary_unregister(void)
*/
if (target_node_info_ptr->type != PRIMARY)
{
log_error(_("node \"%s\" (ID: %i) is a %s, unable to unregister"),
log_error(_("node %s (ID: %i) is a %s, unable to unregister"),
target_node_info_ptr->node_name,
target_node_info_ptr->node_id,
get_node_type_string(target_node_info_ptr->type));
@@ -418,7 +418,7 @@ do_primary_unregister(void)
*/
else if (!runtime_options.force)
{
log_error(_("node \"%s\" (ID: %i) is running as a standby, unable to unregister"),
log_error(_("node %s (ID: %i) is running as a standby, unable to unregister"),
target_node_info_ptr->node_name,
target_node_info_ptr->node_id);
log_hint(_("the node can be registered as a standby with \"repmgr standby register --force\""));
@@ -443,7 +443,7 @@ do_primary_unregister(void)
if (primary_record_found == false)
{
log_error(_("node \"%s\" (ID: %i) is a primary node, but no primary node record found"),
log_error(_("node %s (ID: %i) is a primary node, but no primary node record found"),
target_node_info_ptr->node_name,
target_node_info_ptr->node_id);
log_hint(_("register this node as primary with \"repmgr primary register --force\""));
@@ -458,7 +458,7 @@ do_primary_unregister(void)
*/
if (primary_node_info.node_id == target_node_info_ptr->node_id)
{
log_error(_("node \"%s\" (ID: %i) is the current primary node, unable to unregister"),
log_error(_("node %s (ID: %i) is the current primary node, unable to unregister"),
target_node_info_ptr->node_name,
target_node_info_ptr->node_id);
@@ -480,7 +480,7 @@ do_primary_unregister(void)
{
if (!runtime_options.force)
{
log_error(_("node \"%s\" (ID: %i) is marked as active, unable to unregister"),
log_error(_("node %s (ID: %i) is marked as active, unable to unregister"),
target_node_info_ptr->node_name,
target_node_info_ptr->node_id);
log_hint(_("run \"repmgr primary unregister --force\" to unregister this node"));
@@ -491,7 +491,7 @@ do_primary_unregister(void)
if (runtime_options.dry_run == true)
{
log_notice(_("node \"%s\" (ID: %i) would now be unregistered"),
log_notice(_("node %s (ID: %i) would now be unregistered"),
target_node_info_ptr->node_name,
target_node_info_ptr->node_id);
log_hint(_("run the same command without the --dry-run option to unregister this node"));
@@ -504,7 +504,7 @@ do_primary_unregister(void)
if (delete_success == false)
{
log_error(_("unable to unregister node \"%s\" (ID: %i)"),
log_error(_("unable to unregister node %s (ID: %i)"),
target_node_info_ptr->node_name,
target_node_info_ptr->node_id);
PQfinish(primary_conn);
@@ -513,14 +513,14 @@ do_primary_unregister(void)
initPQExpBuffer(&event_details);
appendPQExpBuffer(&event_details,
_("node \"%s\" (ID: %i) unregistered"),
_("node %s (ID: %i) unregistered"),
target_node_info_ptr->node_name,
target_node_info_ptr->node_id);
if (target_node_info_ptr->node_id != config_file_options.node_id)
{
appendPQExpBuffer(&event_details,
_(" from node \"%s\" (ID: %i)"),
_(" from node %s (ID: %i)"),
config_file_options.node_name,
config_file_options.node_id);
}
@@ -533,7 +533,7 @@ do_primary_unregister(void)
event_details.data);
termPQExpBuffer(&event_details);
log_info(_("node \"%s\" (ID: %i) was successfully unregistered"),
log_info(_("node %s (ID: %i) was successfully unregistered"),
target_node_info_ptr->node_name,
target_node_info_ptr->node_id);
}

View File

@@ -1,535 +0,0 @@
/*
* repmgr-action-service.c
*
* Implements repmgrd actions for the repmgr command line utility
* Copyright (c) 2ndQuadrant, 2010-2019
*
* 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 <signal.h>
#include <sys/stat.h> /* for stat() */
#include "repmgr.h"
#include "repmgr-client-global.h"
#include "repmgr-action-service.h"
/*
* Possibly also show:
* - repmgrd start time?
* - repmgrd mode
* - priority
* - whether promotion candidate (due to zero priority/different location)
*/
typedef enum
{
STATUS_ID = 0,
STATUS_NAME,
STATUS_ROLE,
STATUS_PG,
STATUS_UPSTREAM_NAME,
STATUS_LOCATION,
STATUS_PRIORITY,
STATUS_REPMGRD,
STATUS_PID,
STATUS_PAUSED,
STATUS_UPSTREAM_LAST_SEEN
} StatusHeader;
#define STATUS_HEADER_COUNT 11
struct ColHeader headers_status[STATUS_HEADER_COUNT];
static void fetch_node_records(PGconn *conn, NodeInfoList *node_list);
static void _do_repmgr_pause(bool pause);
void
do_service_status(void)
{
PGconn *conn = NULL;
NodeInfoList nodes = T_NODE_INFO_LIST_INITIALIZER;
NodeInfoListCell *cell = NULL;
int i;
RepmgrdInfo **repmgrd_info;
ItemList warnings = {NULL, NULL};
bool connection_error_found = false;
/* Connect to local database to obtain cluster connection data */
log_verbose(LOG_INFO, _("connecting to database"));
if (strlen(config_file_options.conninfo))
conn = establish_db_connection(config_file_options.conninfo, true);
else
conn = establish_db_connection_by_params(&source_conninfo, true);
fetch_node_records(conn, &nodes);
repmgrd_info = (RepmgrdInfo **) pg_malloc0(sizeof(RepmgrdInfo *) * nodes.node_count);
if (repmgrd_info == NULL)
{
log_error(_("unable to allocate memory"));
exit(ERR_OUT_OF_MEMORY);
}
strncpy(headers_status[STATUS_ID].title, _("ID"), MAXLEN);
strncpy(headers_status[STATUS_NAME].title, _("Name"), MAXLEN);
strncpy(headers_status[STATUS_ROLE].title, _("Role"), MAXLEN);
strncpy(headers_status[STATUS_PG].title, _("Status"), MAXLEN);
strncpy(headers_status[STATUS_UPSTREAM_NAME].title, _("Upstream"), MAXLEN);
/* following only displayed with the --detail option */
strncpy(headers_status[STATUS_LOCATION].title, _("Location"), MAXLEN);
if (runtime_options.compact == true)
strncpy(headers_status[STATUS_PRIORITY].title, _("Prio."), MAXLEN);
else
strncpy(headers_status[STATUS_PRIORITY].title, _("Priority"), MAXLEN);
strncpy(headers_status[STATUS_REPMGRD].title, _("repmgrd"), MAXLEN);
strncpy(headers_status[STATUS_PID].title, _("PID"), MAXLEN);
strncpy(headers_status[STATUS_PAUSED].title, _("Paused?"), MAXLEN);
if (runtime_options.compact == true)
strncpy(headers_status[STATUS_UPSTREAM_LAST_SEEN].title, _("Upstr. last"), MAXLEN);
else
strncpy(headers_status[STATUS_UPSTREAM_LAST_SEEN].title, _("Upstream last seen"), MAXLEN);
for (i = 0; i < STATUS_HEADER_COUNT; i++)
{
headers_status[i].max_length = strlen(headers_status[i].title);
headers_status[i].display = true;
}
if (runtime_options.detail == false)
{
headers_status[STATUS_LOCATION].display = false;
headers_status[STATUS_PRIORITY].display = false;
}
i = 0;
for (cell = nodes.head; cell; cell = cell->next)
{
int j;
PQExpBufferData node_status;
PQExpBufferData upstream;
repmgrd_info[i] = pg_malloc0(sizeof(RepmgrdInfo));
repmgrd_info[i]->node_id = cell->node_info->node_id;
repmgrd_info[i]->pid = UNKNOWN_PID;
repmgrd_info[i]->recovery_type = RECTYPE_UNKNOWN;
repmgrd_info[i]->paused = false;
repmgrd_info[i]->running = false;
repmgrd_info[i]->pg_running = true;
repmgrd_info[i]->wal_paused_pending_wal = false;
repmgrd_info[i]->upstream_last_seen = -1;
cell->node_info->conn = establish_db_connection_quiet(cell->node_info->conninfo);
if (PQstatus(cell->node_info->conn) != CONNECTION_OK)
{
connection_error_found = true;
if (runtime_options.verbose)
{
char error[MAXLEN];
strncpy(error, PQerrorMessage(cell->node_info->conn), MAXLEN);
item_list_append_format(&warnings,
"when attempting to connect to node \"%s\" (ID: %i), following error encountered :\n\"%s\"",
cell->node_info->node_name, cell->node_info->node_id, trim(error));
}
else
{
item_list_append_format(&warnings,
"unable to connect to node \"%s\" (ID: %i)",
cell->node_info->node_name, cell->node_info->node_id);
}
repmgrd_info[i]->pg_running = false;
maxlen_snprintf(repmgrd_info[i]->repmgrd_running, "%s", _("n/a"));
maxlen_snprintf(repmgrd_info[i]->pid_text, "%s", _("n/a"));
}
else
{
cell->node_info->node_status = NODE_STATUS_UP;
cell->node_info->recovery_type = get_recovery_type(cell->node_info->conn);
repmgrd_info[i]->pid = repmgrd_get_pid(cell->node_info->conn);
repmgrd_info[i]->running = repmgrd_is_running(cell->node_info->conn);
if (repmgrd_info[i]->running == true)
{
maxlen_snprintf(repmgrd_info[i]->repmgrd_running, "%s", _("running"));
}
else
{
maxlen_snprintf(repmgrd_info[i]->repmgrd_running, "%s", _("not running"));
}
if (repmgrd_info[i]->pid == UNKNOWN_PID)
{
maxlen_snprintf(repmgrd_info[i]->pid_text, "%s", _("n/a"));
}
else
{
maxlen_snprintf(repmgrd_info[i]->pid_text, "%i", repmgrd_info[i]->pid);
}
repmgrd_info[i]->paused = repmgrd_is_paused(cell->node_info->conn);
repmgrd_info[i]->recovery_type = get_recovery_type(cell->node_info->conn);
if (repmgrd_info[i]->recovery_type == RECTYPE_STANDBY)
{
repmgrd_info[i]->wal_paused_pending_wal = is_wal_replay_paused(cell->node_info->conn, true);
if (repmgrd_info[i]->wal_paused_pending_wal == true)
{
item_list_append_format(&warnings,
_("WAL replay is paused on node \"%s\" (ID: %i) with WAL replay pending; this node cannot be manually promoted until WAL replay is resumed"),
cell->node_info->node_name, cell->node_info->node_id);
}
}
repmgrd_info[i]->upstream_last_seen = get_upstream_last_seen(cell->node_info->conn, cell->node_info->type);
if (repmgrd_info[i]->upstream_last_seen < 0)
{
maxlen_snprintf(repmgrd_info[i]->upstream_last_seen_text, "%s", _("n/a"));
}
else
{
if (runtime_options.compact == true)
{
maxlen_snprintf(repmgrd_info[i]->upstream_last_seen_text, _("%i sec(s) ago"), repmgrd_info[i]->upstream_last_seen);
}
else
{
maxlen_snprintf(repmgrd_info[i]->upstream_last_seen_text, _("%i second(s) ago"), repmgrd_info[i]->upstream_last_seen);
}
}
}
initPQExpBuffer(&node_status);
initPQExpBuffer(&upstream);
(void)format_node_status(cell->node_info, &node_status, &upstream, &warnings);
snprintf(repmgrd_info[i]->pg_running_text, sizeof(cell->node_info->details),
"%s", node_status.data);
snprintf(cell->node_info->upstream_node_name, sizeof(cell->node_info->upstream_node_name),
"%s", upstream.data);
termPQExpBuffer(&node_status);
termPQExpBuffer(&upstream);
PQfinish(cell->node_info->conn);
headers_status[STATUS_NAME].cur_length = strlen(cell->node_info->node_name);
headers_status[STATUS_ROLE].cur_length = strlen(get_node_type_string(cell->node_info->type));
headers_status[STATUS_PG].cur_length = strlen(repmgrd_info[i]->pg_running_text);
headers_status[STATUS_UPSTREAM_NAME].cur_length = strlen(cell->node_info->upstream_node_name);
if (runtime_options.detail == true)
{
PQExpBufferData buf;
headers_status[STATUS_LOCATION].cur_length = strlen(cell->node_info->location);
initPQExpBuffer(&buf);
appendPQExpBuffer(&buf, "%i", cell->node_info->priority);
headers_status[STATUS_PRIORITY].cur_length = strlen(buf.data);
termPQExpBuffer(&buf);
}
headers_status[STATUS_PID].cur_length = strlen(repmgrd_info[i]->pid_text);
headers_status[STATUS_REPMGRD].cur_length = strlen(repmgrd_info[i]->repmgrd_running);
headers_status[STATUS_UPSTREAM_LAST_SEEN].cur_length = strlen(repmgrd_info[i]->upstream_last_seen_text);
for (j = 0; j < STATUS_HEADER_COUNT; j++)
{
if (headers_status[j].cur_length > headers_status[j].max_length)
{
headers_status[j].max_length = headers_status[j].cur_length;
}
}
i++;
}
/* Print column header row (text mode only) */
if (runtime_options.output_mode == OM_TEXT)
{
print_status_header(STATUS_HEADER_COUNT, headers_status);
}
i = 0;
for (cell = nodes.head; cell; cell = cell->next)
{
if (runtime_options.output_mode == OM_CSV)
{
int running = repmgrd_info[i]->running ? 1 : 0;
int paused = repmgrd_info[i]->paused ? 1 : 0;
/* If PostgreSQL is not running, repmgrd status is unknown */
if (repmgrd_info[i]->pg_running == false)
{
running = -1;
paused = -1;
}
printf("%i,%s,%s,%i,%i,%i,%i,%i,%i,%s\n",
cell->node_info->node_id,
cell->node_info->node_name,
get_node_type_string(cell->node_info->type),
repmgrd_info[i]->pg_running ? 1 : 0,
running,
repmgrd_info[i]->pid,
paused,
cell->node_info->priority,
repmgrd_info[i]->pid == UNKNOWN_PID
? -1
: repmgrd_info[i]->upstream_last_seen,
cell->node_info->location);
}
else
{
printf(" %-*i ", headers_status[STATUS_ID].max_length, cell->node_info->node_id);
printf("| %-*s ", headers_status[STATUS_NAME].max_length, cell->node_info->node_name);
printf("| %-*s ", headers_status[STATUS_ROLE].max_length, get_node_type_string(cell->node_info->type));
printf("| %-*s ", headers_status[STATUS_PG].max_length, repmgrd_info[i]->pg_running_text);
printf("| %-*s ", headers_status[STATUS_UPSTREAM_NAME].max_length, cell->node_info->upstream_node_name);
if (runtime_options.detail == true)
{
printf("| %-*s ", headers_status[STATUS_LOCATION].max_length, cell->node_info->location);
printf("| %-*i ", headers_status[STATUS_PRIORITY].max_length, cell->node_info->priority);
}
printf("| %-*s ", headers_status[STATUS_REPMGRD].max_length, repmgrd_info[i]->repmgrd_running);
printf("| %-*s ", headers_status[STATUS_PID].max_length, repmgrd_info[i]->pid_text);
if (repmgrd_info[i]->pid == UNKNOWN_PID)
{
printf("| %-*s ", headers_status[STATUS_PAUSED].max_length, _("n/a"));
printf("| %-*s ", headers_status[STATUS_UPSTREAM_LAST_SEEN].max_length, _("n/a"));
}
else
{
printf("| %-*s ", headers_status[STATUS_PAUSED].max_length, repmgrd_info[i]->paused ? _("yes") : _("no"));
printf("| %-*s ", headers_status[STATUS_UPSTREAM_LAST_SEEN].max_length, repmgrd_info[i]->upstream_last_seen_text);
}
printf("\n");
}
pfree(repmgrd_info[i]);
i++;
}
pfree(repmgrd_info);
/* emit any warnings */
if (warnings.head != NULL && runtime_options.terse == false && runtime_options.output_mode != OM_CSV)
{
ItemListCell *cell = NULL;
printf(_("\nWARNING: following issues were detected\n"));
for (cell = warnings.head; cell; cell = cell->next)
{
printf(_(" - %s\n"), cell->string);
}
if (runtime_options.verbose == false && connection_error_found == true)
{
log_hint(_("execute with --verbose option to see connection error messages"));
}
}
}
void
do_service_pause(void)
{
_do_repmgr_pause(true);
}
void
do_service_unpause(void)
{
_do_repmgr_pause(false);
}
static void
_do_repmgr_pause(bool pause)
{
PGconn *conn = NULL;
NodeInfoList nodes = T_NODE_INFO_LIST_INITIALIZER;
NodeInfoListCell *cell = NULL;
int i;
int error_nodes = 0;
/* Connect to local database to obtain cluster connection data */
log_verbose(LOG_INFO, _("connecting to database"));
if (strlen(config_file_options.conninfo))
conn = establish_db_connection(config_file_options.conninfo, true);
else
conn = establish_db_connection_by_params(&source_conninfo, true);
fetch_node_records(conn, &nodes);
i = 0;
for (cell = nodes.head; cell; cell = cell->next)
{
log_verbose(LOG_DEBUG, "pausing node %i (%s)",
cell->node_info->node_id,
cell->node_info->node_name);
cell->node_info->conn = establish_db_connection_quiet(cell->node_info->conninfo);
if (PQstatus(cell->node_info->conn) != CONNECTION_OK)
{
log_warning(_("unable to connect to node %i"),
cell->node_info->node_id);
error_nodes++;
}
else
{
if (runtime_options.dry_run == true)
{
if (pause == true)
{
log_info(_("would pause node %i (%s) "),
cell->node_info->node_id,
cell->node_info->node_name);
}
else
{
log_info(_("would unpause node %i (%s) "),
cell->node_info->node_id,
cell->node_info->node_name);
}
}
else
{
bool success = repmgrd_pause(cell->node_info->conn, pause);
if (success == false)
error_nodes++;
log_notice(_("node %i (%s) %s"),
cell->node_info->node_id,
cell->node_info->node_name,
success == true
? pause == true ? "paused" : "unpaused"
: pause == true ? "not paused" : "not unpaused");
}
PQfinish(cell->node_info->conn);
}
i++;
}
if (error_nodes > 0)
{
if (pause == true)
{
log_error(_("unable to pause %i node(s)"), error_nodes);
}
else
{
log_error(_("unable to unpause %i node(s)"), error_nodes);
}
log_hint(_("execute \"repmgr service status\" to view current status"));
exit(ERR_REPMGRD_PAUSE);
}
exit(SUCCESS);
}
void
fetch_node_records(PGconn *conn, NodeInfoList *node_list)
{
bool success = get_all_node_records_with_upstream(conn, node_list);
if (success == false)
{
/* get_all_node_records() will display any error message */
PQfinish(conn);
exit(ERR_BAD_CONFIG);
}
if (node_list->node_count == 0)
{
log_error(_("no node records were found"));
log_hint(_("ensure at least one node is registered"));
PQfinish(conn);
exit(ERR_BAD_CONFIG);
}
}
void do_service_help(void)
{
print_help_header();
printf(_("Usage:\n"));
printf(_(" %s [OPTIONS] service status\n"), progname());
printf(_(" %s [OPTIONS] service pause\n"), progname());
printf(_(" %s [OPTIONS] service unpause\n"), progname());
puts("");
printf(_("SERVICE STATUS\n"));
puts("");
printf(_(" \"service status\" shows the status of repmgrd on each node in the cluster\n"));
puts("");
printf(_(" --csv emit output as CSV\n"));
printf(_(" --detail show additional detail\n"));
printf(_(" --verbose show text of database connection error messages\n"));
puts("");
printf(_("SERVICE PAUSE\n"));
puts("");
printf(_(" \"service pause\" instructs repmgrd on each node to pause failover detection\n"));
puts("");
printf(_(" --dry-run check if nodes are reachable but don't pause repmgrd\n"));
puts("");
printf(_("SERVICE UNPAUSE\n"));
puts("");
printf(_(" \"service unpause\" instructs repmgrd on each node to resume failover detection\n"));
puts("");
printf(_(" --dry-run check if nodes are reachable but don't unpause repmgrd\n"));
puts("");
puts("");
}

View File

@@ -1,28 +0,0 @@
/*
* repmgr-action-service.h
* Copyright (c) 2ndQuadrant, 2010-2019
*
* 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/>.
*/
#ifndef _REPMGR_ACTION_SERVICE_H_
#define _REPMGR_ACTION_SERVICE_H_
extern void do_service_status(void);
extern void do_service_pause(void);
extern void do_service_unpause(void);
extern void do_service_help(void);
#endif

Some files were not shown because too many files have changed in this diff Show More