
    AHjI                        d Z ddl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mZmZmZ e	rddlmZ ddlZddlmZmZ ddlmZ d	d
lmZ d	dlmZ d	dlmZ e	rddlmZ  ee e
f   Zne
Zddl!m"Z"  G d de"      Z# G d de      Z$y)z
Dual Cache implementation - Class to update both Redis and an in-memory cache simultaneously.

Has 4 primary methods:
    - set_cache
    - get_cache
    - async_set_cache
    - async_get_cache
    N)ThreadPoolExecutor)Lock)TYPE_CHECKINGAnyDictListOptionalTupleUnion)RedisPipelineIncrementOperation)print_verboseverbose_logger)"DEFAULT_MAX_REDIS_BATCH_CACHE_SIZE   )	BaseCache)InMemoryCache)
RedisCache)Span)OrderedDictc                   .     e Zd Zdd fd
Z fdZ xZS )LimitedSizeOrderedDictd   max_sizec                2    t        |   |i | || _        y N)super__init__r   )selfr   argskwargs	__class__s       R/root/tools/cai/cai_env/lib/python3.12/site-packages/litellm/caching/dual_cache.pyr   zLimitedSizeOrderedDict.__init__(   s    $)&)     c                 z    t        |       | j                  k\  r| j                  d       t        |   ||       y )NF)last)lenr   popitemr   __setitem__)r   keyvaluer"   s      r#   r)   z"LimitedSizeOrderedDict.__setitem__,   s0    t9%LLeL$C'r$   )__name__
__module____qualname__r   r)   __classcell__r"   s   @r#   r   r   '   s    '* !( (r$   r   c                   R    e Zd ZdZdddddefdee   dee   dee   dee   dee   de	d	df fd
Z
dee   dee   fdZd(defdZ	 d(de	ded	e	fdZ	 	 d)dee   defdZ	 	 d)dedee   defdZ	 	 d)dee   defdZdedee   dee   d	eee   eeee   f   f   fdZdeeee   f   d	dfdZ	 	 d)dedee   defdZd(defdZ	 d(dedefdZ	 	 d)dedee   ded	ee   fdZ	 	 d*ded    dedee   d	eee      fd!Z	 d(deded	dfd"Z d# Z!d$ Z"d%efd&Z#d%ed	ee	   fd'Z$ xZ%S )+	DualCachea5  
    DualCache is a cache implementation that updates both Redis and an in-memory cache simultaneously.
    When data is updated or inserted, it is written to both the in-memory cache + Redis.
    This ensures that even if Redis hasn't been updated yet, the in-memory cache reflects the most recent data.
    Nin_memory_cacheredis_cachedefault_in_memory_ttldefault_redis_ttl default_redis_batch_cache_expiry"default_max_redis_batch_cache_sizereturnc                 4   t         |           |xs
 t               | _        || _        t        |      | _        t               | _        |xs t        j                  xs d| _        |xs t        j                  | _        |xs t        j                  | _        y )Nr   
   )r   r   r   r3   r4   r   last_redis_batch_access_timer   "_last_redis_batch_access_time_locklitellmr7   redis_batch_cache_expiryr5   r6   )r   r3   r4   r5   r6   r7   r8   r"   s          r#   r   zDualCache.__init__:   s     	.A-/&,B7-
) 37&/, 77 	% "BW%B%B 	" "3!Og6O6Or$   c                 *    ||| _         ||| _        y y r   )r5   r6   )r   r5   r6   s      r#   update_cache_ttlzDualCache.update_cache_ttlV   s%     !,)>D&(%6D" )r$   
local_onlyc                 :   	 | j                   =d|vr| j                  | j                  |d<    | j                   j                  ||fi | | j                  $|du r | j                  j                  ||fi | y y y # t        $ r}t        |       Y d }~y d }~ww xY w)NttlF)r3   r5   	set_cacher4   	Exceptionr   r   r*   r+   rB   r!   es         r#   rE   zDualCache.set_cache_   s    
	##/&4+E+E+Q$($>$>F5M.$$..sEDVD+
