Commit 571cb737 authored by Kirill Smelkov's avatar Kirill Smelkov

fixup! X bigfile/_file_zodb: Fix logic around ZSync usage

Don't use regular mutex to protect _zsyncReg updates as this can
deadlock because one of _zsyncReg mutators (on_zconn_dealloc) is invoked
by automatic GC that can be triggered any time.
parent 066d7203
......@@ -58,7 +58,6 @@ from cpython cimport PyCapsule_New
from ZODB.Connection import Connection as ZConnection
from ZODB.utils import u64
from wendelin.lib.zodb import zconn_at
from golang import sync as pysync
import weakref
......@@ -159,8 +158,7 @@ cdef wcfs.PyConn pywconnOf(zconn):
# back into DB pool).
#
# ZSync cares itself to stay alive as long as zconn stays alive.
_zsyncRegMu = pysync.Mutex()
_zsyncReg = {} # id(zsync) -> zsync
_zsyncReg = {} # id(zsync) -> zsync (protected by GIL)
class ZSync:
# .zconn_ref weakref[zodb.Connection]
# .wconn (py) wcfs.Connection
......@@ -178,13 +176,19 @@ class ZSync:
zconn.onResyncCallback(zsync)
# keep zsync in _zsyncReg for zsync to stay alive independently of the caller.
with _zsyncRegMu:
#
# NOTE we cannot use regular mutex to protect _zsyncReg updates because
# the other _zsyncReg mutator (on_zconn_dealloc) is invoked by
# automatic GC that can be triggered any time.
#
# on CPython dict updates are "atomic" - they happen without releasing GIL.
if 1: # = `with gil:` (GIL already held in python code)
_zsyncReg[id(zsync)] = zsync
# .zconn dealloc -> wconn.close; release zsync
def on_zconn_dealloc(zsync, _):
zsync.wconn.close()
with _zsyncRegMu:
if 1: # = `with gil:` (see note in __init__)
del _zsyncReg[id(zsync)]
# DB resyncs .zconn onto new database view.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment