diff options
author | Mike Bayer <mike_mp@zzzcomputing.com> | 2012-04-14 18:00:31 -0400 |
---|---|---|
committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2012-04-14 18:00:31 -0400 |
commit | a1dc7581b29ed01ad006276f7cf08dad80b4ea46 (patch) | |
tree | 57236dd294b3ebbe7b8af6afa38e00364c0eb636 /dogpile/core/nameregistry.py | |
parent | 83fb66a9b5605c0d3b3bdaabf4ca9c4e866edfea (diff) | |
download | dogpile-core-a1dc7581b29ed01ad006276f7cf08dad80b4ea46.tar.gz |
renaming to dogpile.core so that we are doing a more traditional namespace
package setup
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() |