e0C*  **3@@ 1D+ 	!	s   A7A< <	BBBr+   c                 $   	 |}| j                    | j                   j                  ||fi |}| j                  "|du r | j                  j                  ||fi |}|S # t        $ r(}t	        j
                  dt        |              |d}~ww xY w)z
        Key - the key in cache

        Value - int - the value you want to increment by

        Returns - int - the incremented value
        NF)LiteLLM Cache: Excepton async add_cache: )r3   increment_cacher4   rF   r   errorstr)r   r*   r+   rB   r!   resultrH   s          r#   rK   zDualCache.increment_cachem   s    	F##/=--==c5SFS+
e0C9))99#uOOM 	  #LSQRVH!UVG	s   AA 	B'#B

Bparent_otel_spanc                    	 d }| j                   ! | j                   j                  |fi |}||}|O| j                  C|du r?| j                  j                  ||      }| | j                   j                  ||fi | |}t	        d|        |S # t
        $ r* t        j                  t        j                                Y y w xY w)NFrO   get cache: cache result: )
r3   	get_cacher4   rE   r   rF   r   rL   	traceback
format_excr   r*   rO   rB   r!   rN   in_memory_resultredis_results           r#   rS   zDualCache.get_cache   s    	9F##/#A4#7#7#A#A##P#P #/-F~$"2"2">:QVCV#//99*:  :    +2D((223OO%5fX>?M 	9  !5!5!78	9s   BB 0CCkeysc                 $   	 t               		j                  d       	 fd}	 t        j                         }t	        d      5 }|j                  |      }|j                         cd d d        S # 1 sw Y   y xY w# t        $ r
  |       cY S w xY w)Nr   c                  8   t        j                         } 	 t        j                  |        | j                   j                  di       | j                          t        j                  d       S # | j                          t        j                  d       w xY w)z9Run the coroutine in a new event loop within this thread.N )asyncionew_event_loopset_event_looprun_until_completeasync_batch_get_cacheclose)new_loopreceived_argsr   s    r#   run_in_new_loopz2DualCache.batch_get_cache.<locals>.run_in_new_loop   s{    --/H-&&x022.D..??  &&t,  &&t,s   5A2 2'Br   )max_workers)localspopr]   get_running_loopr   submitrN   RuntimeError)
