o
    پi                     @  s*  d dl mZ 	 	 d dlZd dlZd dlmZ d dlmZ d dlm	Z	m
Z
mZmZ d dlZd dlmZ d dlmZmZmZmZmZmZmZ d dlmZ d d	lmZmZmZmZ d d
lm Z  d dl!m"Z" e	rjd dl#m$Z$ d dl%Z%e%&e'Z(G dd dZ)dddZ*dddZ+G dd dZ,G dd deZ-dS )    )annotationsN)defaultdict)partial)TYPE_CHECKINGListOptionalTuple)float64)BasePrefixCacheEvictParamsEvictResultInsertParamsInsertResultMatchPrefixParamsMatchResult)CacheInitParams)RadixKey_key_match_page_size1_key_match_pagedget_child_key)SWATokenToKVPoolAllocator)convert_to_bigram_key)Reqc                   @  sJ   e Zd ZdZdZedZddddZed	d
 Z	edd Z
dddZdS )TreeNoder            ?NidOptional[int]c                 C  s   t t| _d | _d | _d | _d| _d| _d| _t	 | _
d| _d | _d | _d | _d | _d | _|d u r4tjn|| _t jd7  _d | _d S )NFr   r   )r   r   childrenparentkeyvalueswa_tombstonefull_lock_refswa_lock_refget_last_access_timelast_access_time	hit_count
host_valueprevnextswa_prevswa_nextcounterr   swa_uuid)selfr    r0   X/home/ubuntu/.local/lib/python3.10/site-packages/sglang/srt/mem_cache/swa_radix_cache.py__init__@   s"   

zTreeNode.__init__c                 C  s
   | j d u S N)r!   r/   r0   r0   r1   evicted_      
zTreeNode.evictedc                 C  s
   | j d uS r3   )r(   r4   r0   r0   r1   backupedc   r6   zTreeNode.backupedother
'TreeNode'c                 C  s   | j |j k S r3   )r&   )r/   r8   r0   r0   r1   __lt__g   s   zTreeNode.__lt__r3   )r   r   )r8   r9   )__name__
__module____qualname__r-   swa_uuid_counterr	   last_access_time_counter_floatr2   propertyr5   r7   r:   r0   r0   r0   r1   r   :   s    

r   returnintc                   C  s   t  jd7  _t jS )Nr   )r   r>   r0   r0   r0   r1   gen_swa_uuidk   s   rC   r	   c                  C  s   t j} t  jd7  _| S )Nr   )r   r?   )retr0   r0   r1   r%   p   s   r%   c                   @  s   e Zd Zd-d.ddZdd Zdd	 Zd
d Zd/ddZdd Zdd Z	dd Z
d0ddZd/ddZd/ddZ	d1d2d d!Zd1d3d"d#Zd4d$d%Zd&d' Zd5d*d+Zd,S )6LRUListFis_swa_listboolc                 C  sp   || _ | j rd| _d| _d| _n	d| _d| _d| _t | _t | _t| j| j| j t| j| j| j i | _d S )Nr+   r,   r$   r)   r*   r#   )	rF   prvnxtlock_refr   headtailsetattrcache)r/   rF   r0   r0   r1   r2   w   s   
zLRUList.__init__c                 C  s   |  | j| dS )z8Helper to add node right after head (most recently used)N)_add_node_afterrK   r/   noder0   r0   r1   	_add_node   s   zLRUList._add_nodec                 C  sL   t || j| t || jt|| j t t|| j| j| t || j| dS )z'Helper to add node right after old_nodeN)rM   rH   rI   getattr)r/   old_nodenew_noder0   r0   r1   rO      s   zLRUList._add_node_afterc                 C  s@   t t|| j| jt|| j t t|| j| jt|| j dS )z&Helper to remove node from linked listN)rM   rS   rH   rI   rP   r0   r0   r1   _remove_node   s   zLRUList._remove_noderA   Optional[TreeNode]c                 C  s    t | jdkr	dS t| j| jS )z2
        Get the least recently used node
        r   N)lenrN   rS   rL   rH   r4   r0   r0   r1   _get_lru   s   zLRUList._get_lruc                 C  sR   |j | jv sJ d|j d| jr|jrJ d|j | | | | dS )zG
        Move a (existing) node to most recently used position
        Resetting node node.id= not in lru listz6Resetting swa tombstone node in swa lru list: node.id=N)r   rN   rF   r"   rV   rR   rP   r0   r0   r1   reset_node_mru      

