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 |