98 lines
2.5 KiB
Python
98 lines
2.5 KiB
Python
|
import time
|
||
|
from itertools import takewhile
|
||
|
import operator
|
||
|
from collections import OrderedDict
|
||
|
|
||
|
|
||
|
class IStorage:
|
||
|
"""
|
||
|
Local storage for this node.
|
||
|
IStorage implementations of get must return the same type as put in by set
|
||
|
"""
|
||
|
|
||
|
def __setitem__(self, key, value):
|
||
|
"""
|
||
|
Set a key to the given value.
|
||
|
"""
|
||
|
raise NotImplementedError
|
||
|
|
||
|
def __getitem__(self, key):
|
||
|
"""
|
||
|
Get the given key. If item doesn't exist, raises C{KeyError}
|
||
|
"""
|
||
|
raise NotImplementedError
|
||
|
|
||
|
def get(self, key, default=None):
|
||
|
"""
|
||
|
Get given key. If not found, return default.
|
||
|
"""
|
||
|
raise NotImplementedError
|
||
|
|
||
|
def iteritemsOlderThan(self, secondsOld):
|
||
|
"""
|
||
|
Return the an iterator over (key, value) tuples for items older
|
||
|
than the given secondsOld.
|
||
|
"""
|
||
|
raise NotImplementedError
|
||
|
|
||
|
def __iter__(self):
|
||
|
"""
|
||
|
Get the iterator for this storage, should yield tuple of (key, value)
|
||
|
"""
|
||
|
raise NotImplementedError
|
||
|
|
||
|
|
||
|
class ForgetfulStorage(IStorage):
|
||
|
def __init__(self, ttl=604800):
|
||
|
"""
|
||
|
By default, max age is a week.
|
||
|
"""
|
||
|
self.data = OrderedDict()
|
||
|
self.ttl = ttl
|
||
|
|
||
|
def __setitem__(self, key, value):
|
||
|
if key in self.data:
|
||
|
del self.data[key]
|
||
|
self.data[key] = (time.monotonic(), value)
|
||
|
self.cull()
|
||
|
|
||
|
def cull(self):
|
||
|
for _, _ in self.iteritemsOlderThan(self.ttl):
|
||
|
self.data.popitem(last=False)
|
||
|
|
||
|
def get(self, key, default=None):
|
||
|
self.cull()
|
||
|
if key in self.data:
|
||
|
return self[key]
|
||
|
return default
|
||
|
|
||
|
def __getitem__(self, key):
|
||
|
self.cull()
|
||
|
return self.data[key][1]
|
||
|
|
||
|
def __iter__(self):
|
||
|
self.cull()
|
||
|
return iter(self.data)
|
||
|
|
||
|
def __repr__(self):
|
||
|
self.cull()
|
||
|
return repr(self.data)
|
||
|
|
||
|
def iteritemsOlderThan(self, secondsOld):
|
||
|
minBirthday = time.monotonic() - secondsOld
|
||
|
zipped = self._tripleIterable()
|
||
|
matches = takewhile(lambda r: minBirthday >= r[1], zipped)
|
||
|
return list(map(operator.itemgetter(0, 2), matches))
|
||
|
|
||
|
def _tripleIterable(self):
|
||
|
ikeys = self.data.keys()
|
||
|
ibirthday = map(operator.itemgetter(0), self.data.values())
|
||
|
ivalues = map(operator.itemgetter(1), self.data.values())
|
||
|
return zip(ikeys, ibirthday, ivalues)
|
||
|
|
||
|
def items(self):
|
||
|
self.cull()
|
||
|
ikeys = self.data.keys()
|
||
|
ivalues = map(operator.itemgetter(1), self.data.values())
|
||
|
return zip(ikeys, ivalues)
|