[MERGE] Better LRUCache implementation
Ian Clatworthy
ian.clatworthy at internode.on.net
Tue Mar 24 05:23:39 GMT 2009
John Arbash Meinel wrote:
> I realized that my submission still has some "assert" statement, which
> I'll certainly clean out before I submit.
Please. There's also an "import pdb; ..." in _remove_node which needs to go.
I'd be tempted to remove the asserts altogether in _record_access as that
code path ought to be hit often, but I'll let you make the call on that.
bb:tweak
Some other tweaks ...
> def add(self, key, value, cleanup=None):
> """Add a new value to the cache.
>
> @@ -61,20 +137,29 @@
> 'value' sohuld be cleaned up.
> """
The docstrings for the add methods needs some tweaks:
1. "..., call cleanup, passing it the key and value ..."
2. s/sohuld/should/
3. It refers to the "queue" when "cache" would be better?
The docstring for LRUSizeCache() also needs a tweak: it says that
the values must support len() when in fact the compute_size parameter
can be used instead.
> - # This approximates that texts are > 0.5k in size. It only really
> - # effects when we clean up the queue, so we don't want it to be too
> - # large.
> self._update_max_size(max_size, after_cleanup_size=after_cleanup_size)
> LRUCache.__init__(self, max_cache=max(int(max_size/512), 1))
This int(max_size/512) magic appears twice in the code and it's a complete
mystery to me. I gather that comment was trying to explain it in one of
those places. For the sake of code clarity, I'd appreciate it if that magic
was moved into a method that explained the basis for the heuristic.
> value_len = self._compute_size(value)
> if value_len >= self._after_cleanup_size:
> + if node is not None:
> + # The new value is too large, we won't be replacing the value,
> + # just removing the node completely
> + self._remove_node(node)
> return
Hmm. I was uncomfortable about this at first but I think your logic here
is sound. I wonder if it's worthy of a mutter() so we get a clue that the
cache size needs consideration/tuning?
> - self.assertEqual([1, 2, 3, 4, 5, 2, 5, 3, 2], list(cache._queue))
> - self.assertEqual({1:1, 2:3, 3:2, 4:1, 5:2}, cache._refcount)
> -
> - # Compacting should save the last position
> - cache._compact_queue()
> - self.assertEqual([1, 4, 5, 3, 2], list(cache._queue))
> - self.assertEqual({1:1, 2:1, 3:1, 4:1, 5:1}, cache._refcount)
> + self.assertEqual([2, 3, 5, 4, 1], [n.key for n in cache._walk_lru()])
>
I'm happy with your changes to the tests but test_compact_preserves_last_access_order()
needs renaming if the test is no longer testing that. :-)
Otherwise, well done on this.
Ian C.
More information about the bazaar
mailing list