Read-only locks should close fd before opening for write. (#1906)
- Fixes bad file descriptor error in lock acquire, #1904 - Fix bug introduced in previous PR #1857 - Backported fix from soon-to-be merged fine-grained DB locking branch.
This commit is contained in:
parent
9daafc32f1
commit
bff1656a1a
@ -69,6 +69,14 @@ def _lock(self, op, timeout):
|
|||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
while (time.time() - start_time) < timeout:
|
while (time.time() - start_time) < timeout:
|
||||||
try:
|
try:
|
||||||
|
# If this is already open read-only and we want to
|
||||||
|
# upgrade to an exclusive write lock, close first.
|
||||||
|
if self._fd is not None:
|
||||||
|
flags = fcntl.fcntl(self._fd, fcntl.F_GETFL)
|
||||||
|
if op == fcntl.LOCK_EX and flags | os.O_RDONLY:
|
||||||
|
os.close(self._fd)
|
||||||
|
self._fd = None
|
||||||
|
|
||||||
if self._fd is None:
|
if self._fd is None:
|
||||||
mode = os.O_RDWR if op == fcntl.LOCK_EX else os.O_RDONLY
|
mode = os.O_RDWR if op == fcntl.LOCK_EX else os.O_RDONLY
|
||||||
self._fd = os.open(self._file_path, mode)
|
self._fd = os.open(self._file_path, mode)
|
||||||
|
@ -157,6 +157,35 @@ def test_write_lock_timeout_with_multiple_readers_3_2(self):
|
|||||||
self.acquire_read, self.acquire_read, self.acquire_read,
|
self.acquire_read, self.acquire_read, self.acquire_read,
|
||||||
self.timeout_write, self.timeout_write)
|
self.timeout_write, self.timeout_write)
|
||||||
|
|
||||||
|
#
|
||||||
|
# Test that read can be upgraded to write.
|
||||||
|
#
|
||||||
|
def test_upgrade_read_to_write(self):
|
||||||
|
# ensure lock file exists the first time, so we open it read-only
|
||||||
|
# to begin wtih.
|
||||||
|
touch(self.lock_path)
|
||||||
|
|
||||||
|
lock = Lock(self.lock_path)
|
||||||
|
self.assertTrue(lock._reads == 0)
|
||||||
|
self.assertTrue(lock._writes == 0)
|
||||||
|
|
||||||
|
lock.acquire_read()
|
||||||
|
self.assertTrue(lock._reads == 1)
|
||||||
|
self.assertTrue(lock._writes == 0)
|
||||||
|
|
||||||
|
lock.acquire_write()
|
||||||
|
self.assertTrue(lock._reads == 1)
|
||||||
|
self.assertTrue(lock._writes == 1)
|
||||||
|
|
||||||
|
lock.release_write()
|
||||||
|
self.assertTrue(lock._reads == 1)
|
||||||
|
self.assertTrue(lock._writes == 0)
|
||||||
|
|
||||||
|
lock.release_read()
|
||||||
|
self.assertTrue(lock._reads == 0)
|
||||||
|
self.assertTrue(lock._writes == 0)
|
||||||
|
self.assertTrue(lock._fd is None)
|
||||||
|
|
||||||
#
|
#
|
||||||
# Longer test case that ensures locks are reusable. Ordering is
|
# Longer test case that ensures locks are reusable. Ordering is
|
||||||
# enforced by barriers throughout -- steps are shown with numbers.
|
# enforced by barriers throughout -- steps are shown with numbers.
|
||||||
|
Loading…
Reference in New Issue
Block a user