[Zodb-checkins] SVN: ZODB/trunk/ merge 70049:70059 from the jinty-doom branch.

Brian Sutherland jinty at web.de
Fri Sep 8 10:55:54 EDT 2006


Log message for revision 70066:
  merge 70049:70059 from the jinty-doom branch.
  
  These are the ZODB part of the patches I posted to
  http://www.zope.org/Collectors/Zope3-dev/655 with an additional import cleanup.
  The issue was silent for over 2 weeks.
  
  Also my attempts at subscribing to zodb-dev or sending a message there
  dissapeared were doomed;)
  
  I'm fully willing to revert this if someone has an issue with it.
  
      ------------------------------------------------------------------------
      r70059 | jinty | 2006-09-08 16:26:44 +0200 (Fri, 08 Sep 2006) | 1 line
  
      Forgot the NEWS entry. Hope I did it right.
      ------------------------------------------------------------------------
      r70053 | jinty | 2006-09-08 14:43:26 +0200 (Fri, 08 Sep 2006) | 1 line
  
      Clean up wierd import dance with ZODB. This is unnecessary since the transaction module stopped being imported in ZODB/__init__.py in rev 39622.
      ------------------------------------------------------------------------
      r70051 | jinty | 2006-09-08 13:24:45 +0200 (Fri, 08 Sep 2006) | 1 line
  
      Add the ability to ask a transaction if it has been doomed i.e. isDoomed().
      ------------------------------------------------------------------------
      r70050 | jinty | 2006-09-08 13:13:06 +0200 (Fri, 08 Sep 2006) | 1 line
  
      Add the doom() function to transactions. Look at tests/doom.txt for more info.
      ------------------------------------------------------------------------
  
  
  

Changed:
  U   ZODB/trunk/NEWS.txt
  U   ZODB/trunk/src/transaction/__init__.py
  U   ZODB/trunk/src/transaction/_manager.py
  U   ZODB/trunk/src/transaction/_transaction.py
  U   ZODB/trunk/src/transaction/interfaces.py
  A   ZODB/trunk/src/transaction/tests/doom.txt
  U   ZODB/trunk/src/transaction/tests/test_transaction.py

-=-
Modified: ZODB/trunk/NEWS.txt
===================================================================
--- ZODB/trunk/NEWS.txt	2006-09-08 14:46:08 UTC (rev 70065)
+++ ZODB/trunk/NEWS.txt	2006-09-08 14:55:53 UTC (rev 70066)
@@ -1,3 +1,31 @@
+What's new on ZODB 3.8a1?
+=========================
+
+Transactions
+------------
+
+- (3.8a1) Add a doom() and isDoomed() interface to the transaction module.
+
+  First step towards the resolution of
+  http://www.zope.org/Collectors/Zope3-dev/655
+
+  A doomed transaction behaves exactly the same way as an active transaction
+  but raises an error on any attempt to commit it, thus forcing an abort.
+
+  Doom is useful in places where abort is unsafe and an exception cannot be
+  raised.  This occurs when the programmer wants the code following the doom to
+  run but not commit. It is unsafe to abort in these circumstances as a
+  following get() may implicitly open a new transaction.
+
+  Any attempt to commit a doomed transaction will raise a DoomedTransaction
+  exception.
+
+- (3.8a1) Clean up the ZODB imports in transaction.
+
+  Clean up weird import dance with ZODB. This is unnecessary since the
+  transaction module stopped being imported in ZODB/__init__.py in rev 39622.
+
+
 What's new on ZODB 3.7b2?
 =========================
 

Modified: ZODB/trunk/src/transaction/__init__.py
===================================================================
--- ZODB/trunk/src/transaction/__init__.py	2006-09-08 14:46:08 UTC (rev 70065)
+++ ZODB/trunk/src/transaction/__init__.py	2006-09-08 14:55:53 UTC (rev 70066)
@@ -24,4 +24,6 @@
 begin = manager.begin
 commit = manager.commit
 abort = manager.abort
+doom = manager.doom
+isDoomed = manager.isDoomed
 savepoint = manager.savepoint

Modified: ZODB/trunk/src/transaction/_manager.py
===================================================================
--- ZODB/trunk/src/transaction/_manager.py	2006-09-08 14:46:08 UTC (rev 70065)
+++ ZODB/trunk/src/transaction/_manager.py	2006-09-08 14:55:53 UTC (rev 70066)
@@ -19,9 +19,11 @@
 
 import thread
 
+from ZODB.utils import WeakSet, deprecated37
+
 from transaction._transaction import Transaction
 
-# Used for deprecated arguments.  ZODB.utils.DEPRECATED_ARGUMENT is
+# Used for deprecated arguments.  ZODB.utils.DEPRECATED_ARGUMENT was
 # too hard to use here, due to the convoluted import dance across
 # __init__.py files.
 _marker = object()