r   rY   rO   rB   r!   re   _executorfuturerd   s
   `        @r#   batch_get_cachezDualCache.batch_get_cache   s     &!
	-	%((*A $2 'h!9}}' ' '  	%"$$	%s/    A< !A0&	A< 0A95A< 9A< <BBc                   K   	 t        d| d|        d }| j                  7 | j                  j                  |fi | d {   }t        d|        ||}|_| j                  S|du rO| j                  j                  ||       d {   }|& | j                  j                  ||fi | d {    |}t        d|        |S 7 7 @7 # t
        $ r* t        j                  t        j                                Y y w xY ww)Nzasync get cache: cache key: ; local_only: zin_memory_result: FrQ   rR   )
r   r3   async_get_cacher4   async_set_cacherF   r   rL   rT   rU   rV   s           r#   rr   zDualCache.async_get_cache   sF    	9.se>*N F##/)M)=)=)M)M*!* $   23C2DEF#/-F~$"2"2">:QVCV%)%5%5%E%E*: &F &    +>$..>>\-3   &5fX>?M/$   	9  !5!5!78	9s_   D?C CAC C'C 4C5C 
DC C C 0DDDDcurrent_timerN   c                 b   g }i }| j                   5  t        ||      D ]t  \  }}|	|| j                  vs || j                  |   z
  | j                  k\  s7|j	                  |       | j                  j                  |      ||<   || j                  |<   v 	 ddd       ||fS # 1 sw Y   ||fS xY w)z
        Atomically choose keys to fetch from Redis and reserve their access time.
        This prevents check-then-act races under concurrent async callers.
        N)r=   zipr<   r?   appendget)r   rt   rY   rN   sublist_keysprevious_access_timesr*   r+   s           r#   _reserve_redis_batch_keysz#DualCache._reserve_redis_batch_keys   s     #%<>44 	J!$/ J
U$ t@@@#d&G&G&LL445 !'',151R1R1V1V2)#. >JD55c:J	J  222!	J  222s   AB"A B""B.rz   c                     | j                   5  |j                         D ]3  \  }}|| j                  j                  |d        %|| j                  |<   5 	 d d d        y # 1 sw Y   y xY wr   )r=   itemsr<   rh   )r   rz   r*   previous_times       r#   &_rollback_redis_batch_key_reservationsz0DualCache._rollback_redis_batch_key_reservations  sq     44 	K&;&A&A&C K"] (5599#tD=JD55c:	K	K 	K 	Ks   AAA'c                 t  K   	 d gt        |      z  }| j                  ) | j                  j                  |fi | d {   }||}d |v r| j                  |du r	 t	        j                         }| j                  |||      \  }}	t        |      dkD  r	 | j                  j                  ||       d {   }
|
 t        d |
j                         D              r|S t        |      D ci c]  \  }}||
 }}}|
j                         D ]C  \  }}||||   <   || j                   | j                  j                  ||fi | d {    E |S 7 7 # t        $ r | j                  |	        w xY wc c}}w 7 2# t        $ r* t        j                  t        j                                 Y y w xY ww)NFr   rQ   c              3   $   K   | ]  }|d u  
 y wr   r\   ).0vs     r#   	<genexpr>z2DualCache.async_batch_get_cache.<locals>.<genexpr>D  s      3&'T	3s   )r'   r3   ra   r4   timer{   rF   r   allvalues	enumerater}   rs   r   rL   rT   rU   )r   rY   rO   rB   r!   rN   rW   rt   ry   rz   rX   ir*   key_to_indexr+   s                  r#   ra   zDualCache.async_batch_get_cache  s    6	9Vc$i'F##/)S)=)=)S)S*"* $  $/-Fv~$"2"2">:QVCV  $yy{6:6T6T $733
 |$q(
-1-=-=-S-S(;K .T . ( $+s 3+7+>+>+@3 0  & :C4#Ivq#CF#IL#I '3&8&8&: 
U49|C01 ,1E1E1Q"F$"6"6"F"F #U#.4#  	 Mc$*( % CC1  $J
  	9  !5!5!78	9s   F8;F E AF  E 7E8E <#F F8 F .E:;#F F ,!F F F F8F E E77
F 0F52F84F55F8c                   K   t        d| d| d|        	 | j                  Ed|vr| j                  | j                  |d<    | j                  j                  ||fi | d {    | j                  ,|du r' | j                  j                  ||fi | d {    y y y 7 =7 	# t
        $ r+}t        j                  dt        |              Y d }~y d }~ww xY ww)Nzasync set cache: cache key: rq   z	; value: rD   FrJ   )	r   r3   r5   rs   r4   rF   r   	exceptionrM   rG   s         r#   rs   zDualCache.async_set_cacheY  s     *3%~j\SXRYZ	
	##/&4+E+E+Q$($>$>F5M:d**::3PPPP+
e0C6d&&66sELVLLL 1D+ Q M 	$$;CF8D 	sS   CAB& $B"%5B& B$B& C"B& $B& &	C/!CCCC
cache_listc                   K   t        d| d|        	 | j                  Ed|vr| j                  | j                  |d<    | j                  j                  d	d|i| d{    | j                  =|du r8 | j                  j                  d	||j                  dd      d| d{    yyy7 N7 	# t        $ r+}t        j                  dt        |              Y d}~yd}~ww xY ww)
z1
        Batch write values to the cache
        z#async batch set cache: cache keys: rq   NrD   r   F)r   rD   rJ   r\   )
r   r3   r5   async_set_cache_pipeliner4   rh   rF   r   r   rM   )r   r   rB   r!   rH   s        r#   r   z"DualCache.async_set_cache_pipelinek  s     	1*^J<X	
	##/&4+E+E+Q$($>$>F5MCd**CC )-3   +
e0C?d&&?? )vzz%/FJP   1D+	
  	$$;CF8D 	sT   C+AB4 !B0"AB4 (B2)B4 -C+0B4 2B4 4	C(=!C#C+#C((C+c           	      j  K   d}	 | j                   & | j                   j                  ||fi | d{   }| j                  ;|du r7| j                  j                  ||||j                  dd             d{   }|S 7 M7 # t        $ r"}t        j                  d|       |cY d}~S d}~ww xY ww)z
        Key - the key in cache

        Value - float - the value you want to increment by

        Returns - the incremented value, or None if no cache backend is
        available (in_memory_cache is None and Redis failed/is absent).
        NFrD   )rO   rD   zHRedis async_increment_cache failed, falling back to in-memory result: %s)r3   async_incrementr4   rx   rF   r   warning)r   r*   r+   rO   rB   r!   rN   rH   s           r#   async_increment_cachezDualCache.async_increment_cache  s       #'	##/Ct33CC "(   +
e0C#//??%5

5$/	  @    M
  	""Z M	sW   B3-B BAB :B;B  B3B B 	B0B+%B0&B3+B00B3increment_listr   c                 D  K   d }	 | j                   %| j                   j                  ||       d {   }| j                  )|du r%| j                  j                  ||       d {   }|S 7 ;7 # t        $ r"}t	        j
                  d|       |cY d }~S d }~ww xY ww)N)r   rO   FzQRedis async_increment_cache_pipeline failed, falling back to in-memory result: %s)r3   async_increment_pipeliner4   rF   r   r   )r   r   rB   rO   r!   rN   rH   s          r#   async_increment_cache_pipelinez(DualCache.async_increment_cache_pipeline  s      )-	##/#33LL#1%5  M   
 +
e0C#//HH#1%5  I   
 M  	""c M	sV   B ,A2 A.4A2 'A0(A2 -B .A2 0A2 2	B;BBB BB c                 L  K   	 | j                   6| j                   j                  |||j                  dd             d{   }| j                  :|du r6| j                  j                  |||j                  dd             d{   }y7 K7 # t        $ r}|d}~ww xY ww)z
        Add value to a set

        Key - the key in cache

        Value - str - the value you want to add to the set

        Returns - None
        NrD   )rD   F)r3   async_set_cache_saddrx   r4   rF   )r   r*   r+   rB   r!   rl   rH   s          r#   r   zDualCache.async_set_cache_sadd  s     	##/..CCFJJud$; D   +
e0C**??FJJud$; @   

  	G	sM   B$=B BAB BB B$B B 	B!BB!!B$c                     | j                   | j                   j                          | j                  | j                  j                          y y r   )r3   flush_cacher4   )r   s    r#   r   zDualCache.flush_cache  sC    +  ,,.'((* (r$   c                     | j                   | j                   j                  |       | j                  | j                  j                  |       yyz-
        Delete a key from the cache
        N)r3   delete_cacher4   r   r*   s     r#   r   zDualCache.delete_cache  sI     +  --c2'))#. (r$   r*   c                    K   | j                   | j                   j                  |       | j                  $| j                  j                  |       d{    yy7 wr   )r3   r   r4   async_delete_cacher   s     r#   r   zDualCache.async_delete_cache  sV      +  --c2'""55c::: (:s   AAAAc                    K   | j                   j                  |       d{   }|/| j                  #| j                  j                  |       d{   }|S 7 77 w)zL
        Get the remaining TTL of a key in in-memory cache or redis
        N)r3   async_get_ttlr4   )r   r*   rD   s      r#   r   zDualCache.async_get_ttl  sX      ((66s;;;4++7((66s;;C
 <;s!   AA0AAAA)F)NF)FN)&r,   r-   r.   __doc__r   r	   r   r   floatintr   rA   boolrE   rK   r   rS   listro   rr   r   rM   r   r
   r   r{   r   ra   rs   r   r   r   r   r   r   r   r   r/   r0   s   @r#   r2   r2   3   s    48,015-1<@2TP!-0P j)P  (	P
 $E?P +35/P -0P 
P87%-e_7IQRW7  38+/	4 ,0 	9 #4.9 	9H ,0 	!%!% #4.!% 	!%L ,0 	'9 #4.'9 	'9R33 3i3 S		3
 
tCy$sHUO344	53>K%)#x*>%?K	K ,0 	=9=9 #4.=9 	=9~D & 49,0< ,0 % % #4.	%
 % 
%%T !+/	>?  #4.	 
$u+	< 49,0	6+/;C ;s x} r$   r2   )%r   r]   r   rT   concurrent.futuresr   	threadingr   typingr   r   r   r   r	   r
   r   litellm.types.cachingr   r>   litellm._loggingr   r   litellm.constantsr   
base_cacher   r3   r   r4   r   opentelemetry.tracer   _Spancollectionsr   r   r2   r\   r$   r#   <module>r      sr       1  I I IE  : @ ! * #1DD #	([ 	(P	 Pr$   