Commit 959ae2d0 authored by Kirill Smelkov's avatar Kirill Smelkov

lib/zodb: Add patch to ZODB.Connection to support callback on connection DB view change

Wendelin.core 2 will need to hook into when client ZODB.Connection
changes its database view and readjust WCFS-level client connection
accordingly.

ZODB.Connection can change its view on either connection reopen, or even
without reopen on start of new transaction.

This patch implements ZODB.Connection.onResyncCallback for ZODB5 only.

ZODB4 and ZODB3 support is TODO.
parent 3bd82127
...@@ -306,6 +306,51 @@ def test_zconn_at(): ...@@ -306,6 +306,51 @@ def test_zconn_at():
assert zconn_at(conn_at0) == at0 assert zconn_at(conn_at0) == at0
# verify that ZODB.Connection.onResyncCallback works
@xfail(zmajor < 5, reason="ZODB.Connection.onResyncCallback is TODO for ZODB4 and ZODB3")
@func
def test_zodb_onresync():
stor = testdb.getZODBStorage()
defer(stor.close)
db = DB(stor)
class T:
def __init__(t):
t.nresync = 0
def on_connection_resync(t):
t.nresync += 1
t = T()
conn = db.open()
conn.onResyncCallback(t)
assert t.nresync == 0
# abort makes conn to enter new transaction
transaction.abort()
assert t.nresync == 1
# close/reopen -> new transaction
conn.close()
assert t.nresync == 1
conn_ = db.open()
assert conn_ is conn
assert t.nresync == 2
# commit -> new transaction
root = conn.root()
root['r'] = 1
assert t.nresync == 2
transaction.commit()
assert t.nresync == 3
transaction.commit()
assert t.nresync == 4
transaction.commit()
assert t.nresync == 5
conn.close()
# ---- misc ---- # ---- misc ----
# zsync syncs ZODB storage. # zsync syncs ZODB storage.
......
...@@ -259,3 +259,43 @@ def Connection_open(self, transaction_manager=None, delegate=True): ...@@ -259,3 +259,43 @@ def Connection_open(self, transaction_manager=None, delegate=True):
f.on_connection_open() f.on_connection_open()
ZODB.Connection.Connection.open = Connection_open ZODB.Connection.Connection.open = Connection_open
# patch for ZODB.Connection to support callback on after database view is changed
ZODB.Connection.Connection._onResyncCallbacks = None
def Connection_onResyncCallback(self, f):
if zmajor <= 4:
raise AssertionError("onResyncCallback: TODO: add support for ZODB34")
if self._onResyncCallbacks is None:
# NOTE WeakSet does not work for bound methods - they are always created
# anew for each obj.method access, and thus will go away almost immediately
self._onResyncCallbacks = WeakSet()
self._onResyncCallbacks.add(f)
assert not hasattr(ZODB.Connection.Connection, 'onResyncCallback')
ZODB.Connection.Connection.onResyncCallback = Connection_onResyncCallback
# ZODB5: hook into Connection.newTransaction
if zmajor >= 5:
_orig_Connection_newTransaction = ZODB.Connection.Connection.newTransaction
def _ZConnection_newTransaction(self, transaction, sync=True):
_orig_Connection_newTransaction(self, transaction, sync)
# FIXME method name hardcoded. Better not do it and allow f to be general
# callable, but that does not work with bound method - see above.
# ( Something like WeakMethod from py3 could help )
if self._onResyncCallbacks:
for f in self._onResyncCallbacks:
f.on_connection_resync()
ZODB.Connection.Connection.newTransaction = _ZConnection_newTransaction
# ZODB4: hook into Connection._storage_sync
elif zmajor == 4:
pass # raises in onResyncCallback
# ZODB3: TODO
else:
pass # raises in onResyncCallback
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