HEX
Server: LiteSpeed
System: Linux us-phx-web1284.main-hosting.eu 4.18.0-553.109.1.lve.el8.x86_64 #1 SMP Thu Mar 5 20:23:46 UTC 2026 x86_64
User: u300739242 (300739242)
PHP: 8.2.30
Disabled: system, shell_exec, passthru, mysql_list_dbs, ini_alter, dl, symlink, link, chgrp, leak, popen, apache_child_terminate, virtual, mb_send_mail
Upload Files
File: //opt/alt/python311/lib/python3.11/site-packages/redis/__pycache__/cluster.cpython-311.pyc
�

$�;fv/����ddlZddlZddlZddlZddlZddlZddlZddlmZddl	m
Z
mZmZddl
mZmZddlmZmZmZmZddlmZmZddlmZmZmZmZmZmZmZm Z m!Z!m"Z"m#Z#m$Z$m%Z%m&Z&m'Z'ddl(m)Z)m*Z*m+Z+m,Z,m-Z-ej.e/��Z0d	�Z1d
�Z2d�Z3d�Z4d
�Z5dZ6dZ7dZ8dZ9dZ:e;gd���Z<d�Z=Gd�de��Z>Gd�de��Z?Gd�d��Z@Gd�d��ZAGd�d��ZBGd�d e��ZCGd!�d"e?��ZDd#�ZEeEe?jF��eD_FeEe?jG��eD_GeEe?jH��eD_HeEe?jI��eD_IeEe?jJ��eD_JeEe?jK��eD_KeEe?jL��eD_LeEe?jM��eD_MeEe?jN��eD_NeEe?jO��eD_OeEe?jP��eD_PeEe?jQ��eD_QeEe?jR��eD_ReEe?jS��eD_SeEe?jT��eD_TeEe?jU��eD_UeEe?jV��eD_VeEe?jW��eD_WeEe?jX��eD_XeEe?jY��eD_YeEe?jZ��eD_ZeEe?j[��eD_[eEe?j\��eD_\eEe?j]��eD_]eEe?j^��eD_^eEe?j_��eD__eEe?j`��eD_`eEe?ja��eD_aeEe?jb��eD_beEe?jc��eD_ceEe?jd��eD_deEe?je��eD_eeEe?jf��eD_fGd$�d%��ZgGd&�d'��ZhdS)(�N)�OrderedDict)�CaseInsensitiveDict�PubSub�Redis)�CommandsParser�RedisClusterCommands)�ConnectionPool�
DefaultParser�Encoder�	parse_url)�REDIS_CLUSTER_HASH_SLOTS�key_slot)�AskError�BusyLoadingError�ClusterCrossSlotError�ClusterDownError�ClusterError�ConnectionError�	DataError�MasterDownError�
MovedError�RedisClusterException�
RedisError�
ResponseError�SlotNotCoveredError�TimeoutError�
TryAgainError)�
dict_merge�list_keys_to_dict�merge_result�safe_str�str_if_bytesc��|�d|��S)N�:���host�ports  �@/opt/alt/python311/lib/python3.11/site-packages/redis/cluster.py�
get_node_namer**s�����T����c�B�|jp|jj|dfi|��S)Nr)�
connection�connection_pool�get_connection)�
redis_node�args�optionss   r)r/r/.s;��� ��$M�J�$>�$M��Q��%�%��%�%�r+c�R�g}|���D]
}||dz
}�d|fS)N�r)�values)�command�resr2�	keys_list�primary_ress     r)�parse_scan_resultr:4s8���I��z�z�|�|�$�$���[��^�#�	�	��i�<�r+c���t��}|���D]0}|D]+\}}	||xx|z
cc<�#t$r|||<Y�(wxYw�1d�|���D��}|S)Nc��g|]	\}}||f��
Sr%r%)�.0�channel�numsubs   r)�
<listcomp>z'parse_pubsub_numsub.<locals>.<listcomp>Ds!��L�L�L����7�F�#�L�L�Lr+)rr5�KeyError�items)r6r7r2�numsub_d�numsub_tupsr>�	numsubbed�
ret_numsubs        r)�parse_pubsub_numsubrG;s����}�}�H��z�z�|�|�.�.��"-�	.�	.��G�Y�
.���!�!�!�Y�.�!�!�!�!���
.�
.�
.�$-���!�!�!�
.����	.�M�L�8�>�>�;K�;K�L�L�L�J��s�>�A�Ac���	�|�dd����fd��	i}|D]3}|dd�\}}}|dd�}�	|��	fd�|D��d�|||f<�4|S)N�current_host�c�B��t|d��p�|dfS�Nrr4)r")r1rIs �r)�
fix_serverz'parse_cluster_slots.<locals>.fix_serverKs#����D��G�$�$�4��d�1�g�=�=r+�c���g|]}�|���Sr%r%)r=�replicarMs  �r)r@z'parse_cluster_slots.<locals>.<listcomp>Ts ���F�F�F�'���W�-�F�F�Fr+)�primary�replicas)�get)
�respr2�slots�slot�start�endrQrRrIrMs
        @@r)�parse_cluster_slotsrYHs������;�;�~�r�2�2�L�>�>�>�>�>�
�E��
�
��"�2�A�2�h���s�G�����8��!�z�7�+�F�F�F�F�X�F�F�F�
�
��e�S�j���
�Lr+rQrPzslot-id)�charset�connection_classr.�client_name�db�decode_responses�encoding�encoding_errors�errorsr'�max_connections�
nodes_flag�redis_connect_func�passwordr(�retry�retry_on_timeout�socket_connect_timeout�socket_keepalive�socket_keepalive_options�socket_timeout�ssl�ssl_ca_certs�ssl_certfile�
ssl_cert_reqs�ssl_keyfile�ssl_password�unix_socket_path�usernamer&)'�BITCOUNT�BITPOS�EXISTS�GEODIST�GEOHASH�GEOPOS�	GEORADIUS�GEORADIUSBYMEMBER�GET�GETBIT�GETRANGE�HEXISTS�HGET�HGETALL�HKEYS�HLEN�HMGET�HSTRLEN�HVALS�KEYS�LINDEX�LLEN�LRANGE�MGET�PTTL�	RANDOMKEY�SCARD�SDIFF�SINTER�	SISMEMBER�SMEMBERS�SRANDMEMBER�STRLEN�SUNION�TTL�ZCARD�ZCOUNT�ZRANGE�ZSCOREc�B�d�|���D��}|S)z9
    Remove unsupported or disabled keys from kwargs
    c�>�i|]\}}|tv�|tv�||��Sr%)�REDIS_ALLOWED_KEYS�KWARGS_DISABLED_KEYS)r=�k�vs   r)�
<dictcomp>z"cleanup_kwargs.<locals>.<dictcomp>�s?������A�q��"�"�"�q�0D�'D�'D�	
�1�'D�'D�'Dr+)rB)�kwargs�connection_kwargss  r)�cleanup_kwargsr��s1�����L�L�N�N������r+c
�>�eZdZeejeeee	e
ed���ZdS)�
ClusterParser)�ASK�TRYAGAIN�MOVED�CLUSTERDOWN�	CROSSSLOT�
MASTERDOWNN)�__name__�
__module__�__qualname__rr
�EXCEPTION_CLASSESrrrrrrr%r+r)r�r��sD������"�
��'��%��+�.�)�
	
