o
    Lj,                     @   s|   d Z ddlmZmZ ddlmZmZmZmZm	Z	m
Z
mZmZ dd ZdddZdd	d
Zdd Zdd Zdd Zdd ZdS )aY  Shared HIMPORT wire-execution helpers for the synchronous clients.

The PREPARE / SET / DISCARD packed-write drain loops, per-connection version
bookkeeping, and ``NoSuchFieldsetError`` re-prepare-and-retry are identical for
the standalone (:class:`redis.Redis`) and cluster (:class:`redis.RedisCluster`)
sync clients, differing only in (a) which object provides ``parse_response`` and
(b) the cluster-only ASK-redirect handling. These functions take that object as
``node`` and an ``asking`` flag (``False`` -- and a no-op -- for standalone), so
both clients share one implementation instead of copy-pasting the logic. The
per-class ``_himport_*`` methods are thin delegators to these functions.

The async mirror lives in :mod:`redis.asyncio._himport_exec`; the two are kept
separate on purpose (the project maintains parallel sync/async stacks by hand).
    )NoSuchFieldsetErrorResponseError)HIMPORT_DISCARDHIMPORT_PREPAREHIMPORT_SETHImportRegistryhimport_discard_commandhimport_prepare_commandhimport_set_commandparse_himport_set_argsc                 C   s   |j }|du s|j|jkrdS |j}|t|j}|r\||dd |D  d}|D ](}z| |t	 W n t
yM } z
|pB|}W Y d}~nd}~ww |j|d q-|dur\|||_dS )ai  DISCARD, on ``conn``, any prepared fieldset removed from the registry.

    Runs at most once per registry mutation: the connection records the registry
    ``revision`` it last reconciled against, so unchanged registries are a no-op.
    ``node`` supplies ``parse_response`` (the standalone client itself, or the
    owning node's client in cluster mode).
    Nc                 S   s   g | ]}t |qS  )r   ).0nr   r   Q/home/djax/ivt_ai_plugin/venv/lib/python3.10/site-packages/redis/_himport_exec.py
<listcomp>2   s    z&reconcile_discards.<locals>.<listcomp>)himport_registry_himport_reconciled_revisionrevisionnames_to_discardlist_himport_preparedsend_packed_commandpack_commandsparse_responser   r   pop)nodeconnregistryreconciled_tostalefirst_errorr   er   r   r   reconcile_discards   s*   
r"   Fc              
   C   s(  t ||jg}|r|d |t||| ||| d } }	}
d}z| |t W n tyC } z|}W Y d}~nd}~ww |rcz| |d W n tyb } z|}	W Y d}~nd}~ww z| |t	}W n ty } z|}
W Y d}~nd}~ww |r||j
|j|< |	r|	|
r|
|S )a  PREPARE ``fieldset`` bundled with the SET on ``conn`` (one packed write).

    When ``asking`` is set (an ASK-redirected cluster SET) the batch becomes
    ``[PREPARE, ASKING, SET]`` so the per-command ASKING allowance falls
    immediately before the SET -- the only slot-scoped command. PREPARE is a
    connection-session command the ASKING flag does not gate, so placing it
    before ASKING is safe. Every reply is drained even on a per-command error so
    the packed replies never desync the pooled socket.
    ASKINGNr$   )r	   fieldsappendr
   r   r   r   r   r   r   versionr   )r   r   keyfieldset_namevaluesfieldsetaskingcommands
prep_error	ask_error	set_errorset_respr!   r   r   r   prepare_and_setD   sD   

r2   c           	      C   s*  t | | |j}|dur||nd}|dur+|j||jkr+t| ||||||dS |rd||dt|||g z| 	|d W n) t
yc } zz	| 	|t W | t
y^   Y |w d}~ww |jt|||  z| 	|tW S  ty   |du r |j|d t| ||||||d Y S w )a  Execute an ``HIMPORT SET`` on ``conn`` with the required session setup.

    Reconciles deferred discards, lazily bundles PREPARE with the SET on first
    use of a fieldset, and recovers once from a mid-connection fieldset loss
    (``NoSuchFieldsetError``) by re-PREPARE-and-retry. When ``asking`` is set the
    ASKING allowance is folded into the SET's own packed write so it immediately
    precedes the (slot-scoped) SET; the session setup runs first, since those are
    connection-session commands the flag does not gate.
    N)r,   r#   r$   )r"   r   getr   r'   r2   r   r   r
   r   r   r   send_commandr   r   )	r   r   r(   r)   r*   r,   r   r+   r/   r   r   r   execute_seto   sJ   


r5   c                 C   sD   t | ||}|s
dS ||t| t| ||}|dur |dS )aq  Pre-flight ``conn`` for a pipeline batch containing ``HIMPORT SET``s.

    The packed pipeline write bypasses the per-command lazy-PREPARE path, so the
    fieldsets referenced by the buffered SETs must be PREPAREd on ``conn`` first.
    Reconciles deferred discards, then PREPAREs every distinct registered fieldset
    the batch references that this connection has not already prepared, in one
    packed write. ``command_arg_lists`` is the batch's per-command positional-arg
    sequences (the caller extracts them from its own command representation).
    No-op when the batch has no registry-backed ``HIMPORT SET``.
    N)pipeline_preparesr   r   prepare_wire_commandsdrain_pipeline_prepares)r   r   command_arg_lists
to_preparer    r   r   r   prepare_pipeline   s   r;   c           
      C   s   t |dd}t|tsg S t| | g }t }|D ]0}t|}|du r$q|d }||v r-q|| ||}	|	durI|j||	j	krI|
|	 q|S )a  Return the fieldsets that must be PREPAREd on ``conn`` for this batch.

    Like :func:`prepare_pipeline`, but does **not** send the PREPAREs: the caller
    folds them into the same packed write as the queued commands (see the pipeline
    executors), so the first pipeline use of a fieldset on a fresh or reconnected
    connection stays a single round trip instead of a separate PREPARE exchange
    followed by the batch. Deferred-discard reconciliation is still performed here,
    but it only touches the socket when discards are actually pending (rare); the
    common warm-up cost -- the first-use PREPARE -- is what gets folded. Returns an
    empty list when the batch references no not-yet-prepared registered fieldset,
    or when ``conn`` carries no real HIMPORT registry.
    r   N   )getattr
isinstancer   r"   setr   addr3   r   r'   r&   )
r   r   r9   r   r:   seenargsparsedr)   r+   r   r   r   r6      s(   




r6   c                 C   s   dd | D S )zLThe leading ``HIMPORT PREPARE`` wire commands the caller folds into a batch.c                 S   s   g | ]	}t |j|jqS r   )r	   namer%   )r   fsr   r   r   r      s    z)prepare_wire_commands.<locals>.<listcomp>r   )	fieldsetsr   r   r   r7      s   r7   c                 C   s^   d}|D ](}z|  |t W n ty$ } z
|p|}W Y d}~qd}~ww |j|j|j< q|S )ar  Drain the ``len(fieldsets)`` leading PREPARE replies of a folded pipeline
    write, marking each fieldset prepared on success.

    Returns the first ``ResponseError`` (or ``None``). The caller must still drain
    the queued command replies and only then surface this error: every reply on
    the wire has to be read before raising, or the pooled socket desyncs.
    N)r   r   r   r'   r   rD   )r   r   rF   r    rE   r!   r   r   r   r8      s   r8   N)F)__doc__redis.exceptionsr   r   redis.himportr   r   r   r   r   r	   r
   r   r"   r2   r5   r;   r6   r7   r8   r   r   r   r   <module>   s    (
'
+<$