Skip to content

Commit

Permalink
Merge pull request #14 from NextThought/free-resources
Browse files Browse the repository at this point in the history
Free DataManagers when a transaction becomes non-current.
  • Loading branch information
jimfulton committed May 20, 2016
2 parents 3dfa2d7 + 2eb00f9 commit 86a1828
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 7 deletions.
6 changes: 6 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
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)
------------------

Expand Down
2 changes: 1 addition & 1 deletion docs/hooks.rst
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,7 @@ can be executed. We don't support execution dependencies at this level.

>>> 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

.. doctest::
Expand Down
21 changes: 15 additions & 6 deletions transaction/_transaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def _makeLogger(): #pragma NO COVER
if _LOGGER is not None:
return _LOGGER
return logging.getLogger("txn.%d" % get_thread_ident())


# The point of this is to avoid hiding exceptions (which the builtin
# hasattr() does).
Expand Down Expand Up @@ -281,8 +281,7 @@ def commit(self):
finally:
del t, v, tb
else:
if self._manager:
self._manager.free(self)
self._free()
self._synchronizers.map(lambda s: s.afterCompletion(self))
self._callAfterCommitHooks(status=True)
self.log.debug("commit")
Expand Down Expand Up @@ -434,6 +433,17 @@ def _cleanup(self, L):
self.log.error("Error in tpc_abort() on manager %s",
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):
""" See ITransaction.
"""
Expand All @@ -447,7 +457,7 @@ def abort(self):
t = None
v = None
tb = None

for rm in self._resources:
try:
rm.abort(self)
Expand All @@ -457,8 +467,7 @@ def abort(self):
self.log.error("Failed to abort resource manager: %s",
rm, exc_info=sys.exc_info())

if self._manager:
self._manager.free(self)
self._free()

self._synchronizers.map(lambda s: s.afterCompletion(self))

Expand Down
27 changes: 27 additions & 0 deletions transaction/tests/test__transaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,7 @@ def _hook2(*args, **kw):
self.assertEqual(_hooked1, [((True, 'one',), {'uno': 1})])
self.assertEqual(_hooked2, [((True,), {})])
self.assertEqual(txn._after_commit, [])
self.assertEqual(txn._resources, [])

def test_commit_error_w_afterCompleteHooks(self):
from transaction import _transaction
Expand Down Expand Up @@ -528,6 +529,17 @@ def tpc_begin(self, txn):
self.assertTrue(synch._before is txn)
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):
txn = self._makeOne()
self.assertEqual(list(txn.getBeforeCommitHooks()), [])
Expand Down Expand Up @@ -878,6 +890,7 @@ def _hook2(*args, **kw):
self.assertEqual(_hooked2, [])
self.assertEqual(list(txn.getAfterCommitHooks()),
[(_hook1, ('one',), {'uno': 1}), (_hook2, (), {})])
self.assertEqual(txn._resources, [])

def test_abort_error_w_afterCompleteHooks(self):
from transaction import _transaction
Expand Down Expand Up @@ -945,6 +958,17 @@ def abort(self, txn):
self.assertTrue(synch._before is t)
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):
txn = self._makeOne()
try:
Expand Down Expand Up @@ -1486,3 +1510,6 @@ def test_suite():
unittest.makeSuite(NoRollbackSavepointTests),
unittest.makeSuite(MiscellaneousTests),
))

if __name__ == '__main__':
unittest.main()

0 comments on commit 86a1828

Please sign in to comment.