�	
�
�
���r+r�c���eZdZdZdZdZdZdZdZeeeeehZ	e
egd�e��edd	ge��egd
�e����Z
ide�de�d
e�de�de�de�de�de�de�de�de�de�de�de�de�de�de�dei�Ze
edge��edgd���ed d!ge��egd"�d#���ed$d%gd&���ed'gd(���ed)ge����ZeeefZ								dPd/�Zd0�Zd1�Zd2�Zd3�Ze d4���Z!d5�Z"d6�Z#dQd7�Z$d8�Z%d9�Z&d:�Z'd;�Z(dRd<�Z)d=�Z*d>�Z+dSd?�Z,dQd@�Z-dTdA�Z.dB�Z/dC�Z0dD�Z1dE�Z2dF�Z3dG�Z4dH�Z5dI�Z6dJ�Z7dK�Z8dL�Z9dM�Z:dN�Z;dO�Z<d*S)U�RedisCluster��	primariesrR�all�randomzdefault-node)CzACL CATzACL DELUSERzACL GENPASSzACL GETUSERzACL HELPzACL LISTzACL LOGzACL LOADzACL SAVEzACL SETUSERz	ACL USERSz
ACL WHOAMIzCLIENT LIST�CLIENT SETNAMEzCLIENT GETNAME�
CONFIG SET�CONFIG REWRITE�CONFIG RESETSTAT�TIME�PUBSUB CHANNELS�
PUBSUB NUMPAT�
PUBSUB NUMSUB�PING�INFO�SHUTDOWNr��SCAN�DBSIZE�BGSAVEzSLOWLOG GETzSLOWLOG LEN�
SLOWLOG RESET�WAIT�SAVE�MEMORY PURGEzMEMORY MALLOC-STATSzMEMORY STATS�LASTSAVEzCLIENT TRACKINGINFO�CLIENT PAUSE�CLIENT UNPAUSE�CLIENT UNBLOCKz	CLIENT IDzCLIENT REPLYzCLIENT GETREDIRzCLIENT INFOzCLIENT KILL�READONLY�	READWRITEzCLUSTER INFO�CLUSTER MEETz
CLUSTER NODESzCLUSTER REPLICAS�
CLUSTER RESET�CLUSTER SET-CONFIG-EPOCH�
CLUSTER SLOTS�CLUSTER COUNT-FAILURE-REPORTS�CLUSTER KEYSLOT�COMMANDz
COMMAND COUNTzCOMMAND GETKEYSz
CONFIG GET�DEBUGr�r�r�r��FLUSHALL�FLUSHDB)�CLUSTER COUNTKEYSINSLOT�CLUSTER DELSLOTS�CLUSTER GETKEYSINSLOT�CLUSTER SETSLOTzCLUSTER ADDSLOTSr�r�r�zCLUSTER FAILOVERzCLUSTER FORGETr�r�r�zCLUSTER REPLICATEr�zCLUSTER SAVECONFIGr�r�r��ASKINGr�r�r�r�c�^�tt|�������S�N)�sum�listr5�r6r7s  r)�<lambda>zRedisCluster.<lambda>Rs���T�#�*�*�,�,�%7�%7�!8�!8�r+r�r�)r�r�r�r�r�r�r�r�r�r�r�c�r�t|t��r!t|�����n|Sr�)�
isinstance�dictr�r5r�s  r)r�zRedisCluster.<lambda>i�+��j��d�6K�6K�!T��S�Z�Z�\�\�!2�!2�!2�QT�r+r�r�c�r�t|t��r!t|�����n|Sr�)r�r�r�r5r�s  r)r�zRedisCluster.<lambda>pr�r+r�c�T�t|�����dkrdndSrL)r�r5r�s  r)r�zRedisCluster.<lambda>vs$��c�#�*�*�,�,�&7�&7�!�&;�&;����r+r�N��rNF�
c	��t�d��|�g}d|	vrtd���d}
|��d}
t|��}d|vrtd���d|vr|dd	krtd
���|	�|��|	�d��}|	�d|��}|�t||����nJ|�&|�$|�t||����n"t|��d	krtd
���t�	d|����|	�
dd��|_|	�d|ji��tdi|	��}	t|	�dd��|	�dd��|	�dd����|_||_|jj���|_|jj���|_||_d	|_||_d|_t7d||
|d�|	��|_t9|jj��|_t9|jj��|_ tC|��|_"tGj$��|_%dS)ag	
         Initialize a new RedisCluster client.

         :startup_nodes: 'list[ClusterNode]'
             List of nodes from which initial bootstrapping can be done
         :host: 'str'
             Can be used to point to a startup node
         :port: 'int'
             Can be used to point to a startup node
         :require_full_coverage: 'bool'
            When set to False (default value): the client will not require a
            full coverage of the slots. However, if not all slots are covered,
            and at least one node has 'cluster-require-full-coverage' set to
            'yes,' the server will throw a ClusterDownError for some key-based
            commands. See -
            https://redis.io/topics/cluster-tutorial#redis-cluster-configuration-parameters
            When set to True: all slots must be covered to construct the
            cluster client. If not all slots are covered, RedisClusterException
            will be thrown.
        :read_from_replicas: 'bool'
             Enable read from replicas in READONLY mode. You can read possibly
             stale data.
             When set to true, read commands will be assigned between the
             primary and its replications in a Round-Robin manner.
        :cluster_error_retry_attempts: 'int'
             Retry command execution attempts when encountering ClusterDownError
             or ConnectionError
        :reinitialize_steps: 'int'
            Specifies the number of MOVED errors that need to occur before
            reinitializing the whole cluster topology. If a MOVED error occurs
            and the cluster does not need to be reinitialized on this current
            error handling, only the MOVED slot will be patched with the
            redirected node.
            To reinitialize the cluster on every MOVED error, set
            reinitialize_steps to 1.
            To avoid reinitializing the cluster on moved errors, set
            reinitialize_steps to 0.

         :**kwargs:
             Extra arguments that will be sent into Redis instance when created
             (See Official redis-py doc for supported kwargs
         [https://github.com/andymccurdy/redis-py/blob/master/redis/client.py])
             Some kwargs are not supported and will raise a
             RedisClusterException:
                 - db (Redis do not support database SELECT in cluster mode)
        z.Creating a new instance of RedisCluster clientNr]z4Argument 'db' is not possible to use in cluster modeFT�pathzFRedisCluster does not currently support Unix Domain Socket connectionsrz9A ``db`` querystring option can only be 0 in cluster moder'r(a5RedisCluster requires at least one node to discover the cluster. Please provide one of the followings:
1. host and port, for example:
 RedisCluster(host='localhost', port=6379)
2. list of startup nodes, for example:
 RedisCluster(startup_nodes=[ClusterNode('localhost', 6379), ClusterNode('localhost', 6378)])zstartup_nodes : rdr_�utf-8r`�strictr^)�
startup_nodes�from_url�require_full_coverager%)&�log�inforr�updaterS�append�ClusterNode�len�debug�pop�user_on_connect_func�
on_connectr�r�encoder�cluster_error_retry_attempts�	__class__�
COMMAND_FLAGS�copy�
command_flags�
NODE_FLAGS�
node_flags�read_from_replicas�reinitialize_counter�reinitialize_steps�
nodes_manager�NodesManagerr�#CLUSTER_COMMANDS_RESPONSE_CALLBACKS�cluster_response_callbacks�RESULT_CALLBACKS�result_callbacksr�commands_parser�	threading�Lock�_lock)�selfr'r(r�r�r�rr�urlr�r��url_optionss            r)�__init__zRedisCluster.__init__�s���t	���A�B�B�B�� ��M��6�>�>�'�F���
�
���?��H�#�C�.�.�K���$�$�+�)�����{�"�"�{�4�'8�A�'=�'=�+�O����
�M�M�+�&�&�&��:�:�f�%�%�D��:�:�f�d�+�+�D�� � ��T�4�!8�!8�9�9�9�9�
�
�$�"2�� � ��T�4�!8�!8�9�9�9�9�
��
�
�1�
$�
$�'�4���
�	�	�	�4�]�4�4�5�5�5�%+�J�J�/C�T�$J�$J��!��
�
�+�T�_�=�>�>�>��)�)�&�)�)����J�J�z�7�+�+��J�J�(�(�3�3��J�J�)�5�1�1�
�
���
-I��)�!�^�9�>�>�@�@����.�3�8�8�:�:���"4���$%��!�"4���!���)�
�'��"7�
�
��	
�
���+>��N�>�+
�+
��'�!4�D�N�4S� T� T���-�d�3�3����^�%�%��
�
�
r+c��|Sr�r%�rs r)�	__enter__zRedisCluster.__enter__s���r+c�.�|���dSr���close�r�exc_type�	exc_value�	tracebacks    r)�__exit__zRedisCluster.__exit__����
�
�����r+c�.�|���dSr�rrs r)�__del__zRedisCluster.__del__r!r+c��|���D]9}|jr0	|jj����)#t$rY�5wxYw�:dSr�)�	get_nodes�redis_connectionr.�
disconnect�OSError�r�nodes  r)�disconnect_connection_poolsz(RedisCluster.disconnect_connection_poolssu���N�N�$�$�	�	�D��$�
���)�9�D�D�F�F�F�F�������D�����
�	�	s�>�
A�
Ac��|dd|i|��S)a
        Return a Redis client object configured from the given URL

        For example::

            redis://[[username]:[password]]@localhost:6379/0
            rediss://[[username]:[password]]@localhost:6379/0
            unix://[[username]:[password]]@/path/to/socket.sock?db=0

        Three URL schemes are supported:

        - `redis://` creates a TCP socket connection. See more at:
          <https://www.iana.org/assignments/uri-schemes/prov/redis>
        - `rediss://` creates a SSL wrapped TCP socket connection. See more at:
          <https://www.iana.org/assignments/uri-schemes/prov/rediss>
        - ``unix://``: creates a Unix Domain Socket connection.

        The username, password, hostname, path and all querystring values
        are passed through urllib.parse.unquote in order to replace any
        percent-encoded values with their corresponding characters.

        There are several ways to specify a database number. The first value
        found will be used:

            1. A ``db`` querystring option, e.g. redis://localhost?db=0
            2. If using the redis:// or rediss:// schemes, the path argument
               of the url, e.g. redis://localhost/0
            3. A ``db`` keyword argument to this function.

        If none of these options are specified, the default db=0 is used.

        All querystring options are cast to their appropriate Python types.
        Boolean arguments can be specified with string values "True"/"False"
        or "Yes"/"No". Values that cannot be properly cast cause a
        ``ValueError`` to be raised. Once parsed, the querystring arguments
        and keyword arguments are passed to the ``ConnectionPool``'s
        class initializer. In the case of conflicting arguments, querystring
        arguments always win.

        rr%r%)�clsrr�s   r)r�zRedisCluster.from_url!s ��T�s�%�%�s�%�f�%�%�%r+c�>�|�t��|���|jrI|�d��t|�����dkrtd���|j�|�|��dSdS)z�
        Initialize the connection, authenticate and select a database and send
         READONLY if it is set during object initialization.
        r��OKzREADONLY command failedN)	�
