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 )a[  Shared HIMPORT wire-execution helpers for the asynchronous clients.

Async mirror of :mod:`redis._himport_exec`. 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.asyncio.Redis`) and cluster (async ``ClusterNode``) clients,
differing only in (a) which object provides ``parse_response`` and (b) the
cluster-only ASK-redirect handling. These coroutines take that object as
``node`` and an ``asking`` flag (``False`` -- and a no-op -- for standalone), so
both clients share one implementation. The per-class ``_himport_*`` methods are
thin delegators to these coroutines.

The sync version lives in :mod:`redis._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                    s   |j }|du s|j|jkrdS |j}|t|j}|rc||dd |D I dH  d}|D ]+}z| |t	I dH  W n t
yT } z
|pI|}W Y d}~nd}~ww |j|d q1|durc|||_dS )ak  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 ``ClusterNode`` in cluster mode).
    Nc                 S   s   g | ]}t |qS  )r   ).0nr   r   Y/home/djax/ivt_ai_plugin/venv/lib/python3.10/site-packages/redis/asyncio/_himport_exec.py
<listcomp>4   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              
      sB  t ||jg}|r|d |t||| |||I dH  d } }	}
d}z| |tI dH  W n tyJ } z|}W Y d}~nd}~ww |rmz| |dI dH  W n tyl } z|}	W Y d}~nd}~ww z| |t	I dH }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_setF   sF   
r2   c           	         s\  t | |I dH  |j}|dur||nd}|dur2|j||jkr2t| ||||||dI dH S |rt||dt|||gI dH  z| 	|dI dH  W n/ t
ys } zz| 	|tI dH  W | t
yn   Y |w d}~ww |jt||| I dH  z
| 	|tI dH W S  ty   |du r |j|d t| ||||||dI dH  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_sets   sL   

r5   c                    sX   t | ||I dH }|sdS ||t|I dH  t| ||I dH }|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           
         s   t |dd}t|tsg S t| |I dH  g }t }|D ]0}t|}|du r(q|d }||v r1q|| ||}	|	durM|j||	j	krM|
|	 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                    sf   d}|D ]+}z|  |tI dH  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    ()

-<$