def _merge_permanent_slots(self, slots: Dict[str, Dict[str, Any]], permanent_slots: Dict[str, Any],
                               name: str, role: 'PostgresqlRole', can_advance_slots: bool) -> List[str]:
        """Merge replication *slots* for members with *permanent_slots*.

        Perform validation of configured permanent slot name, skipping invalid names.

        Will update *slots* in-line based on ``type`` of slot, ``physical`` or ``logical``, and name of node.
        Type is assumed to be ``physical`` if there are no attributes stored as the slot value.

        :param slots: Slot names with existing attributes if known.
        :param name: name of this node.
        :param role: role of the node. One of :class:`~patroni.postgresql.misc.PostgresqlRole` values.
        :param permanent_slots: dictionary containing slot name key and slot information values.
        :param can_advance_slots: ``True`` if ``pg_replication_slot_advance()`` function is available,
                                  ``False`` otherwise.

        :returns: List of disabled permanent, logical slot names, if postgresql version < 11.
        """
        from ..postgresql.misc import PostgresqlRole

        name = slot_name_from_member_name(name)
        topology = {slot_name_from_member_name(m.name): m.replicatefrom and slot_name_from_member_name(m.replicatefrom)
                    for m in self.members}

        disabled_permanent_logical_slots: List[str] = []

        for slot_name, value in permanent_slots.items():
            if not slot_name_re.match(slot_name):
                logger.error("Invalid permanent replication slot name '%s'", slot_name)
                logger.error("Slot name may only contain lower case letters, numbers, and the underscore chars")
                continue

            tmp = deepcopy(value) if value else {'type': 'physical'}
            if isinstance(tmp, dict):
                value = cast(Dict[str, Any], tmp)
                if 'type' not in value:
                    value['type'] = 'logical' if value.get('database') and value.get('plugin') else 'physical'

                if value['type'] == 'physical':
                    # Don't try to create permanent physical replication slot for yourself
                    if slot_name not in slots and slot_name != name:
                        # On the leader we expected to have permanent slots active, except the case when it is a slot
                        # for a cascading replica. Lets consider a configuration with C being a permanent slot. In this
                        # case we should have the following: A(B: active, C: inactive) <- B (C: active) <- C
                        # We don't consider the same situation on node B, because if node C doesn't exists, we will not
                        # be able to know its `replicatefrom` tag value.
                        expected_active = not topology.get(slot_name) and role in (PostgresqlRole.PRIMARY,
                                                                                   PostgresqlRole.STANDBY_LEADER)
                        slots[slot_name] = {**value, 'expected_active': expected_active}
                    continue

                if self.is_logical_slot(value):
                    if not can_advance_slots:
                        disabled_permanent_logical_slots.append(slot_name)
                    elif slot_name in slots:
                        logger.error("Permanent logical replication slot {'%s': %s} is conflicting with"
                                     " physical replication slot for cluster member", slot_name, value)
                    else:
                        slots[slot_name] = value
                    continue

            logger.error("Bad value for slot '%s' in permanent_slots: %s", slot_name, permanent_slots[slot_name])
        return disabled_permanent_logical_slots
Merge replication *slots* for members with *permanent_slots*.

        Perform validation of configured permanent slot name, skipping invalid names.

        Will update *slots* in-line based on ``type`` of slot, ``physical`` or ``logical``, and name of node.
        Type is assumed to be ``physical`` if there are no attributes stored as the slot value.

        :param slots: Slot names with existing attributes if known.
        :param name: name of this node.
        :param role: role of the node. One of :class:`~patroni.postgresql.misc.PostgresqlRole` values.
        :param permanent_slots: dictionary containing slot name key and slot information values.
        :param can_advance_slots: ``True`` if ``pg_replication_slot_advance()`` function is available,
                                  ``False`` otherwise.

        :returns: List of disabled permanent, logical slot names, if postgresql version < 11.
        
patroni/dcs/__init__.py