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 Lock |
| 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 = Lock() |
| 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 |