
    ^h+<                         S r SSKrSSKrSSKrSSKJr  SSKJrJrJ	r	J
r
  SSKrSSKJrJr  SSKJr  SSKJr  SS	KJr  \(       a	  SS
KJr  \rO\rSSKJr   " S S\5      r " S S\5      rg)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)TYPE_CHECKINGAnyListOptional)print_verboseverbose_logger   )	BaseCache)InMemoryCache)
RedisCache)Span)OrderedDictc                   <   ^  \ rS rSrSS.U 4S jjrU 4S jrSrU =r$ )LimitedSizeOrderedDict"   d   max_sizec                2   > [         TU ]  " U0 UD6  Xl        g N)super__init__r   )selfr   argskwargs	__class__s       T/home/james-whalen/.local/lib/python3.13/site-packages/litellm/caching/dual_cache.pyr   LimitedSizeOrderedDict.__init__#   s    $)&)     c                 t   > [        U 5      U R                  :  a  U R                  SS9  [        TU ]  X5        g )NF)last)lenr   popitemr   __setitem__)r   keyvaluer   s      r   r%   "LimitedSizeOrderedDict.__setitem__'   s.    t9%LLeL$C'r    )__name__
__module____qualname____firstlineno__r   r%   __static_attributes____classcell__r   s   @r   r   r   "   s    '* ! !( (r    r   c                     ^  \ rS rSrSr      S%S\\   S\\   S\\   S\\   S\\   S	\	S
S4U 4S jjjr
S\\   S\\   4S jrS&S\4S jjr S&S\	S\S
\	4S jjr  S'S\\   S\4S jjr  S'S\S\\   S\4S jjr  S'S\\   S\4S jjrS\S\\   S\\   S
\\   4S jr  S'S\S\\   S\4S jjrS&S\4S jjr S&S\S\4S jjr  S'S\S\\   S\S
\4S jjr S&S\S\S
S4S jjrS rS  rS!\4S" jrS!\S
\\	   4S# jr S$r!U =r"$ )(	DualCache.   a%  
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                 @  > [         TU ]  5         U=(       d
    [        5       U l        X l        [        US9U l        U=(       d    [        R                  =(       d    SU l	        U=(       d    [        R                  U l
        U=(       d    [        R                  U l        g )Nr   
   )r   r   r   r3   r4   r   last_redis_batch_access_timelitellmr7   redis_batch_cache_expiryr5   r6   )r   r3   r4   r5   r6   r7   r8   r   s          r   r   DualCache.__init__5   s     	.A-/&,B7-
) - 77 	% "BW%B%B 	" "3!Og6O6Or    c                 *    Ub  Xl         Ub  X l        g g r   )r5   r6   )r   r5   r6   s      r   update_cache_ttlDualCache.update_cache_ttlP   s!     !,)>&(%6" )r    
local_onlyc                 D    U R                   b?  SU;  a  U R                  b  U R                  US'   U R                   R                  " X40 UD6  U R                  b$  USL a  U R                  R                  " X40 UD6  g g g ! [         a  n[        U5         S nAg S nAff = f)NttlF)r3   r5   	set_cacher4   	Exceptionr   r   r&   r'   rC   r   es         r   rF   DualCache.set_cacheY   s    
	##/&4+E+E+Q$($>$>F5M$$..sDVD+
e0C  **3@@ 1D+ 	!	s   A;B   
B
BBr'   c                 *    UnU R                   b  U R                   R                  " X40 UD6nU R                  b"  USL a  U R                  R                  " X40 UD6nU$ ! [         a)  n[        R
                  " S[        U5       35        UeSnAff = f)zq
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   rG   r	   errorstr)r   r&   r'   rC   r   resultrI   s          r   rM   DualCache.increment_cacheg   s    	F##/--==cSFS+
e0C))99#OOM 	  #LSQRVH!UVG	s   AA 
B)$BBparent_otel_spanc                     S nU R                   b"  U R                   R                  " U40 UD6nUb  UnUcM  U R                  b@  USL a;  U R                  R                  XS9nUb  U R                   R                  " X40 UD6  Un[	        SU 35        U$ ! [
         a,    [        R                  " [        R                  " 5       5         g f = f)NFrR   get cache: cache result: )
