Index: third_party/google-endpoints/dogpile/cache/api.py |
diff --git a/third_party/google-endpoints/dogpile/cache/api.py b/third_party/google-endpoints/dogpile/cache/api.py |
new file mode 100644 |
index 0000000000000000000000000000000000000000..dbab2db384928103741141408739aac66dc0379f |
--- /dev/null |
+++ b/third_party/google-endpoints/dogpile/cache/api.py |
@@ -0,0 +1,207 @@ |
+import operator |
+from ..util.compat import py3k |
+ |
+ |
+class NoValue(object): |
+ """Describe a missing cache value. |
+ |
+ The :attr:`.NO_VALUE` module global |
+ should be used. |
+ |
+ """ |
+ @property |
+ def payload(self): |
+ return self |
+ |
+ if py3k: |
+ def __bool__(self): # pragma NO COVERAGE |
+ return False |
+ else: |
+ def __nonzero__(self): # pragma NO COVERAGE |
+ return False |
+ |
+NO_VALUE = NoValue() |
+"""Value returned from ``get()`` that describes |
+a key not present.""" |
+ |
+ |
+class CachedValue(tuple): |
+ """Represent a value stored in the cache. |
+ |
+ :class:`.CachedValue` is a two-tuple of |
+ ``(payload, metadata)``, where ``metadata`` |
+ is dogpile.cache's tracking information ( |
+ currently the creation time). The metadata |
+ and tuple structure is pickleable, if |
+ the backend requires serialization. |
+ |
+ """ |
+ payload = property(operator.itemgetter(0)) |
+ """Named accessor for the payload.""" |
+ |
+ metadata = property(operator.itemgetter(1)) |
+ """Named accessor for the dogpile.cache metadata dictionary.""" |
+ |
+ def __new__(cls, payload, metadata): |
+ return tuple.__new__(cls, (payload, metadata)) |
+ |
+ def __reduce__(self): |
+ return CachedValue, (self.payload, self.metadata) |
+ |
+ |
+class CacheBackend(object): |
+ """Base class for backend implementations.""" |
+ |
+ key_mangler = None |
+ """Key mangling function. |
+ |
+ May be None, or otherwise declared |
+ as an ordinary instance method. |
+ |
+ """ |
+ |
+ def __init__(self, arguments): # pragma NO COVERAGE |
+ """Construct a new :class:`.CacheBackend`. |
+ |
+ Subclasses should override this to |
+ handle the given arguments. |
+ |
+ :param arguments: The ``arguments`` parameter |
+ passed to :func:`.make_registry`. |
+ |
+ """ |
+ raise NotImplementedError() |
+ |
+ @classmethod |
+ def from_config_dict(cls, config_dict, prefix): |
+ prefix_len = len(prefix) |
+ return cls( |
+ dict( |
+ (key[prefix_len:], config_dict[key]) |
+ for key in config_dict |
+ if key.startswith(prefix) |
+ ) |
+ ) |
+ |
+ def has_lock_timeout(self): |
+ return False |
+ |
+ def get_mutex(self, key): |
+ """Return an optional mutexing object for the given key. |
+ |
+ This object need only provide an ``acquire()`` |
+ and ``release()`` method. |
+ |
+ May return ``None``, in which case the dogpile |
+ lock will use a regular ``threading.Lock`` |
+ object to mutex concurrent threads for |
+ value creation. The default implementation |
+ returns ``None``. |
+ |
+ Different backends may want to provide various |
+ kinds of "mutex" objects, such as those which |
+ link to lock files, distributed mutexes, |
+ memcached semaphores, etc. Whatever |
+ kind of system is best suited for the scope |
+ and behavior of the caching backend. |
+ |
+ A mutex that takes the key into account will |
+ allow multiple regenerate operations across |
+ keys to proceed simultaneously, while a mutex |
+ that does not will serialize regenerate operations |
+ to just one at a time across all keys in the region. |
+ The latter approach, or a variant that involves |
+ a modulus of the given key's hash value, |
+ can be used as a means of throttling the total |
+ number of value recreation operations that may |
+ proceed at one time. |
+ |
+ """ |
+ return None |
+ |
+ def get(self, key): # pragma NO COVERAGE |
+ """Retrieve a value from the cache. |
+ |
+ The returned value should be an instance of |
+ :class:`.CachedValue`, or ``NO_VALUE`` if |
+ not present. |
+ |
+ """ |
+ raise NotImplementedError() |
+ |
+ def get_multi(self, keys): # pragma NO COVERAGE |
+ """Retrieve multiple values from the cache. |
+ |
+ The returned value should be a list, corresponding |
+ to the list of keys given. |
+ |
+ .. versionadded:: 0.5.0 |
+ |
+ """ |
+ raise NotImplementedError() |
+ |
+ def set(self, key, value): # pragma NO COVERAGE |
+ """Set a value in the cache. |
+ |
+ The key will be whatever was passed |
+ to the registry, processed by the |
+ "key mangling" function, if any. |
+ The value will always be an instance |
+ of :class:`.CachedValue`. |
+ |
+ """ |
+ raise NotImplementedError() |
+ |
+ def set_multi(self, mapping): # pragma NO COVERAGE |
+ """Set multiple values in the cache. |
+ |
+ ``mapping`` is a dict in which |
+ the key will be whatever was passed |
+ to the registry, processed by the |
+ "key mangling" function, if any. |
+ The value will always be an instance |
+ of :class:`.CachedValue`. |
+ |
+ When implementing a new :class:`.CacheBackend` or cutomizing via |
+ :class:`.ProxyBackend`, be aware that when this method is invoked by |
+ :meth:`.Region.get_or_create_multi`, the ``mapping`` values are the |
+ same ones returned to the upstream caller. If the subclass alters the |
+ values in any way, it must not do so 'in-place' on the ``mapping`` dict |
+ -- that will have the undesirable effect of modifying the returned |
+ values as well. |
+ |
+ .. versionadded:: 0.5.0 |
+ |
+ """ |
+ raise NotImplementedError() |
+ |
+ def delete(self, key): # pragma NO COVERAGE |
+ """Delete a value from the cache. |
+ |
+ The key will be whatever was passed |
+ to the registry, processed by the |
+ "key mangling" function, if any. |
+ |
+ The behavior here should be idempotent, |
+ that is, can be called any number of times |
+ regardless of whether or not the |
+ key exists. |
+ """ |
+ raise NotImplementedError() |
+ |
+ def delete_multi(self, keys): # pragma NO COVERAGE |
+ """Delete multiple values from the cache. |
+ |
+ The key will be whatever was passed |
+ to the registry, processed by the |
+ "key mangling" function, if any. |
+ |
+ The behavior here should be idempotent, |
+ that is, can be called any number of times |
+ regardless of whether or not the |
+ key exists. |
+ |
+ .. versionadded:: 0.5.0 |
+ |
+ """ |
+ raise NotImplementedError() |