backup: avoid deadlock on logging during restore

When both threads and processes are used, logging module can deadlock.
Workaround this by re-initializating locks in logging module.
See https://bugs.python.org/issue6721 for details.
Revert this commit when the python issue is fixed (in the python version
used for backup restore).
This commit is contained in:
Marek Marczykowski-Górecki 2018-07-16 01:54:31 +02:00
parent 86a4f59fd4
commit a7bfc03509
No known key found for this signature in database
GPG Key ID: 063938BA42CFA724

View File

@ -248,6 +248,30 @@ def launch_scrypt(action, input_name, output_name, passphrase):
p.pty = pty p.pty = pty
return p return p
def _fix_logging_lock_after_fork():
"""
HACK:
This is running in a child process, parent might hold some lock
while fork was called (but will be released only in a parent
process). This specifically applies to a logging module and
results in a deadlock (if one is unlucky). "Fix" this by
reinitialize a lock on all registered logging handlers
just after a fork() call, until fixed upstream:
https://bugs.python.org/issue6721
"""
if not hasattr(logging, '_handlerList'):
return
# pylint: disable=protected-access
for handler_ref in logging._handlerList:
handler = handler_ref()
if handler is None:
continue
if handler.lock:
handler.lock = type(handler.lock)()
class ExtractWorker3(Process): class ExtractWorker3(Process):
'''Process for handling inner tar layer of backup archive''' '''Process for handling inner tar layer of backup archive'''
# pylint: disable=too-many-instance-attributes # pylint: disable=too-many-instance-attributes
@ -362,6 +386,7 @@ class ExtractWorker3(Process):
def run(self): def run(self):
try: try:
_fix_logging_lock_after_fork()
self.__run__() self.__run__()
except Exception: except Exception:
# Cleanup children # Cleanup children