Skip to content

Commit 8073bce

Browse files
committed
Removed threading & newly written test.
1 parent 9846986 commit 8073bce

File tree

4 files changed

+196
-203
lines changed

4 files changed

+196
-203
lines changed

ring/func/base.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -562,6 +562,7 @@ def factory(
562562
# keyword-only arguments from here
563563
# building blocks
564564
coder, miss_value, user_interface, storage_class,
565+
maxsize=128,
565566
default_action=Ellipsis,
566567
coder_registry=Ellipsis,
567568
# callback
@@ -638,7 +639,7 @@ class RingRope(RopeCore):
638639
def __init__(self, *args, **kwargs):
639640
super(RingRope, self).__init__(*args, **kwargs)
640641
self.user_interface = self.user_interface_class(self)
641-
self.storage = self.storage_class(self, storage_backend)
642+
self.storage = self.storage_class(self, storage_backend, maxsize)
642643
_ignorable_keys = suggest_ignorable_keys(
643644
self.callable, ignorable_keys)
644645
_key_prefix = suggest_key_prefix(self.callable, key_prefix)
@@ -747,9 +748,10 @@ class BaseStorage(object):
747748
are mandatory; Otherwise not.
748749
"""
749750

750-
def __init__(self, rope, backend):
751+
def __init__(self, rope, backend, maxsize):
751752
self.rope = rope
752753
self.backend = backend
754+
self.maxsize = maxsize
753755

754756
@abc.abstractmethod
755757
def get(self, key): # pragma: no cover

ring/func/sync.py

Lines changed: 52 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
import time
99
import re
1010
import hashlib
11-
import threading, random, time
1211

1312
from . 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

280267
class 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

331314
class 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

tests/test_dict_gc.py

Lines changed: 0 additions & 127 deletions
This file was deleted.

0 commit comments

Comments
 (0)