[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