[CalendarServer-changes] [8103] CalendarServer/trunk/twext/enterprise

source_changes at macosforge.org source_changes at macosforge.org
Thu Sep 15 10:31:34 PDT 2011


Revision: 8103
          http://trac.macosforge.org/projects/calendarserver/changeset/8103
Author:   glyph at apple.com
Date:     2011-09-15 10:31:31 -0700 (Thu, 15 Sep 2011)
Log Message:
-----------
Don't bother to execute commit() or rollback() if the connection has not been used at all by the transaction; just re-pool it and let the existing connection management logic take over.

Modified Paths:
--------------
    CalendarServer/trunk/twext/enterprise/adbapi2.py
    CalendarServer/trunk/twext/enterprise/test/test_adbapi2.py

Modified: CalendarServer/trunk/twext/enterprise/adbapi2.py
===================================================================
--- CalendarServer/trunk/twext/enterprise/adbapi2.py	2011-09-14 23:21:13 UTC (rev 8102)
+++ CalendarServer/trunk/twext/enterprise/adbapi2.py	2011-09-15 17:31:31 UTC (rev 8103)
@@ -187,7 +187,7 @@
                 Do the database work and set appropriate flags.  Executed in the
                 cursor thread.
                 """
-                if self._cursor is None:
+                if self._cursor is None or self._first:
                     return
                 really()
                 self._first = True

Modified: CalendarServer/trunk/twext/enterprise/test/test_adbapi2.py
===================================================================
--- CalendarServer/trunk/twext/enterprise/test/test_adbapi2.py	2011-09-14 23:21:13 UTC (rev 8102)
+++ CalendarServer/trunk/twext/enterprise/test/test_adbapi2.py	2011-09-15 17:31:31 UTC (rev 8103)
@@ -719,6 +719,11 @@
         txns = []
         txns.append(self.pool.connection())
         txns.append(self.pool.connection())
+        for txn in txns:
+            # Make sure rollback will actually be executed.
+            results = resultOf(txn.execSQL("maybe change something!"))
+            [[[counter, echo]]] = results
+            self.assertEquals("maybe change something!", echo)
         # Fail one (and only one) call to rollback().
         self.factory.rollbackFail = True
         stopResult = resultOf(self.pool.stopService())
@@ -877,6 +882,57 @@
         self.assertEquals(self.factory.connections[1].closed, False)
 
 
+    def test_reConnectWhenFirstExecOnExistingConnectionFails(self):
+        """
+        Another situation that might arise is that a connection will be
+        successfully connected, executed and recycled into the connection pool;
+        then, the database server will shut down and the connections will die,
+        but we will be none the wiser until we try to use them.
+        """
+        txn = self.pool.connection()
+        self.assertEquals(len(self.factory.connections), 1,
+                          "Sanity check failed.")
+        results = resultOf(txn.execSQL("hello, world!"))
+        txn.commit()
+        [[[counter, echo]]] = results
+        self.assertEquals("hello, world!", echo)
+        txn2 = self.pool.connection()
+        self.assertEquals(len(self.factory.connections), 1,
+                          "Sanity check failed.")
+        self.factory.connections[0].executeWillFail(RuntimeError)
+        results = resultOf(txn2.execSQL("second try!"))
+        txn2.commit()
+        [[[counter, echo]]] = results
+        self.assertEquals("second try!", echo)
+
+
+    def test_noOpCommitDoesntHinderReconnection(self):
+        """
+        Until you've executed a query or performed a statement on an ADBAPI
+        connection, the connection is semantically idle (between transactions).
+        A .commit() or .rollback() followed immediately by a .commit() is
+        therefore pointless, and can be ignored.  Furthermore, actually
+        executing the commit and propagating a possible connection-oriented
+        error causes clients to see errors, when, if those clients had actually
+        executed any statements, the connection would have been recycled and the
+        statement transparently re-executed by the logic tested by
+        L{test_reConnectWhenFirstExecFails}.
+        """
+        txn = self.pool.connection()
+        self.factory.commitFail = True
+        self.factory.rollbackFail = True
+        [x] = resultOf(txn.commit())
+
+        # No statements have been executed, so 'commit' will *not* be executed.
+        self.assertEquals(self.factory.commitFail, True)
+        self.assertIdentical(x, None)
+        self.assertEquals(len(self.pool._free), 1)
+        self.assertIn(txn._baseTxn, self.pool._free)
+        self.assertEquals(self.pool._finishing, [])
+        self.assertEquals(len(self.factory.connections), 1)
+        self.assertEquals(self.factory.connections[0].closed, False)
+
+
     def test_reConnectWhenSecondExecFailsThenFirstExecFails(self):
         """
         Other connection-oriented errors might raise exceptions if they occur in
@@ -921,6 +977,9 @@
         size the same.
         """
         txn = self.pool.connection()
+        results = resultOf(txn.execSQL("maybe change something!"))
+        [[[counter, echo]]] = results
+        self.assertEquals("maybe change something!", echo)
         self.factory.rollbackFail = True
         [x] = resultOf(txn.abort())
         # Abort does not propagate the error on, the transaction merely gets
@@ -944,6 +1003,9 @@
         """
         txn = self.pool.connection()
         self.factory.commitFail = True
+        results = resultOf(txn.execSQL("maybe change something!"))
+        [[[counter, echo]]] = results
+        self.assertEquals("maybe change something!", echo)
         [x] = resultOf(txn.commit())
         x.trap(CommitFail)
         self.assertEquals(len(self.pool._free), 1)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20110915/26cd1de0/attachment.html>


More information about the calendarserver-changes mailing list