@@ -156,7 +156,7 @@ def __setstate__(self, state: Mapping[str, Any]) -> Any:
156156 )
157157 self ._version = 0
158158 self ._memory_lock = threading .RLock ()
159- self ._index_read (0 )
159+ self ._index_read (random . randint ( 0 , 2 ** 64 - 1 ) )
160160
161161 def __init__ (
162162 self ,
@@ -245,6 +245,24 @@ def _deleter(self, item: tuple[Any, Entry]) -> None:
245245 )
246246 )
247247
248+ def refresh (self ) -> None :
249+ """Refresh the this cache from storage
250+
251+ Note: This happens automatically at function import-time if
252+ fine_grain_persistence is enabled, after function call.
253+
254+ """
255+ self ._index_read (random .randint (0 , 2 ** 64 - 1 ))
256+
257+ def commit (self ) -> None :
258+ """Save this cache into storage.
259+
260+ Note: This happens automatically at function import-time if
261+ fine_grain_persistence is enabled, after function call.
262+
263+ """
264+ self ._index_write (random .randint (0 , 2 ** 64 - 1 ))
265+
248266 def _index_read (self , call_id : int ) -> None :
249267 with self ._memory_lock , self ._index_lock .reader :
250268 self ._index_read_nolock (call_id )
@@ -263,6 +281,7 @@ def _index_read_nolock(self, call_id: int) -> None:
263281 ],
264282 self ._pickler .loads (self ._obj_store [self ._index_key ]),
265283 )
284+ # TODO: catch the case where this is unpicklable or does not exist.
266285 if other_version > current_version :
267286 self ._version = other_version
268287 self ._index .update (other_index )
@@ -286,7 +305,7 @@ def _index_read_nolock(self, call_id: int) -> None:
286305 def _index_write (self , call_id : int ) -> None :
287306 with perf_ctx ("index_write" , call_id ), self ._memory_lock , self ._index_lock .writer :
288307 self ._index_read_nolock (call_id )
289- self ._evict ()
308+ self ._evict (call_id )
290309 self ._version += 1
291310 self ._obj_store [self ._index_key ] = self ._pickler .dumps (
292311 (
@@ -320,7 +339,17 @@ def _system_state(self) -> Any:
320339 with self ._memory_lock :
321340 return (__version__ ,) + none_tuple (self ._extra_system_state ())
322341
323- def _evict (self ) -> None :
342+ def evict (self ) -> None :
343+ """If the size of the cache is greater than ``self._size``, use ``self._replacement_policy``.
344+
345+ Note: this is automatically triggered automatically either
346+ when the function gets called or atexit, depending on the
347+ group-level options.
348+
349+ """
350+ self ._evict (random .randint (0 , 2 ** 64 - 1 ))
351+
352+ def _evict (self , call_id : int ) -> None :
324353 with self ._memory_lock :
325354 total_size : bitmath .Bitmath = bitmath .Byte (0 )
326355
@@ -350,6 +379,7 @@ def _evict(self) -> None:
350379 "obj_key" : obj_key ,
351380 "entry.data_size" : entry .data_size .bytes ,
352381 "new_total_size" : (total_size - entry .data_size ).bytes ,
382+ "call_id" : call_id ,
353383 }
354384 )
355385 )
@@ -627,6 +657,7 @@ def __call__(
627657 hit , value = self ._try_unpickle (value_ser , call_id )
628658 else :
629659 hit , value = True , cast (FuncReturn , entry .value )
660+ # TODO: allow a hit if entry is None but value_ser is not.
630661
631662 if ops_logger .isEnabledFor (logging .DEBUG ):
632663 ops_logger .debug (
@@ -671,7 +702,7 @@ def __call__(
671702
672703 # Update time_cost
673704 if self .group ._fine_grain_eviction :
674- self .group ._evict ()
705+ self .group ._evict (call_id )
675706
676707 if self .group ._fine_grain_persistence :
677708 self .group ._index_write (call_id )
@@ -766,6 +797,17 @@ def would_hit(self, *args: FuncParams.args, **kwargs: FuncParams.kwargs) -> bool
766797 )
767798 return would_hit
768799
800+ def clear_entry (
801+ self ,
802+ * args : FuncParams .args ,
803+ ** kwargs : FuncParams .kwargs ,
804+ ) -> None :
805+ call_id = random .randint (0 , 2 ** 64 - 1 )
806+ key , entry , obj_key , value_ser = self ._would_hit (call_id , * args , ** kwargs )
807+ if entry is not None :
808+ self .group ._deleter ((key , entry ))
809+ assert not self .would_hit (* args , ** kwargs )
810+
769811 def _would_hit (
770812 self , call_id : int , * args : FuncParams .args , ** kwargs : FuncParams .kwargs
771813 ) -> Tuple [Tuple [Any , ...], Optional [Entry ], int , Optional [bytes ]]:
@@ -789,12 +831,14 @@ def _would_hit(
789831 with self .group ._memory_lock :
790832 if self .group ._fine_grain_persistence :
791833 self .group ._index_read (call_id )
792- return (
793- key ,
794- self .group ._index .get (key , None ),
795- obj_key ,
796- self .group ._obj_store .get (obj_key , None ) if self ._use_obj_store else None ,
797- )
834+ entry = self .group ._index .get (key , None )
835+ value_ser = self .group ._obj_store .get (obj_key , None ) if self ._use_obj_store else None
836+ return (
837+ key ,
838+ entry ,
839+ obj_key ,
840+ value_ser ,
841+ )
798842
799843 def __get__ (self , instance : Any , instancetype : Type [Any ]) -> BoundMemoized [FuncParams , FuncReturn ]:
800844 """Implement the descriptor protocol to make decorating instance
0 commit comments