~bzr-pqm/bzr/bzr.dev

3882.3.1 by John Arbash Meinel
Add LRUCache.resize(), and change the init arguments for LRUCache.
1
# Copyright (C) 2006, 2008 Canonical Ltd
2993.1.1 by Robert Collins
* New module ``lru_cache`` providing a cache for use by tasks that need
2
#
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
2993.1.1 by Robert Collins
* New module ``lru_cache`` providing a cache for use by tasks that need
16
17
"""A simple least-recently-used (LRU) cache."""
18
4178.3.7 by John Arbash Meinel
Review tweaks from Ian.
19
from bzrlib import (
20
    symbol_versioning,
21
    trace,
22
    )
2993.1.1 by Robert Collins
* New module ``lru_cache`` providing a cache for use by tasks that need
23
4287.1.10 by John Arbash Meinel
Restore the ability to handle None as a key.
24
_null_key = object()
2993.1.1 by Robert Collins
* New module ``lru_cache`` providing a cache for use by tasks that need
25
4178.3.3 by John Arbash Meinel
LRUCache is now implemented with a dict to a linked list,
26
class _LRUNode(object):
27
    """This maintains the linked-list which is the lru internals."""
28
4287.1.5 by John Arbash Meinel
Switch to using prev as the object and next_key as the pointer.
29
    __slots__ = ('prev', 'next_key', 'key', 'value', 'cleanup', 'size')
4178.3.3 by John Arbash Meinel
LRUCache is now implemented with a dict to a linked list,
30
31
    def __init__(self, key, value, cleanup=None):
4287.1.5 by John Arbash Meinel
Switch to using prev as the object and next_key as the pointer.
32
        self.prev = None
4287.1.10 by John Arbash Meinel
Restore the ability to handle None as a key.
33
        self.next_key = _null_key
4178.3.3 by John Arbash Meinel
LRUCache is now implemented with a dict to a linked list,
34
        self.key = key
35
        self.value = value
36
        self.cleanup = cleanup
37
        # TODO: We could compute this 'on-the-fly' like we used to, and remove
38
        #       one pointer from this object, we just need to decide if it
39
        #       actually costs us much of anything in normal usage
40
        self.size = None
41
42
    def __repr__(self):
4287.1.5 by John Arbash Meinel
Switch to using prev as the object and next_key as the pointer.
43
        if self.prev is None:
44
            prev_key = None
4287.1.4 by John Arbash Meinel
use indirection on both next and prev.
45
        else:
4287.1.11 by John Arbash Meinel
Small tweaks from Ian.
46
            prev_key = self.prev.key
4178.3.3 by John Arbash Meinel
LRUCache is now implemented with a dict to a linked list,
47
        return '%s(%r n:%r p:%r)' % (self.__class__.__name__, self.key,
4287.1.5 by John Arbash Meinel
Switch to using prev as the object and next_key as the pointer.
48
                                     self.next_key, prev_key)
4178.3.3 by John Arbash Meinel
LRUCache is now implemented with a dict to a linked list,
49
50
    def run_cleanup(self):
51
        if self.cleanup is not None:
52
            self.cleanup(self.key, self.value)
53
        self.cleanup = None
54
        # Just make sure to break any refcycles, etc
55
        self.value = None
56
57
2993.1.1 by Robert Collins
* New module ``lru_cache`` providing a cache for use by tasks that need
58
class LRUCache(object):
59
    """A class which manages a cache of entries, removing unused ones."""
60
3882.3.1 by John Arbash Meinel
Add LRUCache.resize(), and change the init arguments for LRUCache.
61
    def __init__(self, max_cache=100, after_cleanup_count=None,
62
                 after_cleanup_size=symbol_versioning.DEPRECATED_PARAMETER):
63
        if symbol_versioning.deprecated_passed(after_cleanup_size):
64
            symbol_versioning.warn('LRUCache.__init__(after_cleanup_size) was'
65
                                   ' deprecated in 1.11. Use'
66
                                   ' after_cleanup_count instead.',
67
                                   DeprecationWarning)
