[IMP] core: rebuild LRU on OrderedDict
That's pretty much the entire point of OrderedDict's existence. Also removed the iteration methods: they're not used and they're not thread-safe, since they're written as generators they "return" instantaneously when called immediately unlocking, then the iteration itself is unprotected, so the entire thing is useless. They could be reimplemented with explicit locking (a `with self._lock` internally) if there's ever a use case for it, but that doesn't seem to be the case at the moment. closes odoo/odoo#46061 Signed-off-by: Xavier Morel (xmo) <xmo@odoo.com>
This commit is contained in:
+15
-84
@@ -1,31 +1,21 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# taken from http://code.activestate.com/recipes/252524-length-limited-o1-lru-cache-implementation/
|
||||
import collections
|
||||
import threading
|
||||
|
||||
from .func import synchronized
|
||||
|
||||
__all__ = ['LRU']
|
||||
|
||||
class LRUNode(object):
|
||||
__slots__ = ['prev', 'next', 'me']
|
||||
def __init__(self, prev, me):
|
||||
self.prev = prev
|
||||
self.me = me
|
||||
self.next = None
|
||||
|
||||
class LRU(object):
|
||||
"""
|
||||
Implementation of a length-limited O(1) LRU queue.
|
||||
Built for and used by PyPE:
|
||||
http://pype.sourceforge.net
|
||||
Copyright 2003 Josiah Carlson.
|
||||
Implementation of a length-limited O(1) LRU map.
|
||||
|
||||
Original Copyright 2003 Josiah Carlson, later rebuilt on OrderedDict.
|
||||
"""
|
||||
def __init__(self, count, pairs=[]):
|
||||
def __init__(self, count, pairs=()):
|
||||
self._lock = threading.RLock()
|
||||
self.count = max(count, 1)
|
||||
self.d = {}
|
||||
self.first = None
|
||||
self.last = None
|
||||
self.d = collections.OrderedDict()
|
||||
for key, value in pairs:
|
||||
self[key] = value
|
||||
|
||||
@@ -41,88 +31,29 @@ class LRU(object):
|
||||
|
||||
@synchronized()
|
||||
def __getitem__(self, obj):
|
||||
a = self.d[obj].me
|
||||
self[a[0]] = a[1]
|
||||
return a[1]
|
||||
a = self.d[obj]
|
||||
self.d.move_to_end(obj, last=False)
|
||||
return a
|
||||
|
||||
@synchronized()
|
||||
def __setitem__(self, obj, val):
|
||||
if obj in self.d:
|
||||
del self[obj]
|
||||
nobj = LRUNode(self.last, (obj, val))
|
||||
if self.first is None:
|
||||
self.first = nobj
|
||||
if self.last:
|
||||
self.last.next = nobj
|
||||
self.last = nobj
|
||||
self.d[obj] = nobj
|
||||
if len(self.d) > self.count:
|
||||
if self.first == self.last:
|
||||
self.first = None
|
||||
self.last = None
|
||||
return
|
||||
a = self.first
|
||||
a.next.prev = None
|
||||
self.first = a.next
|
||||
a.next = None
|
||||
del self.d[a.me[0]]
|
||||
del a
|
||||
self.d[obj] = val
|
||||
self.d.move_to_end(obj, last=False)
|
||||
while len(self.d) > self.count:
|
||||
self.d.popitem(last=True)
|
||||
|
||||
@synchronized()
|
||||
def __delitem__(self, obj):
|
||||
nobj = self.d[obj]
|
||||
if nobj.prev:
|
||||
nobj.prev.next = nobj.next
|
||||
else:
|
||||
self.first = nobj.next
|
||||
if nobj.next:
|
||||
nobj.next.prev = nobj.prev
|
||||
else:
|
||||
self.last = nobj.prev
|
||||
del self.d[obj]
|
||||
|
||||
@synchronized()
|
||||
def __iter__(self):
|
||||
cur = self.first
|
||||
while cur is not None:
|
||||
cur2 = cur.next
|
||||
yield cur.me[1]
|
||||
cur = cur2
|
||||
|
||||
@synchronized()
|
||||
def __len__(self):
|
||||
return len(self.d)
|
||||
|
||||
# FIXME: should this have a P2 and a P3 version or something?
|
||||
@synchronized()
|
||||
def iteritems(self):
|
||||
cur = self.first
|
||||
while cur is not None:
|
||||
cur2 = cur.next
|
||||
yield cur.me
|
||||
cur = cur2
|
||||
items = iteritems
|
||||
|
||||
@synchronized()
|
||||
def iterkeys(self):
|
||||
return iter(self.d)
|
||||
|
||||
@synchronized()
|
||||
def itervalues(self):
|
||||
return iter(self.d.values())
|
||||
|
||||
@synchronized()
|
||||
def keys(self):
|
||||
return list(self.d)
|
||||
|
||||
@synchronized()
|
||||
def pop(self,key):
|
||||
v=self[key]
|
||||
del self[key]
|
||||
return v
|
||||
return self.d.pop(key)
|
||||
|
||||
@synchronized()
|
||||
def clear(self):
|
||||
self.d = {}
|
||||
self.first = None
|
||||
self.last = None
|
||||
self.d.clear()
|
||||
|
||||
Reference in New Issue
Block a user