zLRUList.reset_node_mruc                 C  sh   | j }||kr2| jr|js)|j| jv sJ d|jd| | | || |}|j}||ksdS dS )z
        Move an (existing) node and its parents to most recently used position. Child node is
        more recently used than parent node.
        rZ   z4 not in lru list when resetting node and parents mruN)rK   rF   r"   r   rN   rV   rO   r   )r/   rQ   	root_node	prev_noder0   r0   r1   reset_node_and_parents_mru   s   
z"LRUList.reset_node_and_parents_mruc                 C  sb   | j r|jrJ d|j|j| jvs$J d|jd| j|j j|| j|j< | | dS )z;
        Insert a (new) node as most recently used
        z6Inserting swa tombstone node in swa lru list: node.id=zInserting node node.id=z< already in lru list, existing node: self.cache[node.id].id=N)rF   r"   r   rN   rR   rP   r0   r0   r1   
insert_mru   s   
zLRUList.insert_mrurQ   r   c                 C  sR   |j | jv sJ d|j d| jr|jrJ d|j | j|j = | | dS )z+
        Remove node from lru list
        zRemoving node node.id=r[   z7Removing swa tombstone node from swa lru list: node.id=N)r   rN   rF   r"   rV   rP   r0   r0   r1   remove_node   r]   zLRUList.remove_nodec                 C     | j | jddS )zE
        Get the least recently used node that is not locked
        Fcheck_id)get_prev_no_lockrL   r4   r0   r0   r1   get_lru_no_lock      zLRUList.get_lru_no_lockc                 C  rc   )zJ
        Get the least recently used leaf node that is not locked
        Frd   )get_prev_leaf_no_lockrL   r4   r0   r0   r1   get_leaf_lru_no_lock   rh   zLRUList.get_leaf_lru_no_lockTre   c                 C  sl   |r|j | jv sJ d|j dt|| j}t|| jdkr-t|| j}t|| jdks|| jkr4dS |S )zT
        Get the previous (i.e. more recently used) node that is not locked
        Getting prev of node node.id=r[   r   N)r   rN   rS   rH   rJ   rK   r/   rQ   re   xr0   r0   r1   rf      s   
zLRUList.get_prev_no_lockc                 C  s   |r|j | jv sJ d|j dt|| j}t|| jdks&t|jdkr;t|| j}t|| jdks&t|jdks&|| jkrBdS |S )zY
        Get the previous (i.e. more recently used) leaf node that is not locked
        rk   r[   r   N)r   rN   rS   rH   rJ   rX   r   rK   rl   r0   r0   r1   ri      s   
zLRUList.get_prev_leaf_no_lockc                 C  s   |sdS |j | jv S )z6
        Check if the node is in the lru list
        F)r   rN   rP   r0   r0   r1   in_list
  s   zLRUList.in_listc                 C  s<   |   }d}| |r|t|j7 }| |}| |s|S )z[
        Check the evictable size (i.e. the size of the nodes that are not locked)
        r   )rg   rn   rX   r!   rf   )r/   rQ   evictable_sizer0   r0   r1   sanity_check_evictable_size  s   


z#LRUList.sanity_check_evictable_size
tree_cache'SWARadixCache'c                 C  s  z| j r	| }n| }t|}t| jd }t| t|t| jd ks9J dt| dt| jd  |  }t|rt|}||j	krLq=||ks`J d| j d|j
d|j
|jdksuJ d|jd	|jd
|j
|jdksJ d|jd	|jd
|j
t|| j}t|sA| j r| }|  }n| }|  }||ksJ d| j d| d| d| d| 
W dS  ty }	 zd|	 }
t|
 t|
d}	~	ww )z
        Check if the lru list is valid by rebuilding the lru list from the tree, heapifying it, and
        checking if the lru list is valid.
        r   zlen(nodes): z != len(self.cache) + 1: z%Incorrect LRU list, self.is_swa_list=z
, x: x.id=z != x_lru: x_lru.id=r   z:x_lru should not be locked when idle, x_lru.full_lock_ref=z, x_lru.swa_uuid=z, x_lru.id=z9x_lru should not be locked when idle, x_lru.swa_lock_ref=zself.is_swa_list=z, total nodes: z, total lru plus 1: z, evictable size: z != lru list evictable size: z6SWA Radix tree sanity check failed, ping @hanming-lu: N)rF   _collect_nontombstone_nodes_collect_all_nodesrX   rN   heapqheapifyrY   heappopr^   r   r#   r.   r$   rS   rH   swa_evictable_sizerp   full_evictable_size	Exceptionloggererror)r/   rq   nodestotal_nodestotal_lru_plus_1x_lrurm   ro   lru_list_evictable_sizeemsgr0   r0   r1   sanity_check  sP   






"


zLRUList.sanity_checkNF)rF   rG   )rA   rW   rQ   r   T)rQ   r   re   rG   rA   rW   )rQ   r   re   rG   )rQ   rW   )rq   rr   )r;   r<   r=   r2   rR   rO   rV   rY   r\   r`   ra   rb   rg   rj   rf   ri   rn   rp   r   r0   r0   r0   r1   rE   v   s$    
	



	rE   c                   @  sv  e Zd ZdrddZdsddZdtd