68
            after_cleanup_count = after_cleanup_size
2993.1.1 by Robert Collins
* New module ``lru_cache`` providing a cache for use by tasks that need
69
        self._cache = {}
4178.3.3 by John Arbash Meinel
LRUCache is now implemented with a dict to a linked list,
70
        # The "HEAD" of the lru linked list
71
        self._most_recently_used = None
72
        # The "TAIL" of the lru linked list
4287.1.11 by John Arbash Meinel
Small tweaks from Ian.
73
        self._least_recently_used = None
3882.3.1 by John Arbash Meinel
Add LRUCache.resize(), and change the init arguments for LRUCache.
74
        self._update_max_cache(max_cache, after_cleanup_count)
2993.1.1 by Robert Collins
* New module ``lru_cache`` providing a cache for use by tasks that need
75
76
    def __contains__(self, key):
77
        return key in self._cache
78
79
    def __getitem__(self, key):
4287.1.6 by John Arbash Meinel
Remove the double getattr() for self._cache.
80
        cache = self._cache
81
        node = cache[key]
4178.3.4 by John Arbash Meinel
Shave off approx 100ms by inlining _record_access into __getitem__,
82
        # Inlined from _record_access to decrease the overhead of __getitem__
83
        # We also have more knowledge about structure if __getitem__ is
84
        # succeeding, then we know that self._most_recently_used must not be
85
        # None, etc.
86
        mru = self._most_recently_used
87
        if node is mru:
88
            # Nothing to do, this node is already at the head of the queue
89
            return node.value
90
        # Remove this node from the old location
4287.1.5 by John Arbash Meinel
Switch to using prev as the object and next_key as the pointer.
91
        node_prev = node.prev
4287.1.4 by John Arbash Meinel
use indirection on both next and prev.
92
        next_key = node.next_key
4287.1.10 by John Arbash Meinel
Restore the ability to handle None as a key.
93
        # benchmarking shows that the lookup of _null_key in globals is faster
4287.1.11 by John Arbash Meinel
Small tweaks from Ian.
94
        # than the attribute lookup for (node is self._least_recently_used)
4287.1.10 by John Arbash Meinel
Restore the ability to handle None as a key.
95
        if next_key is _null_key:
4287.1.11 by John Arbash Meinel
Small tweaks from Ian.
96
            # 'node' is the _least_recently_used, because it doesn't have a
4287.1.7 by John Arbash Meinel
Fairly significant savings... avoid looking at self._last_recently_used.
97
            # 'next' item. So move the current lru to the previous node.
4287.1.11 by John Arbash Meinel
Small tweaks from Ian.
98
            self._least_recently_used = node_prev
4287.1.4 by John Arbash Meinel
use indirection on both next and prev.
99
        else:
4287.1.6 by John Arbash Meinel
Remove the double getattr() for self._cache.
100
            node_next = cache[next_key]
4287.1.5 by John Arbash Meinel
Switch to using prev as the object and next_key as the pointer.
101
            node_next.prev = node_prev
4287.1.7 by John Arbash Meinel
Fairly significant savings... avoid looking at self._last_recently_used.
102
        node_prev.next_key = next_key
4287.1.4 by John Arbash Meinel
use indirection on both next and prev.
103
        # Insert this node at the front of the list
104
        node.next_key = mru.key
4287.1.5 by John Arbash Meinel
Switch to using prev as the object and next_key as the pointer.
105
        mru.prev = node
4178.3.4 by John Arbash Meinel
Shave off approx 100ms by inlining _record_access into __getitem__,
106
        self._most_recently_used = node
4287.1.5 by John Arbash Meinel
Switch to using prev as the object and next_key as the pointer.
107
        node.prev = None
4178.3.3 by John Arbash Meinel
LRUCache is now implemented with a dict to a linked list,
108
        return node.value
2993.1.1 by Robert Collins
* New module ``lru_cache`` providing a cache for use by tasks that need
109
110
    def __len__(self):
111
        return len(self._cache)