r3   	get_cacher4   rF   r   rG   r	   rN   	traceback
format_excr   r&   rR   rC   r   rP   in_memory_resultredis_results           r   rV   DualCache.get_cache~   s    	9F##/#'#7#7#A#A##P#P #/-F~$"2"2">:QVCV#//99  :    +((223OO%5fX>?M 	9  !5!5!78	9s   BB 3C	C	keysc                 .  ^ ^	 [        5       m	T	R                  S5        U	U 4S jn [        R                  " 5       n[	        SS9 nUR                  U5      nUR                  5       sS S S 5        $ ! , (       d  f       g = f! [         a
    U" 5       s $ f = f)Nr   c                  @  > [         R                  " 5       n  [         R                  " U 5        U R                  TR                  " S0 TD65      U R                  5         [         R                  " S5        $ ! U R                  5         [         R                  " S5        f = f)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_loop2DualCache.batch_get_cache.<locals>.run_in_new_loop   sy    --/H-&&x022..??  &&t,  &&t,s   6A5 5(Br
   )max_workers)localspopra   get_running_loopr   submitrP   RuntimeError)
r   r]   rR   rC   r   ri   _executorfuturerh   s
   `        @r   batch_get_cacheDualCache.batch_get_cache   sz     &!
	-	%((*A $2h!9}} 322  	%"$$	%s/   B  !A/%	B  /
A=9B  =B   BBc                   #     [        SU SU 35        S nU R                  b8  U R                  R                  " U40 UD6I S h  vN n[        SU 35        Ub  UnUc]  U R                  bP  USL aK  U R                  R                  XS9I S h  vN nUb%  U R                  R                  " X40 UD6I S h  vN   Un[        SU 35        U$  N N@ N! [
         a,    [        R                  " [        R                  " 5       5         g f = f7f)Nzasync get cache: cache key: ; local_only: zin_memory_result: FrT   rU   )
r   r3   async_get_cacher4   async_set_cacherG   r	   rN   rW   rX   rY   s           r   rx   DualCache.async_get_cache   s:    	9.se>*N F##/)-)=)=)M)M*!* $   23C2DEF#/-F~$"2"2">:QVCV%)%5%5%E%E &F &    +..>>-3   &5fX>?M/$   	9  !5!5!78	9s`   DA C CAC C'C 5C6C DC C C 3DDDDcurrent_timerP   c                     / n[        X#5       HK  u  pVUb  M
  XPR                  ;  d!  XR                  U   -
  U R                  :  d  M:  UR                  U5        MM     U$ r   )zipr<   r>   append)r   r{   r]   rP   sublist_keysr&   r'   s          r   get_redis_batch_keysDualCache.get_redis_batch_keys   sb     d+JC}@@@#&G&G&LL445 !'', , r    c                 6  #     [        [        U5      5       Vs/ s H  nS PM     nnU R                  b*  U R                  R                  " U40 UD6I S h  vN nUb  UnS U;   a  U R                  b  USL a   [
        R
                  " 5       nU R                  XU5      n	[        U	5      S:  a  U R                  R                  XS9I S h  vN n
U
bR  U
R                  5        H>  u  pUb(  U R                  R                  " XU   40 UD6I S h  vN   XR                  U'   M@     U
R                  5        H  u  pUR                  U5      nXU'   M     U$ s  snf  GN N NP! [         a,    [        R                  " [        R                  " 5       5         g f = f7f)NFr   rT   )ranger#   r3   re   r4   timer   itemsry   r<   indexrG   r	   rN   rW   rX   )r   r]   rR   rC   r   rq   rP   rZ   r{   r   r[   r&   r'   r   s                 r   re   DualCache.async_batch_get_cache   s    )	9$)#d)$45$4qd$4F5##/)-)=)=)S)S*"* $  $/-Fv~$"2"2">:QVCV  $yy{#88VT |$q()-)9)9)O)O$ *P * $L $/*6*<*<*>JC$0&*&:&:&J&J$'c):'">D'" !" !" FR==cB +? '3&8&8&:
 $

