[Erp5-report] r16724 - /erp5/trunk/products/ERP5Type/patches/Transaction.py
nobody at svn.erp5.org
nobody at svn.erp5.org
Sat Sep 29 21:50:55 CEST 2007
Author: yo
Date: Sat Sep 29 21:50:54 2007
New Revision: 16724
URL: http://svn.erp5.org?rev=16724&view=rev
Log:
Backport beforeCommitHook from Zope 2.8.
Modified:
erp5/trunk/products/ERP5Type/patches/Transaction.py
Modified: erp5/trunk/products/ERP5Type/patches/Transaction.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5Type/patches/Transaction.py?rev=16724&r1=16723&r2=16724&view=diff
==============================================================================
--- erp5/trunk/products/ERP5Type/patches/Transaction.py (original)
+++ erp5/trunk/products/ERP5Type/patches/Transaction.py Sat Sep 29 21:50:54 2007
@@ -1,168 +1,54 @@
-##############################################################################
+############################################################################
#
-# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
-# Copyright (c) 2002,2005 Nexedi SARL and Contributors. All Rights Reserved.
+# Copyright (c) 2004 Zope Corporation and Contributors.
+# Copyright (c) 2002,2005,2007 Nexedi SA and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
-# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE
+# FOR A PARTICULAR PURPOSE.
#
-##############################################################################
+############################################################################
-import sys
+# Add beforeCommitHook into Transaction under Zope 2.7. This API is compatible
+# with Zope 2.8.
+try:
+ from ZODB.Transaction import Transaction
+
+ super__commit = Transaction.commit
+ super__init = Transaction.__init__
-# Adding commit_prepare to the zodb transaction
-try:
- from ZODB import Transaction, POSException
- from zLOG import LOG, ERROR
-
- hosed = Transaction.hosed
- hosed_msg = Transaction.hosed_msg
- free_transaction = Transaction.free_transaction
- jar_cmp = Transaction.jar_cmp
-
+ def __init__(self, *args, **kw):
+ super__init(self, *args, **kw)
+ self._before_commit = []
+
def commit(self, subtransaction=None):
- """Finalize the transaction."""
- objects = self._objects
-
- subjars = []
- if subtransaction:
- if self._sub is None:
- # Must store state across multiple subtransactions
- # so that the final commit can commit all subjars.
- self._sub = {}
- else:
- if self._sub is not None:
- # This commit is for a top-level transaction that
- # has previously committed subtransactions. Do
- # one last subtransaction commit to clear out the
- # current objects, then commit all the subjars.
- if objects:
- self.commit(1)
- objects = []
- subjars = self._sub.values()
- subjars.sort(jar_cmp)
- self._sub = None
-
- # If there were any non-subtransaction-aware jars
- # involved in earlier subtransaction commits, we need
- # to add them to the list of jars to commit.
- if self._non_st_objects is not None:
- objects.extend(self._non_st_objects)
- self._non_st_objects = None
+ """Finalize the transaction."""
+ if not subtransaction:
+ self._callBeforeCommitHooks()
- if (objects or subjars) and hosed:
- # Something really bad happened and we don't
- # trust the system state.
- raise POSException.TransactionError, hosed_msg
+ return super__commit(self, subtransaction=subtransaction)
+
+ def beforeCommitHook(self, hook, *args, **kws):
+ self._before_commit.append((hook, args, kws))
- # It's important that:
- #
- # - Every object in self._objects is either committed or
- # aborted.
- #
- # - For each object that is committed we call tpc_begin on
- # it's jar at least once
- #
- # - For every jar for which we've called tpc_begin on, we
- # either call tpc_abort or tpc_finish. It is OK to call
- # these multiple times, as the storage is required to ignore
- # these calls if tpc_begin has not been called.
- #
- # - That we call tpc_begin() in a globally consistent order,
- # so that concurrent transactions involving multiple storages
- # do not deadlock.
- try:
- ncommitted = 0
- jars = self._get_jars(objects, subtransaction)
- try:
- # Do prepare until number of jars is stable - this could
- # create infinite loop
- jars_len = -1
- objects_len = len(self._objects)
- while len(jars) != jars_len:
- jars_len = len(jars)
- self._commit_prepare(jars, subjars, subtransaction)
- if len(self._objects) != objects_len:
- objects.extend(self._objects[objects_len:])
- objects_len = len(self._objects)
- jars = self._get_jars(objects, subtransaction)
- # If not subtransaction, then jars will be modified.
- self._commit_begin(jars, subjars, subtransaction)
- ncommitted += self._commit_objects(objects)
- if not subtransaction:
- # Unless this is a really old jar that doesn't
- # implement tpc_vote(), it must raise an exception
- # if it can't commit the transaction.
- for jar in jars:
- try:
- vote = jar.tpc_vote
- except AttributeError:
- pass
- else:
- vote(self)
+ def _callBeforeCommitHooks(self):
+ # Call all hooks registered, allowing further registrations
+ # during processing.
+ while self._before_commit:
+ hook, args, kws = self._before_commit.pop(0)
+ hook(*args, **kws)
- # Handle multiple jars separately. If there are
- # multiple jars and one fails during the finish, we
- # mark this transaction manager as hosed.
- if len(jars) == 1:
- self._finish_one(jars[0])
- else:
- self._finish_many(jars)
- except:
- # Ugh, we got an got an error during commit, so we
- # have to clean up. First save the original exception
- # in case the cleanup process causes another
- # exception.
- error = sys.exc_info()
- try:
- self._commit_error(objects, ncommitted, jars, subjars)
- except:
- LOG('ZODB', ERROR,
- "A storage error occured during transaction "
- "abort. This shouldn't happen.",
- error=error)
- raise error[0], error[1], error[2]
- finally:
- del objects[:] # clear registered
- if not subtransaction and self._id is not None:
- free_transaction()
-
- def _commit_prepare(self, jars, subjars, subtransaction):
- if subtransaction:
- assert not subjars
- for jar in jars:
- tpc_prepare = getattr(jar, 'tpc_prepare', None)
- if tpc_prepare is not None:
- try:
- tpc_prepare(self, subtransaction)
- except TypeError:
- # Assume that TypeError means that tpc_begin() only
- # takes one argument, and that the jar doesn't
- # support subtransactions.
- tpc_prepare(self)
- else:
- # Perform tpc_prepare for both jars and subjars.
- # Note that it must not be executed for the same jar
- # more than once. Also, this should not merge the jars
- # in place, as _commit_begin will do that.
- for jar in subjars:
- tpc_prepare = getattr(jar, 'tpc_prepare', None)
- if tpc_prepare is not None:
- tpc_prepare(self)
-
- for jar in jars:
- if jar not in subjars:
- tpc_prepare = getattr(jar, 'tpc_prepare', None)
- if tpc_prepare is not None:
- tpc_prepare(self)
-
- Transaction.Transaction.commit = commit
- Transaction.Transaction._commit_prepare = _commit_prepare
+ from new import instancemethod
+ Transaction.__init__ = instancemethod(__init__, None, Transaction)
+ Transaction.commit = instancemethod(commit, None, Transaction)
+ Transaction.beforeCommitHook = instancemethod(beforeCommitHook, None,
+ Transaction)
+ Transaction._callBeforeCommitHooks = instancemethod(_callBeforeCommitHooks,
+ None, Transaction)
except ImportError:
- # On Zope 2.8, do not patch Transaction. Instead, we use a before commit hook.
+ # On Zope 2.8, do not patch Transaction.
pass
More information about the Erp5-report
mailing list