diff options
Diffstat (limited to 'dogpile/core/nameregistry.py')
-rw-r--r-- | dogpile/core/nameregistry.py | 92 |
1 files changed, 92 insertions, 0 deletions
diff --git a/dogpile/core/nameregistry.py b/dogpile/core/nameregistry.py new file mode 100644 index 0000000..ab3ad7b --- /dev/null +++ b/dogpile/core/nameregistry.py @@ -0,0 +1,92 @@ +from util 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. + + :class:`.NameRegistry` is a utility object that + is used to maintain new :class:`.Dogpile` objects + against a certain key, for as long as that particular key + is referenced within the application. An application + can deal with an arbitrary number of keys, ensuring that + all threads requesting a certain key use the same + :class:`.Dogpile` object, without the need to maintain + each :class:`.Dogpile` object persistently in memory. + + :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() |