Have the interprocess lock follow lock conventions

The python locking api specifies a acquire/release
function pair. It is nice to have the interprocess
lock api also follow said api so that its objects
can be used in areas where the standard threading
locks are used.

Change-Id: If393bec863ced8c9ef413b4baa3267d2a5b38416
This commit is contained in:
Joshua Harlow
2014-01-17 19:32:35 -08:00
parent ccc8ac9c05
commit fab74ff451
2 changed files with 54 additions and 3 deletions

View File

@@ -75,7 +75,7 @@ class _InterProcessLock(object):
self.lockfile = None
self.fname = name
def __enter__(self):
def acquire(self):
basedir = os.path.dirname(self.fname)
if not os.path.exists(basedir):
@@ -92,7 +92,7 @@ class _InterProcessLock(object):
# to have a laughable 10 attempts "blocking" mechanism.
self.trylock()
LOG.debug(_('Got file lock "%s"'), self.fname)
return self
return True
except IOError as e:
if e.errno in (errno.EACCES, errno.EAGAIN):
# external locks synchronise things like iptables
@@ -101,7 +101,11 @@ class _InterProcessLock(object):
else:
raise
def __exit__(self, exc_type, exc_val, exc_tb):
def __enter__(self):
self.acquire()
return self
def release(self):
try:
self.unlock()
self.lockfile.close()
@@ -110,6 +114,9 @@ class _InterProcessLock(object):
self.fname)
LOG.debug(_('Released file lock "%s"'), self.fname)
def __exit__(self, exc_type, exc_val, exc_tb):
self.release()
def trylock(self):
raise NotImplementedError()

View File

@@ -85,6 +85,50 @@ class LockTestCase(test.BaseTestCase):
self.assertEqual(foo.__name__, 'foo', "Wrapped function's name "
"got mangled")
def test_lock_acquire_release(self):
lock_dir = tempfile.mkdtemp()
lock_file = os.path.join(lock_dir, 'lock')
lock = lockutils.InterProcessLock(lock_file)
def try_lock():
lock.release() # child co-owns it before fork
try:
my_lock = lockutils.InterProcessLock(lock_file)
my_lock.lockfile = open(lock_file, 'w')
my_lock.trylock()
my_lock.unlock()
os._exit(1)
except IOError:
os._exit(0)
def attempt_acquire(count):
children = []
for i in range(count):
child = multiprocessing.Process(target=try_lock)
child.start()
children.append(child)
exit_codes = []
for child in children:
child.join()
exit_codes.append(child.exitcode)
return sum(exit_codes)
self.assertTrue(lock.acquire())
try:
acquired_children = attempt_acquire(10)
self.assertEqual(0, acquired_children)
finally:
lock.release()
try:
acquired_children = attempt_acquire(5)
self.assertNotEqual(0, acquired_children)
finally:
try:
shutil.rmtree(lock_dir)
except IOError:
pass
def test_lock_internally(self):
"""We can lock across multiple green threads."""
saved_sem_num = len(lockutils._semaphores)