@@ -34,8 +36,6 @@
 # alive (e.g., the cache, and everything reachable from it too).
 # Therefore we use "weak sets" internally.
 #
-# Obscure:  because of the __init__.py maze, we can't import WeakSet
-# at top level here.
 
 # Call the ISynchronizer newTransaction() method on every element of
 # WeakSet synchs.
@@ -58,8 +58,6 @@
 class TransactionManager(object):
 
     def __init__(self):
-        from ZODB.utils import WeakSet
-
         self._txn = None
         self._synchs = WeakSet()
 
@@ -85,11 +83,16 @@
     def unregisterSynch(self, synch):
         self._synchs.remove(synch)
 
+    def isDoomed(self):
+        return self.get().isDoomed()
+
+    def doom(self):
+        return self.get().doom()
+
     def commit(self, sub=_marker):
         if sub is _marker:
             sub = None
         else:
-            from ZODB.utils import deprecated37
             deprecated37("subtransactions are deprecated; use "
                          "transaction.savepoint() instead of "
                          "transaction.commit(1)")
@@ -99,7 +102,6 @@
         if sub is _marker:
             sub = None
         else:
-            from ZODB.utils import deprecated37
             deprecated37("subtransactions are deprecated; use "
                          "sp.rollback() instead of "
                          "transaction.abort(1), where `sp` is the "
@@ -132,7 +134,6 @@
 
         synchs = self._synchs.get(tid)
         if synchs is None:
-            from ZODB.utils import WeakSet
             synchs = self._synchs[tid] = WeakSet()
 
         txn = self._txns[tid] = Transaction(synchs, self)
@@ -145,7 +146,6 @@
         if txn is None:
             synchs = self._synchs.get(tid)
             if synchs is None:
-                from ZODB.utils import WeakSet
                 synchs = self._synchs[tid] = WeakSet()
             txn = self._txns[tid] = Transaction(synchs, self)
         return txn
@@ -159,7 +159,6 @@
         tid = thread.get_ident()
         ws = self._synchs.get(tid)
         if ws is None:
-            from ZODB.utils import WeakSet
             ws = self._synchs[tid] = WeakSet()
         ws.add(synch)
 

Modified: ZODB/trunk/src/transaction/_transaction.py
===================================================================
--- ZODB/trunk/src/transaction/_transaction.py	2006-09-08 14:46:08 UTC (rev 70065)
+++ ZODB/trunk/src/transaction/_transaction.py	2006-09-08 14:55:53 UTC (rev 70066)
@@ -169,16 +169,14 @@
 from cStringIO import StringIO
 
 from zope import interface
+from ZODB.utils import WeakSet
+from ZODB.utils import deprecated37, deprecated38
+from ZODB.POSException import TransactionFailedError
+from ZODB.utils import oid_repr
+
+
 from transaction import interfaces
 
-# Sigh.  In the maze of __init__.py's, ZODB.__init__.py takes 'get'
-# out of transaction.__init__.py, in order to stuff the 'get_transaction'
-# alias in __builtin__.  So here in _transaction.py, we can't import
-# exceptions from ZODB.POSException at top level (we're imported by
-# our __init__.py, which is imported by ZODB's __init__, so the ZODB
-# package isn't well-formed when we're first imported).
-# from ZODB.POSException import TransactionError, TransactionFailedError
-
 _marker = object()
 
 # The point of this is to avoid hiding exceptions (which the builtin
@@ -193,6 +191,8 @@
     COMMITTING   = "Committing"
     COMMITTED    = "Committed"
 
+    DOOMED = "Doomed"
+
     # commit() or commit(True) raised an exception.  All further attempts
     # to commit or join this transaction will raise TransactionFailedError.
     COMMITFAILED = "Commit failed"
@@ -227,7 +227,6 @@
 
         # Weak set of synchronizer objects to call.
         if synchronizers is None:
-            from ZODB.utils import WeakSet
             synchronizers = WeakSet()
         self._synchronizers = synchronizers
 
@@ -258,11 +257,21 @@
         # List of (hook, args, kws) tuples added by addAfterCommitHook().
         self._after_commit = []
 
+    def isDoomed(self):
+        return self.status is Status.DOOMED
+
+    def doom(self):
+        if self.status is not Status.DOOMED:
+            if self.status is not Status.ACTIVE:
+                # should not doom transactions in the middle,
+                # or after, a commit
+                raise AssertionError()
+            self.status = Status.DOOMED
+
     # Raise TransactionFailedError, due to commit()/join()/register()
     # getting called when the current transaction has already suffered
     # a commit/savepoint failure.
     def _prior_operation_failed(self):
-        from ZODB.POSException import TransactionFailedError
         assert self._failure_traceback is not None
         raise TransactionFailedError("An operation previously failed, "
                 "with traceback:\n\n%s" %
@@ -272,11 +281,12 @@
         if self.status is Status.COMMITFAILED:
             self._prior_operation_failed() # doesn't return
 
-        if self.status is not Status.ACTIVE:
+        if (self.status is not Status.ACTIVE and
+                self.status is not Status.DOOMED):
             # TODO: Should it be possible to join a committing transaction?
             # I think some users want it.
-            raise ValueError("expected txn status %r, but it's %r" % (
-                             Status.ACTIVE, self.status))
+            raise ValueError("expected txn status %r or %r, but it's %r" % (
+                             Status.ACTIVE, Status.DOOMED, self.status))
         # TODO: the prepare check is a bit of a hack, perhaps it would
         # be better to use interfaces.  If this is a ZODB4-style
         # resource manager, it needs to be adapted, too.
@@ -363,10 +373,12 @@
             adapter.objects.append(obj)
 
     def commit(self, subtransaction=_marker, deprecation_wng=True):
+        if self.status is Status.DOOMED:
+            raise interfaces.DoomedTransaction()
+
         if subtransaction is _marker:
             subtransaction = 0
         elif deprecation_wng:
-            from ZODB.utils import deprecated37
             deprecated37("subtransactions are deprecated; instead of "
                          "transaction.commit(1), use "
                          "transaction.savepoint(optimistic=True) in "
@@ -431,7 +443,6 @@
         self._before_commit.append((hook, tuple(args), kws))
 
     def beforeCommitHook(self, hook, *args, **kws):
-        from ZODB.utils import deprecated38
 
         deprecated38("Use addBeforeCommitHook instead of beforeCommitHook.")
         self.addBeforeCommitHook(hook, args, kws)
@@ -539,7 +550,6 @@
         if subtransaction is _marker:
             subtransaction = 0
         elif deprecation_wng:
-            from ZODB.utils import deprecated37
             deprecated37("subtransactions are deprecated; use "
                          "sp.rollback() instead of "
                          "transaction.abort(1), where `sp` is the "
@@ -659,8 +669,6 @@
     This function does not raise an exception.
     """
 
-    from ZODB.utils import oid_repr
-
     # We should always be able to get __class__.
     klass = o.__class__.__name__
     # oid would be great, but may this isn't a persistent object.

Modified: ZODB/trunk/src/transaction/interfaces.py
===================================================================
--- ZODB/trunk/src/transaction/interfaces.py	2006-09-08 14:46:08 UTC (rev 70065)
+++ ZODB/trunk/src/transaction/interfaces.py	2006-09-08 14:55:53 UTC (rev 70066)
@@ -45,6 +45,14 @@
         """Abort the current transaction.
         """
 
+    def doom():
+        """Doom the current transaction.
+        """
+
+    def isDoomed():
+        """Returns True if the current transaction is doomed, otherwise False.
+        """
+
     def savepoint(optimistic=False):
         """Create a savepoint from the current transaction.
 
@@ -115,7 +123,17 @@
         This is called from the application.  This can only be called
         before the two-phase commit protocol has been started.
         """
+    
+    def doom():
+        """Doom the transaction.
 
+        Dooms the current transaction. This will cause
+        DoomedTransactionException to be raised on any attempt to commit the
+        transaction.
+
+        Otherwise the transaction will behave as if it was active.
+        """
+
     def savepoint(optimistic=False):
         """Create a savepoint.
 
@@ -453,3 +471,6 @@
         This hook is called when, and only when, a transaction manager's
         begin() method is called explictly.
         """
+
+class DoomedTransaction(Exception):
+    """A commit was attempted on a transaction that was doomed."""

Copied: ZODB/trunk/src/transaction/tests/doom.txt (from rev 70065, ZODB/branches/jinty-doom/src/transaction/tests/doom.txt)

Modified: ZODB/trunk/src/transaction/tests/test_transaction.py
===================================================================
--- ZODB/trunk/src/transaction/tests/test_transaction.py	2006-09-08 14:46:08 UTC (rev 70065)
+++ ZODB/trunk/src/transaction/tests/test_transaction.py	2006-09-08 14:55:53 UTC (rev 70066)
@@ -992,8 +992,9 @@
     """
 
 def test_suite():
-    from zope.testing.doctest import DocTestSuite
+    from zope.testing.doctest import DocTestSuite, DocFileSuite
     return unittest.TestSuite((
+        DocFileSuite('doom.txt'),
         DocTestSuite(),
         unittest.makeSuite(TransactionTests),
         ))



More information about the Zodb-checkins mailing list