26
26
class _LRUNode(object):
27
27
"""This maintains the linked-list which is the lru internals."""
29
__slots__ = ('prev', 'next_key', 'key', 'value', 'cleanup')
29
__slots__ = ('prev', 'next_key', 'key', 'value')
31
def __init__(self, key, value, cleanup=None):
31
def __init__(self, key, value):
33
33
self.next_key = _null_key
36
self.cleanup = cleanup
38
37
def __repr__(self):
39
38
if self.prev is None:
43
42
return '%s(%r n:%r p:%r)' % (self.__class__.__name__, self.key,
44
43
self.next_key, prev_key)
46
def run_cleanup(self):
48
if self.cleanup is not None:
49
self.cleanup(self.key, self.value)
51
# cleanup might raise an exception, but we want to make sure
52
# to break refcycles, etc
57
46
class LRUCache(object):
58
47
"""A class which manages a cache of entries, removing unused ones."""
102
91
def __len__(self):
103
92
return len(self._cache)
94
@symbol_versioning.deprecated_method(
95
symbol_versioning.deprecated_in((2, 5, 0)))
105
96
def add(self, key, value, cleanup=None):
106
"""Add a new value to the cache.
108
Also, if the entry is ever removed from the cache, call
111
:param key: The key to store it under
112
:param value: The object to store
113
:param cleanup: None or a function taking (key, value) to indicate
114
'value' should be cleaned up.
97
if cleanup is not None:
98
raise ValueError("Per-node cleanup functions no longer supported")
99
return self.__setitem__(key, value)
101
def __setitem__(self, key, value):
102
"""Add a new value to the cache"""
116
103
if key is _null_key:
117
104
raise ValueError('cannot use _null_key as a key')
118
105
if key in self._cache:
119
106
node = self._cache[key]
123
# Maintain the LRU properties, even if cleanup raises an
126
node.cleanup = cleanup
127
self._record_access(node)
108
self._record_access(node)
129
node = _LRUNode(key, value, cleanup=cleanup)
110
node = _LRUNode(key, value)
130
111
self._cache[key] = node
131
112
self._record_access(node)
173
154
while len(self._cache) > self._after_cleanup_count:
174
155
self._remove_lru()
176
def __setitem__(self, key, value):
177
"""Add a value to the cache, there will be no cleanup function."""
178
self.add(key, value, cleanup=None)
180
157
def _record_access(self, node):
181
158
"""Record that key was accessed."""
182
159
# Move 'node' to the front of the queue
210
187
# If we have removed all entries, remove the head pointer as well
211
188
if self._least_recently_used is None:
212
189
self._most_recently_used = None
216
# cleanup might raise an exception, but we want to make sure to
217
# maintain the linked list
218
if node.prev is not None:
219
node.prev.next_key = node.next_key
220
if node.next_key is not _null_key:
221
node_next = self._cache[node.next_key]
222
node_next.prev = node.prev
223
# And remove this node's pointers
225
node.next_key = _null_key
190
if node.prev is not None:
191
node.prev.next_key = node.next_key
192
if node.next_key is not _null_key:
193
node_next = self._cache[node.next_key]
194
node_next.prev = node.prev
195
# And remove this node's pointers
197
node.next_key = _null_key
227
199
def _remove_lru(self):
228
200
"""Remove one entry from the lru, and handle consequences.
285
257
self._update_max_size(max_size, after_cleanup_size=after_cleanup_size)
286
258
LRUCache.__init__(self, max_cache=max(int(max_size/512), 1))
288
def add(self, key, value, cleanup=None):
289
"""Add a new value to the cache.
291
Also, if the entry is ever removed from the cache, call
294
:param key: The key to store it under
295
:param value: The object to store
296
:param cleanup: None or a function taking (key, value) to indicate
297
'value' should be cleaned up.
260
def __setitem__(self, key, value):
261
"""Add a new value to the cache"""
299
262
if key is _null_key:
300
263
raise ValueError('cannot use _null_key as a key')
301
264
node = self._cache.get(key, None)
310
273
if node is not None:
311
274
# We won't be replacing the old node, so just remove it
312
275
self._remove_node(node)
313
if cleanup is not None:
317
node = _LRUNode(key, value, cleanup=cleanup)
278
node = _LRUNode(key, value)
318
279
self._cache[key] = node
320
281
self._value_size -= self._compute_size(node.value)