From 252a1b78ed715b9696fa94a0135d1f45caf089de Mon Sep 17 00:00:00 2001 From: Alexander Kukushkin Date: Mon, 11 Nov 2019 16:18:53 +0100 Subject: [PATCH] Make it possible to change use_slots online (#1261) Previously it required restarting Patroni and removing slots manually Fixes https://github.com/zalando/patroni/issues/1158 --- patroni/dcs/__init__.py | 6 ++++-- patroni/postgresql/config.py | 3 ++- patroni/postgresql/slots.py | 11 +++-------- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/patroni/dcs/__init__.py b/patroni/dcs/__init__.py index aafcfd46..384fc413 100644 --- a/patroni/dcs/__init__.py +++ b/patroni/dcs/__init__.py @@ -442,14 +442,16 @@ class Cluster(namedtuple('Cluster', 'initialize,config,leader,last_leader_operat # the current master, because that member would replicate from elsewhere. We still create the slot if # the replicatefrom destination member is currently not a member of the cluster (fallback to the # master), or if replicatefrom destination member happens to be the current master + use_slots = self.config and self.config.data.get('postgresql', {}).get('use_slots', True) if role in ('master', 'standby_leader'): - slot_members = [m.name for m in self.members if m.name != name and + slot_members = [m.name for m in self.members if use_slots and m.name != name and (m.replicatefrom is None or m.replicatefrom == name or not self.has_member(m.replicatefrom))] permanent_slots = (self.config and self.config.permanent_slots or {}).copy() else: # only manage slots for replicas that replicate from this one, except for the leader among them - slot_members = [m.name for m in self.members if m.replicatefrom == name and m.name != self.leader.name] + slot_members = [m.name for m in self.members if use_slots and + m.replicatefrom == name and m.name != self.leader.name] permanent_slots = {} slots = {slot_name_from_member_name(name): {'type': 'physical'} for name in slot_members} diff --git a/patroni/postgresql/config.py b/patroni/postgresql/config.py index 20c49588..2c48d457 100644 --- a/patroni/postgresql/config.py +++ b/patroni/postgresql/config.py @@ -502,7 +502,8 @@ class ConfigHandler(object): primary_conninfo = self.primary_conninfo_params(member) if primary_conninfo: recovery_params['primary_conninfo'] = primary_conninfo - if self._postgresql.slots_handler.use_slots and not (is_remote_master and member.no_replication_slot): + if self.get('use_slots', True) and self._postgresql.major_version >= 90400 \ + and not (is_remote_master and member.no_replication_slot): recovery_params['primary_slot_name'] = member.primary_slot_name if is_remote_master \ else slot_name_from_member_name(self._postgresql.name) diff --git a/patroni/postgresql/slots.py b/patroni/postgresql/slots.py index 91d6b743..fac8eced 100644 --- a/patroni/postgresql/slots.py +++ b/patroni/postgresql/slots.py @@ -15,19 +15,14 @@ class SlotsHandler(object): def __init__(self, postgresql): self._postgresql = postgresql - self._use_slots = postgresql.config.get('use_slots', True) self._replication_slots = {} # already existing replication slots self.schedule() - @property - def use_slots(self): - return self._use_slots and self._postgresql.major_version >= 90400 - def _query(self, sql, *params): return self._postgresql.query(sql, *params, retry=False) def load_replication_slots(self): - if self.use_slots and self._schedule_load_slots: + if self._postgresql.major_version >= 90400 and self._schedule_load_slots: replication_slots = {} cursor = self._query('SELECT slot_name, slot_type, plugin, database FROM pg_catalog.pg_replication_slots') for r in cursor: @@ -45,7 +40,7 @@ class SlotsHandler(object): return cursor.rowcount == 1 def sync_replication_slots(self, cluster): - if self.use_slots: + if self._postgresql.major_version >= 90400: try: self.load_replication_slots() @@ -104,5 +99,5 @@ class SlotsHandler(object): def schedule(self, value=None): if value is None: - value = self.use_slots + value = self._postgresql.major_version >= 90400 self._schedule_load_slots = value