
    sgJ:                         d Z ddlZddlZddlZddlZddlZddlZddlmZm	Z	m
Z
  G d d      Z G d d      Z G d	 d
      Z G d d      Zdddej                  ej                  fdZddZ	 ddZy)zDisk Cache Recipes
    N   )ENOVALargs_to_key	full_namec                   *    e Zd ZdZddZd Zd Zd Zy)AverageraL  Recipe for calculating a running average.

    Sometimes known as "online statistics," the running average maintains the
    total and count. The average can then be calculated at any time.

    Assumes the key will not be evicted. Set the eviction policy to 'none' on
    the cache to guarantee the key is not evicted.

    >>> import diskcache
    >>> cache = diskcache.FanoutCache()
    >>> ave = Averager(cache, 'latency')
    >>> ave.add(0.080)
    >>> ave.add(0.120)
    >>> ave.get()
    0.1
    >>> ave.add(0.160)
    >>> ave.pop()
    0.12
    >>> print(ave.get())
    None

    Nc                 <    || _         || _        || _        || _        y N_cache_key_expire_tagselfcachekeyexpiretags        D/var/www/html/venv/lib/python3.12/site-packages/diskcache/recipes.py__init__zAverager.__init__&       		    c                 L   | j                   j                  d      5  | j                   j                  | j                  d      \  }}||z  }|dz  }| j                   j	                  | j                  ||f| j
                  | j                         ddd       y# 1 sw Y   yxY w)zAdd `value` to average.Tretryg        r   defaultr   r   r   N)r   transactgetr   setr   r   )r   valuetotalcounts       r   addzAverager.add,   s    [[!!!- 		;;??499h?GLE5UNEQJEKKOO		||II	  			 		 		s   A4BB#c                 p    | j                   j                  | j                  dd      \  }}|dk(  rdS ||z  S )z:Get current average or return `None` if count equals zero.r   Tr   r   r   N)r   r"   r   r   r%   r&   s      r   r"   zAverager.get9   7    {{tyy($Ouzt4uu}4r   c                 p    | j                   j                  | j                  dd      \  }}|dk(  rdS ||z  S )z&Return current average and delete key.r   Tr)   r   N)r   popr   r*   s      r   r-   zAverager.pop>   r+   r   NN)__name__
__module____qualname____doc__r   r'   r"   r-    r   r   r   r      s    .5
5r   r   c                   6    e Zd ZdZd	dZd Zd Zd Zd Zd Z	y)
Lockan  Recipe for cross-process and cross-thread lock.

    Assumes the key will not be evicted. Set the eviction policy to 'none' on
    the cache to guarantee the key is not evicted.

    >>> import diskcache
    >>> cache = diskcache.Cache()
    >>> lock = Lock(cache, 'report-123')
    >>> lock.acquire()
    >>> lock.release()
    >>> with lock:
    ...     pass

    Nc                 <    || _         || _        || _        || _        y r
   r   r   s        r   r   zLock.__init__T   r   r   c                     	 | j                   j                  | j                  d| j                  | j                  d      }|ryt        j                  d       W)z'Acquire lock using spin-lock algorithm.TNr   r   r   MbP?)r   r'   r   r   r   timesleep)r   addeds     r   acquirezLock.acquireZ   sP    KKOO		||II $ E JJu r   c                 R    | j                   j                  | j                  d       y)zRelease lock by deleting key.Tr   N)r   deleter   r   s    r   releasezLock.releaseh   s    499D1r   c                 2    | j                   | j                  v S )z$Return true if the lock is acquired.)r   r   r@   s    r   lockedzLock.lockedl   s    yyDKK''r   c                 $    | j                          y r
   r=   r@   s    r   	__enter__zLock.__enter__p       r   c                 $    | j                          y r
   rA   r   exc_infos     r   __exit__zLock.__exit__s   rG   r   r.   )
r/   r0   r1   r2   r   r=   rA   rC   rF   rL   r3   r   r   r5   r5   D   s%    2(r   r5   c                   0    e Zd ZdZddZd Zd Zd Zd Zy)	RLocka)  Recipe for cross-process and cross-thread re-entrant lock.

    Assumes the key will not be evicted. Set the eviction policy to 'none' on
    the cache to guarantee the key is not evicted.

    >>> import diskcache
    >>> cache = diskcache.Cache()
    >>> rlock = RLock(cache, 'user-123')
    >>> rlock.acquire()
    >>> rlock.acquire()
    >>> rlock.release()
    >>> with rlock:
    ...     pass
    >>> rlock.release()
    >>> rlock.release()
    Traceback (most recent call last):
      ...
    AssertionError: cannot release un-acquired lock

    Nc                 <    || _         || _        || _        || _        y r
   r   r   s        r   r   zRLock.__init__   r   r   c                    t        j                         }t        j                         }dj	                  ||      }	 | j
                  j                  d      5  | j
                  j                  | j                  d      \  }}||k(  s|dk(  rL| j
                  j                  | j                  ||dz   f| j                  | j                         	 d	d	d	       y		 d	d	d	       t        j                  d
       # 1 sw Y   xY w)z=Acquire lock by incrementing count using spin-lock algorithm.{}-{}Tr   Nr   r   r   r   r    Nr9   )osgetpid	threading	get_identformatr   r!   r"   r   r#   r   r   r:   r;   )r   pidtidpid_tidr$   r&   s         r   r=   zRLock.acquire   s    iik!!#..c*%%D%1 	#{{tyy)Lue#uzKKOO		 %!),#|| II	 $  	 	'1	 JJu 	 	s   A8C88Dc                    t        j                         }t        j                         }dj	                  ||      }| j
                  j                  d      5  | j
                  j                  | j                  d      \  }}||k(  xr |dkD  }|sJ d       | j
                  j                  | j                  ||dz
  f| j                  | j                  	       d
d
d
       y
# 1 sw Y   y
xY w)z#Release lock by decrementing count.rQ   Tr   rR   r   r   zcannot release un-acquired lockr   r    N)rS   rT   rU   rV   rW   r   r!   r"   r   r#   r   r   )r   rX   rY   rZ   r$   r&   is_owneds          r   rA   zRLock.release   s    iik!!#..c*[[!!!- 		;;??499i?HLE5%'5EAIH>>>8KKOO			"||II	  			 		 		s   BC""C+c                 $    | j                          y r
   rE   r@   s    r   rF   zRLock.__enter__   rG   r   c                 $    | j                          y r
   rI   rJ   s     r   rL   zRLock.__exit__   rG   r   r.   	r/   r0   r1   r2   r   r=   rA   rF   rL   r3   r   r   rN   rN   w   s     *&"r   rN   c                   0    e Zd ZdZddZd Zd Zd Zd Zy)	BoundedSemaphorea`  Recipe for cross-process and cross-thread bounded semaphore.

    Assumes the key will not be evicted. Set the eviction policy to 'none' on
    the cache to guarantee the key is not evicted.

    >>> import diskcache
    >>> cache = diskcache.Cache()
    >>> semaphore = BoundedSemaphore(cache, 'max-cons', value=2)
    >>> semaphore.acquire()
    >>> semaphore.acquire()
    >>> semaphore.release()
    >>> with semaphore:
    ...     pass
    >>> semaphore.release()
    >>> semaphore.release()
    Traceback (most recent call last):
      ...
    AssertionError: cannot release un-acquired semaphore

    Nc                 J    || _         || _        || _        || _        || _        y r
   )r   r   _valuer   r   )r   r   r   r$   r   r   s         r   r   zBoundedSemaphore.__init__   s%    		r   c                    	 | j                   j                  d      5  | j                   j                  | j                  | j                        }|dkD  rJ| j                   j                  | j                  |dz
  | j                  | j                         	 ddd       y	 ddd       t        j                  d       # 1 sw Y   xY w)	zBAcquire semaphore by decrementing value using spin-lock algorithm.Tr   r   r   r   r    Nr9   )
r   r!   r"   r   rc   r#   r   r   r:   r;   r   r$   s     r   r=   zBoundedSemaphore.acquire   s    %%D%1 			4;;G19KKOO			#|| II	 $  	 		 JJu 	 	s   A8B>>Cc                 x   | j                   j                  d      5  | j                   j                  | j                  | j                        }| j                  |kD  sJ d       |dz  }| j                   j                  | j                  || j                  | j                         ddd       y# 1 sw Y   yxY w)z(Release semaphore by incrementing value.Tr   r   z$cannot release un-acquired semaphorer   r    N)r   r!   r"   r   rc   r#   r   r   re   s     r   rA   zBoundedSemaphore.release   s    [[!!!- 		KKOODIIt{{OCE;;&N(NN&QJEKKOO		||II	  			 		 		s   B
B00B9c                 $    | j                          y r
   rE   r@   s    r   rF   zBoundedSemaphore.__enter__   rG   r   c                 $    | j                          y r
   rI   rJ   s     r   rL   zBoundedSemaphore.__exit__   rG   r   )r   NNr_   r3   r   r   ra   ra      s     *r   ra   c                 .      fd}|S )a(  Decorator to throttle calls to function.

    Assumes keys will not be evicted. Set the eviction policy to 'none' on the
    cache to guarantee the keys are not evicted.

    >>> import diskcache, time
    >>> cache = diskcache.Cache()
    >>> count = 0
    >>> @throttle(cache, 2, 1)  # 2 calls per 1 second
    ... def increment():
    ...     global count
    ...     count += 1
    >>> start = time.time()
    >>> while (time.time() - start) <= 2:
    ...     increment()
    >>> count in (6, 7)  # 6 or 7 calls depending on CPU load
    True

    c           	           t        	      z  t               n        }j                  |fd       t        j                          
fd       }|S )NTr8   c                  V   	 j                  d      5  j                  
      \  }}        }|||z
  z  z  }d}|kD  rj                  
|dz
  f       n&|dk\  rj                  
||dz
  f       nd|z
  z  }d d d        r	 |       nn 	| i |S # 1 sw Y   xY w)NTr   r   r   )r!   r"   r#   )argskwargslasttallynowdelayr   r&   r   funcr   rate
sleep_func	time_funcs         r   wrapperz,throttle.<locals>.decorator.<locals>.wrapper"  s    ^^$^/ 3"'))C.KD%#+CcDjD00EEu}		#UQY'7@!		#UQY'7@!"Ud 23 u%# & (((%3 3s   A-BB()floatr   r#   	functoolswraps)rr   rp   rv   r   rs   r   r&   r   namesecondsrt   r   ru   s   `  @@r   	decoratorzthrottle.<locals>.decorator  sh    uW~%!%io4k		#U|F4	H			) 	) 
	), r   r3   )	r   r&   r{   rz   r   r   ru   rt   r|   s	   ```````` r   throttler}      s    < > r   c                 "      fd}|S )a  Barrier to calling decorated function.

    Supports different kinds of locks: Lock, RLock, BoundedSemaphore.

    Assumes keys will not be evicted. Set the eviction policy to 'none' on the
    cache to guarantee the keys are not evicted.

    >>> import diskcache, time
    >>> cache = diskcache.Cache()
    >>> @barrier(cache, Lock)
    ... def work(num):
    ...     print('worker started')
    ...     time.sleep(1)
    ...     print('worker finished')
    >>> import multiprocessing.pool
    >>> pool = multiprocessing.pool.ThreadPool(2)
    >>> _ = pool.map(work, range(2))
    worker started
    worker finished
    worker started
    worker finished
    >>> pool.terminate()

    c                 ~     t               n} |      t        j                          fd       }|S )Nr    c                  D    5   | i |cd d d        S # 1 sw Y   y xY wr
   r3   )rl   rm   rr   locks     r   rv   z+barrier.<locals>.decorator.<locals>.wrapper\  s(     -T,V,- - -s   )r   rx   ry   )	rr   r   rv   r   r   r   lock_factoryrz   r   s	   `  @r   r|   zbarrier.<locals>.decoratorX  sD    !%io4E3v3?			- 
	- r   r3   )r   r   rz   r   r   r|   s   ````` r   barrierr   >  s    4	 	 r   c                 *      fd}|S )a/	  Memoizing cache decorator with cache stampede protection.

    Cache stampedes are a type of system overload that can occur when parallel
    computing systems using memoization come under heavy load. This behaviour
    is sometimes also called dog-piling, cache miss storm, cache choking, or
    the thundering herd problem.

    The memoization decorator implements cache stampede protection through
    early recomputation. Early recomputation of function results will occur
    probabilistically before expiration in a background thread of
    execution. Early probabilistic recomputation is based on research by
    Vattani, A.; Chierichetti, F.; Lowenstein, K. (2015), Optimal Probabilistic
    Cache Stampede Prevention, VLDB, pp. 886-897, ISSN 2150-8097

    If name is set to None (default), the callable name will be determined
    automatically.

    If typed is set to True, function arguments of different types will be
    cached separately. For example, f(3) and f(3.0) will be treated as distinct
    calls with distinct results.

    The original underlying function is accessible through the `__wrapped__`
    attribute. This is useful for introspection, for bypassing the cache, or
    for rewrapping the function with a different cache.

    >>> from diskcache import Cache
    >>> cache = Cache()
    >>> @memoize_stampede(cache, expire=1)
    ... def fib(number):
    ...     if number == 0:
    ...         return 0
    ...     elif number == 1:
    ...         return 1
    ...     else:
    ...         return fib(number - 1) + fib(number - 2)
    >>> print(fib(100))
    354224848179261915075

    An additional `__cache_key__` attribute can be used to generate the cache
    key used for the given arguments.

    >>> key = fib.__cache_key__(100)
    >>> del cache[key]

    Remember to call memoize when decorating a callable. If you forget, then a
    TypeError will occur.

    :param cache: cache to store callable arguments and return values
    :param float expire: seconds until arguments expire
    :param str name: name given for callable (default None, automatic)
    :param bool typed: cache different types separately (default False)
    :param str tag: text to associate with arguments (default None)
    :param set ignore: positional or keyword args to ignore (default ())
    :return: callable decorator

    c                      	t               fn	f fdt        j                         
fd       fd}|_        S )z/Decorator created by memoize call for callable.c                  r    t        j                          } | i |}t        j                          |z
  }||fS )z:Time execution of `func` and return result and time delta.)r:   )rl   rm   startresultdeltarr   s        r   timerz2memoize_stampede.<locals>.decorator.<locals>.timer  s7    IIKE4*6*FIIK%'E5= r   c                       j                    i j                  t        dd      \  }}|t        ur|\  }}t        j                         }||z
  }| z  t	        j
                  t        j                               z  |k  r|S t        fz   }j                  |d|d      }	|	r8 fd}
t        j                  |
      }d|_
        |j                          |S   i }j                  |d       |d   S )	z:Wrapper for callable to cache arguments and return values.T)r   expire_timer   N)r   r   c                  p    5   i } j                  | d       d d d        y # 1 sw Y   y xY w)NTr8   )r#   )pairrl   r   r   r   rm   r   r   s    r   	recomputezGmemoize_stampede.<locals>.decorator.<locals>.wrapper.<locals>.recompute  sJ    " #($#9&#9D!II # $'-$'&* &   s   ,5)targetr8   r   )__cache_key__r"   r   r:   mathlograndomr'   rU   Threaddaemonr   r#   )rl   rm   r   r   r   r   rp   ttl
thread_keythread_addedr   threadr   betar   r   r   r   rv   s   ``          @r   rv   z4memoize_stampede.<locals>.decorator.<locals>.wrapper  s    ('''88C %		 	 !* !D+ 6! $iik!C'FTMDHHV]]_$==D!M !F9_
$yy 	  )    	 	 '--Y?F$(FMLLN$)&)DIIc4CtID7Nr   c                  "    t        | |      S )z,Make key for cache given function arguments.)r   )rl   rm   baseignoretypeds     r   r   z:memoize_stampede.<locals>.decorator.<locals>.__cache_key__  s    tT65&AAr   )r   rx   ry   r   )rr   r   r   r   rv   r   r   r   r   rz   r   r   s   ` @@@r   r|   z#memoize_stampede.<locals>.decorator  sT    %)\	$!w	! 
	1	 1	 
1	f	B !.r   r3   )r   r   rz   r   r   r   r   r|   s   ``````` r   memoize_stampeder   f  s    xD DL r   )NNN)NFNr   r3   )r2   rx   r   rS   r   rU   r:   corer   r   r   r   r5   rN   ra   r;   r}   r   r   r3   r   r   <module>r      s      	    0 035 35l0 0fD DN= =H 
iizz=@%R EGBr   