112
4178.3.3 by John Arbash Meinel
LRUCache is now implemented with a dict to a linked list,
113
    def _walk_lru(self):
4178.3.6 by John Arbash Meinel
Remove the asserts, and change some to AssertionError.
114
        """Walk the LRU list, only meant to be used in tests."""
4178.3.3 by John Arbash Meinel
LRUCache is now implemented with a dict to a linked list,
115
        node = self._most_recently_used
116
        if node is not None:
4287.1.5 by John Arbash Meinel
Switch to using prev as the object and next_key as the pointer.
117
            if node.prev is not None:
4178.3.6 by John Arbash Meinel
Remove the asserts, and change some to AssertionError.
118
                raise AssertionError('the _most_recently_used entry is not'
119
                                     ' supposed to have a previous entry'
120
                                     ' %s' % (node,))
4178.3.3 by John Arbash Meinel
LRUCache is now implemented with a dict to a linked list,
121
        while node is not None:
4287.1.10 by John Arbash Meinel
Restore the ability to handle None as a key.
122
            if node.next_key is _null_key:
4287.1.11 by John Arbash Meinel
Small tweaks from Ian.
123
                if node is not self._least_recently_used:
4178.3.6 by John Arbash Meinel
Remove the asserts, and change some to AssertionError.
124
                    raise AssertionError('only the last node should have'
125
                                         ' no next value: %s' % (node,))
4287.1.4 by John Arbash Meinel
use indirection on both next and prev.
126
                node_next = None
4178.3.3 by John Arbash Meinel
LRUCache is now implemented with a dict to a linked list,
127
            else:
4287.1.4 by John Arbash Meinel
use indirection on both next and prev.
128
                node_next = self._cache[node.next_key]
4287.1.5 by John Arbash Meinel
Switch to using prev as the object and next_key as the pointer.
129
                if node_next.prev is not node:
4178.3.6 by John Arbash Meinel
Remove the asserts, and change some to AssertionError.
130
                    raise AssertionError('inconsistency found, node.next.prev'
131
                                         ' != node: %s' % (node,))
4287.1.5 by John Arbash Meinel
Switch to using prev as the object and next_key as the pointer.
132
            if node.prev is None:
4178.3.6 by John Arbash Meinel
Remove the asserts, and change some to AssertionError.
133
                if node is not self._most_recently_used:
134
                    raise AssertionError('only the _most_recently_used should'
135
                                         ' not have a previous node: %s'
136
                                         % (node,))
4178.3.3 by John Arbash Meinel
LRUCache is now implemented with a dict to a linked list,
137
            else:
4287.1.5 by John Arbash Meinel
Switch to using prev as the object and next_key as the pointer.
138
                if node.prev.next_key != node.key:
4178.3.6 by John Arbash Meinel
Remove the asserts, and change some to AssertionError.
139
                    raise AssertionError('inconsistency found, node.prev.next'
140
                                         ' != node: %s' % (node,))
4178.3.3 by John Arbash Meinel
LRUCache is now implemented with a dict to a linked list,
141
            yield node
4287.1.4 by John Arbash Meinel
use indirection on both next and prev.
142
            node = node_next
4178.3.3 by John Arbash Meinel
LRUCache is now implemented with a dict to a linked list,
143
2993.1.1 by Robert Collins
* New module ``lru_cache`` providing a cache for use by tasks that need
144
    def add(self, key, value, cleanup=None):
145
        """Add a new value to the cache.
146
4178.3.7 by John Arbash Meinel
Review tweaks from Ian.
147
        Also, if the entry is ever removed from the cache, call
148
        cleanup(key, value).
2993.1.1 by Robert Collins
* New module ``lru_cache`` providing a cache for use by tasks that need
149
150
        :param key: The key to store it under
151
        :param value: The object to store
152
        :param cleanup: None or a function taking (key, value) to indicate
4178.3.7 by John Arbash Meinel
Review tweaks from Ian.
153
                        'value' should be cleaned up.
2993.1.1 by Robert Collins
* New module ``lru_cache`` providing a cache for use by tasks that need
154
        """
