| Index: third_party/google-endpoints/dogpile/util/nameregistry.py
|
| diff --git a/third_party/google-endpoints/dogpile/util/nameregistry.py b/third_party/google-endpoints/dogpile/util/nameregistry.py
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..a5102b238702b1eb74a773222b2539570789c62f
|
| --- /dev/null
|
| +++ b/third_party/google-endpoints/dogpile/util/nameregistry.py
|
| @@ -0,0 +1,84 @@
|
| +from .compat import threading
|
| +import weakref
|
| +
|
| +
|
| +class NameRegistry(object):
|
| + """Generates and return an object, keeping it as a
|
| + singleton for a certain identifier for as long as its
|
| + strongly referenced.
|
| +
|
| + e.g.::
|
| +
|
| + class MyFoo(object):
|
| + "some important object."
|
| + def __init__(self, identifier):
|
| + self.identifier = identifier
|
| +
|
| + registry = NameRegistry(MyFoo)
|
| +
|
| + # thread 1:
|
| + my_foo = registry.get("foo1")
|
| +
|
| + # thread 2
|
| + my_foo = registry.get("foo1")
|
| +
|
| + Above, ``my_foo`` in both thread #1 and #2 will
|
| + be *the same object*. The constructor for
|
| + ``MyFoo`` will be called once, passing the
|
| + identifier ``foo1`` as the argument.
|
| +
|
| + When thread 1 and thread 2 both complete or
|
| + otherwise delete references to ``my_foo``, the
|
| + object is *removed* from the :class:`.NameRegistry` as
|
| + a result of Python garbage collection.
|
| +
|
| + :param creator: A function that will create a new
|
| + value, given the identifier passed to the :meth:`.NameRegistry.get`
|
| + method.
|
| +
|
| + """
|
| + _locks = weakref.WeakValueDictionary()
|
| + _mutex = threading.RLock()
|
| +
|
| + def __init__(self, creator):
|
| + """Create a new :class:`.NameRegistry`.
|
| +
|
| +
|
| + """
|
| + self._values = weakref.WeakValueDictionary()
|
| + self._mutex = threading.RLock()
|
| + self.creator = creator
|
| +
|
| + def get(self, identifier, *args, **kw):
|
| + """Get and possibly create the value.
|
| +
|
| + :param identifier: Hash key for the value.
|
| + If the creation function is called, this identifier
|
| + will also be passed to the creation function.
|
| + :param \*args, \**kw: Additional arguments which will
|
| + also be passed to the creation function if it is
|
| + called.
|
| +
|
| + """
|
| + try:
|
| + if identifier in self._values:
|
| + return self._values[identifier]
|
| + else:
|
| + return self._sync_get(identifier, *args, **kw)
|
| + except KeyError:
|
| + return self._sync_get(identifier, *args, **kw)
|
| +
|
| + def _sync_get(self, identifier, *args, **kw):
|
| + self._mutex.acquire()
|
| + try:
|
| + try:
|
| + if identifier in self._values:
|
| + return self._values[identifier]
|
| + else:
|
| + self._values[identifier] = value = self.creator(identifier, *args, **kw)
|
| + return value
|
| + except KeyError:
|
| + self._values[identifier] = value = self.creator(identifier, *args, **kw)
|
| + return value
|
| + finally:
|
| + self._mutex.release()
|
|
|