Skip to content

Commit

Permalink
Merge pull request #226 from zopefoundation/sunew-failing-test-for-208
Browse files Browse the repository at this point in the history
Fix KeyError on releasing resources of a Connection when closing the DB.
  • Loading branch information
Michael Howitz committed Oct 25, 2018
2 parents dd92b75 + bf34467 commit 04ba442
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 3 deletions.
5 changes: 4 additions & 1 deletion CHANGES.rst
Expand Up @@ -5,7 +5,10 @@
5.5.1 (unreleased)
==================

- TBD
- Fix KeyError on releasing resources of a Connection when closing the DB.
This requires at least version 2.4 of the `transaction` package.
See `issue 208 <https://github.com/zopefoundation/ZODB/issues/208>`.


5.5.0 (2018-10-13)
==================
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Expand Up @@ -72,7 +72,7 @@ def read(path):
'persistent >= 4.4.0',
'BTrees >= 4.2.0',
'ZConfig',
'transaction >= 2.0.3',
'transaction >= 2.4',
'six',
'zc.lockfile',
'zope.interface',
Expand Down
5 changes: 4 additions & 1 deletion src/ZODB/Connection.py
Expand Up @@ -884,7 +884,10 @@ def open(self, transaction_manager=None, delegate=True):
"""

if transaction_manager is None:
transaction_manager = transaction.manager
# The .manager bit below unwraps the threaded
# manager so we can call unregisterSynch in close
# when close is called from another thread.
transaction_manager = transaction.manager.manager

self.transaction_manager = transaction_manager

Expand Down
55 changes: 55 additions & 0 deletions src/ZODB/tests/testThreadedShutdown.py
@@ -0,0 +1,55 @@
import threading
import time
import unittest

import ZODB


class ZODBClientThread(threading.Thread):

def __init__(self, db, test):
threading.Thread.__init__(self)
self._exc_info = None
self.setDaemon(True)
self.db = db
self.test = test
self.event = threading.Event()

def run(self):
conn = self.db.open()
conn.sync()
self.event.set()
time.sleep(15)

# conn.close calls self.transaction_manager.unregisterSynch(self)
# and this succeeds.
conn.close()


class ShutdownTest(ZODB.tests.util.TestCase):

def setUp(self):
# Our default transaction manager is
# transaction._manager.ThreadTransactionManager
# so no need to set it.
ZODB.tests.util.TestCase.setUp(self)
self._storage = ZODB.FileStorage.FileStorage(
'ZODBTests.fs', create=1)
self._db = ZODB.DB(self._storage)

def check_shutdown(self):
client_thread = ZODBClientThread(self._db, self)
client_thread.start()
client_thread.event.wait()
# calls conn._release_resources, that calls conn.close(),
# that calls conn.transaction_manager.unregisterSynch(self),
# but from a different thread, so transaction_manager._synchs
# have different contents.
self._db.close()

def tearDown(self):
ZODB.tests.util.TestCase.tearDown(self)


def test_suite():
return unittest.makeSuite(ShutdownTest, "check")

0 comments on commit 04ba442

Please sign in to comment.