diff --git a/docs/dynamic_configuration.rst b/docs/dynamic_configuration.rst index bfcfc384..b12aac20 100644 --- a/docs/dynamic_configuration.rst +++ b/docs/dynamic_configuration.rst @@ -30,7 +30,7 @@ In order to change the dynamic configuration you can use either :ref:`patronictl - **failsafe\_mode**: Enables :ref:`DCS Failsafe Mode `. Defaults to `false`. - **postgresql**: - - **use\_pg\_rewind**: whether or not to use pg_rewind. Defaults to `false`. + - **use\_pg\_rewind**: whether or not to use pg_rewind. Defaults to `false`. Note that either the cluster must be initialized with ``data page checksums`` (``--data-checksums`` option for ``initdb``) and/or ``wal_log_hints`` must be set to ``on``, or ``pg_rewind`` will not work. - **use\_slots**: whether or not to use replication slots. Defaults to `true` on PostgreSQL 9.4+. - **recovery\_conf**: additional configuration settings written to recovery.conf when configuring follower. There is no recovery.conf anymore in PostgreSQL 12, but you may continue using this section, because Patroni handles it transparently. - **parameters**: list of configuration settings for Postgres. diff --git a/docs/ha_multi_dc.rst b/docs/ha_multi_dc.rst index 0a7f610e..2a9bfd27 100644 --- a/docs/ha_multi_dc.rst +++ b/docs/ha_multi_dc.rst @@ -44,7 +44,7 @@ You should not use ``pg_ctl promote`` in this scenario, you need "manually promo In case you want to return to the "initial" state, there are only two ways of resolving it: -- Add the standby_cluster section back and it will trigger pg_rewind, but there are chances that pg_rewind will fail. +- Add the standby_cluster section back and it will trigger ``pg_rewind``; however, for ``pg_rewind`` to function properly, either the cluster must be initialized with ``data page checksums`` (``--data-checksums`` option for ``initdb``) and/or ``wal_log_hints`` must be set to ``on``, but there are still chances that ``pg_rewind`` might fail due to other factors. - Rebuild the standby cluster from scratch. Before promoting standby cluster one have to manually ensure that the source cluster is down (STONITH). When DC1 recovers, the cluster has to be converted to a standby cluster. diff --git a/docs/replication_modes.rst b/docs/replication_modes.rst index 3c6fb38e..017abf15 100644 --- a/docs/replication_modes.rst +++ b/docs/replication_modes.rst @@ -79,6 +79,6 @@ Patroni will only assign one or more synchronous standby nodes based on ``synchr On each HA loop iteration Patroni re-evaluates synchronous standby nodes choice. If the current list of synchronous standby nodes are connected and has not requested its synchronous status to be removed it remains picked. Otherwise the cluster member available for sync that is furthest ahead in replication is picked. -.. [1] The data is still there, but recovering it requires a manual recovery effort by data recovery specialists. When Patroni is allowed to rewind with ``use_pg_rewind`` the forked timeline will be automatically erased to rejoin the failed primary with the cluster. +.. [1] The data is still there, but recovering it requires a manual recovery effort by data recovery specialists. When Patroni is allowed to rewind with ``use_pg_rewind`` the forked timeline will be automatically erased to rejoin the failed primary with the cluster. However, for ``use_pg_rewind`` to function properly, either the cluster must be initialized with ``data page checksums`` (``--data-checksums`` option for ``initdb``) and/or ``wal_log_hints`` must be set to ``on``. .. [2] Clients can change the behavior per transaction using PostgreSQL's ``synchronous_commit`` setting. Transactions with ``synchronous_commit`` values of ``off`` and ``local`` may be lost on fail over, but will not be blocked by replication delays. diff --git a/docs/standby_cluster.rst b/docs/standby_cluster.rst index 15c779eb..5aa75e14 100644 --- a/docs/standby_cluster.rst +++ b/docs/standby_cluster.rst @@ -70,6 +70,10 @@ multiple hosts separated by commas, Patroni will: * use ``target_session_attrs=read-write`` when trying to determine whether we need to run ``pg_rewind`` or when executing ``pg_rewind`` on all nodes of the standby cluster. +* It is important to note that for ``pg_rewind`` to operate successfully, + either the cluster must be initialized with ``data page checksums`` + (``--data-checksums`` option for ``initdb``) and/or ``wal_log_hints`` must be set to ``on``. + Otherwise, ``pg_rewind`` will not function properly. There is also a possibility to replicate the standby cluster from another standby cluster or from a standby member of the primary cluster: for that, you diff --git a/docs/yaml_configuration.rst b/docs/yaml_configuration.rst index 331034d0..0929404d 100644 --- a/docs/yaml_configuration.rst +++ b/docs/yaml_configuration.rst @@ -310,7 +310,7 @@ PostgreSQL - **- mapname1 systemname1 pguser1** - **- mapname1 systemname2 pguser2** - **pg\_ctl\_timeout**: How long should pg_ctl wait when doing ``start``, ``stop`` or ``restart``. Default value is 60 seconds. - - **use\_pg\_rewind**: try to use pg\_rewind on the former leader when it joins cluster as a replica. + - **use\_pg\_rewind**: try to use pg\_rewind on the former leader when it joins cluster as a replica. Either the cluster must be initialized with ``data page checksums`` (``--data-checksums`` option for ``initdb``) and/or ``wal_log_hints`` must be set to ``on``, or ``pg_rewind`` will not work. - **remove\_data\_directory\_on\_rewind\_failure**: If this option is enabled, Patroni will remove the PostgreSQL data directory and recreate the replica. Otherwise it will try to follow the new leader. Default value is **false**. - **remove\_data\_directory\_on\_diverged\_timelines**: Patroni will remove the PostgreSQL data directory and recreate the replica if it notices that timelines are diverging and the former primary can not start streaming from the new primary. This option is useful when ``pg_rewind`` can not be used. While performing timelines divergence check on PostgreSQL v10 and older Patroni will try to connect with replication credential to the "postgres" database. Hence, such access should be allowed in the pg_hba.conf. Default value is **false**. - **replica\_method**: for each create_replica_methods other than basebackup, you would add a configuration section of the same name. At a minimum, this should include "command" with a full path to the actual script to be executed. Other configuration parameters will be passed along to the script in the form "parameter=value". diff --git a/patroni/config.py b/patroni/config.py index 662047f8..6b46f4bb 100644 --- a/patroni/config.py +++ b/patroni/config.py @@ -388,7 +388,6 @@ class Config(object): * ``cluster_name``: set through ``scope`` local configuration or through ``PATRONI_SCOPE`` environment variable; * ``hot_standby``: always enabled; - * ``wal_log_hints``: always enabled. :param parameters: Postgres parameters to be processed. Should be the parsed YAML value of ``postgresql.parameters`` configuration, either from local or from dynamic configuration. diff --git a/patroni/config_generator.py b/patroni/config_generator.py index 1ff4dce0..e898c92a 100644 --- a/patroni/config_generator.py +++ b/patroni/config_generator.py @@ -268,7 +268,8 @@ class SampleConfigGenerator(AbstractConfigGenerator): wal_level = 'hot_standby' if self.pg_major < 90600 else 'replica' self.config['bootstrap']['dcs']['postgresql']['parameters']['wal_level'] = wal_level - self.config['bootstrap']['dcs']['postgresql']['use_pg_rewind'] = True + self.config['bootstrap']['dcs']['postgresql']['use_pg_rewind'] = \ + parse_bool(self.config['bootstrap']['dcs']['postgresql']['parameters']['wal_log_hints']) is True if self.pg_major >= 110000: self.config['postgresql']['authentication'].setdefault( 'rewind', {'username': 'rewind_user'}).setdefault('password', NO_VALUE_MSG) diff --git a/patroni/postgresql/config.py b/patroni/postgresql/config.py index 8b7d0328..3755a258 100644 --- a/patroni/postgresql/config.py +++ b/patroni/postgresql/config.py @@ -325,7 +325,7 @@ class ConfigHandler(object): 'track_commit_timestamp': ('off', _bool_validator, 90500), 'max_replication_slots': (10, IntValidator(min=4), 90400), 'max_worker_processes': (8, IntValidator(min=2), 90400), - 'wal_log_hints': ('on', _bool_is_true_validator, 90400) + 'wal_log_hints': ('on', _bool_validator, 90400) }) _RECOVERY_PARAMETERS = CaseInsensitiveSet(recovery_parameters.keys()) @@ -1101,7 +1101,7 @@ class ConfigHandler(object): def reload_config(self, config: Dict[str, Any], sighup: bool = False) -> None: self._superuser = config['authentication'].get('superuser', {}) server_parameters = self.get_server_parameters(config) - params_skip_changes = CaseInsensitiveSet((*self._RECOVERY_PARAMETERS, 'hot_standby', 'wal_log_hints')) + params_skip_changes = CaseInsensitiveSet((*self._RECOVERY_PARAMETERS, 'hot_standby')) conf_changed = hba_changed = ident_changed = local_connection_address_changed = False param_diff = CaseInsensitiveDict() diff --git a/tests/test_config_generator.py b/tests/test_config_generator.py index e9b82686..640c92b6 100644 --- a/tests/test_config_generator.py +++ b/tests/test_config_generator.py @@ -11,7 +11,7 @@ from patroni.__main__ import main as _main from patroni.config import Config from patroni.config_generator import AbstractConfigGenerator, get_address, NO_VALUE_MSG from patroni.log import PatroniLogger -from patroni.utils import patch_config +from patroni.utils import patch_config, parse_bool from . import psycopg_connect @@ -56,7 +56,8 @@ class TestGenerateConfig(unittest.TestCase): dynamic_config['postgresql']['parameters'] = dict(dynamic_config['postgresql']['parameters']) del dynamic_config['standby_cluster'] dynamic_config['postgresql']['parameters']['wal_keep_segments'] = 8 - dynamic_config['postgresql']['use_pg_rewind'] = True + dynamic_config['postgresql']['use_pg_rewind'] = \ + parse_bool(dynamic_config['postgresql']['parameters']['wal_log_hints']) is True self.config = { 'scope': self.environ['PATRONI_SCOPE'],