/usr/share/pyshared/ZODB/tests/synchronizers.txt is in python-zodb 1:3.9.7-2.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 | =============
Synchronizers
=============
Here are some tests that storage ``sync()`` methods get called at appropriate
times in the life of a transaction. The tested behavior is new in ZODB 3.4.
First define a lightweight storage with a ``sync()`` method:
>>> import ZODB
>>> from ZODB.MappingStorage import MappingStorage
>>> import transaction
>>> class SimpleStorage(MappingStorage):
... sync_called = False
...
... def sync(self, *args):
... self.sync_called = True
Make a change locally:
>>> st = SimpleStorage()
>>> db = ZODB.DB(st)
>>> cn = db.open()
>>> rt = cn.root()
>>> rt['a'] = 1
Sync should not have been called yet.
>>> st.sync_called # False before 3.4
False
``sync()`` is called by the Connection's ``afterCompletion()`` hook after the
commit completes.
>>> transaction.commit()
>>> st.sync_called # False before 3.4
True
``sync()`` is also called by the ``afterCompletion()`` hook after an abort.
>>> st.sync_called = False
>>> rt['b'] = 2
>>> transaction.abort()
>>> st.sync_called # False before 3.4
True
And ``sync()`` is called whenever we explicitly start a new transaction, via
the ``newTransaction()`` hook.
>>> st.sync_called = False
>>> dummy = transaction.begin()
>>> st.sync_called # False before 3.4
True
Clean up. Closing db isn't enough -- closing a DB doesn't close its
`Connections`. Leaving our `Connection` open here can cause the
``SimpleStorage.sync()`` method to get called later, during another test, and
our doctest-synthesized module globals no longer exist then. You get a weird
traceback then ;-)
>>> cn.close()
One more, very obscure. It was the case that if the first action a new
threaded transaction manager saw was a ``begin()`` call, then synchronizers
registered after that in the same transaction weren't communicated to the
`Transaction` object, and so the synchronizers' ``afterCompletion()`` hooks
weren't called when the transaction commited. None of the test suites
(ZODB's, Zope 2.8's, or Zope3's) caught that, but apparently Zope 3 takes this
path at some point when serving pages.
>>> tm = transaction.ThreadTransactionManager()
>>> st.sync_called = False
>>> dummy = tm.begin() # we're doing this _before_ opening a connection
>>> cn = db.open(transaction_manager=tm)
>>> rt = cn.root() # make a change
>>> rt['c'] = 3
>>> st.sync_called
False
Now ensure that ``cn.afterCompletion() -> st.sync()`` gets called by commit
despite that the `Connection` registered after the transaction began:
>>> tm.commit()
>>> st.sync_called
True
And try the same thing with a non-threaded transaction manager:
>>> cn.close()
>>> tm = transaction.TransactionManager()
>>> st.sync_called = False
>>> dummy = tm.begin() # we're doing this _before_ opening a connection
>>> cn = db.open(transaction_manager=tm)
>>> rt = cn.root() # make a change
>>> rt['d'] = 4
>>> st.sync_called
False
>>> tm.commit()
>>> st.sync_called
True
>>> cn.close()
>>> db.close()
|