diff options
author | Justin Santa Barbara <justin@fathomdb.com> | 2011-03-23 19:00:25 -0700 |
---|---|---|
committer | Justin Santa Barbara <justin@fathomdb.com> | 2011-03-23 19:00:25 -0700 |
commit | 21f3fc7cecb4c2f0657bb6bc78098910dca2e6b7 (patch) | |
tree | 96bada7d30eb2325f56328f54dcc0da9ad07ac12 /nova/utils.py | |
parent | 3c295817f91eb7c76a64d157ff4a938c85075a36 (diff) | |
parent | 0759158d08f3f98456ae094fd9d94d36b98216a5 (diff) | |
download | nova-21f3fc7cecb4c2f0657bb6bc78098910dca2e6b7.tar.gz nova-21f3fc7cecb4c2f0657bb6bc78098910dca2e6b7.tar.xz nova-21f3fc7cecb4c2f0657bb6bc78098910dca2e6b7.zip |
Merged with lp:nova, fixed conflicts
Diffstat (limited to 'nova/utils.py')
-rw-r--r-- | nova/utils.py | 74 |
1 files changed, 67 insertions, 7 deletions
diff --git a/nova/utils.py b/nova/utils.py index e624c3f11..352c5d9f9 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,76 @@ def loads(s): return json.loads(s) -def synchronized(name): +_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, + # NOTE(soren): If we ever go natively threaded, this will be racy. + # See http://stackoverflow.com/questions/5390569/dyn\ + # amically-allocating-and-destroying-mutexes + 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: + retval = f(*args, **kwargs) + + # If no-one else is waiting for it, delete it. + # See note about possible raciness above. + if not sem.balance < 1: + del _semaphores[name] + + return retval return inner return wrap |