| OLD | NEW |
| (Empty) |
| 1 # urllib3/_collections.py | |
| 2 # Copyright 2008-2013 Andrey Petrov and contributors (see CONTRIBUTORS.txt) | |
| 3 # | |
| 4 # This module is part of urllib3 and is released under | |
| 5 # the MIT License: http://www.opensource.org/licenses/mit-license.php | |
| 6 | |
| 7 from collections import MutableMapping | |
| 8 from threading import RLock | |
| 9 | |
| 10 try: # Python 2.7+ | |
| 11 from collections import OrderedDict | |
| 12 except ImportError: | |
| 13 from .packages.ordered_dict import OrderedDict | |
| 14 | |
| 15 | |
| 16 __all__ = ['RecentlyUsedContainer'] | |
| 17 | |
| 18 | |
| 19 _Null = object() | |
| 20 | |
| 21 | |
| 22 class RecentlyUsedContainer(MutableMapping): | |
| 23 """ | |
| 24 Provides a thread-safe dict-like container which maintains up to | |
| 25 ``maxsize`` keys while throwing away the least-recently-used keys beyond | |
| 26 ``maxsize``. | |
| 27 | |
| 28 :param maxsize: | |
| 29 Maximum number of recent elements to retain. | |
| 30 | |
| 31 :param dispose_func: | |
| 32 Every time an item is evicted from the container, | |
| 33 ``dispose_func(value)`` is called. Callback which will get called | |
| 34 """ | |
| 35 | |
| 36 ContainerCls = OrderedDict | |
| 37 | |
| 38 def __init__(self, maxsize=10, dispose_func=None): | |
| 39 self._maxsize = maxsize | |
| 40 self.dispose_func = dispose_func | |
| 41 | |
| 42 self._container = self.ContainerCls() | |
| 43 self.lock = RLock() | |
| 44 | |
| 45 def __getitem__(self, key): | |
| 46 # Re-insert the item, moving it to the end of the eviction line. | |
| 47 with self.lock: | |
| 48 item = self._container.pop(key) | |
| 49 self._container[key] = item | |
| 50 return item | |
| 51 | |
| 52 def __setitem__(self, key, value): | |
| 53 evicted_value = _Null | |
| 54 with self.lock: | |
| 55 # Possibly evict the existing value of 'key' | |
| 56 evicted_value = self._container.get(key, _Null) | |
| 57 self._container[key] = value | |
| 58 | |
| 59 # If we didn't evict an existing value, we might have to evict the | |
| 60 # least recently used item from the beginning of the container. | |
| 61 if len(self._container) > self._maxsize: | |
| 62 _key, evicted_value = self._container.popitem(last=False) | |
| 63 | |
| 64 if self.dispose_func and evicted_value is not _Null: | |
| 65 self.dispose_func(evicted_value) | |
| 66 | |
| 67 def __delitem__(self, key): | |
| 68 with self.lock: | |
| 69 value = self._container.pop(key) | |
| 70 | |
| 71 if self.dispose_func: | |
| 72 self.dispose_func(value) | |
| 73 | |
| 74 def __len__(self): | |
| 75 with self.lock: | |
| 76 return len(self._container) | |
| 77 | |
| 78 def __iter__(self): | |
| 79 raise NotImplementedError('Iteration over this class is unlikely to be t
hreadsafe.') | |
| 80 | |
| 81 def clear(self): | |
| 82 with self.lock: | |
| 83 # Copy pointers to all values, then wipe the mapping | |
| 84 # under Python 2, this copies the list of values twice :-| | |
| 85 values = list(self._container.values()) | |
| 86 self._container.clear() | |
| 87 | |
| 88 if self.dispose_func: | |
| 89 for value in values: | |
| 90 self.dispose_func(value) | |
| 91 | |
| 92 def keys(self): | |
| 93 with self.lock: | |
| 94 return self._container.keys() | |
| OLD | NEW |