set_parserr�r�r�send_commandr"�
read_responserr�)rr-s  r)r�zRedisCluster.on_connectMs���
	���m�,�,�,��������"�	A�
�#�#�J�/�/�/��J�4�4�6�6�7�7�4�?�?�%�&?�@�@�@��$�0��%�%�j�1�1�1�1�1�1�0r+c��|jsA|j5|js|j�|g��ddd��n#1swxYwY|jSr�)r&rr�create_redis_connectionsr)s  r)�get_redis_connectionz!RedisCluster.get_redis_connectionbs����$�	H���
H�
H��,�H��&�?�?���G�G�G�
H�
H�
H�
H�
H�
H�
H�
H�
H�
H�
H����
H�
H�
H�
H��$�$s�#>�A�Ac�:�|j�|||��Sr�)r�get_node�rr'r(�	node_names    r)r7zRedisCluster.get_nodeis���!�*�*�4��y�A�A�Ar+c�@�|j�t��Sr�)r�get_nodes_by_server_type�PRIMARYrs r)�
get_primarieszRedisCluster.get_primariesl����!�:�:�7�C�C�Cr+c�@�|j�t��Sr�)rr;�REPLICArs r)�get_replicaszRedisCluster.get_replicasor>r+c�|�tjt|jj�������Sr�)r��choicer�r�nodes_cacher5rs r)�get_random_nodezRedisCluster.get_random_noders,���}�T�$�"4�"@�"G�"G�"I�"I�J�J�K�K�Kr+c�X�t|jj�����Sr�)r�rrDr5rs r)r%zRedisCluster.get_nodesus"���D�&�2�9�9�;�;�<�<�<r+c�&�|�|��}|jj�|��}|�t	|��dkrtd|�d����|r%t	|jj|��dkrdS|rd}nd}||S)z�
        Get the node that holds the key's slot.
        If replica set to True but the slot doesn't have any replicas, None is
        returned.
        Nr�Slot "z " is not covered by the cluster.�r4)�keyslotr�slots_cacherSr�r)r�keyrPrV�
slot_cache�node_idxs      r)�get_node_from_keyzRedisCluster.get_node_from_keyxs����|�|�C� � ���'�3�7�7��=�=�
����Z���A�!5�!5�%�&U�t�&U�&U�&U�V�V�V��	�s�4�-�9�$�?�@�@�1�D�D��4�
�	��H�H��H��(�#�#r+c��|jjS)z0
        Get the cluster's default node
        )r�default_noders r)�get_default_nodezRedisCluster.get_default_node�s���!�.�.r+c���|�|�|j����t�d��dS||j_t�d|����dS)z�
        Set the default node of the cluster.
        :param node: 'ClusterNode'
        :return True if the default node was set, else False
        N�r9zVThe requested node does not exist in the cluster, so the default node was not changed.Fz$Changed the default cluster node to T)r7�namer�r�rrQr)s  r)�set_default_nodezRedisCluster.set_default_node�sk���<�4�=�=�4�9�=�=�=�E��H�H�4�
�
�
��5�*.���'����>��>�>�?�?�?��tr+c��|�|���}|j�td|j�d����|j���S)ai
        Returns a Monitor object for the specified target node.
        The default cluster node will be selected if no target node was
        specified.
        Monitor is useful for handling the MONITOR command to the redis server.
        next_command() method returns one command from monitor
        listen() method yields commands from monitor.
        Nz
Cluster Node z has no redis_connection)rRr&rrU�monitor)r�target_nodes  r)rXzRedisCluster.monitor�s^�����/�/�1�1�K��'�/�'�J�� 0�J�J�J���
��+�3�3�5�5�5r+c�$�t|f|||d�|��S)z~
        Allows passing a ClusterNode, or host&port, to get a pubsub instance
        connected to the specified node
        )r*r'r()�
ClusterPubSub)rr*r'r(r�s     r)�pubsubzRedisCluster.pubsub�s#��
�T�M��4�d�M�M�f�M�M�Mr+c	���|rtd���|rtd���t|j|jj|j|j|j|j|j���S)ac
        Cluster impl:
            Pipelines do not work in cluster mode the same way they
            do in normal mode. Create a clone of this object so
            that simulating pipelines will work correctly. Each
            command will be called directly when used and
            when calling execute() will only return the result stack.
        z(shard_hint is deprecated in cluster modez)transaction is deprecated in cluster mode)rr�r
rr�rr)	r�ClusterPipelinerr�r
rr�rr)r�transaction�
shard_hints   r)�pipelinezRedisCluster.pipeline�sx���	T�'�(R�S�S�S��	U�'�(S�T�T�T���,��,�:�!�2�'+�'F�)-�)J�#�6�#�6�
�
�
�	
r+c���|d}|�dd��}|�|}n|j�|��}|r t�d|�d|����||jjkr|���gS||jjkr|�	��S||jj
kr|���S||jjkr|�
��S||jjkr
|jjgS|j|�}|j�||jo|t(v��}t�d|�d|����|gS)NrrczTarget node/s for z: zTarget for z: slot )r�rrSr�r�r��RANDOMrE�	PRIMARIESr=�REPLICASrA�	ALL_NODESr%�DEFAULT_NODErrQ�determine_slot�get_node_from_slotr�
READ_COMMANDS)rr1r�r6rc�command_flagrVr*s        r)�_determine_nodeszRedisCluster._determine_nodes�s~���q�'���Z�Z��d�3�3�
��!�%�L�L� �-�1�1�'�:�:�L��	F��I�I�D�7�D�D�l�D�D�E�E�E��4�>�0�0�0��(�(�*�*�+�+�
�T�^�5�
5�
5��%�%�'�'�'�
�T�^�4�
4�
4��$�$�&�&�&�
�T�^�5�
5�
5��>�>�#�#�#�
�T�^�8�
8�
8��&�3�4�4�'�4�&��-�D��%�8�8��d�-�J�'�]�2J���D�
�I�I�7�D�7�7��7�7�8�8�8��6�Mr+c�B�|jdkrdS|j|jzdkS)NrF)rrrs r)�_should_reinitializedz"RedisCluster._should_reinitialized�s-��
�"�a�'�'��5��,�t�/F�F�!�K�Kr+c�T�|j�|��}t|��S)z�
        Calculate keyslot for a given key.
        See Keys distribution model in https://redis.io/topics/cluster-spec
        )r��encoder)rrLr�s   r)rJzRedisCluster.keyslots%��

�L����$�$����{�{�r+c�Z�|���j}|jj|g|�R�S)zj
        Get the keys in the command. If the command has no keys in in, None is
        returned.
        )rRr&r�get_keys)rr1�
redis_conns   r)�_get_command_keyszRedisCluster._get_command_keyss6��
�*�*�,�,�=�
�,�t�#�,�Z�?�$�?�?�?�?r+c����j�|d��tkr|dS�j|�}|�t	|��dkrtd|�����t	|��dkrM�fd�|D��}t	|��dkrt|d�d����|���S��|d��S)z@
        Figure out what slot based on command and args
        rr4Nz�No way to dispatch this command to Redis Cluster. Missing key.