4287.1.10 by John Arbash Meinel
Restore the ability to handle None as a key.
155
        if key is _null_key:
156
            raise ValueError('cannot use _null_key as a key')
2993.1.1 by Robert Collins
* New module ``lru_cache`` providing a cache for use by tasks that need
157
        if key in self._cache:
4178.3.3 by John Arbash Meinel
LRUCache is now implemented with a dict to a linked list,
158
            node = self._cache[key]
159
            node.run_cleanup()
160
            node.value = value
161
            node.cleanup = cleanup
162
        else:
163
            node = _LRUNode(key, value, cleanup=cleanup)
164
            self._cache[key] = node
165
        self._record_access(node)
2993.1.1 by Robert Collins
* New module ``lru_cache`` providing a cache for use by tasks that need
166
167
        if len(self._cache) > self._max_cache:
168
            # Trigger the cleanup
169
            self.cleanup()
170
4178.3.1 by John Arbash Meinel
Implement LRUCache.cache_size(), so that it can trivially substitute for FIFOCache.
171
    def cache_size(self):
172
        """Get the number of entries we will cache."""
173
        return self._max_cache
174
2998.2.1 by John Arbash Meinel
Implement LRUCache.get() which acts like dict.get()
175
    def get(self, key, default=None):
4178.3.3 by John Arbash Meinel
LRUCache is now implemented with a dict to a linked list,
176
        node = self._cache.get(key, None)
177
        if node is None:
178
            return default
4178.3.5 by John Arbash Meinel
Add tests that LRUCache.get() properly tracks accesses.
179
        self._record_access(node)
4178.3.3 by John Arbash Meinel
LRUCache is now implemented with a dict to a linked list,
180
        return node.value
2998.2.1 by John Arbash Meinel
Implement LRUCache.get() which acts like dict.get()
181
3763.8.10 by John Arbash Meinel
Add a .keys() member to LRUCache and LRUSizeCache.
182
    def keys(self):
183
        """Get the list of keys currently cached.
184
185
        Note that values returned here may not be available by the time you
186
        request them later. This is simply meant as a peak into the current
187
        state.
188
189
        :return: An unordered list of keys that are currently cached.
190
        """
191
        return self._cache.keys()
192
4178.3.3 by John Arbash Meinel
LRUCache is now implemented with a dict to a linked list,
193
    def items(self):
194
        """Get the key:value pairs as a dict."""
195
        return dict((k, n.value) for k, n in self._cache.iteritems())
196
2993.1.1 by Robert Collins
* New module ``lru_cache`` providing a cache for use by tasks that need
197
    def cleanup(self):
198
        """Clear the cache until it shrinks to the requested size.
199
200
        This does not completely wipe the cache, just makes sure it is under
3882.3.1 by John Arbash Meinel
Add LRUCache.resize(), and change the init arguments for LRUCache.
201
        the after_cleanup_count.
2993.1.1 by Robert Collins
* New module ``lru_cache`` providing a cache for use by tasks that need
202
        """
203
        # Make sure the cache is shrunk to the correct size
3882.3.1 by John Arbash Meinel
Add LRUCache.resize(), and change the init arguments for LRUCache.
204
        while len(self._cache) > self._after_cleanup_count:
2993.1.1 by Robert Collins
* New module ``lru_cache`` providing a cache for use by tasks that need
205
            self._remove_lru()
206
207
    def __setitem__(self, key, value):
208
        """Add a value to the cache, there will be no cleanup function."""
209
        self.add(key, value, cleanup=None)
210
4178.3.3 by John Arbash Meinel
LRUCache is now implemented with a dict to a linked list,
211
    def _record_access(self, node):
2993.1.1 by Robert Collins
* New module ``lru_cache`` providing a cache for use by tasks that need
212
        """Record that key was accessed."""
4178.3.3 by John Arbash Meinel
LRUCache is now implemented with a dict to a linked list,
213
        # Move 'node' to the front of the queue
