提交 ee4f2a97 authored 作者: Frederic Bastien's avatar Frederic Bastien

Don't take the lock by unless needed at exit

上级 54186290
...@@ -1299,13 +1299,17 @@ class ModuleCache(object): ...@@ -1299,13 +1299,17 @@ class ModuleCache(object):
else: else:
age_thresh_use = None age_thresh_use = None
too_old_to_use = self.refresh(
age_thresh_use=age_thresh_use,
delete_if_problem=delete_if_problem,
# The clean up is done at init, no need to trigger it again
cleanup=False)
if not too_old_to_use:
return
with compilelock.lock_ctx(): with compilelock.lock_ctx():
# Update the age of modules that have been accessed by other # Update the age of modules that have been accessed by other
# processes and get all module that are too old to use # processes and get all module that are too old to use
# (not loaded in self.entry_from_key). # (not loaded in self.entry_from_key).
too_old_to_use = self.refresh(
age_thresh_use=age_thresh_use,
delete_if_problem=delete_if_problem)
for entry in too_old_to_use: for entry in too_old_to_use:
# TODO: we are assuming that modules that haven't been # TODO: we are assuming that modules that haven't been
...@@ -1392,86 +1396,101 @@ class ModuleCache(object): ...@@ -1392,86 +1396,101 @@ class ModuleCache(object):
if min_age is None: if min_age is None:
min_age = self.age_thresh_del_unversioned min_age = self.age_thresh_del_unversioned
with compilelock.lock_ctx(): # As this delete object that we build and other don't use, we
all_key_datas = list(self.module_hash_to_key_data.values()) # don't need the lock.
for key_data in all_key_datas: all_key_datas = list(self.module_hash_to_key_data.values())
if not key_data.keys: for key_data in all_key_datas:
# May happen for broken versioned keys. if not key_data.keys:
continue # May happen for broken versioned keys.
for key_idx, key in enumerate(key_data.keys): continue
version, rest = key for key_idx, key in enumerate(key_data.keys):
if version: version, rest = key
# Since the version is included in the module hash, if version:
# it should not be possible to mix versioned and # Since the version is included in the module hash,
# unversioned keys in the same KeyData object. # it should not be possible to mix versioned and
assert key_idx == 0 # unversioned keys in the same KeyData object.
break assert key_idx == 0
if not version: break
# Note that unversioned keys cannot be broken, so we can if not version:
# set do_manual_check to False to speed things up. # Note that unversioned keys cannot be broken, so we can
key_data.delete_keys_from(self.entry_from_key, # set do_manual_check to False to speed things up.
do_manual_check=False) key_data.delete_keys_from(self.entry_from_key,
entry = key_data.get_entry() do_manual_check=False)
# Entry is guaranteed to be in this dictionary, because entry = key_data.get_entry()
# an unversioned entry should never have been loaded via # Entry is guaranteed to be in this dictionary, because
# refresh. # an unversioned entry should never have been loaded via
assert entry in self.module_from_name # refresh.
assert entry in self.module_from_name
del self.module_from_name[entry]
del self.module_hash_to_key_data[key_data.module_hash] del self.module_from_name[entry]
del self.module_hash_to_key_data[key_data.module_hash]
parent = os.path.dirname(entry) parent = os.path.dirname(entry)
assert parent.startswith(os.path.join(self.dirname, 'tmp')) assert parent.startswith(os.path.join(self.dirname, 'tmp'))
_rmtree(parent, msg='unversioned', level=logging.INFO, _rmtree(parent, msg='unversioned', level=logging.INFO,
ignore_nocleanup=True) ignore_nocleanup=True)
# Sanity check: all unversioned keys should have been removed at # Sanity check: all unversioned keys should have been removed at
# this point. # this point.
for key in self.entry_from_key: for key in self.entry_from_key:
assert key[0] assert key[0]
time_now = time.time() to_del = []
for filename in os.listdir(self.dirname): time_now = time.time()
if filename.startswith('tmp'): for filename in os.listdir(self.dirname):
try: if filename.startswith('tmp'):
open(os.path.join(self.dirname, filename, 'key.pkl') try:
).close() open(os.path.join(self.dirname, filename, 'key.pkl')
has_key = True ).close()
except IOError: has_key = True
has_key = False except IOError:
if not has_key: has_key = False
# Use the compiled file by default if not has_key:
path = module_name_from_dir(os.path.join(self.dirname, # Use the compiled file by default
filename), path = module_name_from_dir(os.path.join(self.dirname,
False) filename),
# If it don't exist, use any file in the directory. False)
if path is None: # If it don't exist, use any file in the directory.
path = os.path.join(self.dirname, filename) if path is None:
files = os.listdir(path) path = os.path.join(self.dirname, filename)
if files: files = os.listdir(path)
path = os.path.join(path, files[0]) if files:
else: path = os.path.join(path, files[0])
# If the directory is empty skip it. else:
# They are deleted elsewhere. # If the directory is empty skip it.
continue # They are deleted elsewhere.
age = time_now - last_access_time(path) continue
age = time_now - last_access_time(path)
# In normal case, the processus that created this
# directory will delete it. However, if this processus # In normal case, the processus that created this
# crashes, it will not be cleaned up. # directory will delete it. However, if this processus
# As we don't know if this directory is still used, # crashes, it will not be cleaned up.
# we wait one week and suppose that the processus # As we don't know if this directory is still used,
# crashed, and we take care of the clean-up. # we wait one week and suppose that the processus
if age > min_age: # crashed, and we take care of the clean-up.
_rmtree(os.path.join(self.dirname, filename), if age > min_age:
msg='old unversioned', level=logging.INFO, to_del.append(os.path.join(self.dirname, filename))
ignore_nocleanup=True)
if not to_del:
return
with compilelock.lock_ctx():
for f in to_del:
_rmtree(f,
msg='old unversioned', level=logging.INFO,
ignore_nocleanup=True)
def _on_atexit(self): def _on_atexit(self):
# Note: no need to call refresh() since it is called by clear_old(). # Note: no need to call refresh() since it is called by clear_old().
with compilelock.lock_ctx():
self.clear_old() # Note: no need to take the lock. For unversioned files, we
self.clear_unversioned() # don't need it as they aren't shared. For old unversioned
# files, this happen rarely, so we take the lock only when
# this happen.
# Note: for clear_old(), as this happen unfrequently, we only
# take the lock when it happen.
self.clear_old()
self.clear_unversioned()
_logger.debug('Time spent checking keys: %s', _logger.debug('Time spent checking keys: %s',
self.time_spent_in_check_key) self.time_spent_in_check_key)
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论