You can execute the command by specifying target nodes.
Command: c�:��h|]}��|����Sr%)rJ)r=rLrs  �r)�	<setcomp>z.RedisCluster.determine_slot.<locals>.<setcomp>$s%���7�7�7�3�T�\�\�#�&�&�7�7�7r+z) - all keys must map to the same key slot)rrS�SLOT_IDrtr�rr�rJ)rr1�keysrUs`   r)rhzRedisCluster.determine_slots������!�!�$�q�'�*�*�g�5�5���7�N�&�t�%�t�,���<�3�t�9�9��>�>�'�2�+/�2�2���
��t�9�9�q�=�=�8�7�7�7�$�7�7�7�E��5�z�z�Q���+��A�w�I�I�I�����9�9�;�;���<�<��Q��(�(�(r+c�8�|j���dSr�)r�
initializers r)�reinitialize_cachesz RedisCluster.reinitialize_caches.s����%�%�'�'�'�'�'r+c��|jS)z.
        Get the connections' encoder
        )r�rs r)�get_encoderzRedisCluster.get_encoder1s���|�r+c��|jjS)z9
        Get the connections' key-word arguments
        )rr�rs r)�get_connection_kwargsz"RedisCluster.get_connection_kwargs7s���!�3�3r+c�>�t|t��o||jvSr�)r��strr)r�target_nodess  r)�_is_nodes_flagzRedisCluster._is_nodes_flag=s���,��,�,�P����1P�Pr+c��t|t��r|}nbt|t��r|g}nIt|t��r|���}ntdt
|�������|S)Nz�target_nodes type can be one of the following: node_flag (PRIMARIES, REPLICAS, RANDOM, ALL_NODES),ClusterNode, list<ClusterNode>, or dict<any, ClusterNode>. The passed type is )r�r�r�r�r5�	TypeError�type)rr��nodess   r)�_parse_target_nodesz RedisCluster._parse_target_nodes@s����l�D�)�)�	� �E�E�
��k�
2�
2�	�!�N�E�E�
��d�
+�
+�	�!�'�'�)�)�E�E��;�'+�<�&8�&8�;�;���
��r+c��d}d}|�dd��}|�,|�|��s|�|��}d}|rdn|j}d}t	d|��D]�}	i}	|s&|j|i|�d|i��}|st
d|�d	����|D]}
|j|
g|�Ri|��|	|
j<�|j	|d|	fi|��cS#t$r*}t|��tj
vr|}n|�Yd}~��d}~wwxYw|�)
a"
        Wrapper for ERRORS_ALLOW_RETRY error handling.

        It will try the number of times specified by the config option
        "self.cluster_error_retry_attempts" which defaults to 3 unless manually
        configured.

        If it reaches the number of times, the command will raise the exception

        Key argument :target_nodes: can be passed with the following types:
            nodes_flag: PRIMARIES, REPLICAS, ALL_NODES, RANDOM
            ClusterNode
            list<ClusterNode>
            dict<Any, ClusterNode>
        FNr�Tr4rrcz!No targets were found to execute z command on)r�r�r�r��rangerlr�_execute_commandrU�_process_result�
BaseExceptionr�r��ERRORS_ALLOW_RETRY)rr1r��target_nodes_specifiedr��passed_targets�retry_attempts�	exception�_r7r*�es            r)�execute_commandzRedisCluster.execute_commandTs��� "'�������N�D�9�9���%�d�.A�.A�.�.Q�.Q�%��3�3�N�C�C�L�%)�"�(�N�A�A�T�-N�	��	��q�.�)�)�	�	�A�
���-��#8�4�#8��$�!'�$�$�4B�$�$�$�L�(��3�Q��Q�Q�Q����)�R�R�D�%:�T�%:�4�%Q�$�%Q�%Q�%Q�&�%Q�%Q�C��	�N�N�+�t�+�D��G�S�C�C�F�C�C�C�C�C�� �
�
�
���7�7�l�=�=�=�!"�I�I��G��I�I�I�I�����	
�����s�)AC�
C<� C7�7C<c���|d}d}d}d}d}d}	t|j��}
d}|
dk�r1|
dz}
	|r|�|���}n7|	r5|j|�}|j�||jo|tv��}d}	t�	d|�d|j
�d|j����|�|��}t|g|�Ri|��}|r&|�d	��|j|d	fi|��d}|j|�|j||fi|��}
||jvr|j||
fi|��}
|
|�|j�|��SS#t&t(f$r-}t�t-|�����d}~wt.t0f$r�}t�t-|����|�|���|dz
}|d
krt5jd��n|j����Yd}~�n�d}~wt:$r�}t�d��|xjdz
c_|���r!|j���d|_n|j� |��d
}	Yd}~�nnd}~wtB$r@t�d��|
|jdzkrt5jd��Y�n"tD$rA}t�d��tG|j$|j%���}d
}Yd}~n�d}~wtL$rN}t�d��t5jd��|j���|�d}~wtN$r8}|�(��}t�d|����|�d}~wtR$r7}t�d��|r|���|�d}~wwxYw|�|j�|��n"#|�|j�|��wwxYw|
dk��1tUd���)z9
        Send a command to a node in the cluster
        rNFr4rTzExecuting command z on target node: � r��g�?rTrrIg�������?rr&rzResponseError: r�zTTL exhausted.)+�int�RedisClusterRequestTTLr7rhrrirrjr�r��server_typerUr5r/r1�parse_responserr.�releaserrr�r�rrr'�time�sleepr{rrrn�update_moved_exceptionrrr*r'r(rr�__str__r�r)rrYr1r�r6r0r-�
redirect_addr�asking�moved�ttl�connection_error_retry_counterrV�responser��messages                r)r�zRedisCluster._execute_command�si���q�'���
��
��
������$�-�.�.��)*�&��A�g�g��1�H�C�e
C��	"�"&�-�-�-�-�"H�"H�K�K��"�/�4�.��5�D�"&�"4�"G�"G��d�5�R�'�]�:R�#�#�K�"�E��	�	�D��D�D�"�.�D�D�1<�1A�D�D����"�6�6�{�C�C�
�+�J�H��H�H�H��H�H�
��#��+�+�H�5�5�5�-�J�-�j�(�M�M�f�M�M�M�"�F�'�
�'��.�.�4�:�4�Z��S�S�F�S�S���d�=�=�=�G�t�>�w�G� � � �$*� � �H� �N�)��.�6�6�z�B�B�B�B�*��K*�+;�<�
�
�
��
�
�d�1�g�g�&�&�&������#�\�2�
�
�
��
�
�d�1�g�g�&�&�&��)��)�)�+�+�+�.�!�3�.�2�A�5�5��J�t�$�$�$�$��&�1�1�3�3�3��%�$�$�$�$������
�
�
��
�
�l�+�+�+��)�)�Q�.�)�)��-�-�/�/�A��&�1�1�3�3�3�01�D�-�-��&�=�=�a�@�@�@������������ �
%�
%�
%��
�
�o�.�.�.���4�q�8�8�8��J�t�$�$�$����
�
�
��
�
�j�)�)�)� -�1�6��� G� G� G�
������������#�
�
�
��
�
�0�1�1�1��
�4� � � ��"�-�-�/�/�/������� �
�
�
��)�)�+�+���
�
�9��9�9�:�:�:������� �
�
�
��
�
�o�.�.�.��,��)�)�+�+�+�������	
�����)��.�6�6�z�B�B�B����)��.�6�6�z�B�B�B�B�*����M�A�g�g�R�+�,�,�,s��DE�P�&(F�P�"A7H�P8�
P�,A;J-�'P8�-A	P�6P8�9	P�7L>�9P8�>
P�A	N�
P�!3O�
P�!2P�P�P8�8Qc��	|j5|jr|j���ddd��dS#1swxYwYdS#t$rYdSwxYwr�)rrr�AttributeErrorrs r)rzRedisCluster.closes���	���
/�
/��%�/��&�,�,�.�.�.�
/�
/�
/�
/�
/�
/�
/�
/�
/�
/�
/�
/����
/�
/�
/�
/�
/�
/���	�	�	��D�D�	���s,�A�!7�A�;�A�;�A�
A�Ac��||jvr|j|||fi|��St|��dkr't|�����dS|S)a
        Process the result of the executed command.
        The function would return a dict or a single value.

        :type command: str
        :type res: dict

        `res` should be in the following format:
            Dict<node_name, command_result>
        r4r)r
r�r�r5)rr6r7r�s    r)r�zRedisCluster._process_resultse���d�+�+�+�1�4�(��1�'�3�I�I�&�I�I�I�
��X�X��]�]���
�
���%�%�a�(�(��Jr+)Nr�NrNFr�FN�NNN)Fr��NN)=r�r�r�r�rdrerfrcrgrrrrxr�boolr�r�rYr
rGr r:rrrrr�rrr r#r+�classmethodr�r�r5r7r=rArEr%rOrRrVrXr\rarlrnrJrtrhr|r~r�r�r�r�r�rr�r%r+r)r�r��s#���������I��H��I�
�F�!�L��X�y�&�,�G�J��J���D
�D
�D
�J
�MG	
�G	
�P	����
�
�	
�	
�	��
�
�
�
�	
�	
�aY�Y�M�v+��D�+�'��+�	"�3�+�	�D�	+�
	�D�+�	�$�
+�	 ��+�	�3�+�	��+�	�T�+�	��+�	�d�+�	#�D�+�	�4�+�	�,�+� 	�$�!+�"	�D�#+�$	�T�%+�+�'�*"�z����
�
 �		
�	
�	���
�
9�8�		
�	
�	���!�
�
�	
�	
�	��
�
�
�
U�T�	
�	
� 	����
�
U�T�	
�	
�	�� �
�
C�B�		
�	
�	���
�
�		
�	
�c7�7��t	������
��%&�#�� ��G&�G&�G&�G&�R�������������)&�)&��[�)&�V2�2�2�*%�%�%�B�B�B�B�D�D�D�D�D�D�L�L�L�=�=�=�$�$�$�$�(/�/�/���� 6�6�6�6�"N�N�N�N�
�
�
�
�2!�!�!�FL�L�L����@�@�@�)�)�)�<(�(�(����4�4�4�Q�Q�Q����(=�=�=�~v-�v-�v-�p�������r+r�c�(�eZdZdd�Zd�Zd�Zd�ZdS)r�Nc��|dkrtj|��}||_||_t	||��|_||_||_dS)N�	localhost)�socket�
gethostbynamer'r(r*rUr�r&)rr'r(r�r&s     r)rzClusterNode.__init__*sR���;����'��-�-�D���	���	�!�$��-�-��	�&��� 0����r+c�X�d|j�d|j�d|j�d|j�d|j�d�S)Nz[host=z,port=z,name=z
,server_type=z,redis_connection=�])r'r(rUr�r&rs r)�__repr__zClusterNode.__repr__4sa��
9�T�Y�
9�
9��I�
9�
9��I�
9�
9� �+�
9�
9�!%� 5�	
9�
9�
9�	
r+c�L�t|t��o|j|jkSr�)r�r�rU)r�objs  r)�__eq__zClusterNode.__eq__=s ���#�{�+�+�E���D�I�0E�Er+c�J�|j�|j���dSdSr�)r&rrs r)r#zClusterNode.__del__@s.��� �,��!�'�'�)�)�)�)�)�-�,r+r�)r�r�r�rr�r�r#r%r+r)r�r�)sX������1�1�1�1�
�
�
�F�F�F�*�*�*�*�*r+r�c�&�eZdZdZdd�Zd�Zd�ZdS)�LoadBalancerz$
    Round-Robin Load Balancing
    rc�"�i|_||_dSr�)�primary_to_idx�start_index)rr�s  r)rzLoadBalancer.__init__Js�� ���&����r+c�f�|j�||j��}|dz|z|j|<|S)Nr4)r��
setdefaultr�)rrQ�	list_size�server_indexs    r)�get_server_indexzLoadBalancer.get_server_indexNs:���*�5�5�g�t�?O�P�P��(4�q�(8�I�'E���G�$��r+c�8�|j���dSr�)r��clearrs r)�resetzLoadBalancer.resetTs����!�!�#�#�#�#�#r+N)r)r�r�r��__doc__rr�r�r%r+r)r�r�EsP��������'�'�'�'����$�$�$�$�$r+r�c�h�eZdZ			dd�Zdd�Zd�Zd�Zdd�Zd�Zd	�Z	d
�Z
d�Zd�Zd
�Z
d�Zd�ZdS)r	FNc�&�i|_i|_i|_d|_|�|��||_||_d|_||_t��|_
|�tj��}||_
|���dSr�)rDrKr�rQ�populate_startup_nodesr��_require_full_coverage�_moved_exceptionr�r��read_load_balancerrrrr{)rr�r�r��lockr�s      r)rzNodesManager.__init__Ys������������ ����#�#�M�2�2�2� ��
�&;��#� $���!'���".�.�.����<��>�#�#�D���
��������r+c��|rE|rC|dkrtj|��}|j�t	||�����S|r|j�|��St
�d��dS)z�
        Get the requested node from the cluster's nodes.
        nodes.
        :return: ClusterNode if the node exists, else None
        r�r&zEget_node requires one of the following: 1. node name 2. host and portN)r�r�rDrSr*r��errorr8s    r)r7zNodesManager.get_nodeps����
	�D�
	��{�"�"��+�D�1�1���#�'�'�
�4�d�(K�(K�(K�L�L�L�
�	��#�'�'�	�2�2�2��I�I�#�
�
�
�
�4r+c��||_dSr�)r�)rr�s  r)r�z#NodesManager.update_moved_exception�s�� )����r+c�p�|j}|�|j|j���}|�|jt
urt
|_n/t
|j|jt
��}||j|j<||j	|j
vr�|j	|j
d}t|_|j	|j
�|��|j	|j
�
|��||j	|j
d<|j|kr||_n|g|j	|j
<d|_dS)z@
        Update the slot's node with the redirected one
        r&Nr)r�r7r'r(r�r<r�rDrUrK�slot_idr@r��removerQ)rr��redirected_node�old_primarys    r)�_update_moved_slotsz NodesManager._update_moved_slots�s)��
�!���-�-�Q�V�!�&�-�A�A���&��*�'�9�9�.5��+��*�!�&�!�&�'�B�B�O�5D�D��_�1�2��d�.�q�y�9�9�9��*�1�9�5�a�8�K�'.�K�#���Q�Y�'�.�.�{�;�;�;�
��Q�Y�'�.�.��?�?�?�-<�D��Q�Y�'��*�� �K�/�/�$3��!��
,;�*;�D��Q�Y�'� $����r+c��|jr:|j5|jr|���ddd��n#1swxYwY|j�|���t|j|��dkrt
d|�d|j�d����|durL|j|dj}|j	�
|t|j|����}n^|�)|tkst|j|��dkrd}n0tj
dt|j|��dz
��}|j||S)z9
        Gets a node that servers this hash slot
        NrrHz5" not covered by the cluster. "require_full_coverage=�"Tr4)r�rr�rKrSr�rr�rUr�r�r<r��randint)rrVrr��primary_namerNs      r)rizNodesManager.get_node_from_slot�s���� �	/���
/�
/��(�/��,�,�.�.�.�
/�
/�
/�
/�
/�
/�
/�
/�
/�
/�
/����
/�
/�
/�
/������%�%�-��T�5E�d�5K�1L�1L�PQ�1Q�1Q�%�I��I�I�*.�*E�I�I�I���
�
��%�%��+�D�1�!�4�9�L��.�?�?��c�$�"2�4�"8�9�9���H�H�
���g�%�%��4�#�D�)�*�*�a�/�/��H�H��~�a��T�-=�d�-C�)D�)D�q�)H�I�I�H����%�h�/�/s�7�;�;c�N���fd�|j���D��S)z�
        Get all nodes with the specified server type
        :param server_type: 'primary' or 'replica'
        :return: list of ClusterNode
        c�*��g|]}|j�k�
|��Sr%)r�)r=r*r�s  �r)r@z9NodesManager.get_nodes_by_server_type.<locals>.<listcomp>�s1���
�
�
����;�.�.�
�.�.�.r+)rDr5)rr�s `r)r;z%NodesManager.get_nodes_by_server_type�s=���
�
�
�
��(�/�/�1�1�
�
�
�	
r+c�.�|D]}||j|j<�dS)zK
        Populate all startup nodes and filters out any duplicates
        N)r�rU)rr��ns   r)r�z#NodesManager.populate_startup_nodes�s/���	+�	+�A�)*�D��q�v�&�&�	+�	+r+c�D�tdt��D]	}||vrdS�
dS)NrFT)r�r
)rrK�is   r)�check_slots_coveragez!NodesManager.check_slots_coverage�s:���q�2�3�3�	�	�A���#�#��u�u�$��tr+c�f�|D]-}|j�$|jd|j|jd�|j��|_�.dS)zV
        This function will create a redis connection to all nodes in :nodes:
        Nr&r%)r&�create_redis_noder'r(r�)rr�r*s   r)r4z%NodesManager.create_redis_connections�s_���	�	�D��$�,�(>��(>�)�����)�)��,�)�)��%��	�	r+c���|jrI|�d|i��|�d|i��ttdi|�����}ntd||d�|��}|S)Nr'r()r.r&r%)r�r�rr	)rr'r(r��rs     r)r�zNodesManager.create_redis_node�sw���=�	6��M�M�6�4�.�)�)�)��M�M�6�4�.�)�)�)��n�&>�&>�v�&>�&>�?�?�?�A�A��5�4�d�5�5�f�5�5�A��r+c
��
��t�d��|���i}i}g}d}d}|j}|j���D�]8}	|jr|j}n\tj|��}	|	�	ddd���|j
|j|jfi|	��}||j|j
_t|����d����durt#d���t%|�d����}
d}n�#t(t*f$r7}|j}t�d	|j
�d
|����Yd}~��d}~wt0$rV}t�d��|���}
d
|
vsd|
vrYd}~��et#d|�d|
�����d}~wt2$r3}|���}
t#d|j
�d|
�����d}~wwxYwt5|
��dkrSt5|
ddd��dkr.t5|j��dkr|j|
ddd<|
D�]���d}|d}|dkr|j}t7|d��}|�t9||����}|�t;||t<��}|||j
<t?t7�d��t7�d��dz��D�]C}||vr�g||<||� |���fd�t?dt5�����D��}|D]r}|d}|d}|�t9||����}|�t;||tB��}||� |��|||j
<�s��||d}|j
|j
kr_|� |j
�d|j
�d|����t5|��dkr%t#dd�"|���������E���|�#|��}|rn��:|st#d���|�$tK|�������|s/|j&r(t#dt5|���dtN�d ����||_(||_)|�*t<��d|_+|�,|j(�����d|_-dS)!z�
        Initializes the nodes cache, slots cache and redis connections.
        :startup_nodes:
            Responsible for discovering other nodes in the cluster
        z/Initializing the nodes' topology of the clusterFTr�)r^r_�cluster_enabledz(Cluster mode is not enabled on this noder�zQAn exception occurred while trying to initialize the cluster using the seed node z:
Nz6ReseponseError sending "cluster slots" to redis serverr�r�z7ERROR sending "cluster slots" command to redis server: z	. error: z6ERROR sending "cluster slots" command to redis server r4rrIrJc� ��g|]
}�|��Sr%r%)r=�jrVs  �r)r@z+NodesManager.initialize.<locals>.<listcomp>`s���(N�(N�(N�Q��a��(N�(N�(Nr+rNz vs z
 on slot: r�z6startup_nodes could not agree on a valid slots cache: z, zORedis Cluster cannot be connected. Please provide at least one reachable node. z9All slots are not covered after query all startup_nodes. z of z covered...).r�r�r�r�r�r5r&r�deepcopyr�r�r'r(rUr�r�rSrr"r�rrr�r�r�	Exceptionr�r�r*r�r<r�r�r@�joinr�r4r�r�r
rDrKr;rQr�r�)r�tmp_nodes_cache�	tmp_slots�
disagreements�startup_nodes_reachable�
fully_coveredr��startup_noder��copy_kwargs�
cluster_slotsr��msgr��primary_noder'r(rYr��
replica_nodes�replica_node�target_replica_node�tmp_slotrVs                       @r)r{zNodesManager.initializes���	�	�	�C�D�D�D��
�
�������	��
�"'���
��'�� �.�5�5�7�7�r	�r	�L�-
��0�
O�$�5�A�A�#'�-��"7�"7�K��&�&�D�g�'V�'V�W�W�W�.��.�$�)�<�+<���@K���A�NO�D�&�|�'8�9�J���������%6�7�7�8�8�E�A�A�/�B����!-�Q�->�->��-O�-O� P� P�
�*.�'�'��#�\�2�
�
�
��i���
�
�4�$�)�4�4�.1�4�4����
��������� �
�
�
��
�
�V�W�W�W��)�)�+�+�� �G�+�+�|�w�/F�/F��H�H�H�H�/�D�#/�D�D�:A�D�D���������
�
�
��)�)�+�+��+�D�*�/�D�D�:A�D�D��������
�����M�"�"�a�'�'��
�a�(��+�A�.�/�/�1�4�4���*�+�+�q�0�0�)5�):�
�a� ��#�A�&�%�.
"�.
"��#�A�w��#�A����2�:�:�'�,�D��<��?�+�+��-�1�1�-��d�2K�2K�L�L���&�"-�d�D�'�"B�"B�K�4?��� 0�1��s�4��7�|�|�S��a��\�\�A�-=�>�>�!"�!"�A��	�)�)�')�	�!��!�!��+�+�K�8�8�8�(N�(N�(N�(N�%��3�t�9�9�:M�:M�(N�(N�(N�
�,9�
4�
4�L�#/��?�D�#/��?�D�2A�2E�2E� -�d�D� 9� 9�3�3�/� 3�:�6A�$��g�6V�6V� 3�%�a�L�/�/�0C�D�D�D�!4�,� 3� 8���
4�"$-�Q�<��?��#�=�K�,<�<�<�)�0�0�#+�=� U� U�k�6F� U� U�RS� U� U���� #�=�1�1�A�5�5�&;�%O�48�I�I�m�4L�4L�%O�%O�'"�'"�!"��=!"�F!�5�5�i�@�@�M��
���
�
'�	�'�'���
�	
�%�%�d�?�+A�+A�+C�+C�&D�&D�E�E�E��	��!<�	�(���y�>�>���'?������
�+���$��� �9�9�'�B�B�1�E����#�#�D�$4�$;�$;�$=�$=�>�>�>� $����s7�CD3�3H�,E6�6
H�6G�?G�
H�!.H�Hc��d|_|j���D]"}|jr|j����#dSr�)rQrDr5r&rr)s  r)rzNodesManager.close�sS�� ����$�+�+�-�-�	.�	.�D��$�
.��%�+�+�-�-�-��	.�	.r+c�\�	|j���dS#t$rYdSwxYwr�)r�r�r�rs r)r�zNodesManager.reset�sD��	��#�)�)�+�+�+�+�+���	�	�	��D�D�	���s��
+�+)FFNr�)FN)r�r�r�rr7r�r�rir;r�r�r4r�r{rr�r%r+r)r	r	Xs��������#�
�����.����**�*�*�%%�%%�%%�N!0�!0�!0�!0�F

�

�

�+�+�+����
�
�
����]%�]%�]%�~.�.�.�����r+r	c�D��eZdZdZd	�fd�	Zd	d�Zd�Zd�Zd�Zd�Z	�xZ
S)
r[z�
    Wrapper for PubSub class.

    IMPORTANT: before using ClusterPubSub, read about the known limitations
    with pubsub in Cluster mode and learn how to workaround them:
    https://redis-py-cluster.readthedocs.io/en/stable/pubsub.html
    Nc���t�d��d|_|�||||��|j�dn|�|j��j}||_t��jdi|�||j	d���dS)a*
        When a pubsub instance is created without specifying a node, a single
        node will be transparently chosen for the pubsub connection on the
        first command execution. The node will be determined by:
         1. Hashing the channel name in the request to find its keyslot
         2. Selecting a node that handles the keyslot: If read_from_replicas is
            set to true, a replica can be selected.

        :type redis_cluster: RedisCluster
        :type node: ClusterNode
        :type host: str
        :type port: int
        z&Creating new instance of ClusterPubSubN)r.r�r%)
r�r�r*�set_pubsub_noder5r.�cluster�superrr�)r�
redis_clusterr*r'r(r�r.r�s       �r)rzClusterPubSub.__init__�s����	���9�:�:�:���	����]�D�$��=�=�=��y� �
�D��3�3�D�I�>�>�N�	�
%��������	
�	
��	
�&5�}�?T�	
�	
�	
�	
�	
�	
�	
r+c��|�%|�|||j|j��|}nZ|�4|�2|�||���}|�||||��|}n$t	||g��durtd���d}||_dS)aN
        The pubsub node will be set according to the passed node, host and port
        When none of the node, host, or port are specified - the node is set
        to None and will be determined by the keyslot of the channel in the
        first command to be executed.
        RedisClusterException will be thrown if the passed node does not exist
        in the cluster.
        If host is passed without port, or vice versa, a DataError will be
        thrown.
        :type cluster: RedisCluster
        :type node: ClusterNode
        :type host: str
        :type port: int
        Nr&Tz6Passing a host requires passing a port, and vice versa)�_raise_on_invalid_noder'r(r7�anyrr*)rrr*r'r(�pubsub_nodes      r)rzClusterPubSub.set_pubsub_node�s������'�'���t�y�$�)�L�L�L��K�K�
�
�$�"2��#�#��D�#�9�9�D��'�'���t�T�B�B�B��K�K�
�$���
�
�$�
&�
&��W�X�X�X��K���	�	�	r+c��|jS)zJ
        Get the node that is being used as the pubsub connection
        )r*rs r)�get_pubsub_nodezClusterPubSub.get_pubsub_node�s���y�r+c�l�|�|�|j����td|�d|�d����dS)zl
        Raise a RedisClusterException if the node is None or doesn't exist in
        the cluster.
        NrTzNode r$z doesn't exist in the cluster)r7rUr)rrr*r'r(s     r)rz$ClusterPubSub._raise_on_invalid_node�sR��
�<�=�1�1�D�I�1�F�F�N�'�B��B�B�t�B�B�B���
�O�Nr+c�,�|j��|j��t|��dkrM|d}|j�|��}|jj�||jj��}n|j���}||_	|j�
|��}|j|_|j�d|j��|_|j�
|j��|j}|j||jg|�R�dS)z�
        Execute a publish/subscribe command.

        Taken code from redis-py and tweak to make it work within a cluster.
        Nr4r\)r-r.r�rrJrrirrEr*r5r/r`�register_connect_callbackr��_executer1)rr1r�r>rVr*r&r-s        r)r�zClusterPubSub.execute_commands���?�"��#�+��t�9�9�q�=�=�#�1�g�G��<�/�/��8�8�D��<�5�H�H��d�l�=���D�D�
 �<�7�7�9�9�D� ��	�#'�<�#D�#D�T�#J�#J� �'7�'G��$�"�2�A�A��$�/���D�O�

�O�5�5�d�o�F�F�F��_�
���
�j�*�"9�A�D�A�A�A�A�A�Ar+c�,�|j�|jjSdS)zH
        Get the Redis connection of the pubsub connected node.
        N)r*r&rs r)r5z"ClusterPubSub.get_redis_connection(s���9� ��9�-�-�!� r+r�)r�r�r�r�rrrrr�r5�
__classcell__�r�s@r)r[r[�s����������
�
�
�
�
�
�6 � � � �B������!B�!B�!B�F.�.�.�.�.�.�.r+r[c����eZdZdZeeeeefZ							d!�fd�	Z
d�Zd�Zd	�Z
d
�Zd�Zd�Zd
�Zd�Zd�Zd�Zd�Zd"d�Zd�Z	d#d�Z	d#�fd�	Zd�Zd�Zd�Zd�Zd�Zd�Zd�Z d�Z!d�Z"d �Z#�xZ$S)$r^z8
    Support for Redis pipeline
    in cluster mode
    NFr�r�c�6��t�d��g|_||_d|_|p|jj���|_|r|ng|_	||_
|jj���|_||_
||_d|_||_t#|�dd��|�dd��|�dd����|_t)t+����|_d	S)
r�z(Creating new instance of ClusterPipelineFrr_r�r`r�r^N)r�r��
command_stackr�refresh_table_asapr�rrr
r�rrrrr�rrrrSr�rrr)
rrr
rr�rr�rr�r�s
         �r)rzClusterPipeline.__init__>s���	���;�<�<�<����*���"'����F��� ?� D� D� F� F�	
��/<�C�]�]����"4���!�^�9�>�>�@�@���*D��'�,H��)�$%��!�"4�����J�J�z�7�+�+��J�J�(�(�3�3��J�J�)�5�1�1�
�
��� .�e�g�g�6�6����r+c�,�t|��j�S�r�)r�r�rs r)r�zClusterPipeline.__repr__cs���t�*�*�%�'�'r+c��|Srr%rs r)rzClusterPipeline.__enter__gs���r+c�.�|���dS�r�N)r�rs    r)r zClusterPipeline.__exit__ks���
�
�����r+c�R�	|���dS#t$rYdSwxYwr�)r�r�rs r)r#zClusterPipeline.__del__os:��	��J�J�L�L�L�L�L���	�	�	��D�D�	���s��
&�&c�*�t|j��Sr)r�rrs r)�__len__zClusterPipeline.__len__us���4�%�&�&�&r+c��dS)z@Pipeline instances should  always evaluate to True on Python 2.7Tr%rs r)�__nonzero__zClusterPipeline.__nonzero__y����tr+c��dS)z?Pipeline instances should  always evaluate to True on Python 3+Tr%rs r)�__bool__zClusterPipeline.__bool__}r"r+c��|j|i|��S)z?
        Wrapper function for pipeline_execute_command
        )�pipeline_execute_command�rr1r�s   r)r�zClusterPipeline.execute_command�s��-�t�,�d�=�f�=�=�=r+c	�|�|j�t||t|j������|S)zN
        Appends the executed command to the pipeline's command stack
        )rr��PipelineCommandr��rr1r2s   r)r&z(ClusterPipeline.pipeline_execute_command�s@��	
��!�!��D�'�3�t�/A�+B�+B�C�C�	
�	
�	
��r+c��|D]D}|j}t|t��r&|�||jdz|j��|��EdS)z8
        Raise the first exception on the stack
        r4N)�resultr�r��annotate_exception�positionr1)r�stack�cr�s    r)�raise_first_errorz!ClusterPipeline.raise_first_error�s`���	�	�A���A��!�Y�'�'�
��'�'��1�:��>�1�6�B�B�B���
�	�	r+c��d�tt|����}d|�d|�d|jd��}|f|jdd�z|_dS)zS
        Provides extra context to the exception prior to it being handled
        r�z
Command # z (z) of pipeline caused error: rr4N)r��mapr!r1)rr��numberr6�cmdr�s      r)r-z"ClusterPipeline.annotate_exception�st���h�h�s�8�W�-�-�.�.��
1��
1�
1�3�
1�
1�&�^�A�.�
1�
1�	���)�.����"4�4�	���r+Tc��|j}	|�||��|���S#|���wxYw)zB
        Execute all the commands in the current pipeline
        )r�send_cluster_commandsr�)r�raise_on_errorr/s   r)�executezClusterPipeline.execute�sE���"��	��-�-�e�^�D�D��J�J�L�L�L�L��D�J�J�L�L�L�L���s	�3�A	c�V�g|_t��|_d|_d|_dS)z/
        Reset back to empty pipeline.
        FN)r�set�scripts�watching�explicit_transactionrs r)r�zClusterPipeline.reset�s.�� ����u�u��� ��
�$)��!�!�!r+c��|sgStd|j��D],}	|�|||���cS#t$rY�)wxYwtd���)a
        Wrapper for CLUSTERDOWN error handling.

        If the cluster reports it is down it is assumed that:
         - connection_pool was disconnected
         - connection_pool was reseted
         - refereh_table_asap set to True

        It will try the number of times specified by
        the config option "self.cluster_error_retry_attempts"
        which defaults to 3 unless manually configured.

        If it reaches the number of times, the command will
        raises ClusterDownException.
        r)r8�allow_redirectionsz0CLUSTERDOWN error. Unable to rebuild the cluster)r�r��_send_cluster_commandsr)rr/r8r@r�s     r)r7z%ClusterPipeline.send_cluster_commands�s���$�	��I��q�$�;�<�<�
	�
	�A�	
��2�2��#1�'9�3�������
$�
�
�
���
�����Q�R�R�Rs�7�
A�Ac���t|d����}i}|D]�}|j|j�}|j�||jo|jdtv��}|j}	|	|vrH|�|��}
t|
|j��}t|
j|
j|��||	<||	�
|����|���}|D]}
|
����|D]}
|
����|���D]!}
|
j�|
j���"td�|D��d����}|r�|r�t&�d|dj�dt+|dj��j�d	t1|dj������|xjd
z
c_|���r|j���|D]I}	t9��j|ji|j��|_�,#t>$r}||_Yd}~�Bd}~wwxYwd�t|d
����D��}|r|� |��|S)z�
        Send a bunch of cluster commands to the redis cluster.

        `allow_redirections` If the pipeline should follow
        `ASK` & `MOVED` responses automatically. If set
        to false it will raise RedisClusterException.
        c��|jSr��r.��xs r)r�z8ClusterPipeline._send_cluster_commands.<locals>.<lambda>s��a�j�r+)rLrc3�XK�|]%}t|jtj���!|V��&dSr�)r�r,r^r��r=r0s  r)�	<genexpr>z9ClusterPipeline._send_cluster_commands.<locals>.<genexpr>KsK����
�
���a�h��(J�K�K�
��
�
�
�
�
�
r+c��|jSr�rDrEs r)r�z8ClusterPipeline._send_cluster_commands.<locals>.<lambda>Ps��!�*�r+z7An exception occurred during pipeline execution. args: ���z	, error: r�r4Nc��g|]	}|j��
Sr%)r,rHs  r)r@z:ClusterPipeline._send_cluster_commands.<locals>.<listcomp>xs��N�N�N��A�H�N�N�Nr+c��|jSr�rDrEs r)r�z8ClusterPipeline._send_cluster_commands.<locals>.<lambda>xs��!�*�r+)!�sortedrhr1rrirrjrUr5r/�NodeCommandsr�r.r�r5�write�readr�r-r�r�r�r,r�r�rrnr{rr�r2rr1)rr/r8r@�attemptr�r0rVr*r9r0r-�
node_commandsr�r�r�r�s                �r)rAz&ClusterPipeline._send_cluster_commands�s�����$8�$8�9�9�9����
�	'�	'�A�'�4�&���/�D��%�8�8��d�-�L�!�&��)�}�2L���D��	�I���%�%�!�6�6�t�<�<�
�+�J���?�?�
�#/��-�z�/I�:�$�$��i� �
�)��#�#�A�&�&�&�&������
��	�	�A�
�G�G�I�I�I�I��	�	�A�
�F�F�H�H�H�H�(�����	4�	4�A�
��%�%�a�l�3�3�3�3��
�
� �
�
�
�
%�$�

�
�
���"	!�)�"	!�&
�M�M�-� ���)�-�-��w�r�{�1�2�2�;�-�-��w�r�{�)�*�*�-�-�
�
�
�
�%�%��*�%�%��)�)�+�+�
0��"�-�-�/�/�/��
!�
!��!� 7�u�w�w�6���L�!�)�L�L�A�H�H��!�!�!�!� �A�H�H�H�H�H�H�����!����
O�N�f�U�8L�8L�&M�&M�&M�N�N�N���	*��"�"�5�)�)�)��s�
(H6�6
I�I�Ic�(�|std���dS)r�z4ASK & MOVED redirection not allowed in this pipelineN�r)rr@s  r)�_fail_on_redirectz!ClusterPipeline._fail_on_redirects)��!�	�'�F���
�	�	r+c� �td���)r�z method eval() is not implementedrUrs r)�evalzClusterPipeline.eval�s��#�$F�G�G�Gr+c� �td���)r�z!method multi() is not implementedrUrs r)�multizClusterPipeline.multi����#�$G�H�H�Hr+c� �td���)r�z5method immediate_execute_command() is not implementedrUr*s   r)�immediate_execute_commandz)ClusterPipeline.immediate_execute_command�s��#�C�
�
�	
r+c� �td���)r�z0method _execute_transaction() is not implementedrUr's   r)�_execute_transactionz$ClusterPipeline._execute_transaction�s��#�$V�W�W�Wr+c� �td���)r�z(method load_scripts() is not implementedrUrs r)�load_scriptszClusterPipeline.load_scripts�s��#�$N�O�O�Or+c� �td���)r�z!method watch() is not implementedrU�r�namess  r)�watchzClusterPipeline.watch�r[r+c� �td���)r�z#method unwatch() is not implementedrUrs r)�unwatchzClusterPipeline.unwatch�s��#�$I�J�J�Jr+c� �td���)r�z4method script_load_for_pipeline() is not implementedrUr's   r)�script_load_for_pipelinez(ClusterPipeline.script_load_for_pipeline�s��#�B�
�
�	
r+c�~�t|��dkrtd���|�d|d��S)z7
        "Delete a key specified by ``names``"
        r4z=deleting multiple keys is not implemented in pipeline command�DELr)r�rr�rcs  r)�deletezClusterPipeline.delete�sD���u�:�:��?�?�'�R���
��#�#�E�5��8�4�4�4r+)NNNFr�r�)T)TT)%r�r�r�r�rrrrrr�rr�rr r#rr!r$r�r&r1r-r9r�r7rArVrXrZr]r_rarergrirlrrs@r)r^r^0s0���������	��������#'�� �%&��#7�#7�#7�#7�#7�#7�J(�(�(����������'�'�'�������>�>�>�������	5�	5�	5�����*�*�*�B>B�#S�#S�#S�#S�L>B�I�I�I�I�I�I�V���H�H�H�I�I�I�
�
�
�X�X�X�P�P�P�I�I�I�K�K�K�
�
�
�	5�	5�	5�	5�	5�	5�	5r+r^c����fd�}|S)zi
    Prints error because some pipelined commands should
    be blocked when running in cluster-mode
    c�4��td�j�d����)Nz"ERROR: Calling pipelined function z1 is blocked when running redis in cluster mode...)rr�)r1r��funcs  �r)�innerz%block_pipeline_command.<locals>.inner�s-���#�
5���
5�
5�
5�
�
�	
r+r%)rorps` r)�block_pipeline_commandrq�s#���
�
�
�
�
��Lr+c��eZdZdZdd�ZdS)r)r�Nc�b�||_|�i}||_||_d|_d|_d|_dS)NF)r1r2r.r,r*r�)rr1r2r.s    r)rzPipelineCommand.__init__�s:����	��?��G���� ��
������	�����r+r�)r�r�r�r�rr%r+r)r)r)�s-�������G������r+r)c�*�eZdZdZd�Zd�Zd�Zd�ZdS)rOr�c�>�||_||_||_g|_dSr)r�r.r-�commands)rr�r.r-s    r)rzNodeCommands.__init__�s$��,���.���$�����
�
�
r+c�:�|j�|��dSr)rvr�)rr0s  r)r�zNodeCommands.appends���
���Q�����r+c��|j}|j}|D]	}d|_�
	|�|�d�|D������dS#t