dZduddZdvddZdwdxddZdydzddZ	dtddZ
d{d d!Zd|d$d%Zd}d)d*Zd~dd-d.Zd/d0 Zd{d1d2Zdd4d5Zdd6d7Zd{d8d9Zdd:d;Zdd<d=Zdd?d@ZddBdCZddGdHZddJdKZddPdQZddTdUZ	VdddYdZZ	dydd]d^Zdd`daZddbdcZddddeZ ddfdgZ!ddidjZ"ddkdlZ#ddndoZ$d{dpdqZ%d+S )SWARadixCacheparamsr   c                 C  s   t |jtsJ |j| _|j| _|j| _|j| _|j| _| jr%| jj| _ntd| _| jdkr7t	| _
t| _ntt| jd| _
tt| jd| _| jrNt| _ndd | _|jrZ|   |j| _|   d S )Ncpur   )	page_sizec                 S  s   | S r3   r0   r    r0   r0   r1   <lambda>k  s    z(SWARadixCache.__init__.<locals>.<lambda>)
isinstancetoken_to_kv_pool_allocatorr   req_to_token_poolr   disableis_eagledevicetorchr   key_match_fnr   get_child_key_fnr   r   r   key_convert_fnenable_metricsinit_metrics_collectorsliding_window_sizereset)r/   r   r0   r0   r1   r2   T  s*   

zSWARadixCache.__init__rA   rG   c                 C  s   | j d us	J ddS )Nz1sliding_window_size must be set for SWARadixCacheT)r   r4   r0   r0   r1   supports_swau  s   zSWARadixCache.supports_swaNonec                 C  s\   t  | _g | j_g | j_d| j_d| j_d| _d| _d| _d| _	t
dd| _t
dd| _d S )Nr   r   F)rF   T)r   r^   r    r!   r#   r$   full_evictable_size_swa_evictable_size_full_protected_size_swa_protected_size_rE   full_lru_listswa_lru_listr4   r0   r0   r1   r   {  s   zSWARadixCache.resetr   r   c                 C  sT   |  |}|du rttjdtj| jd| j| jdS | |\}}}| ||||S )a  Find the matching prefix from the radix tree.
        Args:
            params: MatchPrefixParams containing key.
        Returns:
            A tuple of a tensor of matching prefix token IDs and
            the last node that contains the prefix values. Note that
            this API can modify the internal state of the Radix tree.
            The last node create a new child if the prefix is shorter
            than the last node's value.
        Nr   dtyper   device_indiceslast_device_nodelast_host_node)	_match_pre_processorr   r   emptyint64r   r^   _match_prefix_helper_match_post_processor)r/   r   r    r!   	last_nodebest_value_lenr0   r0   r1   match_prefix  s   

zSWARadixCache.match_prefixr   r   c                 C  s   | j rtddS |j}|j}|j}|j}| |j|_|d u r-tj	dd |jD tj
d}| jr8|d t| }| | j||||}t|dS )Nr   )
prefix_lenc                 S  s   g | ]}|qS r0   r0   ).0rm   r0   r0   r1   
<listcomp>  s    z(SWARadixCache.insert.<locals>.<listcomp>)r   )r   r   r    r!   prev_prefix_lenswa_evicted_seqlenr   	token_idsr   tensorr   r   rX   _insert_helperr^   )r/   r   r    r!   r   r   r   r0   r0   r1   insert  s   

zSWARadixCache.insertTreqr   	is_insertc                 C  sV  |  }| jr| jj|jd|f }| j| dS |j|j d| }| j	r+|d n|}| jj|jd|f }| j
dkrR|| j
 | j
 }|d| jtjdd}n
|}|jtjdd}| j	rc|d n|}	t|j}
| j	rv|
|jkrv|
d8 }
|r| tt|d|	 |j||
|jd n
| j||
|  | j||d  | |j|j dS )zCache request when it finishes.Nr   Tr   copy)r    r!   r   r   )pop_committed_kv_cacher   r   req_to_tokenreq_pool_idxr   freeorigin_input_ids
output_idsr   r   tor   r   rX   prefix_indicescache_protected_lenr   r   r   	extra_keyr   dec_lock_refr   swa_uuid_for_lock)r/   r   r   kv_committed_len
kv_indicesr   actual_kv_lenpage_aligned_lenpage_aligned_kv_indicespage_aligned_token_lenold_prefix_lenr0   r0   r1   cache_finished_req  sL   

	
z SWARadixCache.cache_finished_reqFc                 C  s  | j r| jj|jdt|jf }||_dS |j}t|}| jr$|d n|}| jj|jd|f }| jdkrK|| j | j }|d| j	t
jdd}n
|}|j	t
jdd}| jr\|d n|}	|d|	 }
t|j}| jru||jkru|d8 }| tt|
|j||d}|j}| tt|
|jd}|j|j}}|t|ksJ d|jd||t|ksJ d	|d|| j|jt|t|f||d  t||_| |j|j | |}| jdkrt
||t|d g|_n| jrt
|||d g|_n||_||_||_dS )
z$Cache request when it is unfinished.Nr   Tr   )r    r!   r   r   zreq.prefix_indices=z, new_indices=znew_prefix_len=)r   r   r   r   rX   fill_idsr   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   writeslicer   r   r   inc_lock_refcat)r/   r   chunkedr   r   all_token_lenr   r   r   r   page_aligned_token_idsr   resultnew_prefix_lenmatch_resultnew_indicesnew_last_noder   r0   r0   r1   cache_unfinished_req  s~   


 




z"SWARadixCache.cache_unfinished_reqc                 C  s2   |  | jd |  \}}td| d|  d S )Nr   z#full_tokens: z, #swa_tokens: )_print_helperr^   _total_size_helperprint)r/   
total_sizetotal_swa_sizer0   r0   r1   pretty_printR  s   zSWARadixCache.pretty_printTuple[int, int]c                 C  s   |   S r3   )r   r4   r0   r0   r1   r   W  s   zSWARadixCache.total_sizer   r   c           
      C  s  | j rt S t }|j}|j}d}d}|dkr| j }||k r| j|r|| j	ks4J d|j
|jdksAJ d|j
| j|j |t|j7 }|t|j7 }| j|}| j| | j| | | | |\}}	||	7 }t|jjdkr| j }|}||k r| j|s'||k r?| j }||k r?| j|r?|jrJ d|j
|| j	ksJ d|j
|jdksJ d|j
t|jdkr| j|j |t|j7 }| j|}| j| | | n?|jdksJ d|j
| j|j |t|j7 }|t|j7 }| j|}| j| | j| | | | | |}||k r?| j|s| || | t||dS )	Nr   z2root node should not exist in full lru list, x.id=znode is in use, x.id=z#duplicate swa tombstone node, x.id=z!root node is not evictable, x.id=z'node is in use by swa kv indices, x.id=z7leaf node with full lock must also have swa lock, x.id=)num_tokens_evictedswa_num_tokens_evicted)r   r   timeperf_counter
num_tokensswa_num_tokensr   rj   rn   r^   r   r#   r   r   r!   rX   ri   rb   r   _delete_leaf"_iteratively_delete_tombstone_leafr   r   rg   r"   r$   free_swarf   _tombstone_internal_nodeupdate_eviction_metrics)
r/   r   
start_timefull_num_tokensr   full_num_evictedswa_num_evictedrm   x_nextleaf_full_num_evictedr0   r0   r1   evictZ  sp   








&zSWARadixCache.evictrQ   r   r   c                 C  s"  | j rdS d}d}|| jkr|jdksJ d|jd|j|jdkr8|  jt|j8  _|  jt|j7  _| jd7  _|| jk r|j	rOJ d|j|j
dkrh|  jt|j8  _|  jt|j7  _| j
d7  _
|t|j7 }|| jkr|jdu rt |_|j}|j}|| jks|S )aM  
        Increment the lock reference count for the node. Returns the swa_uuid_for_lock, which needs
        to be passed to dec_lock_ref.
        It locks the full_lock_ref for nodes between the [last node, root), exclusive.
        It locks the swa_lock_ref for nodes between the [last node, swa_uuid_for_lock], inclusive.
        Nr   z-inc_lock_ref on node with node.full_lock_ref=
, node.id=r   z,inc_lock_swa on swa_tombstone node, node.id=)r   r^   r#   r   r   rX   r!   r   r   r"   r$   r   r   r.   rC   r   )r/   rQ   swa_lock_sizer   r0   r0   r1   r     s:   







zSWARadixCache.inc_lock_refNr   c                 C  s   | j rdS d}|| jkr|jdksJ d|jd|j|jdkr6|  jt|j7  _|  jt|j8  _| jd8  _|r|jrJJ d|j|j	dks[J d|j	d|j|j	dkrt|  j
t|j7  _
|  jt|j8  _| j	d8  _	|r|j|krd	}|j}|| jksdS dS )
aI  
        Decrement the lock reference count for the node.
        It unlocks the full_lock_ref for nodes between the [last node, root), exclusive.
        It unlocks the swa_lock_ref for nodes between the [last node, swa_uuid_for_lock], inclusive.
        If swa_uuid_for_lock is None, it unlocks to the root, exclusive.
        NTr   z-dec_lock_ref on node with node.full_lock_ref=r   r   z,dec_lock_ref on swa_tombstone node, node.id=z,dec_lock_ref on node with node.swa_lock_ref=F)r   r^   r#   r   r   rX   r!   r   r"   r$   r   r   r.   r   )r/   rQ   r   dec_lock_swar0   r0   r1   r     s6   



zSWARadixCache.dec_lock_refc                 C  s   | j |  | j|  d S r3   )r   r   r   r4   r0   r0   r1   r     s   zSWARadixCache.sanity_checkc                 C     t r3   NotImplementedErrorr4   r0   r0   r1   ro        zSWARadixCache.evictable_sizerB   c                 C     | j S r3   )r   r4   r0   r0   r1   ry   
     z!SWARadixCache.full_evictable_sizec                 C  r  r3   )r   r4   r0   r0   r1   rx     r  z SWARadixCache.swa_evictable_sizec                 C  r   r3   r   r4   r0   r0   r1   protected_size  r  zSWARadixCache.protected_sizec                 C  r  r3   )r   r4   r0   r0   r1   full_protected_size     z!SWARadixCache.full_protected_sizec                 C  r  r3   )r   r4   r0   r0   r1   swa_protected_size  r  z SWARadixCache.swa_protected_sizetorch.Tensorc                   s(   g d fdd  | j  tS )NrQ   r   c                   s,   | j  D ]\}}|j  | qd S r3   )r   itemsappendr!   )rQ   _child_dfs_helpervaluesr0   r1   r    s   
z5SWARadixCache.all_values_flatten.<locals>._dfs_helperr   )r^   r   r   r4   r0   r  r1   all_values_flatten  s   

z SWARadixCache.all_values_flattenstrc                 C  sn   | j  }| j  }|  }|  }d||  d|d|d||  d|d|d| j  d| j  d	S )
NzAvailable full tokens: z (full_available_size=z + full_evictable_size=z)
Available swa tokens: z (swa_available_size=z + swa_evictable_size=z )
Full LRU list evictable size: z
SWA LRU list evictable size: 
)r   full_available_sizeswa_available_sizery   rx   r   rp   r   )r/   r  r  ry   rx   r0   r0   r1   available_and_evictable_str'  s    

z)SWARadixCache.available_and_evictable_strr    r   (Tuple[List[torch.Tensor], TreeNode, int]c                 C  s6  | j }| |}g }td}d}|}t|dkr||j v r|j| }|jr4|| jkr2t|}|}d}| |j	|}	|	t|j	k r]| 
|j	||	}
||
j |
jsZ|t|
j7 }|
}n.||j |jsm|t|j7 }|}||	d }t|r~| |}t|dkr||j v s|| jkrt|}|}|||fS )aX  
        SWA prefix matching helper. It factors in the sliding window size such that
        the matched node is guaranteed to either 1. connected to root without swa tombstone,
        or 2. the number of matching tokens from the matched node to the last swa tombstone
        node is greater than or equal to the sliding window size.
        infr   N)r^   r   floatrX   r   keysr"   r   r   r    _split_noder
  r!   )r/   r    rQ   	child_keyr!   match_len_since_tombstoner   best_last_noder  r   rU   r0   r0   r1   r   5  sB   	





z"SWARadixCache._match_prefix_helperOptional[RadixKey]c                 C  sX   |j }| |j|_| jst|dkrdS | jdkr*t|| j | j }|d| }|S )z#Preprocess the key before matching.r   Nr   )r    r   r   r   rX   r   )r/   r   r    r   r0   r0   r1   r   j  s   
z"SWARadixCache._match_pre_processorr!   List[torch.Tensor]r   r   c                 C  s   |}| j || j | j|| j t }|r#||_|d8 }|j}|s|d| }|r1t|}n
tj	dtj
| jd}t|||dS )z Post-process the matched result.gh㈵>Nr   r   r   )r   r`   r^   r   r%   r&   r   r   r   r   r   r   r   )r/   r   r!   r   r   node_updatecur_timer0   r0   r1   r   x  s(   z#SWARadixCache._match_post_processorr  	split_lenc                 C  s8  t  }| ||d  |i|_|j|_|j|_|j|_|j|_|jd | |_t|jdks2J d|j	d | 
 |_	|j|_d |_t |_| j| |jsV| j| ||_|j|d  |_t|jdkslJ d|j	|d  
 |_	||jj| |< | j| | j| |js| j| | j| |S )Nr   z new_node.key should not be emptyzchild.key should not be empty)r   r   r   r   r"   r#   r$   r    rX   r!   cloner.   r%   r&   r   rb   r   ra   )r/   r    r  r"  rU   r0   r0   r1   r    s4   zSWARadixCache._split_noder   update_kv_after_lenr   c                 C  s
  t  |_|| jkr| j| |js| j| t|dkr dS | |}d}t|dkrF||j	
 v rF|j	| }t  |_| j| |jsN| j| | |j|}|t|jk rf| |j||}	|	}||| k r|jr|jdksJ d|jd|jd|j|| j dksJ d|d| j||kr| j|jd |  |d |  |_d|_| j| |  jt|j7  _nZ||| k r	|| }