214
        if self._most_recently_used is None:
215
            self._most_recently_used = node
4287.1.11 by John Arbash Meinel
Small tweaks from Ian.
216
            self._least_recently_used = node
4178.3.3 by John Arbash Meinel
LRUCache is now implemented with a dict to a linked list,
217
            return
218
        elif node is self._most_recently_used:
219
            # Nothing to do, this node is already at the head of the queue
220
            return
221
        # We've taken care of the tail pointer, remove the node, and insert it
222
        # at the front
223
        # REMOVE
4287.1.11 by John Arbash Meinel
Small tweaks from Ian.
224
        if node is self._least_recently_used:
225
            self._least_recently_used = node.prev
4287.1.5 by John Arbash Meinel
Switch to using prev as the object and next_key as the pointer.
226
        if node.prev is not None:
227
            node.prev.next_key = node.next_key
4287.1.10 by John Arbash Meinel
Restore the ability to handle None as a key.
228
        if node.next_key is not _null_key:
4287.1.4 by John Arbash Meinel
use indirection on both next and prev.
229
            node_next = self._cache[node.next_key]
4287.1.5 by John Arbash Meinel
Switch to using prev as the object and next_key as the pointer.
230
            node_next.prev = node.prev
4178.3.3 by John Arbash Meinel
LRUCache is now implemented with a dict to a linked list,
231
        # INSERT
4287.1.4 by John Arbash Meinel
use indirection on both next and prev.
232
        node.next_key = self._most_recently_used.key
4287.1.5 by John Arbash Meinel
Switch to using prev as the object and next_key as the pointer.
233
        self._most_recently_used.prev = node
4178.3.3 by John Arbash Meinel
LRUCache is now implemented with a dict to a linked list,
234
        self._most_recently_used = node
4287.1.5 by John Arbash Meinel
Switch to using prev as the object and next_key as the pointer.
235
        node.prev = None
4178.3.3 by John Arbash Meinel
LRUCache is now implemented with a dict to a linked list,
236
237
    def _remove_node(self, node):
4287.1.11 by John Arbash Meinel
Small tweaks from Ian.
238
        if node is self._least_recently_used:
239
            self._least_recently_used = node.prev
4178.3.6 by John Arbash Meinel
Remove the asserts, and change some to AssertionError.
240
        self._cache.pop(node.key)
4178.3.3 by John Arbash Meinel
LRUCache is now implemented with a dict to a linked list,
241
        # If we have removed all entries, remove the head pointer as well
4287.1.11 by John Arbash Meinel
Small tweaks from Ian.
242
        if self._least_recently_used is None:
4178.3.3 by John Arbash Meinel
LRUCache is now implemented with a dict to a linked list,
243
            self._most_recently_used = None
244
        node.run_cleanup()
4287.1.2 by John Arbash Meinel
Properly remove the nodes from the internal linked list in _remove_node.
245
        # Now remove this node from the linked list
4294.1.1 by John Arbash Meinel
When removing a node from an LRUCache, properly remove it from the linked list.
246
        if node.prev is not None:
4287.1.5 by John Arbash Meinel
Switch to using prev as the object and next_key as the pointer.
247
            node.prev.next_key = node.next_key
4287.1.10 by John Arbash Meinel
Restore the ability to handle None as a key.
248
        if node.next_key is not _null_key:
4287.1.4 by John Arbash Meinel
use indirection on both next and prev.
249
            node_next = self._cache[node.next_key]
4287.1.5 by John Arbash Meinel
Switch to using prev as the object and next_key as the pointer.
250
            node_next.prev = node.prev
4287.1.2 by John Arbash Meinel
Properly remove the nodes from the internal linked list in _remove_node.
251
        # And remove this node's pointers
4294.1.1 by John Arbash Meinel
When removing a node from an LRUCache, properly remove it from the linked list.
252
        node.prev = None
4287.1.10 by John Arbash Meinel
Restore the ability to handle None as a key.
253
        node.next_key = _null_key
