Commit e8aa1484 authored by Sebastien Robin's avatar Sebastien Robin

added patch for zope Transaction so that it can handle _commit_prepare


git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@878 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent 789dbca9
...@@ -614,3 +614,163 @@ class ERP5TransitionDefinition (TransitionDefinition): ...@@ -614,3 +614,163 @@ class ERP5TransitionDefinition (TransitionDefinition):
lambda k: self.getWorkflow().transitions[k].trigger_type == TRIGGER_WORKFLOW_METHOD, self.getWorkflow().transitions.keys()) lambda k: self.getWorkflow().transitions[k].trigger_type == TRIGGER_WORKFLOW_METHOD, self.getWorkflow().transitions.keys())
TransitionDefinition.getAvailableScriptIds = ERP5TransitionDefinition.getAvailableScriptIds TransitionDefinition.getAvailableScriptIds = ERP5TransitionDefinition.getAvailableScriptIds
##############################################################################
# Adding commit_prepare to the zodb transaction
from ZODB import Transaction
#class ERP5Transaction(Transaction):
hosed = Transaction.hosed
free_transaction = Transaction.free_transaction
jar_cmp = Transaction.jar_cmp
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
if (objects or subjars) and hosed:
# Something really bad happened and we don't
# trust the system state.
raise POSException.TransactionError, hosed_msg
# 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
# Do prepare until number of jars is stable - this could
# create infinite loop
jars_len = -1
jars = self._get_jars(objects, subtransaction)
while len(jars) != jars_len:
jars_len = len(jars)
self._commit_prepare(jars, subjars, subtransaction)
jars = self._get_jars(objects, subtransaction)
try:
# 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)
# 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:
try:
jar.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.
jar.tpc_prepare(self)
except AttributeError:
# Assume that KeyError means that tpc_prepare
# not available
pass
else:
# Merge in all the jars used by one of the subtransactions.
# When the top-level subtransaction commits, the tm must
# call commit_sub() for each jar involved in one of the
# subtransactions. The commit_sub() method should call
# tpc_begin() on the storage object.
# It must also call tpc_begin() on jars that were used in
# a subtransaction but don't support subtransactions.
# These operations must be performed on the jars in order.
# Modify jars inplace to include the subjars, too.
jars += subjars
jars.sort(jar_cmp)
# assume that subjars is small, so that it's cheaper to test
# whether jar in subjars than to make a dict and do has_key.
for jar in jars:
#if jar in subjars:
# pass
#else:
try:
jar.tpc_prepare(self)
except AttributeError:
# Assume that KeyError means that tpc_prepare
# not available
pass
Transaction.Transaction.commit = commit
Transaction.Transaction._commit_prepare = _commit_prepare
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment