| OLD | NEW |
| (Empty) |
| 1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
| 2 # Use of this source code is governed by a BSD-style license that can be | |
| 3 # found in the LICENSE file. | |
| 4 | |
| 5 import time | |
| 6 | |
| 7 from appengine_wrappers import CACHE_TIMEOUT | |
| 8 from future import Future | |
| 9 from object_store import ObjectStore | |
| 10 | |
| 11 class _CacheEntry(object): | |
| 12 def __init__(self, value, expire_time): | |
| 13 self.value = value | |
| 14 self._never_expires = (expire_time == 0) | |
| 15 self._expiry = time.time() + expire_time | |
| 16 | |
| 17 def HasExpired(self): | |
| 18 if self._never_expires: | |
| 19 return False | |
| 20 return time.time() > self._expiry | |
| 21 | |
| 22 class _AsyncGetFuture(object): | |
| 23 """A future for memcache gets. | |
| 24 | |
| 25 Properties: | |
| 26 - |cache| the in-memory cache used by InMemoryObjectStore | |
| 27 - |time| the cache timeout | |
| 28 - |future| the |Future| from the backing |ObjectStore| | |
| 29 - |initial_mapping| a mapping of cache items already in memory | |
| 30 """ | |
| 31 def __init__(self, cache, time, future, initial_mapping): | |
| 32 self._cache = cache | |
| 33 self._time = time | |
| 34 self._future = future | |
| 35 self._mapping = initial_mapping | |
| 36 | |
| 37 def Get(self): | |
| 38 if self._future is not None: | |
| 39 result = self._future.Get() | |
| 40 self._cache.update( | |
| 41 dict((k, _CacheEntry(v, self._time)) for k, v in result.iteritems())) | |
| 42 self._mapping.update(result) | |
| 43 return self._mapping | |
| 44 | |
| 45 class InMemoryObjectStore(ObjectStore): | |
| 46 def __init__(self, object_store): | |
| 47 self._object_store = object_store | |
| 48 self._cache = {} | |
| 49 | |
| 50 def SetMulti(self, mapping, time=CACHE_TIMEOUT): | |
| 51 for k, v in mapping.iteritems(): | |
| 52 self._cache[k] = _CacheEntry(v, time) | |
| 53 # TODO(cduvall): Use a batch set? App Engine kept throwing: | |
| 54 # ValueError: Values may not be more than 1000000 bytes in length | |
| 55 # for the batch set. | |
| 56 self._object_store.Set(k, v, time=time) | |
| 57 | |
| 58 def GetMulti(self, keys, time=CACHE_TIMEOUT): | |
| 59 keys = keys[:] | |
| 60 mapping = {} | |
| 61 for key in keys: | |
| 62 cache_entry = self._cache.get(key, None) | |
| 63 if cache_entry is None or cache_entry.HasExpired(): | |
| 64 mapping[key] = None | |
| 65 else: | |
| 66 mapping[key] = cache_entry.value | |
| 67 keys.remove(key) | |
| 68 future = self._object_store.GetMulti(keys, time=time) | |
| 69 return Future(delegate=_AsyncGetFuture(self._cache, | |
| 70 time, | |
| 71 future, | |
| 72 mapping)) | |
| 73 | |
| 74 def Delete(self, key): | |
| 75 if key in self._cache: | |
| 76 self._cache.pop(key) | |
| 77 self._object_store.Delete(key) | |
| OLD | NEW |