tf$r}|D]	}||_�
Yd}~dSd}~wwxYw)z=
        Code borrowed from Redis so it can be fixed
        Nc��g|]	}|j��
Sr%)r1rHs  r)r@z&NodeCommands.write.<locals>.<listcomp>s��)C�)C�)C�Q�!�&�)C�)C�)Cr+)r-rvr,�send_packed_command�
pack_commandsrr)rr-rvr0r�s     r)rPzNodeCommands.writes����_�
��=���	�	�A��A�H�H�	��*�*��(�(�)C�)C�(�)C�)C�)C�D�D�
�
�
�
�
�� ��.�	�	�	��
�
������
�
�
�
�
�
�����	���s�2A�A8�!A3�3A8c�6�|j}|jD]�}|j��	|j||jdfi|j��|_�/#ttf$r}|jD]	}||_�
Yd}~dSd}~wt$r!tj
��d|_Y��wxYw��dS)r�Nrr4)r-rvr,r�r1r2rrr�sys�exc_info)rr-r0r�s    r)rQzNodeCommands.reads����_�
���	1�	1�A�(�x��1�2�t�2�:�q�v�a�y�V�V�A�I�V�V�A�H�H��'��6����!�]�%�%��#$�����F�F�F�F�F�F�����!�1�1�1�"�|�~�~�a�0�A�H�H�H�1���� �)	1�	1s�$>�B�A'�'+B�BN)r�r�r�r�rr�rPrQr%r+r)rOrO�sU�������G���� � � ����,1�1�1�1�1r+rO)ir�loggingr�r�r}rr��collectionsr�redis.clientrrr�redis.commandsrr�redis.connectionr	r
rr�	redis.crcr
r�redis.exceptionsrrrrrrrrrrrrrrr�redis.utilsrrr r!r"�	getLoggerr�r�r*r/r:rGrYr<r@rxr�r��	frozensetrjr�r�r�r�r�r	r[r^rq�bitop�
brpoplpush�client_getname�client_list�client_setname�
config_set�dbsize�flushall�flushdbry�mget�move�mset�msetnx�pfmerge�pfcount�ping�publish�	randomkey�rename�renamenx�	rpoplpush�scan�sdiff�
sdiffstore�sinter�sinterstore�smove�sort�sunion�sunionstore�	readwrite�readonlyr)rOr%r+r)�<module>r�s�����������
�
�
�
�
�
�
�
�
�
�
�
���������#�#�#�#�#�#�;�;�;�;�;�;�;�;�;�;�?�?�?�?�?�?�?�?�N�N�N�N�N�N�N�N�N�N�N�N�8�8�8�8�8�8�8�8�����������������������������������"���������������g���!�!�����������
�
�
����$��
��
����>���	�(�(�(�*�*�
�Z
�
�
������M����Z
�Z
�Z
�Z
�Z
�'�Z
�Z
�Z
�z*�*�*�*�*�*�*�*�8$�$�$�$�$�$�$�$�&U�U�U�U�U�U�U�U�p
}.�}.�}.�}.�}.�F�}.�}.�}.�@C5�C5�C5�C5�C5�l�C5�C5�C5�L��� /�.�|�/A�B�B���3�3�L�4K�L�L���!7�!7��8S�!T�!T���4�4�\�5M�N�N���!7�!7��8S�!T�!T���3�3�L�4K�L�L���/�/��0C�D�D���1�1�,�2G�H�H���0�0��1E�F�F���-�-�l�.?�@�@���-�-�l�.?�@�@���-�-�l�.?�@�@���-�-�l�.?�@�@���/�/��0C�D�D���0�0��1E�F�F���0�0��1E�F�F���-�-�l�.?�@�@���0�0��1E�F�F���2�2�<�3I�J�J���/�/��0C�D�D���1�1�,�2G�H�H���2�2�<�3I�J�J���-�-�l�.?�@�@���.�.�|�/A�B�B���3�3�L�4K�L�L���/�/��0C�D�D���4�4�\�5M�N�N���.�.�|�/A�B�B���-�-�l�.?�@�@���/�/��0C�D�D���4�4�\�5M�N�N���2�2�<�3I�J�J���1�1�,�2G�H�H�����������C1�C1�C1�C1�C1�C1�C1�C1�C1�C1r+