Commit 0016a36e authored by Jeremy Hylton's avatar Jeremy Hylton

Make hososity more likely for failed multi-jar commits.

The old code would avoid hosing the system when the first jar failed
during its finish.  The logic is that the failure means that
transaction did not commit, so it was safe for all the other jars to
abort.  There are counter-examples to this assumption.  For example,
ZEO could fail after commiting the transaction on the server but
before communicating that success to the client.  It would lead to
inconsistency if the other jars aborted after the first committed.

The solution is to reduce the special case yet further:  If a
single-jar transaction fails during the finish, assume the transaction
is aborted and avoid hosage.  If the jar actually committed, it's
possible to get back to a consistent state since only one jar was
involved.
parent c4b8390c
...@@ -13,8 +13,8 @@ ...@@ -13,8 +13,8 @@
############################################################################## ##############################################################################
"""Transaction management """Transaction management
$Id: Transaction.py,v 1.37 2002/08/14 22:07:09 mj Exp $""" $Id: Transaction.py,v 1.38 2002/09/11 18:41:24 jeremy Exp $"""
__version__='$Revision: 1.37 $'[11:-2] __version__='$Revision: 1.38 $'[11:-2]
import time, sys, struct, POSException import time, sys, struct, POSException
from struct import pack from struct import pack
...@@ -206,12 +206,13 @@ class Transaction: ...@@ -206,12 +206,13 @@ class Transaction:
else: else:
vote(self) # last chance to bail vote(self) # last chance to bail
# Try to finish one jar, since we may be able to # Handle multiple jars separately. If there are
# recover if the first one fails. # multiple jars and one fails during the finish, we
self._finish_one(jarsv) # mark this transaction manager as hosed.
# Once a single jar has finished, it's a fatal (hosed) if len(jarsv) == 1:
# error if another jar fails. self._finish_one(jarsv[0])
self._finish_rest(jarsv) else:
self._finish_many(jarsv)
except: except:
# Ugh, we got an got an error during commit, so we # Ugh, we got an got an error during commit, so we
# have to clean up. # have to clean up.
...@@ -266,11 +267,9 @@ class Transaction: ...@@ -266,11 +267,9 @@ class Transaction:
jars[i] = j jars[i] = j
j.commit_sub(self) j.commit_sub(self)
def _finish_one(self, jarsv): def _finish_one(self, jar):
try: try:
if jarsv: jar.tpc_finish(self) # This should never fail
jarsv[-1].tpc_finish(self) # This should never fail
jarsv.pop() # It didn't, so it's taken care of.
except: except:
# Bug if it does, we need to keep track of it # Bug if it does, we need to keep track of it
LOG('ZODB', ERROR, LOG('ZODB', ERROR,
...@@ -279,7 +278,7 @@ class Transaction: ...@@ -279,7 +278,7 @@ class Transaction:
error=sys.exc_info()) error=sys.exc_info())
raise raise
def _finish_rest(self, jarsv): def _finish_many(self, jarsv):
global hosed global hosed
try: try:
while jarsv: while jarsv:
......
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