Commit 2eb00f90 authored by Jason Madden's avatar Jason Madden

Free DataManagers when a transaction becomes non-current.

parent 3dfa2d7e
Changes Changes
======= =======
1.6.0 (TBD)
-----------
- Drop references to data managers joined to a transaction when it is
committed or aborted.
1.5.0 (2016-05-05) 1.5.0 (2016-05-05)
------------------ ------------------
......
...@@ -360,7 +360,7 @@ can be executed. We don't support execution dependencies at this level. ...@@ -360,7 +360,7 @@ can be executed. We don't support execution dependencies at this level.
>>> reset_log() >>> reset_log()
Test that the associated transaction manager has been cleanup when Test that the associated transaction manager has been cleaned up when
after commit hooks are registered after commit hooks are registered
.. doctest:: .. doctest::
......
...@@ -41,7 +41,7 @@ def _makeLogger(): #pragma NO COVER ...@@ -41,7 +41,7 @@ def _makeLogger(): #pragma NO COVER
if _LOGGER is not None: if _LOGGER is not None:
return _LOGGER return _LOGGER
return logging.getLogger("txn.%d" % get_thread_ident()) return logging.getLogger("txn.%d" % get_thread_ident())
# The point of this is to avoid hiding exceptions (which the builtin # The point of this is to avoid hiding exceptions (which the builtin
# hasattr() does). # hasattr() does).
...@@ -281,8 +281,7 @@ class Transaction(object): ...@@ -281,8 +281,7 @@ class Transaction(object):
finally: finally:
del t, v, tb del t, v, tb
else: else:
if self._manager: self._free()
self._manager.free(self)
self._synchronizers.map(lambda s: s.afterCompletion(self)) self._synchronizers.map(lambda s: s.afterCompletion(self))
self._callAfterCommitHooks(status=True) self._callAfterCommitHooks(status=True)
self.log.debug("commit") self.log.debug("commit")
...@@ -434,6 +433,17 @@ class Transaction(object): ...@@ -434,6 +433,17 @@ class Transaction(object):
self.log.error("Error in tpc_abort() on manager %s", self.log.error("Error in tpc_abort() on manager %s",
rm, exc_info=sys.exc_info()) rm, exc_info=sys.exc_info())
def _free(self):
# Called when the transaction has been committed or aborted
# to break references---this transaction object will not be returned
# as the current transaction from its manager after this, and all
# IDatamanager objects joined to it will forgotten
if self._manager:
self._manager.free(self)
del self._resources[:]
def abort(self): def abort(self):
""" See ITransaction. """ See ITransaction.
""" """
...@@ -447,7 +457,7 @@ class Transaction(object): ...@@ -447,7 +457,7 @@ class Transaction(object):
t = None t = None
v = None v = None
tb = None tb = None
for rm in self._resources: for rm in self._resources:
try: try:
rm.abort(self) rm.abort(self)
...@@ -457,8 +467,7 @@ class Transaction(object): ...@@ -457,8 +467,7 @@ class Transaction(object):
self.log.error("Failed to abort resource manager: %s", self.log.error("Failed to abort resource manager: %s",
rm, exc_info=sys.exc_info()) rm, exc_info=sys.exc_info())
if self._manager: self._free()
self._manager.free(self)
self._synchronizers.map(lambda s: s.afterCompletion(self)) self._synchronizers.map(lambda s: s.afterCompletion(self))
......
...@@ -461,6 +461,7 @@ class TransactionTests(unittest.TestCase): ...@@ -461,6 +461,7 @@ class TransactionTests(unittest.TestCase):
self.assertEqual(_hooked1, [((True, 'one',), {'uno': 1})]) self.assertEqual(_hooked1, [((True, 'one',), {'uno': 1})])
self.assertEqual(_hooked2, [((True,), {})]) self.assertEqual(_hooked2, [((True,), {})])
self.assertEqual(txn._after_commit, []) self.assertEqual(txn._after_commit, [])
self.assertEqual(txn._resources, [])
def test_commit_error_w_afterCompleteHooks(self): def test_commit_error_w_afterCompleteHooks(self):
from transaction import _transaction from transaction import _transaction
...@@ -528,6 +529,17 @@ class TransactionTests(unittest.TestCase): ...@@ -528,6 +529,17 @@ class TransactionTests(unittest.TestCase):
self.assertTrue(synch._before is txn) self.assertTrue(synch._before is txn)
self.assertTrue(synch._after is txn) #called in _cleanup self.assertTrue(synch._after is txn) #called in _cleanup
def test_commit_clears_resources(self):
class DM(object):
tpc_begin = commit = tpc_finish = tpc_vote = lambda s, txn: True
dm = DM()
txn = self._makeOne()
txn.join(dm)
self.assertEqual(txn._resources, [dm])
txn.commit()
self.assertEqual(txn._resources, [])
def test_getBeforeCommitHooks_empty(self): def test_getBeforeCommitHooks_empty(self):
txn = self._makeOne() txn = self._makeOne()
self.assertEqual(list(txn.getBeforeCommitHooks()), []) self.assertEqual(list(txn.getBeforeCommitHooks()), [])
...@@ -878,6 +890,7 @@ class TransactionTests(unittest.TestCase): ...@@ -878,6 +890,7 @@ class TransactionTests(unittest.TestCase):
self.assertEqual(_hooked2, []) self.assertEqual(_hooked2, [])
self.assertEqual(list(txn.getAfterCommitHooks()), self.assertEqual(list(txn.getAfterCommitHooks()),
[(_hook1, ('one',), {'uno': 1}), (_hook2, (), {})]) [(_hook1, ('one',), {'uno': 1}), (_hook2, (), {})])
self.assertEqual(txn._resources, [])
def test_abort_error_w_afterCompleteHooks(self): def test_abort_error_w_afterCompleteHooks(self):
from transaction import _transaction from transaction import _transaction
...@@ -945,6 +958,17 @@ class TransactionTests(unittest.TestCase): ...@@ -945,6 +958,17 @@ class TransactionTests(unittest.TestCase):
self.assertTrue(synch._before is t) self.assertTrue(synch._before is t)
self.assertTrue(synch._after is t) #called in _cleanup self.assertTrue(synch._after is t) #called in _cleanup
def test_abort_clears_resources(self):
class DM(object):
abort = lambda s, txn: True
dm = DM()
txn = self._makeOne()
txn.join(dm)
self.assertEqual(txn._resources, [dm])
txn.abort()
self.assertEqual(txn._resources, [])
def test_note(self): def test_note(self):
txn = self._makeOne() txn = self._makeOne()
try: try:
...@@ -1486,3 +1510,6 @@ def test_suite(): ...@@ -1486,3 +1510,6 @@ def test_suite():
unittest.makeSuite(NoRollbackSavepointTests), unittest.makeSuite(NoRollbackSavepointTests),
unittest.makeSuite(MiscellaneousTests), unittest.makeSuite(MiscellaneousTests),
)) ))
if __name__ == '__main__':
unittest.main()
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