Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(270)

Side by Side Diff: client/third_party/cachetools/ttl.py

Issue 2953253003: Replace custom blob gRPC API with ByteStream (Closed)
Patch Set: Import ndb directly to test code Created 3 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « client/third_party/cachetools/rr.py ('k') | client/third_party/google/README.swarming » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 from __future__ import absolute_import
2
3 import collections
4 import time
5
6 from .cache import Cache
7
8
9 class _Link(object):
10
11 __slots__ = ('key', 'expire', 'next', 'prev')
12
13 def __init__(self, key=None, expire=None):
14 self.key = key
15 self.expire = expire
16
17 def __reduce__(self):
18 return _Link, (self.key, self.expire)
19
20 def unlink(self):
21 next = self.next
22 prev = self.prev
23 prev.next = next
24 next.prev = prev
25
26
27 class _Timer(object):
28
29 def __init__(self, timer):
30 self.__timer = timer
31 self.__nesting = 0
32
33 def __call__(self):
34 if self.__nesting == 0:
35 return self.__timer()
36 else:
37 return self.__time
38
39 def __enter__(self):
40 if self.__nesting == 0:
41 self.__time = time = self.__timer()
42 else:
43 time = self.__time
44 self.__nesting += 1
45 return time
46
47 def __exit__(self, *exc):
48 self.__nesting -= 1
49
50 def __reduce__(self):
51 return _Timer, (self.__timer,)
52
53 def __getattr__(self, name):
54 return getattr(self.__timer, name)
55
56
57 class TTLCache(Cache):
58 """LRU Cache implementation with per-item time-to-live (TTL) value."""
59
60 def __init__(self, maxsize, ttl, timer=time.time, missing=None,
61 getsizeof=None):
62 Cache.__init__(self, maxsize, missing, getsizeof)
63 self.__root = root = _Link()
64 root.prev = root.next = root
65 self.__links = collections.OrderedDict()
66 self.__timer = _Timer(timer)
67 self.__ttl = ttl
68
69 def __contains__(self, key):
70 try:
71 link = self.__links[key] # no reordering
72 except KeyError:
73 return False
74 else:
75 return not (link.expire < self.__timer())
76
77 def __getitem__(self, key, cache_getitem=Cache.__getitem__):
78 try:
79 link = self.__getlink(key)
80 except KeyError:
81 expired = False
82 else:
83 expired = link.expire < self.__timer()
84 if expired:
85 return self.__missing__(key)
86 else:
87 return cache_getitem(self, key)
88
89 def __setitem__(self, key, value, cache_setitem=Cache.__setitem__):
90 with self.__timer as time:
91 self.expire(time)
92 cache_setitem(self, key, value)
93 try:
94 link = self.__getlink(key)
95 except KeyError:
96 self.__links[key] = link = _Link(key)
97 else:
98 link.unlink()
99 link.expire = time + self.__ttl
100 link.next = root = self.__root
101 link.prev = prev = root.prev
102 prev.next = root.prev = link
103
104 def __delitem__(self, key, cache_delitem=Cache.__delitem__):
105 cache_delitem(self, key)
106 link = self.__links.pop(key)
107 link.unlink()
108 if link.expire < self.__timer():
109 raise KeyError(key)
110
111 def __iter__(self):
112 root = self.__root
113 curr = root.next
114 while curr is not root:
115 # "freeze" time for iterator access
116 with self.__timer as time:
117 if not (curr.expire < time):
118 yield curr.key
119 curr = curr.next
120
121 def __len__(self):
122 root = self.__root
123 curr = root.next
124 time = self.__timer()
125 count = len(self.__links)
126 while curr is not root and curr.expire < time:
127 count -= 1
128 curr = curr.next
129 return count
130
131 def __setstate__(self, state):
132 self.__dict__.update(state)
133 root = self.__root
134 root.prev = root.next = root
135 for link in sorted(self.__links.values(), key=lambda obj: obj.expire):
136 link.next = root
137 link.prev = prev = root.prev
138 prev.next = root.prev = link
139 self.expire(self.__timer())
140
141 def __repr__(self, cache_repr=Cache.__repr__):
142 with self.__timer as time:
143 self.expire(time)
144 return cache_repr(self)
145
146 @property
147 def currsize(self):
148 with self.__timer as time:
149 self.expire(time)
150 return super(TTLCache, self).currsize
151
152 @property
153 def timer(self):
154 """The timer function used by the cache."""
155 return self.__timer
156
157 @property
158 def ttl(self):
159 """The time-to-live value of the cache's items."""
160 return self.__ttl
161
162 def expire(self, time=None):
163 """Remove expired items from the cache."""
164 if time is None:
165 time = self.__timer()
166 root = self.__root
167 curr = root.next
168 links = self.__links
169 cache_delitem = Cache.__delitem__
170 while curr is not root and curr.expire < time:
171 cache_delitem(self, curr.key)
172 del links[curr.key]
173 next = curr.next
174 curr.unlink()
175 curr = next
176
177 def clear(self):
178 with self.__timer as time:
179 self.expire(time)
180 Cache.clear(self)
181
182 def get(self, *args, **kwargs):
183 with self.__timer:
184 return Cache.get(self, *args, **kwargs)
185
186 def pop(self, *args, **kwargs):
187 with self.__timer:
188 return Cache.pop(self, *args, **kwargs)
189
190 def setdefault(self, *args, **kwargs):
191 with self.__timer:
192 return Cache.setdefault(self, *args, **kwargs)
193
194 def popitem(self):
195 """Remove and return the `(key, value)` pair least recently used that
196 has not already expired.
197
198 """
199 with self.__timer as time:
200 self.expire(time)
201 try:
202 key = next(iter(self.__links))
203 except StopIteration:
204 raise KeyError('%s is empty' % self.__class__.__name__)
205 else:
206 return (key, self.pop(key))
207
208 if hasattr(collections.OrderedDict, 'move_to_end'):
209 def __getlink(self, key):
210 value = self.__links[key]
211 self.__links.move_to_end(key)
212 return value
213 else:
214 def __getlink(self, key):
215 value = self.__links.pop(key)
216 self.__links[key] = value
217 return value
OLDNEW
« no previous file with comments | « client/third_party/cachetools/rr.py ('k') | client/third_party/google/README.swarming » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698