<s> from synapse . util . caches import cache_counter , caches_by_name <EOL> import logging <EOL> logger = logging . getLogger ( __name__ ) <EOL> class ExpiringCache ( object ) : <EOL> def __init__ ( self , cache_name , clock , max_len = <NUM_LIT:0> , expiry_ms = <NUM_LIT:0> , <EOL> reset_expiry_on_get = False ) : <EOL> """<STR_LIT>""" <EOL> self . _cache_name = cache_name <EOL> self . _clock = clock <EOL> self . _max_len = max_len <EOL> self . _expiry_ms = expiry_ms <EOL> self . _reset_expiry_on_get = reset_expiry_on_get <EOL> self . _cache = { } <EOL> caches_by_name [ cache_name ] = self . _cache <EOL> def start ( self ) : <EOL> if not self . _expiry_ms : <EOL> return <EOL> def f ( ) : <EOL> self . _prune_cache ( ) <EOL> self . _clock . looping_call ( f , self . _expiry_ms / <NUM_LIT:2> ) <EOL> def __setitem__ ( self , key , value ) : <EOL> now = self . _clock . time_msec ( ) <EOL> self . _cache [ key ] = _CacheEntry ( now , value ) <EOL> if self . _max_len and len ( self . _cache . keys ( ) ) > self . _max_len : <EOL> sorted_entries = sorted ( <EOL> self . _cache . items ( ) , <EOL> key = lambda item : item [ <NUM_LIT:1> ] . time , <EOL> ) <EOL> for k , _ in sorted_entries [ self . _max_len : ] : <EOL> self . _cache . pop ( k ) <EOL> def __getitem__ ( self , key ) : <EOL> try : <EOL> entry = self . _cache [ key ] <EOL> cache_counter . inc_hits ( self . _cache_name ) <EOL> except KeyError : <EOL> cache_counter . inc_misses ( self . _cache_name ) <EOL> raise <EOL> if self . _reset_expiry_on_get : <EOL> entry . time = self . _clock . time_msec ( ) <EOL> return entry . value <EOL> def get ( self , key , default = None ) : <EOL> try : <EOL> return self [ key ] <EOL> except KeyError : <EOL> return default <EOL> def _prune_cache ( self ) : <EOL> if not self . _expiry_ms : <EOL> return <EOL> begin_length = len ( self . _cache ) <EOL> now = self . _clock . time_msec ( ) <EOL> keys_to_delete = set ( ) <EOL> for key , cache_entry in self . _cache . items ( ) : <EOL> if now - cache_entry . time > self . _expiry_ms : <EOL> keys_to_delete . add ( key ) <EOL> for k in keys_to_delete : <EOL> self . _cache . pop ( k ) <EOL> logger . debug ( <EOL> "<STR_LIT>" , <EOL> self . _cache_name , begin_length , len ( self . _cache ) <EOL> ) <EOL> def __len__ ( self ) : <EOL> return len ( self . _cache ) <EOL> class _CacheEntry ( object ) : <EOL> def __init__ ( self , time , value ) : <EOL> self . time = time <EOL> self . value = value </s>