| j|j|
|  | |j||
 ||
|  |_| j|d |
  d|_| j| |  jt|j7  _n| j|d |  n
| j|d |  ||7 }||d  }||d  }t|r8| |}t|dkrF||j	
 v s6t|r||krz||t| k rz|| }| j||d | |d | dd	}||d  }||d  }| j|||dd	 |S )
Nr   z>tombstone swa_lock_ref should always be 0, node.full_lock_ref=z, node.swa_lock_ref=r   z<swa_evicted_seqlen must be page aligned, swa_evicted_seqlen=z, self.page_size=FT)r"   )r%   r&   r^   r   r\   r"   r   rX   r   r   r  r   r    r  r$   r#   r   r   r   r   r!   r#  ra   r   _add_new_node)r/   rQ   r    r!   r$  r   r  total_prefix_lengthr   rU   start_update_idxswa_tombstone_lenr0   r0   r1   r     s   






?


zSWARadixCache._insert_helperr   r"   c                 C  s   t |dks
J dt }||_||_| |_||_||j| |< | j	
| |  jt |7  _|sC| j
| |  jt |7  _|S )Nr   zkey should not be empty)rX   r   r   r    r#  r!   r"   r   r   r   ra   r   r   r   )r/   r   r    r!   r"   rU   r0   r0   r1   r%  %  s   
zSWARadixCache._add_new_nodeTuple[TreeNode, int]c                 C  s   d}|j jrit|j jdkri|j | jkr	 ||fS |j jdkr$	 ||fS |j jdks=J d|j jd|j jd|j j| j	|j j
 |t|j j
