88import time
99import re
1010import hashlib
11- import threading , random , time
1211
1312from . import base as fbase , lru_cache as lru_mod
1413
@@ -206,82 +205,68 @@ def touch_value(self, key, expire):
206205 except KeyError :
207206 pass
208207
209- class Gc (object ):
208+ class SizeMaintainer (object ):
209+ _DEBUG = False
210210
211211 def __init__ (self , backend , target_size , expire_f = None ):
212+ from collections import abc
212213 assert round (target_size ) > 0 , 'target_size has to be at least 1'
213214 assert expire_f is None or callable (expire_f ), 'expire_f has to be function or None'
214- assert isinstance (backend , type ({}) ), 'backend has to be dict-like'
215+ assert isinstance (backend , abc . MutableMapping ), 'backend has to be dict-like'
215216 self ._backend = backend
216217 self ._target_size = round (target_size )
217218 self ._expire_f = expire_f
218- self ._mutex = threading .Lock ()
219219
220220 def run (self ):
221- class WorkThread (threading .Thread ):
222- DEBUG = False
223-
224- def __init__ (self , outer_instance ):
225- threading .Thread .__init__ (self )
226- self ._backend = outer_instance ._backend
227- self ._target_size = outer_instance ._target_size
228- self ._expire_f = outer_instance ._expire_f
229- self ._mutex = outer_instance ._mutex
230-
231- def strategy_with_expire (self ):
232- MAX_EXPIRE_RETRY_COUNT = 4
233- now = time .time ()
234- retry_count = 0
235- keys = list (self ._backend .keys ())
236- while (len (self ._backend ) > self ._target_size ) and (retry_count < MAX_EXPIRE_RETRY_COUNT ):
237- k = keys .pop (random .randrange (len (keys )))
238- val = self ._backend .get (k , None )
239- if val is None :
240- continue
241- expire = self ._expire_f (val )
242- if expire < now :
243- self ._backend .pop (k , None )
244- self .print_d ('{} removed from strategy_with_expire => size {}' .format (k , len (self ._backend )))
245- else :
246- retry_count += 1
247- if len (keys ) == 0 :
248- keys = list (self ._backend .keys ())
249-
250- def strategy_with_force (self ):
251- keys = list (self ._backend .keys ())
252- while (len (self ._backend ) > self ._target_size ) and len (keys ) > 0 :
253- k = keys .pop (random .randrange (len (keys )))
254- self ._backend .pop (k , None )
255- self .print_d ('{} removed from strategy_with_force => size {}' .format (k , len (self ._backend )))
256- if len (keys ) == 0 :
257- keys = list (self ._backend .keys ())
258-
259- def run (self ):
260- try :
261- self .print_d ('gc started in size:{}' .format (len (self ._backend )))
262- if self ._expire_f is not None :
263- self .strategy_with_expire ()
264- self .strategy_with_force ()
265- self .print_d ('gc ended in size:{}' .format (len (self ._backend )))
266- finally :
267- self ._mutex .release ()
268-
269-
270- def print_d (self , str_ ):
271- if self .DEBUG :
272- print (str_ )
273-
274- self ._mutex .acquire ()
275- if (len (self ._backend ) > self ._target_size ):
276- WorkThread (self ).start ()
277- else :
278- self ._mutex .release ()
221+ if (len (self ._backend ) <= self ._target_size ):
222+ return
223+
224+ import random , time
225+ def strategy_with_expire ():
226+ MAX_EXPIRE_RETRY_COUNT = 4
227+ now = time .time ()
228+ retry_count = 0
229+
230+ keys = list (self ._backend .keys ())
231+ random .shuffle (keys )
232+ key_index = 0
233+ while (len (self ._backend ) > self ._target_size ) and (retry_count < MAX_EXPIRE_RETRY_COUNT ):
234+ key = keys [key_index ]
235+ val = self ._backend .get (key , None )
236+ expire = self ._expire_f (val )
237+ if expire < now :
238+ self ._backend .pop (key , None )
239+ key_index += 1
240+ if self ._DEBUG :
241+ print ('{} removed from strategy_with_expire => size {}' .format (key , len (self ._backend )))
242+ else :
243+ retry_count += 1
244+
245+ def strategy_with_force ():
246+ keys = list (self ._backend .keys ())
247+ random .shuffle (keys )
248+ key_index = 0
249+ while (len (self ._backend ) > self ._target_size ):
250+ key = keys [key_index ]
251+ self ._backend .pop (key , None )
252+ key_index += 1
253+ if self ._DEBUG :
254+ print ('{} removed from strategy_with_force => size {}' .format (key , len (self ._backend )))
255+
256+ if self ._DEBUG :
257+ print ('gc started in size:{}' .format (len (self ._backend )))
258+
259+ if self ._expire_f is not None :
260+ strategy_with_expire ()
261+ strategy_with_force ()
262+
263+ if self ._DEBUG :
264+ print ('gc ended in size:{}' .format (len (self ._backend )))
265+
279266
280267class ExpirableDictStorage (fbase .CommonMixinStorage , fbase .StorageMixin ):
281- maxsize = 128
282268 in_memory_storage = True
283269 now = time .time
284- _gc = None
285270
286271 def get_value (self , key ):
287272 _now = self .now ()
@@ -302,9 +287,7 @@ def set_value(self, key, value, expire):
302287 self .backend [key ] = expired_time , value
303288
304289 if self .maxsize < len (self .backend ):
305- if self ._gc == None :
306- self ._gc = Gc (self .backend , self .maxsize * 0.75 , lambda x : x [0 ])
307- self ._gc .run ()
290+ SizeMaintainer (self .backend , self .maxsize * 0.75 , lambda x : x [0 ]).run ()
308291
309292 def delete_value (self , key ):
310293 try :
@@ -330,8 +313,6 @@ def touch_value(self, key, expire):
330313
331314class PersistentDictStorage (fbase .CommonMixinStorage , fbase .StorageMixin ):
332315 in_memory_storage = True
333- maxsize = 128
334- _gc = None
335316
336317 def get_value (self , key ):
337318 try :
@@ -343,9 +324,7 @@ def get_value(self, key):
343324 def set_value (self , key , value , expire ):
344325 self .backend [key ] = value
345326 if self .maxsize < len (self .backend ):
346- if self ._gc == None :
347- self ._gc = Gc (self .backend , self .maxsize * 0.75 )
348- self ._gc .run ()
327+ SizeMaintainer (self .backend , self .maxsize * 0.75 ).run ()
349328
350329 def delete_value (self , key ):
351330 try :
@@ -549,11 +528,10 @@ def dict(
549528 storage_class = PersistentDictStorage
550529 else :
551530 storage_class = ExpirableDictStorage
552- storage_class .maxsize = maxsize
553531
554532 return fbase .factory (
555533 obj , key_prefix = key_prefix , on_manufactured = None ,
556- user_interface = user_interface , storage_class = storage_class ,
534+ user_interface = user_interface , storage_class = storage_class , maxsize = maxsize ,
557535 miss_value = None , expire_default = expire , coder = coder ,
558536 ** kwargs )
559537
0 commit comments