Chromium Code Reviews| Index: chrome/common/extensions/docs/server2/cache_chain_object_store.py |
| diff --git a/chrome/common/extensions/docs/server2/cache_chain_object_store.py b/chrome/common/extensions/docs/server2/cache_chain_object_store.py |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..cb4034fea93ed6d2332fe13dc4fb5111a4971601 |
| --- /dev/null |
| +++ b/chrome/common/extensions/docs/server2/cache_chain_object_store.py |
| @@ -0,0 +1,97 @@ |
| +# 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
:)
|
| +# Use of this source code is governed by a BSD-style license that can be |
| +# found in the LICENSE file. |
| + |
| +from future import Future |
| +from object_store import ObjectStore |
| + |
| +class _GetMultiFuture(object): |
| + '''A Future for GetMulti. |
| + |
| + Params: |
| + - |toplevel_cache| CacheChainObjectStore's cache. |
| + - |object_store_futures| a list of (object store, future) pairs, where future |
| + is the result of calling GetMulti on the missing keys for the object store. |
| + - |cached_items| a mapping of cache items already in memory. |
| + - |missing_keys| the keys that were missing from the GetMulti call |
| + ''' |
| + def __init__(self, |
| + toplevel_cache, |
| + object_store_futures, |
| + cached_items, |
| + missing_keys): |
| + self._toplevel_cache = toplevel_cache |
| + self._object_store_futures = object_store_futures |
| + self._results_so_far = cached_items |
| + self._missing_keys = missing_keys |
| + |
| + def Get(self): |
| + # Approach: |
| + # |
| + # Try each object store in order, until there are no more missing keys. |
| + # Don't realise the Future value of an object store that we don't need to; |
| + # this is important e.g. to avoid querying data store constantly. |
| + # |
| + # When a value is found, cache it in all object stores further up the |
| + # chain, including the object-based cache on CacheChainObjectStore. |
| + object_store_updates = [] |
| + for object_store, object_store_future in self._object_store_futures: |
| + if len(self._missing_keys) == 0: |
| + break |
| + result = object_store_future.Get() |
| + for k, v in result.items(): # use items(); changes during iteration |
| + if v is None or k not in self._missing_keys: |
| + del result[k] |
| + continue |
| + self._toplevel_cache[k] = v |
| + self._results_so_far[k] = v |
| + self._missing_keys.remove(k) |
| + for _, updates in object_store_updates: |
| + updates.update(result) |
| + object_store_updates.append((object_store, {})) |
| + # Update the caches of all object stores that need it. |
| + for object_store, updates in object_store_updates: |
| + if updates: |
| + object_store.SetMulti(updates) |
| + return self._results_so_far |
| + |
| +class CacheChainObjectStore(ObjectStore): |
| + '''Maintains an in-memory cache along with a chain of other object stores to |
| + try for the same keys. This is useful for implementing a multi-layered cache. |
| + The in-memory cache is inbuilt since it's synchronous, but the object store |
| + interface is asynchronous. |
| + The rules for the object store chain are: |
| + - When setting (or deleting) items, all object stores in the hierarcy will |
| + have that item set. |
| + - When getting items, each object store is tried in order. The first object |
| + store to find the item will trickle back up, setting it on all object |
| + stores higher in the hierarchy. |
| + ''' |
| + def __init__(self, object_stores): |
| + self._object_stores = object_stores |
| + self._cache = {} |
| + |
| + def SetMulti(self, mapping): |
| + self._cache.update(mapping) |
| + for object_store in self._object_stores: |
| + object_store.SetMulti(mapping) |
| + |
| + def GetMulti(self, keys): |
| + missing_keys = list(keys) |
| + cached_items = {} |
| + for key in keys: |
| + if key in self._cache: |
| + cached_items[key] = self._cache.get(key) |
| + missing_keys.remove(key) |
| + if len(missing_keys) == 0: |
| + return Future(value=cached_items) |
| + object_store_futures = [(object_store, object_store.GetMulti(missing_keys)) |
| + for object_store in self._object_stores] |
| + return Future(delegate=_GetMultiFuture( |
| + self._cache, object_store_futures, cached_items, missing_keys)) |
| + |
| + def DelMulti(self, keys): |
| + for k in keys: |
| + self._cache.pop(k, None) |
| + for object_store in self._object_stores: |
| + object_store.DelMulti(keys) |