2993.1.1 by Robert Collins
* New module ``lru_cache`` providing a cache for use by tasks that need
254
255
    def _remove_lru(self):
256
        """Remove one entry from the lru, and handle consequences.
257
258
        If there are no more references to the lru, then this entry should be
259
        removed from the cache.
260
        """
4287.1.11 by John Arbash Meinel
Small tweaks from Ian.
261
        self._remove_node(self._least_recently_used)
2993.1.1 by Robert Collins
* New module ``lru_cache`` providing a cache for use by tasks that need
262
263
    def clear(self):
264
        """Clear out all of the cache."""
265
        # Clean up in LRU order
3735.34.3 by John Arbash Meinel
Cleanup, in preparation for merging to brisbane-core.
266
        while self._cache:
267
            self._remove_lru()
2993.1.1 by Robert Collins
* New module ``lru_cache`` providing a cache for use by tasks that need
268
3882.3.1 by John Arbash Meinel
Add LRUCache.resize(), and change the init arguments for LRUCache.
269
    def resize(self, max_cache, after_cleanup_count=None):
270
        """Change the number of entries that will be cached."""
271
        self._update_max_cache(max_cache,
272
                               after_cleanup_count=after_cleanup_count)
273
274
    def _update_max_cache(self, max_cache, after_cleanup_count=None):
275
        self._max_cache = max_cache
276
        if after_cleanup_count is None:
277
            self._after_cleanup_count = self._max_cache * 8 / 10
278
        else:
4178.3.3 by John Arbash Meinel
LRUCache is now implemented with a dict to a linked list,
279
            self._after_cleanup_count = min(after_cleanup_count,
280
                                            self._max_cache)
3882.3.1 by John Arbash Meinel
Add LRUCache.resize(), and change the init arguments for LRUCache.
281
        self.cleanup()
282
2993.1.1 by Robert Collins
* New module ``lru_cache`` providing a cache for use by tasks that need
283
284
class LRUSizeCache(LRUCache):
285
    """An LRUCache that removes things based on the size of the values.
286
287
    This differs in that it doesn't care how many actual items there are,
288
    it just restricts the cache to be cleaned up after so much data is stored.
289
4178.3.7 by John Arbash Meinel
Review tweaks from Ian.
290
    The size of items added will be computed using compute_size(value), which
291
    defaults to len() if not supplied.
2993.1.1 by Robert Collins
* New module ``lru_cache`` providing a cache for use by tasks that need
292
    """
293
294
    def __init__(self, max_size=1024*1024, after_cleanup_size=None,
295
                 compute_size=None):
296
        """Create a new LRUSizeCache.
297
298
        :param max_size: The max number of bytes to store before we start
299
            clearing out entries.
300
        :param after_cleanup_size: After cleaning up, shrink everything to this
301
            size.
302
        :param compute_size: A function to compute the size of the values. We
303
            use a function here, so that you can pass 'len' if you are just
304
            using simple strings, or a more complex function if you are using
305
            something like a list of strings, or even a custom object.
306
            The function should take the form "compute_size(value) => integer".
307
            If not supplied, it defaults to 'len()'
308
        """
309
        self._value_size = 0
310
        self._compute_size = compute_size
311
        if compute_size is None:
312
            self._compute_size = len
3882.3.1 by John Arbash Meinel
Add LRUCache.resize(), and change the init arguments for LRUCache.
313
        self._update_max_size(max_size, after_cleanup_size=after_cleanup_size)
314
        LRUCache.__init__(self, max_cache=max(int(max_size/512), 1))
2993.1.1 by Robert Collins
* New module ``lru_cache`` providing a cache for use by tasks that need
315
316
    def add(self, key, value, cleanup=None):
