Update openstack/common/lockutils

The following commits are in this update:

79e6bc6 fix lockutils.lock() to make it thread-safe
ace5120 Add main() to lockutils that creates temp dir for locks
537d8e2 Allow lockutils to get lock_path conf from envvar

Change-Id: Id50b7c0ccbb417493320e19191a92675fcf126ff
This commit is contained in:
Michael Still 2013-11-14 21:03:00 +11:00
parent 8338bdc992
commit 2f44ed535f

View File

@ -20,6 +20,10 @@ import contextlib
import errno import errno
import functools import functools
import os import os
import shutil
import subprocess
import sys
import tempfile
import threading import threading
import time import time
import weakref import weakref
@ -39,6 +43,7 @@ util_opts = [
cfg.BoolOpt('disable_process_locking', default=False, cfg.BoolOpt('disable_process_locking', default=False,
help='Whether to disable inter-process locks'), help='Whether to disable inter-process locks'),
cfg.StrOpt('lock_path', cfg.StrOpt('lock_path',
default=os.environ.get("MARCONI_LOCK_PATH"),
help=('Directory to use for lock files.')) help=('Directory to use for lock files.'))
] ]
@ -131,6 +136,7 @@ else:
InterProcessLock = _PosixLock InterProcessLock = _PosixLock
_semaphores = weakref.WeakValueDictionary() _semaphores = weakref.WeakValueDictionary()
_semaphores_lock = threading.Lock()
@contextlib.contextmanager @contextlib.contextmanager
@ -153,14 +159,11 @@ def lock(name, lock_file_prefix=None, external=False, lock_path=None):
special location for external lock files to live. If nothing is set, then special location for external lock files to live. If nothing is set, then
CONF.lock_path is used as a default. CONF.lock_path is used as a default.
""" """
# NOTE(soren): If we ever go natively threaded, this will be racy. with _semaphores_lock:
# See http://stackoverflow.com/questions/5390569/dyn try:
# amically-allocating-and-destroying-mutexes sem = _semaphores[name]
sem = _semaphores.get(name, threading.Semaphore()) except KeyError:
if name not in _semaphores: sem = threading.Semaphore()
# this check is not racy - we're already holding ref locally
# so GC won't remove the item and there was no IO switch
# (only valid in greenthreads)
_semaphores[name] = sem _semaphores[name] = sem
with sem: with sem:
@ -241,11 +244,12 @@ def synchronized(name, lock_file_prefix=None, external=False, lock_path=None):
def wrap(f): def wrap(f):
@functools.wraps(f) @functools.wraps(f)
def inner(*args, **kwargs): def inner(*args, **kwargs):
try:
with lock(name, lock_file_prefix, external, lock_path): with lock(name, lock_file_prefix, external, lock_path):
LOG.debug(_('Got semaphore / lock "%(function)s"'), LOG.debug(_('Got semaphore / lock "%(function)s"'),
{'function': f.__name__}) {'function': f.__name__})
return f(*args, **kwargs) return f(*args, **kwargs)
finally:
LOG.debug(_('Semaphore / lock released "%(function)s"'), LOG.debug(_('Semaphore / lock released "%(function)s"'),
{'function': f.__name__}) {'function': f.__name__})
return inner return inner
@ -275,3 +279,27 @@ def synchronized_with_prefix(lock_file_prefix):
""" """
return functools.partial(synchronized, lock_file_prefix=lock_file_prefix) return functools.partial(synchronized, lock_file_prefix=lock_file_prefix)
def main(argv):
"""Create a dir for locks and pass it to command from arguments
If you run this:
python -m openstack.common.lockutils python setup.py testr <etc>
a temporary directory will be created for all your locks and passed to all
your tests in an environment variable. The temporary dir will be deleted
afterwards and the return value will be preserved.
"""
lock_dir = tempfile.mkdtemp()
os.environ["MARCONI_LOCK_PATH"] = lock_dir
try:
ret_val = subprocess.call(argv[1:])
finally:
shutil.rmtree(lock_dir, ignore_errors=True)
return ret_val
if __name__ == '__main__':
sys.exit(main(sys.argv))