o
    `j                     @   s4   d Z ddlZddlZddlmZ G dd deZdS )aC  KIP-480 sticky partitioner.

Records with a non-None key are hashed to a partition just like
:class:`~kafka.partitioner.default.DefaultPartitioner`. Records with a
None key go to a *sticky* partition - i.e. the same partition is reused
for every null-key record on a topic until KafkaProducer signals that a
batch has been completed (via :meth:`StickyPartitioner.on_new_batch`),
at which point a different partition is picked.

The goal is to give the RecordAccumulator larger, denser batches for
null-key sends so per-batch overhead (CRC, compression, broker
round-trip) is amortized across more records. Java's benchmark in
KIP-480 reported substantial throughput/latency improvements over the
default-random behavior, though kafka-python is unlikely to see similar
improvements while predominantly CPU-bound on per-record overhead.
    N   )DefaultPartitionerc                       s:   e Zd ZdZdd Z fddZdd Zdd	d
Z  ZS )StickyPartitionera  Partitioner that sticks null-key records to one partition per
    topic until ``on_new_batch`` rotates it.

    Thread-safety: ``_sticky`` mutations are protected by ``_lock`` so
    concurrent ``send()`` callers can't observe a torn read-modify-write.
    c                 C   s   i | _ t | _d S N)_sticky	threadingLock_lock)self r   V/home/djax/ivt_ai_plugin/venv/lib/python3.10/site-packages/kafka/partitioner/sticky.py__init__    s   zStickyPartitioner.__init__c           
         s   ||  vrtd|f |durt ||||||S | jC | j|}|durUt||}t	|
|}	|	rH||	v rG|W  d   S n||v rU|W  d   S | ||W  d   S 1 sew   Y  dS )aJ  Choose a partition for the next record.

        Arguments:
            topic (str): topic to partition on.
            key (any): Unserialized key.
            serialized_key (bytes or None): partitioning key.
            value (any): Unserialized value.
            serialized_value (bytes or None): serialized value.
            cluster (ClusterMetadata): metadata for cluster; provides
                all and available partitions for topic.

        Raises:
            ValueError: if topic is not in ClusterMetadata

        Returns:
            int: chosen partition ID.
        z%Topic %s not found in ClusterMetadataN)topics
ValueErrorsuper	partitionr	   r   getsortedpartitions_for_topiclistavailable_partitions_for_topic_pick_sticky_locked)
r
   topickeyserialized_keyvalueserialized_valueclusterr   all_partitions	available	__class__r   r   r   $   s&   
$zStickyPartitioner.partitionc                 C   s^   | j " | j||kr	 W d   dS | j|||d W d   dS 1 s(w   Y  dS )a'  Hook called by ``KafkaProducer`` on the abort-for-new-batch
        retry path: rotate the sticky for ``topic`` so the next
        null-key record lands on a different partition.

        Stale events (where another thread already rotated us off
        ``prev_partition``) are no-ops.
        Navoid)r	   r   r   r   )r
   r   r   prev_partitionr   r   r   on_new_batchH   s   "zStickyPartitioner.on_new_batchNc                    s   | |}|s	dS t|}t||pd}|r<t|dkr#|d }n dur0 fdd|D n|}|s6|}t|}nt|}|| j|< |S )zPick a new sticky partition for ``topic``. Must be called with
        ``self._lock`` held. Returns None when the topic is no longer in
        cluster metadata (caller is expected to no-op in that case).Nr   r   r   c                    s   g | ]}| kr|qS r   r   ).0pr"   r   r   
<listcomp>d   s    z9StickyPartitioner._pick_sticky_locked.<locals>.<listcomp>)r   r   r   r   lenrandomchoicer   )r
   r   r   r#   r   r   r   
candidatesr   r"   r   r   V   s   



z%StickyPartitioner._pick_sticky_lockedr   )	__name__
__module____qualname____doc__r   r   r%   r   __classcell__r   r   r    r   r      s    $r   )r0   r*   r   defaultr   r   r   r   r   r   <module>   s
    