diff options
author | Mike Bayer <mike_mp@zzzcomputing.com> | 2011-11-20 18:34:53 -0500 |
---|---|---|
committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2011-11-20 18:34:53 -0500 |
commit | 24ba064c57bfa21aa62396cc1c192690585f80ad (patch) | |
tree | 798a1dc300aa675d0c3ef777ab1d7d0060177ae5 /dogpile | |
parent | 1356cd61e5282041cbed77527b0ec10a1008fd12 (diff) | |
download | dogpile-core-24ba064c57bfa21aa62396cc1c192690585f80ad.tar.gz |
- merge dogpile tests under test_dogpile, add coverage out for all options, readwrite, etc.
- cleanup internals to merge newer features into _enter()
Diffstat (limited to 'dogpile')
-rw-r--r-- | dogpile/dogpile.py | 99 | ||||
-rw-r--r-- | dogpile/readwrite_lock.py | 8 |
2 files changed, 65 insertions, 42 deletions
diff --git a/dogpile/dogpile.py b/dogpile/dogpile.py index 165d47b..ae90cf8 100644 --- a/dogpile/dogpile.py +++ b/dogpile/dogpile.py @@ -7,8 +7,9 @@ log = logging.getLogger(__name__) class NeedRegenerationException(Exception): - """An exception that when raised in the 'with' block, forces - the 'has_value' flag to False and incurs a regeneration of the value. + """An exception that when raised in the 'with' block, + forces the 'has_value' flag to False and incurs a + regeneration of the value. """ @@ -17,9 +18,10 @@ NOT_REGENERATED = object() class Dogpile(object): """Dogpile lock class. - Provides an interface around an arbitrary mutex that allows one - thread/process to be elected as the creator of a new value, - while other threads/processes continue to return the previous version + Provides an interface around an arbitrary mutex + that allows one thread/process to be elected as + the creator of a new value, while other threads/processes + continue to return the previous version of that value. :param expiretime: Expiration time in seconds. @@ -74,36 +76,10 @@ class Dogpile(object): """ dogpile = self - if value_and_created_fn: - value_fn = value_and_created_fn - class Lock(object): - if value_fn: - def __enter__(self): - try: - value = value_fn() - if value_and_created_fn: - value, dogpile.createdtime = value - except NeedRegenerationException: - dogpile.createdtime = -1 - value = NOT_REGENERATED - - generated = dogpile._enter(creator) - - if generated is not NOT_REGENERATED: - return generated - elif value is NOT_REGENERATED: - try: - return value_fn() - except NeedRegenerationException: - raise Exception("Generation function should " - "have just been called by a concurrent " - "thread.") - else: - return value - else: - def __enter__(self): - return dogpile._enter(creator) + def __enter__(self): + return dogpile._enter(creator, value_fn, + value_and_created_fn) def __exit__(self, type, value, traceback): dogpile._exit() @@ -111,34 +87,73 @@ class Dogpile(object): @property def is_expired(self): - """Return true if the expiration time is reached, or no value is available.""" + """Return true if the expiration time is reached, or no + value is available.""" return not self.has_value or \ time.time() - self.createdtime > self.expiretime @property def has_value(self): - """Return true if the creation function has proceeded at least once.""" + """Return true if the creation function has proceeded + at least once.""" return self.createdtime > 0 - def _enter(self, creator): + def _enter(self, creator, value_fn=None, value_and_created_fn=None): + if value_and_created_fn: + value_fn = value_and_created_fn + + if not value_fn: + return self._enter_create(creator) + + try: + value = value_fn() + if value_and_created_fn: + value, self.createdtime = value + except NeedRegenerationException: + log.debug("NeedRegenerationException") + self.createdtime = -1 + value = NOT_REGENERATED + + generated = self._enter_create(creator) + + if generated is not NOT_REGENERATED: + if value_and_created_fn: + generated, self.createdtime = generated + return generated + elif value is NOT_REGENERATED: + try: + if value_and_created_fn: + value, self.createdtime = value_fn() + else: + value = value_fn() + return value + except NeedRegenerationException: + raise Exception("Generation function should " + "have just been called by a concurrent " + "thread.") + else: + return value + + def _enter_create(self, creator): if not self.is_expired: return NOT_REGENERATED if self.has_value: if not self.dogpilelock.acquire(False): - log.debug("dogpile entering block while another " - "thread does the create") + log.debug("creation function in progress " + "elsewhere, returning") return NOT_REGENERATED else: log.debug("no value, waiting for create lock") self.dogpilelock.acquire() try: - log.debug("value creation lock acquired") + log.debug("value creation lock %r acquired" % self.dogpilelock) # see if someone created the value already if not self.is_expired: + log.debug("value already present") return NOT_REGENERATED log.debug("Calling creation function") @@ -178,8 +193,8 @@ class SyncReaderDogpile(Dogpile): return Lock() - def _enter(self, creator): - value = super(SyncReaderDogpile, self)._enter(creator) + def _enter(self, *arg, **kw): + value = super(SyncReaderDogpile, self)._enter(*arg, **kw) self.readwritelock.acquire_read_lock() return value diff --git a/dogpile/readwrite_lock.py b/dogpile/readwrite_lock.py index 0c9cc2b..5c1d3fc 100644 --- a/dogpile/readwrite_lock.py +++ b/dogpile/readwrite_lock.py @@ -3,6 +3,9 @@ try: except ImportError: import dummy_threading as threading +import logging +log = logging.getLogger(__name__) + class ReadWriteMutex(object): """A mutex which allows multiple readers, single writer. @@ -41,6 +44,7 @@ class ReadWriteMutex(object): return False self.async += 1 + log.debug("%s acquired read lock", self) finally: self.condition.release() @@ -63,6 +67,7 @@ class ReadWriteMutex(object): elif self.async < 0: raise LockError("Synchronizer error - too many " "release_read_locks called") + log.debug("%s released read lock", self) finally: self.condition.release() @@ -97,6 +102,7 @@ class ReadWriteMutex(object): # we dont want to wait, so forget it self.current_sync_operation = None return False + log.debug("%s acquired write lock", self) finally: self.condition.release() @@ -117,6 +123,8 @@ class ReadWriteMutex(object): # tell everyone to get ready self.condition.notifyAll() + + log.debug("%s released write lock", self) finally: # everyone go !! self.condition.release() |