7 }| j|j  | |j  |j }|j jrit|j jdks||fS )Nr   zEtombstone swa_lock_ref should always be 0, node.parent.full_lock_ref=z, node.parent.swa_lock_ref=z, node.parent.id=)r   r"   rX   r   r^   r#   r$   r   r   r   r!   r   rb   _delete_tombstone_leaf)r/   rQ   r   r0   r0   r1   r   :  s$    z0SWARadixCache._iteratively_delete_tombstone_leafc                 C  s   |j rJ d|jt|jdksJ d|j| |j}|jj|d }||ks3J d| |  jt|j8  _|  j	t|j8  _	d S )Nz6Invariant violated: leaf node is a tombstone, node.id=r    leaf node has children, node.id= parent does not have child key, )
r"   r   rX   r   r   r    r   popr   r   r/   rQ   r    vr0   r0   r1   r   Q  s   
zSWARadixCache._delete_leafc                 C  s<   t |jdksJ d|jd|_|  jt |j8  _d S )Nr   z&Cannot tombstone a leaf node, node.id=T)rX   r   r   r"   r   r    rP   r0   r0   r1   r   \  s   z&SWARadixCache._tombstone_internal_nodec                 C  s~   |j sJ d|jt|jdksJ d|j| |j}|jj|d }||ks3J d| |  jt|j8  _d S )Nz7Deleting a unexpected non-tombstone leaf node, node.id=r   r+  r,  )	r"   r   rX   r   r   r    r   r-  r   r.  r0   r0   r1   r*  a  s   
z$SWARadixCache._delete_tombstone_leafList[TreeNode]c                 C  s@   g }| j g}|r| }|js|| ||j  |s|S r3   )r^   r-  r"   r
  extendr   r  r/   ret_liststackcur_noder0   r0   r1   rs   l  s   
