
    g+<                         d Z ddlZddlZddl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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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)TYPE_CHECKINGAnyListOptional)print_verboseverbose_logger   )	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       O/var/www/openai/venv/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                       e Zd ZdZ	 	 	 	 	 	 d#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   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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                    t         |           |xs
 t               | _        || _        t        |      | _        |xs t        j                  xs d| _	        |xs t        j                  | _
        |xs t        j                  | _        y )Nr   
   )r   r   r   r-   r.   r   last_redis_batch_access_timelitellmr1   redis_batch_cache_expiryr/   r0   )r   r-   r.   r/   r0   r1   r2   r   s          r   r   zDualCache.__init__5   s     	.A-/&,B7-
) - 77 	% "BW%B%B 	" "3!Og6O6Or   c                 *    ||| _         ||| _        y y r   )r/   r0   )r   r/   r0   s      r   update_cache_ttlzDualCache.update_cache_ttlP   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)r-   r/   	set_cacher.   	Exceptionr   r   r$   r%   r;   r   es         r   r>   zDualCache.set_cacheY   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: )r-   increment_cacher.   r?   r	   errorstr)r   r$   r%   r;   r   resultrA   s          r   rD   zDualCache.increment_cacheg   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rH   get cache: cache result: )
r-   	get_cacher.   r>   r   r?   r	   rE   	traceback
format_excr   r$   rH   r;   r   rG   in_memory_resultredis_results           r   rL   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poprV   get_running_loopr   submitrG   RuntimeError)
r   rR   rH   r;   r   r^   _executorfuturer]   s
   `        @r   batch_get_cachezDualCache.batch_get_cache   sz     &!
	-	%((*A $2h!9}} 322  	%"$$	%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: FrJ   rK   )
r   r-   async_get_cacher.   async_set_cacher?   r	   rE   rM   rN   rO   s           r   rk   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_timerG   c                     g }t        ||      D ]G  \  }}|	|| j                  vs || j                  |   z
  | j                  k\  s7|j                  |       I |S r   )zipr6   r8   append)r   rm   rR   rG   sublist_keysr$   r%   s          r   get_redis_batch_keyszDualCache.get_redis_batch_keys   sj     dF+JC}t@@@#d&G&G&LL445 !'', , r   c                 "  K   	 t        t        |            D cg c]  }d  }}| j                  ) | j                  j                  |fi | d {   }||}d |v r| j                  |du r	 t        j
                         }| j                  |||      }	t        |	      dkD  r| j                  j                  |	|       d {   }
|
R|
j                         D ]?  \  }}|) | j                  j                  ||
|   fi | d {    || j                  |<   A |
j                         D ]  \  }}|j                  |      }|||<    |S c c}w 7 7 7 O# t        $ r* t        j                  t        j                                Y y w xY ww)NFr   rJ   )ranger!   r-   rZ   r.   timerr   itemsrl   r6   indexr?   r	   rE   rM   rN   )r   rR   rH   r;   r   re   rG   rP   rm   rq   rQ   r$   r%   rw   s                 r   rZ   zDualCache.async_batch_get_cache   s    )	9$)#d)$45$4qd$4F5##/)S)=)=)S)S*"* $  $/-Fv~$"2"2">:QVCV  $yy{#88tVT |$q()-)9)9)O)O$7G *P * $L $/*6*<*<*>JC$0&Jd&:&:&J&J$'c):'">D'" !" !" FRD==cB +? '3&8&8&:
U $

3(-u '; MM 6$$$!"  	9  !5!5!78	9sk   FE 	E.E EA2E EAE EAE FE E E 0F	FFFc                   K   t        d| d| d|        	 | j                  & | 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: rj   z	; value: FrC   )r   r-   rl   r.   r?   r	   	exceptionrF   r@   s         r   rl   zDualCache.async_set_cache.  s     *3%~j\SXRYZ	
		##/:d**::3PPPP+
e0C6d&&66sELVLLL 1D+ Q M 	$$;CF8D 	sR   B>-B B5B ;B<B  B>B B 	B;!B61B>6B;;B>
cache_listc                   K   t        d| d|        	 | j                  & | 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: rj   Nrz   Fr=   )rz   r=   rC   rU   )	r   r-   async_set_cache_pipeliner.   ra   r?   r	   ry   rF   )r   rz   r;   r   rA   s        r   r|   z"DualCache.async_set_cache_pipeline>  s      	1*^J<X	
	##/Cd**CC )-3   +
e0C?d&&?? )vzz%/FJP   1D+	
  	$$;CF8D 	sS   C-B BAB 	B
B CB B 	C	!C?CC		Cc           	      4  K   	 |}| j                   & | j                   j                  ||fi | d{   }| j                  ;|du r7| j                  j                  ||||j                  dd             d{   }|S 7 M7 # t        $ r}|d}~ww xY ww)z
        Key - the key in cache

        Value - float - the value you want to increment by

        Returns - float - the incremented value
        NFr=   )rH   r=   )r-   async_incrementr.   getr?   )r   r$   r%   rH   r;   r   rG   rA   s           r   async_increment_cachezDualCache.async_increment_cacheV  s     	!F##/Ct33CC "(   +
e0C#//??%5

5$/	  @    M
  	G	sK   B/B BAB :B;B  B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
        Nr=   )r=   F)r-   async_set_cache_saddr   r.   r?   )r   r$   r%   r;   r   re   rA   s          r   r   zDualCache.async_set_cache_saddx  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   )r-   flush_cacher.   )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)r-   delete_cacher.   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   )r-   r   r.   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)r-   async_get_ttlr.   )r   r$   r=   s      r   r   zDualCache.async_get_ttl  sX      ((66s;;;4++7((66s;;C
 <;s!   AA0AAAA)NNNNNr   )F)NF)!r&   r'   r(   __doc__r   r   r   floatintr   r:   boolr>   rD   r   rL   listrh   rk   r   rF   r   rr   rZ   rl   r|   r   r   r   r   r   r   r)   r*   s   @r   r,   r,   .   s]    48,015-1<@25P!-0P j)P  (	P
 $E?P +35/P -0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   r,   )r   rV   ru   rM   concurrent.futuresr   typingr   r   r   r   r7   litellm._loggingr   r	   
base_cacher   r-   r   r.   r   opentelemetry.tracer   _Spancollectionsr   r   r,   rU   r   r   <module>r      sZ       1 5 5  : ! * #1DD #	([ 	(D	 Dr   