diff options
author | Soren Hansen <soren@linux2go.dk> | 2011-03-22 10:35:43 +0100 |
---|---|---|
committer | Soren Hansen <soren@linux2go.dk> | 2011-03-22 10:35:43 +0100 |
commit | d1860ce5d26fbbadb2310e8225e924879cde9a6c (patch) | |
tree | f7391ff764c1c3a98a336ec016c7c0bb7dbd5d23 /nova/utils.py | |
parent | e40d692c55a02fa686e83bd87eca29a3cfa3d15e (diff) | |
download | nova-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.py | 67 |
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 |