[ZODB-Dev] ZODB3, DataManagerAdapter and sortKey
Sidnei da Silva
sidnei at awkly.org
Tue Jun 22 17:57:55 EDT 2004
While using zope.app.rdb connections in zope3, the connection gets
registered with the transaction manager I think, and at some point
ZopeDBTransactionManager gets wrapped into a DataManagerAdapter. Upon
the transaction commit, the resource managers are sorted, including a
DataManagerAdapter which is adapting a ZopeDBTransactionManager.
DataManagerAdapter doesn't have a sortKey method, so it fails with an
AttributeError.
The IDataManager interface doesn't have a sortKey method either.
What is the right thing to do here? I've made some changes to get it
to run, including a test to reproduce the behavior
but I'm not quite sure about the right thing to do here.
Anybody cares to clarify the issue here?
I attached a patch with the changes I've did to get it to run.
--
Sidnei da Silva <sidnei at awkly.org>
http://awkly.org - dreamcatching :: making your dreams come true
http://www.enfoldsystems.com
http://plone.org/about/team#dreamcatcher
"It runs like _x, where _x is something unsavory"
-- Prof. Romas Aleliunas, CS 435
-------------- next part --------------
Index: src/transaction/_transaction.py
===================================================================
--- src/transaction/_transaction.py (revision 25925)
+++ src/transaction/_transaction.py (working copy)
@@ -580,3 +580,7 @@
def tpc_vote(self, transaction):
if not self._sub:
self._datamanager.prepare(transaction)
+
+ def sortKey(self):
+ return self._datamanager.sortKey()
+
Index: src/zope/app/rdb/tests/test_zopedbtransactionmanager.py
===================================================================
--- src/zope/app/rdb/tests/test_zopedbtransactionmanager.py (revision 25925)
+++ src/zope/app/rdb/tests/test_zopedbtransactionmanager.py (working copy)
@@ -43,11 +43,44 @@
get_transaction().commit()
self.assertEqual(self.conn._called.get('commit'), 1)
+
+class TwoTxnMgrSortKeyTest(TestCase):
+
+ # We test two transaction managers here so that when calling
+ # commit or abort it triggers the code that calls sortKey()
+
+ def setUp(self):
+ self.conn1 = ConnectionStub()
+ self.conn2 = ConnectionStub()
+ zc1 = ZopeConnection(self.conn1, TypeInfoStub())
+ self.datamgr1 = ZopeDBTransactionManager(zc1)
+ zc2 = ZopeConnection(self.conn2, TypeInfoStub())
+ self.datamgr1 = ZopeDBTransactionManager(zc2)
+ zc1.registerForTxn()
+ zc2.registerForTxn()
+ self.txn_factory = get_transaction
+
+ def tearDown(self):
+ """ make sure the global env is clean"""
+ get_transaction().abort()
+
+ def test_abort(self):
+ get_transaction().abort()
+ self.assertEqual(self.conn1._called.get('rollback'), 1)
+ self.assertEqual(self.conn2._called.get('rollback'), 1)
+
+ def test_commit(self):
+ get_transaction().commit()
+ self.assertEqual(self.conn1._called.get('commit'), 1)
+ self.assertEqual(self.conn2._called.get('commit'), 1)
+
+
def test_suite():
from doctest import DocTestSuite
return TestSuite((
DocTestSuite('zope.app.rdb'),
makeSuite(TxnMgrTest),
+ makeSuite(TwoTxnMgrTest),
))
if __name__=='__main__':
Index: src/zope/app/rdb/__init__.py
===================================================================
--- src/zope/app/rdb/__init__.py (revision 25925)
+++ src/zope/app/rdb/__init__.py (working copy)
@@ -46,7 +46,7 @@
"""
Escape data suitable for inclusion in generated ANSI SQL92 code for
cases where bound variables are not suitable.
-
+
>>> sqlquote('''Hi''')
"'Hi'"
>>> sqlquote('''It's mine''')
@@ -137,7 +137,7 @@
# Note: I added the general Exception, since the DA can return
# implementation-specific errors. But we really want to catch all
# issues at this point, so that we can convert it to a
- # DatabaseException.
+ # DatabaseException.
except Exception, error:
raise DatabaseException, str(error)
@@ -389,8 +389,18 @@
"""
return NoSavepointSupportRollback(self)
-
+ def sortKey(self):
+ """
+ ZODB uses a global sort order to prevent deadlock when it commits
+ transactions involving multiple resource managers. The resource
+ manager must define a sortKey() method that provides a global ordering
+ for resource managers.
+
+ (excerpt from transaction/notes.txt)
+ """
+ return 'rdb' + str(id(self))
+
class Row(object):
"""Represents a row in a ResultSet"""
More information about the ZODB-Dev
mailing list