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 future import Future | |
8 from object_store import ObjectStore, CACHE_TIMEOUT | |
9 from memcache_object_store import MemcacheObjectStore | |
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 - |namespace| the namespace of the cache items | |
29 - |future| the |Future| from the backing |ObjectStore| | |
30 - |initial_mapping| a mapping of cache items already in memory | |
31 """ | |
32 def __init__(self, cache, time, namespace, future, initial_mapping): | |
33 self._cache = cache | |
34 self._time = time | |
35 self._namespace = namespace | |
36 self._future = future | |
37 self._mapping = initial_mapping | |
38 | |
39 def Get(self): | |
40 if self._future is not None: | |
41 result = self._future.Get() | |
42 self._cache[self._namespace].update( | |
43 dict((k, _CacheEntry(v, self._time)) for k, v in result.iteritems())) | |
44 self._mapping.update(result) | |
45 return self._mapping | |
46 | |
47 class InMemoryObjectStore(ObjectStore): | |
48 def __init__(self, branch): | |
49 self._branch = branch | |
50 self._cache = {} | |
51 self._object_store = MemcacheObjectStore() | |
52 | |
53 def _SetInMemory(self, key, value, namespace, time): | |
not at google - send to devlin
2012/08/21 01:43:22
it's only used in 1 place (SetMulti) so i'd just i
cduvall
2012/08/21 01:50:10
Done.
| |
54 if namespace not in self._cache: | |
55 self._cache[namespace] = {} | |
56 self._cache[namespace][key] = _CacheEntry(value, time) | |
57 | |
58 def _TryBackingObjectStore(self, key, namespace, time): | |
not at google - send to devlin
2012/08/21 01:43:22
not called anymore, so you can delete it?
cduvall
2012/08/21 01:50:10
Done.
| |
59 result = self._object_store.Get(key, namespace, time=time) | |
60 if result is not None: | |
61 self._SetInMemory(key, result, namespace, time) | |
62 return result | |
63 | |
64 def _MakeNamespace(self, namespace): | |
65 return 'ObjectStore.%s.%s' % (self._branch, namespace) | |
66 | |
67 def SetMulti(self, mapping, namespace, time=CACHE_TIMEOUT): | |
68 namespace = self._MakeNamespace(namespace) | |
69 for k, v in mapping.iteritems(): | |
70 self._SetInMemory(k, v, namespace, time) | |
71 # TODO(cduvall): Use a batch set? App Engine kept throwing: | |
72 # ValueError: Values may not be more than 1000000 bytes in length | |
73 # for the batch set. | |
74 self._object_store.Set(k, v, namespace, time=time) | |
75 | |
76 def GetMulti(self, keys, namespace, time=CACHE_TIMEOUT): | |
77 namespace = self._MakeNamespace(namespace) | |
78 keys = keys[:] | |
79 mapping = {} | |
80 if namespace not in self._cache: | |
81 self._cache[namespace] = {} | |
82 for key in keys: | |
83 cache_entry = self._cache[namespace].get(key, None) | |
84 if cache_entry is None or cache_entry.HasExpired(): | |
85 mapping[key] = None | |
86 else: | |
87 mapping[key] = cache_entry.value | |
88 keys.remove(key) | |
89 future = self._object_store.GetMulti(keys, namespace, time=time) | |
90 return Future(delegate=_AsyncGetFuture(self._cache, | |
91 time, | |
92 namespace, | |
93 future, | |
94 mapping)) | |
95 | |
96 def Delete(self, key, namespace): | |
97 namespace = self._MakeNamespace(namespace) | |
98 if namespace in self._cache: | |
99 self._cache[namespace].pop(key) | |
100 self._object_store.Delete(key, namespace) | |
OLD | NEW |