Make llnl.util.lock use file objects instead of low-level OS fds.
- Make sure we write, truncate, flush when setting PID and owning host in the file.
This commit is contained in:
@@ -54,7 +54,7 @@ class Lock(object):
|
|||||||
|
|
||||||
def __init__(self, file_path):
|
def __init__(self, file_path):
|
||||||
self._file_path = file_path
|
self._file_path = file_path
|
||||||
self._fd = None
|
self._file = None
|
||||||
self._reads = 0
|
self._reads = 0
|
||||||
self._writes = 0
|
self._writes = 0
|
||||||
|
|
||||||
@@ -75,21 +75,23 @@ def _lock(self, op, timeout):
|
|||||||
try:
|
try:
|
||||||
# If this is already open read-only and we want to
|
# If this is already open read-only and we want to
|
||||||
# upgrade to an exclusive write lock, close first.
|
# upgrade to an exclusive write lock, close first.
|
||||||
if self._fd is not None:
|
if self._file is not None:
|
||||||
flags = fcntl.fcntl(self._fd, fcntl.F_GETFL)
|
if op == fcntl.LOCK_EX and self._file.mode == 'r':
|
||||||
if op == fcntl.LOCK_EX and flags | os.O_RDONLY:
|
self._file.close()
|
||||||
os.close(self._fd)
|
self._file = None
|
||||||
self._fd = None
|
|
||||||
|
|
||||||
if self._fd is None:
|
# Open reader locks read-only if possible.
|
||||||
mode = os.O_RDWR if op == fcntl.LOCK_EX else os.O_RDONLY
|
# lock doesn't exist, open RW + create if it doesn't exist.
|
||||||
self._fd = os.open(self._file_path, mode)
|
if self._file is None:
|
||||||
|
mode = 'r+' if op == fcntl.LOCK_EX else 'r'
|
||||||
|
self._file = open(self._file_path, mode)
|
||||||
|
|
||||||
fcntl.lockf(self._fd, op | fcntl.LOCK_NB)
|
fcntl.lockf(self._file, op | fcntl.LOCK_NB)
|
||||||
if op == fcntl.LOCK_EX:
|
if op == fcntl.LOCK_EX:
|
||||||
os.write(
|
self._file.write(
|
||||||
self._fd,
|
|
||||||
"pid=%s,host=%s" % (os.getpid(), socket.getfqdn()))
|
"pid=%s,host=%s" % (os.getpid(), socket.getfqdn()))
|
||||||
|
self._file.truncate()
|
||||||
|
self._file.flush()
|
||||||
return
|
return
|
||||||
|
|
||||||
except IOError as error:
|
except IOError as error:
|
||||||
@@ -108,9 +110,9 @@ def _unlock(self):
|
|||||||
be masquerading as write locks, but this removes either.
|
be masquerading as write locks, but this removes either.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
fcntl.lockf(self._fd, fcntl.LOCK_UN)
|
fcntl.lockf(self._file, fcntl.LOCK_UN)
|
||||||
os.close(self._fd)
|
self._file.close()
|
||||||
self._fd = None
|
self._file = None
|
||||||
|
|
||||||
def acquire_read(self, timeout=_default_timeout):
|
def acquire_read(self, timeout=_default_timeout):
|
||||||
"""Acquires a recursive, shared lock for reading.
|
"""Acquires a recursive, shared lock for reading.
|
||||||
|
@@ -184,7 +184,7 @@ def test_upgrade_read_to_write(self):
|
|||||||
lock.release_read()
|
lock.release_read()
|
||||||
self.assertTrue(lock._reads == 0)
|
self.assertTrue(lock._reads == 0)
|
||||||
self.assertTrue(lock._writes == 0)
|
self.assertTrue(lock._writes == 0)
|
||||||
self.assertTrue(lock._fd is None)
|
self.assertTrue(lock._file is None)
|
||||||
|
|
||||||
#
|
#
|
||||||
# Longer test case that ensures locks are reusable. Ordering is
|
# Longer test case that ensures locks are reusable. Ordering is
|
||||||
|
Reference in New Issue
Block a user