317
        """Add a new value to the cache.
318
4178.3.7 by John Arbash Meinel
Review tweaks from Ian.
319
        Also, if the entry is ever removed from the cache, call
320
        cleanup(key, value).
2993.1.1 by Robert Collins
* New module ``lru_cache`` providing a cache for use by tasks that need
321
322
        :param key: The key to store it under
323
        :param value: The object to store
324
        :param cleanup: None or a function taking (key, value) to indicate
4178.3.7 by John Arbash Meinel
Review tweaks from Ian.
325
                        'value' should be cleaned up.
2993.1.1 by Robert Collins
* New module ``lru_cache`` providing a cache for use by tasks that need
326
        """
4287.1.10 by John Arbash Meinel
Restore the ability to handle None as a key.
327
        if key is _null_key:
328
            raise ValueError('cannot use _null_key as a key')
4178.3.3 by John Arbash Meinel
LRUCache is now implemented with a dict to a linked list,
329
        node = self._cache.get(key, None)
2993.1.1 by Robert Collins
* New module ``lru_cache`` providing a cache for use by tasks that need
330
        value_len = self._compute_size(value)
331
        if value_len >= self._after_cleanup_size:
4178.3.7 by John Arbash Meinel
Review tweaks from Ian.
332
            # The new value is 'too big to fit', as it would fill up/overflow
333
            # the cache all by itself
334
            trace.mutter('Adding the key %r to an LRUSizeCache failed.'
335
                         ' value %d is too big to fit in a the cache'
336
                         ' with size %d %d', key, value_len,
337
                         self._after_cleanup_size, self._max_size)
4178.3.3 by John Arbash Meinel
LRUCache is now implemented with a dict to a linked list,
338
            if node is not None:
4178.3.7 by John Arbash Meinel
Review tweaks from Ian.
339
                # We won't be replacing the old node, so just remove it
4178.3.3 by John Arbash Meinel
LRUCache is now implemented with a dict to a linked list,
340
                self._remove_node(node)
4178.3.7 by John Arbash Meinel
Review tweaks from Ian.
341
            if cleanup is not None:
342
                cleanup(key, value)
2993.1.1 by Robert Collins
* New module ``lru_cache`` providing a cache for use by tasks that need
343
            return
4178.3.3 by John Arbash Meinel
LRUCache is now implemented with a dict to a linked list,
344
        if node is None:
345
            node = _LRUNode(key, value, cleanup=cleanup)
346
            self._cache[key] = node
347
        else:
348
            self._value_size -= node.size
349
        node.size = value_len
2993.1.1 by Robert Collins
* New module ``lru_cache`` providing a cache for use by tasks that need
350
        self._value_size += value_len
4178.3.3 by John Arbash Meinel
LRUCache is now implemented with a dict to a linked list,
351
        self._record_access(node)
2993.1.1 by Robert Collins
* New module ``lru_cache`` providing a cache for use by tasks that need
352
353
        if self._value_size > self._max_size:
354
            # Time to cleanup
355
            self.cleanup()
356
357
    def cleanup(self):
358
        """Clear the cache until it shrinks to the requested size.
359
360
        This does not completely wipe the cache, just makes sure it is under
361
        the after_cleanup_size.
362
        """
363
        # Make sure the cache is shrunk to the correct size
364
        while self._value_size > self._after_cleanup_size:
365
            self._remove_lru()
366
4178.3.3 by John Arbash Meinel
LRUCache is now implemented with a dict to a linked list,
367
    def _remove_node(self, node):
368
        self._value_size -= node.size
369
        LRUCache._remove_node(self, node)
3882.3.1 by John Arbash Meinel
Add LRUCache.resize(), and change the init arguments for LRUCache.
370
371
    def resize(self, max_size, after_cleanup_size=None):
372
        """Change the number of bytes that will be cached."""
373
        self._update_max_size(max_size, after_cleanup_size=after_cleanup_size)
374
        max_cache = max(int(max_size/512), 1)
375
        self._update_max_cache(max_cache)
376
377
    def _update_max_size(self, max_size, after_cleanup_size=None):
378
        self._max_size = max_size
379
        if after_cleanup_size is None:
380
            self._after_cleanup_size = self._max_size * 8 / 10
381
        else:
382
            self._after_cleanup_size = min(after_cleanup_size, self._max_size)