z)SWARadixCache._collect_nontombstone_nodesc                 C  s:   g }| j g}|r| }|| ||j  |s|S r3   )r^   r-  r
  r1  r   r  r2  r0   r0   r1   rt   x  s   
z SWARadixCache._collect_all_nodesindentc                 C  s   ||fg}|re|  \}}td| |jt|jd|j d|j d| j| d| j	| d|j
  |j D ]#\}}|||d f || |jks`J d|d	| |jq=|sd
S d
S )z1Prints the radix tree in a human-readable format. zfr=zsr=zfll=zsll=zts=   zkey=z#, self.get_child_key_fn(child.key)=N)r-  r   r   rX   r    r#   r$   r   rn   r   r"   r   r	  r
  r   )r/   rQ   r6  r4  current_nodecurrent_indentr    r  r0   r0   r1   r     s*   




zSWARadixCache._print_helperc                 C  sl   d}d}| j g}|r2| }|t|j7 }|js|t|j7 }|j D ]}|jr*q$|| q$|s
||fS )Nr   )	r^   r-  rX   r!   r"   r   r  r5   r
  )r/   r   r   r4  r9  r  r0   r0   r1   r     s   	z SWARadixCache._total_size_helper)r   r   )rA   rG   )rA   r   )r   r   rA   r   )r   r   rA   r   r   )r   r   r   rG   rA   r   r   )r   r   rA   r   )rA   r   )r   r   rA   r   )rQ   r   rA   r   r3   )rQ   r   r   r   rA   rB   )rA   r  )rA   r  )r    r   rA   r  )r   r   rA   r  )
