summaryrefslogtreecommitdiffstats
path: root/nova/utils.py
diff options
context:
space:
mode:
authorSoren Hansen <soren@linux2go.dk>2011-03-22 10:35:43 +0100
committerSoren Hansen <soren@linux2go.dk>2011-03-22 10:35:43 +0100
commitd1860ce5d26fbbadb2310e8225e924879cde9a6c (patch)
treef7391ff764c1c3a98a336ec016c7c0bb7dbd5d23 /nova/utils.py
parente40d692c55a02fa686e83bd87eca29a3cfa3d15e (diff)
downloadnova-d1860ce5d26fbbadb2310e8225e924879cde9a6c.tar.gz
nova-d1860ce5d26fbbadb2310e8225e924879cde9a6c.tar.xz
nova-d1860ce5d26fbbadb2310e8225e924879cde9a6c.zip
Make synchronized support both external (file based) locks as well as internal (semaphore based) locks. Attempt to make it native thread safe at the expense of never cleaning up semaphores.
Diffstat (limited to 'nova/utils.py')
-rw-r--r--nova/utils.py67
1 files changed, 60 insertions, 7 deletions
diff --git a/nova/utils.py b/nova/utils.py
index 499af2039..8936614cc 100644
--- a/nova/utils.py
+++ b/nova/utils.py
@@ -41,6 +41,7 @@ from xml.sax import saxutils
from eventlet import event
from eventlet import greenthread
+from eventlet import semaphore
from eventlet.green import subprocess
None
from nova import exception
@@ -531,17 +532,69 @@ def loads(s):
return json.loads(s)
-def synchronized(name):
+_semaphores_semaphore = semaphore.Semaphore()
+_semaphores = {}
+
+
+class _NoopContextManager(object):
+ def __enter__(self):
+ pass
+
+ def __exit__(self, exc_type, exc_val, exc_tb):
+ pass
+
+
+def synchronized(name, external=False):
+ """Synchronization decorator
+
+ Decorating a method like so:
+ @synchronized('mylock')
+ def foo(self, *args):
+ ...
+
+ ensures that only one thread will execute the bar method at a time.
+
+ Different methods can share the same lock:
+ @synchronized('mylock')
+ def foo(self, *args):
+ ...
+
+ @synchronized('mylock')
+ def bar(self, *args):
+ ...
+
+ This way only one of either foo or bar can be executing at a time.
+
+ The external keyword argument denotes whether this lock should work across
+ multiple processes. This means that if two different workers both run a
+ a method decorated with @synchronized('mylock', external=True), only one
+ of them will execute at a time.
+ """
+
def wrap(f):
@functools.wraps(f)
def inner(*args, **kwargs):
- LOG.debug(_("Attempting to grab %(lock)s for method "
- "%(method)s..." % {"lock": name,
+ with _semaphores_semaphore:
+ if name not in _semaphores:
+ _semaphores[name] = semaphore.Semaphore()
+ sem = _semaphores[name]
+ LOG.debug(_('Attempting to grab semaphore "%(lock)s" for method '
+ '"%(method)s"...' % {"lock": name,
"method": f.__name__}))
- lock = lockfile.FileLock(os.path.join(FLAGS.lock_path,
- 'nova-%s.lock' % name))
- with lock:
- return f(*args, **kwargs)
+ with sem:
+ if external:
+ LOG.debug(_('Attempting to grab file lock "%(lock)s" for '
+ 'method "%(method)s"...' %
+ {"lock": name, "method": f.__name__}))
+ lock_file_path = os.path.join(FLAGS.lock_path,
+ 'nova-%s.lock' % name)
+ lock = lockfile.FileLock(lock_file_path)
+ else:
+ lock = _NoopContextManager()
+
+ with lock:
+ return f(*args, **kwargs)
+
return inner
return wrap