3(-u '; MM 6$$$!"  	9  !5!5!78	9sk   FE  E/E  EA4E  
EAE  EAE  FE  E  E   3FFFFc                   #    [        SU SU SU 35         U R                  b%  U R                  R                  " X40 UD6I S h  vN   U R                  b,  USL a&  U R                  R                  " X40 UD6I S h  vN   g g g  N> N	! [         a,  n[
        R                  " S[        U5       35         S nAg S nAff = f7f)Nzasync set cache: cache key: rw   z	; value: FrL   )r   r3   ry   r4   rG   r	   	exceptionrO   rH   s         r   ry   DualCache.async_set_cache.  s     *3%~j\SXRYZ	
		##/**::3PPPP+
e0C&&66sLVLLL 1D+ Q M 	$$;CF8D 	sR   C-B B6B <B=B CB B 
B>"B94C9B>>C
cache_listc                   #    [        SU SU 35         U R                  b&  U R                  R                  " S	SU0UD6I Sh  vN   U R                  b=  USL a7  U R                  R                  " S	XR	                  SS5      S.UD6I Sh  vN   ggg NO N	! [
         a,  n[        R                  " S[        U5       35         SnAgSnAff = f7f)
z!
Batch write values to the cache
z#async batch set cache: cache keys: rw   Nr   FrE   )r   rE   rL   r`   )	r   r3   async_set_cache_pipeliner4   rm   rG   r	   r   rO   )r   r   rC   r   rI   s        r   r   "DualCache.async_set_cache_pipeline>  s      	1*^J<X	
	##/**CC )-3   +
e0C&&?? )zz%/FJP   1D+	
  	$$;CF8D 	sS   C.B BAB BB CB B 
C!"CCCCc           	      4  #     UnU R                   b%  U R                   R                  " X40 UD6I Sh  vN nU R                  b9  USL a4  U R                  R                  UUUUR                  SS5      S9I Sh  vN nU$  NL N! [         a  nUeSnAff = f7f)zu
Key - the key in cache

Value - float - the value you want to increment by

Returns - float - the incremented value
NFrE   )rR   rE   )r3   async_incrementr4   getrG   )r   r&   r'   rR   rC   r   rP   rI   s           r   async_increment_cacheDualCache.async_increment_cacheV  s     	!F##/#33CC "(   +
e0C#//??%5

5$/	  @    M
  	G	sK   B/B B AB 9B:B ?B B B 
BBBBc                 D  #     U R                   b2  U R                   R                  XUR                  SS5      S9I Sh  vN nU R                  b7  USL a2  U R                  R                  XUR                  SS5      S9I Sh  vN ng NI N! [         a  nUeSnAff = f7f)zp
Add value to a set

Key - the key in cache

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

Returns - None
NrE   )rE   F)r3   async_set_cache_saddr   r4   rG   )r   r&   r'   rC   r   rq   rI   s          r   r   DualCache.async_set_cache_saddx  s     	##/..CCFJJud$; D   +
e0C**??FJJud$; @   

  	G	sK   B :B BAB B
B B B 
B 
BBBB c                     U R                   b  U R                   R                  5         U R                  b  U R                  R                  5         g g r   )r3   flush_cacher4   )r   s    r   r   DualCache.flush_cache  sC    +  ,,.'((* (r    c                     U R                   b  U R                   R                  U5        U R                  b  U R                  R                  U5        ggz
Delete a key from the cache
N)r3   delete_cacher4   r   r&   s     r   r   DualCache.delete_cache  sI     +  --c2'))#. (r    r&   c                    #    U R                   b  U R                   R                  U5        U R                  b$  U R                  R                  U5      I Sh  vN   gg N7fr   )r3   r   r4   async_delete_cacher   s     r   r   DualCache.async_delete_cache  sU      +  --c2'""55c::: (:s   AAAAc                    #    U R                   R                  U5      I Sh  vN nUc0  U R                  b#  U R                  R                  U5      I Sh  vN nU$  N9 N7f)z<
Get the remaining TTL of a key in in-memory cache or redis
N)r3   async_get_ttlr4   )r   r&   rE   s      r   r   DualCache.async_get_ttl  sV      ((66s;;;4++7((66s;;C
 <;s!   AA2AAAA)r5   r6   r3   r<   r>   r4   )NNNNNr   )F)NF)#r)   r*   r+   r,   __doc__r   r   r   floatintr   rA   boolrF   rM   r   rV   listrt   rx   r   rO   r   r   re   ry   r   r   r   r   r   r   r   r-   r.   r/   s   @r   r1   r1   .   sh    48,015-1<@25P!-0P j)P  (	P
 $E?P +35/P -0P 
P P67%-e_7IQRW7  38+/	4 ,0 	9 #4.9 	9H ,0 	!%!% #4.!% 	!%L ,0 	'9 #4.'9 	'9R 3i S		
 
c( ,0 	0909 #4.09 	09dD " 49,08 ,0     #4.	 
   
 F 49,0	6+/;C ;s x}  r    r1   )r   ra   r   rW   concurrent.futuresr   typingr   r   r   r   r=   litellm._loggingr   r	   
base_cacher   r3   r   r4   r   opentelemetry.tracer   _Spancollectionsr   r   r1   r`   r    r   <module>r      sZ       1 5 5  : ! * #1DD #	([ 	(D	 Dr    