r   r   r!   r  r   r   r   rB   rA   r   )r    r   r  r   r"  rB   rA   r   r   )
rQ   r   r    r   r$  rB   r   rB   rA   rB   )
r   r   r    r   r!   r  r"   rG   rA   r   )rQ   r   rA   r)  )rQ   r   rA   r   )rA   r0  )rQ   r   r6  rB   rA   r   )&r;   r<   r=   r2   r   r   r   r   r   r   r   r   r   r   r   r   ro   ry   rx   r  r  r  r  r  r   r   r   r  r   r%  r   r   r   r*  rs   rt   r   r   r0   r0   r0   r1   r   S  sL    

!


<
[


Z)%









5

#*k






	r   r;  )rA   r	   ).
__future__r   ru   r   collectionsr   	functoolsr   typingr   r   r   r   r   numpyr	   &sglang.srt.mem_cache.base_prefix_cacher
   r   r   r   r   r   r   &sglang.srt.mem_cache.cache_init_paramsr    sglang.srt.mem_cache.radix_cacher   r   r   r   $sglang.srt.mem_cache.swa_memory_poolr   sglang.srt.mem_cache.utilsr   "sglang.srt.managers.schedule_batchr   logging	getLoggerr;   r{   r   rC   r%   rE   r   r0   r0   r0   r1   <module>   s2    $	

1
 ^