| 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..4be6643325d9bd68908e1f9e735829f86f277306
|
| --- /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.
|
| +# 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:
|
| + del self._cache[k]
|
| + for object_store in self._object_stores:
|
| + object_store.DelMulti(keys)
|
|
|