OLD | NEW |
1 # This file is part of Buildbot. Buildbot is free software: you can | 1 # This file is part of Buildbot. Buildbot is free software: you can |
2 # redistribute it and/or modify it under the terms of the GNU General Public | 2 # redistribute it and/or modify it under the terms of the GNU General Public |
3 # License as published by the Free Software Foundation, version 2. | 3 # License as published by the Free Software Foundation, version 2. |
4 # | 4 # |
5 # This program is distributed in the hope that it will be useful, but WITHOUT | 5 # This program is distributed in the hope that it will be useful, but WITHOUT |
6 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | 6 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
7 # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more | 7 # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more |
8 # details. | 8 # details. |
9 # | 9 # |
10 # You should have received a copy of the GNU General Public License along with | 10 # You should have received a copy of the GNU General Public License along with |
(...skipping 226 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
237 # in the queue | 237 # in the queue |
238 exp_refcount = dict() | 238 exp_refcount = dict() |
239 for k in self.queue: | 239 for k in self.queue: |
240 exp_refcount[k] = exp_refcount.get(k, 0) + 1 | 240 exp_refcount[k] = exp_refcount.get(k, 0) + 1 |
241 if exp_refcount != self.refcount: | 241 if exp_refcount != self.refcount: |
242 log.msg("INV: refcounts differ:") | 242 log.msg("INV: refcounts differ:") |
243 log.msg(" expected:", sorted(exp_refcount.items())) | 243 log.msg(" expected:", sorted(exp_refcount.items())) |
244 log.msg(" got:", sorted(self.refcount.items())) | 244 log.msg(" got:", sorted(self.refcount.items())) |
245 inv_failed = True | 245 inv_failed = True |
246 | 246 |
| 247 |
| 248 class SyncLRUCache(AsyncLRUCache): |
| 249 """ |
| 250 |
| 251 A least-recently-used cache using the same strategy as AsyncLRUCache, |
| 252 minus the protections for concurrent access. The motivation for this |
| 253 class is to provide a speedier implementation for heavily-used caches |
| 254 that don't need the concurrency protections. |
| 255 |
| 256 The constructor takes the same arguments as the AsyncLRUCache |
| 257 constructor, except C{miss_fn} must return the missing value, I{not} a |
| 258 deferred. |
| 259 """ |
| 260 |
| 261 # utility function to record recent use of this key |
| 262 def _ref_key(self, key): |
| 263 refcount = self.refcount |
| 264 queue = self.queue |
| 265 |
| 266 queue.append(key) |
| 267 refcount[key] = refcount[key] + 1 |
| 268 |
| 269 # periodically compact the queue by eliminating duplicate keys |
| 270 # while preserving order of most recent access. Note that this |
| 271 # is only required when the cache does not exceed its maximum |
| 272 # size |
| 273 if len(queue) > self.max_queue: |
| 274 refcount.clear() |
| 275 queue_appendleft = queue.appendleft |
| 276 queue_appendleft(self.sentinel) |
| 277 for k in ifilterfalse(refcount.__contains__, |
| 278 iter(queue.pop, self.sentinel)): |
| 279 queue_appendleft(k) |
| 280 refcount[k] = 1 |
| 281 |
| 282 def get(self, key, **miss_fn_kwargs): |
| 283 """ |
| 284 Fetch a value from the cache by key, invoking C{self.miss_fn(key)} if |
| 285 the key is not in the cache. |
| 286 |
| 287 No protection is provided against concurrent access. |
| 288 |
| 289 @param key: cache key |
| 290 @param **miss_fn_kwargs: keyword arguments to the miss_fn |
| 291 @returns: cache value |
| 292 """ |
| 293 cache = self.cache |
| 294 weakrefs = self.weakrefs |
| 295 |
| 296 try: |
| 297 result = cache[key] |
| 298 self.hits += 1 |
| 299 self._ref_key(key) |
| 300 return result |
| 301 except KeyError: |
| 302 try: |
| 303 result = weakrefs[key] |
| 304 self.refhits += 1 |
| 305 cache[key] = result |
| 306 self._ref_key(key) |
| 307 return result |
| 308 except KeyError: |
| 309 pass |
| 310 |
| 311 # if we're here, we've missed and need to fetch |
| 312 self.misses += 1 |
| 313 |
| 314 result = self.miss_fn(key, **miss_fn_kwargs) |
| 315 if result is not None: |
| 316 cache[key] = result |
| 317 weakrefs[key] = result |
| 318 self._ref_key(key) |
| 319 self._purge() |
| 320 |
| 321 return result |
| 322 |
| 323 |
247 # for tests | 324 # for tests |
248 inv_failed = False | 325 inv_failed = False |
OLD | NEW |