提交 2be4d824 authored 作者: Olivier Delalleau's avatar Olivier Delalleau

Enabling the (now improved) compilation directory lock mechanism.

- The lock should now be properly released even after abnormal termination - Verbosity of the lock has been reduced while waiting to acquire a lock - Fixed bug where a job would not be able to acquire a lock when the timeout expires
上级 37c084ae
...@@ -12,12 +12,12 @@ def get_lock(): ...@@ -12,12 +12,12 @@ def get_lock():
get_lock.n_lock = 0 get_lock.n_lock = 0
get_lock.lock_dir = os.path.join(compiledir.get_compiledir(), 'lock_dir') get_lock.lock_dir = os.path.join(compiledir.get_compiledir(), 'lock_dir')
if not hasattr(get_lock, 'lock_is_enabled'): if not hasattr(get_lock, 'lock_is_enabled'):
# Currently lock is disabled by default, due to the annoying # Enable lock by default.
# persistence of lock files when compilation is being interrupted. get_lock.lock_is_enabled = True
get_lock.lock_is_enabled = False get_lock.unlocker = Unlocker(get_lock.lock_dir)
# Only really try to acquire the lock if we do not have it already. # Only really try to acquire the lock if we do not have it already.
if get_lock.lock_is_enabled and get_lock.n_lock == 0: if get_lock.lock_is_enabled and get_lock.n_lock == 0:
lock(get_lock.lock_dir, timeout = 60, verbosity = 10) lock(get_lock.lock_dir, timeout = 60, verbosity = 1)
get_lock.n_lock += 1 get_lock.n_lock += 1
def release_lock(): def release_lock():
...@@ -28,7 +28,7 @@ def release_lock(): ...@@ -28,7 +28,7 @@ def release_lock():
assert get_lock.n_lock >= 0 assert get_lock.n_lock >= 0
# Only really release lock once all lock requests have ended. # Only really release lock once all lock requests have ended.
if get_lock.lock_is_enabled and get_lock.n_lock == 0: if get_lock.lock_is_enabled and get_lock.n_lock == 0:
unlock(get_lock.lock_dir) get_lock.unlocker.unlock()
def set_lock_status(use_lock): def set_lock_status(use_lock):
""" """
...@@ -41,7 +41,7 @@ def set_lock_status(use_lock): ...@@ -41,7 +41,7 @@ def set_lock_status(use_lock):
""" """
get_lock.lock_is_enabled = use_lock get_lock.lock_is_enabled = use_lock
def lock(tmp_dir, timeout = 60, min_wait = 5, max_wait = 10, verbosity = 0): def lock(tmp_dir, timeout=60, min_wait=5, max_wait=10, verbosity=0):
""" """
Obtain lock access by creating a given temporary directory (whose base will Obtain lock access by creating a given temporary directory (whose base will
be created if needed, but will not be deleted after the lock is removed). be created if needed, but will not be deleted after the lock is removed).
...@@ -62,7 +62,7 @@ def lock(tmp_dir, timeout = 60, min_wait = 5, max_wait = 10, verbosity = 0): ...@@ -62,7 +62,7 @@ def lock(tmp_dir, timeout = 60, min_wait = 5, max_wait = 10, verbosity = 0):
@type tmp_dir: string @type tmp_dir: string
@param timeout: time (in seconds) to wait before replacing an existing lock @param timeout: time (in seconds) to wait before replacing an existing lock
@type timeout: int @type timeout: int or None
@param min_wait: minimum time (in seconds) to wait before trying again to @param min_wait: minimum time (in seconds) to wait before trying again to
get the lock get the lock
...@@ -107,7 +107,8 @@ def lock(tmp_dir, timeout = 60, min_wait = 5, max_wait = 10, verbosity = 0): ...@@ -107,7 +107,8 @@ def lock(tmp_dir, timeout = 60, min_wait = 5, max_wait = 10, verbosity = 0):
if last_owner == read_owner: if last_owner == read_owner:
if timeout is not None and time.time() - time_start >= timeout: if timeout is not None and time.time() - time_start >= timeout:
# Timeout exceeded. # Timeout exceeded.
break get_lock.unlocker.unlock()
continue
else: else:
last_owner = read_owner last_owner = read_owner
time_start = time.time() time_start = time.time()
...@@ -148,17 +149,34 @@ def lock(tmp_dir, timeout = 60, min_wait = 5, max_wait = 10, verbosity = 0): ...@@ -148,17 +149,34 @@ def lock(tmp_dir, timeout = 60, min_wait = 5, max_wait = 10, verbosity = 0):
raise raise
continue continue
def unlock(tmp_dir): class Unlocker():
""" """
Remove current lock. Class wrapper around release mechanism so that the lock is automatically
This function assumes we have obtained the lock using lock(tmp_dir, ...), released when the program exits (even when crashing or being interrupted),
so it does not check we are the lock owner. using the __del__ class method.
@param tmp_dir: lock directory that will be removed when releasing the lock
@type tmp_dir: string
""" """
lock_file = os.path.join(tmp_dir, 'lock')
if os.path.exists(lock_file): def __init__(self, tmp_dir):
os.remove(lock_file) self.tmp_dir = tmp_dir
if os.path.exists(tmp_dir): # Keep a pointer to the 'os' module, otherwise it may not be accessible
os.rmdir(tmp_dir) # anymore in the __del__ method.
self.os = os
def __del__(self):
self.unlock()
def unlock(self):
"""
Remove current lock.
This function does not crash if it is unable to properly delete the lock
file and directory. The reason is that it should be allowed for multiple
jobs running in parallel to unlock the same directory at the same time
(e.g. when reaching their timeout limit).
"""
try:
self.os.remove(self.os.path.join(self.tmp_dir, 'lock'))
self.os.rmdir(self.tmp_dir)
except:
# Assume someone else tried to unlock this directory at the same time.
pass
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论