summaryrefslogtreecommitdiff
path: root/dogpile
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2011-11-20 18:34:53 -0500
committerMike Bayer <mike_mp@zzzcomputing.com>2011-11-20 18:34:53 -0500
commit24ba064c57bfa21aa62396cc1c192690585f80ad (patch)
tree798a1dc300aa675d0c3ef777ab1d7d0060177ae5 /dogpile
parent1356cd61e5282041cbed77527b0ec10a1008fd12 (diff)
downloaddogpile-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.py99
-rw-r--r--dogpile/readwrite_lock.py8
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()