OLD | NEW |
---|---|
(Empty) | |
1 # Copyright 2013 The Chromium Authors. All rights reserved. | |
cduvall
2013/04/17 23:30:37
I like this class
not at google - send to devlin
2013/04/18 04:05:41
:)
| |
2 # Use of this source code is governed by a BSD-style license that can be | |
3 # found in the LICENSE file. | |
4 | |
5 from future import Future | |
6 from object_store import ObjectStore | |
7 | |
8 class _GetMultiFuture(object): | |
9 '''A Future for GetMulti. | |
10 | |
11 Params: | |
12 - |toplevel_cache| CacheChainObjectStore's cache. | |
13 - |object_store_futures| a list of (object store, future) pairs, where future | |
14 is the result of calling GetMulti on the missing keys for the object store. | |
15 - |cached_items| a mapping of cache items already in memory. | |
16 - |missing_keys| the keys that were missing from the GetMulti call | |
17 ''' | |
18 def __init__(self, | |
19 toplevel_cache, | |
20 object_store_futures, | |
21 cached_items, | |
22 missing_keys): | |
23 self._toplevel_cache = toplevel_cache | |
24 self._object_store_futures = object_store_futures | |
25 self._results_so_far = cached_items | |
26 self._missing_keys = missing_keys | |
27 | |
28 def Get(self): | |
29 # Approach: | |
30 # | |
31 # Try each object store in order, until there are no more missing keys. | |
32 # Don't realise the Future value of an object store that we don't need to; | |
33 # this is important e.g. to avoid querying data store constantly. | |
34 # | |
35 # When a value is found, cache it in all object stores further up the | |
36 # chain, including the object-based cache on CacheChainObjectStore. | |
37 object_store_updates = [] | |
38 for object_store, object_store_future in self._object_store_futures: | |
39 if len(self._missing_keys) == 0: | |
40 break | |
41 result = object_store_future.Get() | |
42 for k, v in result.items(): # use items(); changes during iteration | |
43 if v is None or k not in self._missing_keys: | |
44 del result[k] | |
45 continue | |
46 self._toplevel_cache[k] = v | |
47 self._results_so_far[k] = v | |
48 self._missing_keys.remove(k) | |
49 for _, updates in object_store_updates: | |
50 updates.update(result) | |
51 object_store_updates.append((object_store, {})) | |
52 # Update the caches of all object stores that need it. | |
53 for object_store, updates in object_store_updates: | |
54 if updates: | |
55 object_store.SetMulti(updates) | |
56 return self._results_so_far | |
57 | |
58 class CacheChainObjectStore(ObjectStore): | |
59 '''Maintains an in-memory cache along with a chain of other object stores to | |
60 try for the same keys. This is useful for implementing a multi-layered cache. | |
61 The in-memory cache is inbuilt since it's synchronous, but the object store | |
62 interface is asynchronous. | |
63 The rules for the object store chain are: | |
64 - When setting (or deleting) items, all object stores in the hierarcy will | |
65 have that item set. | |
66 - When getting items, each object store is tried in order. The first object | |
67 store to find the item will trickle back up, setting it on all object | |
68 stores higher in the hierarchy. | |
69 ''' | |
70 def __init__(self, object_stores): | |
71 self._object_stores = object_stores | |
72 self._cache = {} | |
73 | |
74 def SetMulti(self, mapping): | |
75 self._cache.update(mapping) | |
76 for object_store in self._object_stores: | |
77 object_store.SetMulti(mapping) | |
78 | |
79 def GetMulti(self, keys): | |
80 missing_keys = list(keys) | |
81 cached_items = {} | |
82 for key in keys: | |
83 if key in self._cache: | |
84 cached_items[key] = self._cache.get(key) | |
85 missing_keys.remove(key) | |
86 if len(missing_keys) == 0: | |
87 return Future(value=cached_items) | |
88 object_store_futures = [(object_store, object_store.GetMulti(missing_keys)) | |
89 for object_store in self._object_stores] | |
90 return Future(delegate=_GetMultiFuture( | |
91 self._cache, object_store_futures, cached_items, missing_keys)) | |
92 | |
93 def DelMulti(self, keys): | |
94 for k in keys: | |
95 self._cache.pop(k, None) | |
96 for object_store in self._object_stores: | |
97 object_store.DelMulti(keys) | |
OLD | NEW |