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:
@@ -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()
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user