[Zodb-checkins] SVN: ZODB/branches/3.4/src/transaction/ Make
transactions uncommitable if savepoint rollback fails.
Jim Fulton
jim at zope.com
Sun Apr 24 11:26:40 EDT 2005
Log message for revision 30147:
Make transactions uncommitable if savepoint rollback fails.
Added demonstration of transaction non-commitability after savepoint
or savepoint rollback failure.
Updated "previous commit failed" error to "previous operation failed".
Changed:
U ZODB/branches/3.4/src/transaction/_transaction.py
U ZODB/branches/3.4/src/transaction/savepoint.txt
-=-
Modified: ZODB/branches/3.4/src/transaction/_transaction.py
===================================================================
--- ZODB/branches/3.4/src/transaction/_transaction.py 2005-04-24 15:26:37 UTC (rev 30146)
+++ ZODB/branches/3.4/src/transaction/_transaction.py 2005-04-24 15:26:39 UTC (rev 30147)
@@ -231,17 +231,17 @@
# Raise TransactionFailedError, due to commit()/join()/register()
# getting called when the current transaction has already suffered
- # a commit failure.
- def _prior_commit_failed(self):
+ # a commit/savepoint failure.
+ def _prior_operation_failed(self):
from ZODB.POSException import TransactionFailedError
assert self._failure_traceback is not None
- raise TransactionFailedError("commit() previously failed, "
- "with this traceback:\n\n%s" %
+ raise TransactionFailedError("An operation previously failed, "
+ "with traceback:\n\n%s" %
self._failure_traceback.getvalue())
def join(self, resource):
if self.status is Status.COMMITFAILED:
- self._prior_commit_failed() # doesn't return
+ self._prior_operation_failed() # doesn't return
if self.status is not Status.ACTIVE:
# TODO: Should it be possible to join a committing transaction?
@@ -261,15 +261,15 @@
def savepoint(self, optimistic=False):
if self.status is Status.COMMITFAILED:
- self._prior_commit_failed() # doesn't return, it raises
+ self._prior_operation_failed() # doesn't return, it raises
try:
- savepoint = Savepoint(optimistic)
+ savepoint = Savepoint(self, optimistic)
for resource in self._resources:
savepoint.join(resource)
except:
self._cleanup(self._resources)
- self._saveCommitishError() # doesn't return, it raises!
+ self._saveCommitishError() # reraises!
if self._last_savepoint is not None:
savepoint.previous = self._last_savepoint
@@ -330,7 +330,7 @@
return
if self.status is Status.COMMITFAILED:
- self._prior_commit_failed() # doesn't return
+ self._prior_operation_failed() # doesn't return
self._callBeforeCommitHooks()
@@ -598,7 +598,8 @@
"""
interface.implements(interfaces.ISavepoint)
- def __init__(self, optimistic):
+ def __init__(self, transaction, optimistic):
+ self.transaction = transaction
self._savepoints = []
self.valid = True
self.next = self.previous = None
@@ -620,8 +621,12 @@
if not self.valid:
raise interfaces.InvalidSavepointRollbackError
self._invalidate_next()
- for savepoint in self._savepoints:
- savepoint.rollback()
+ try:
+ for savepoint in self._savepoints:
+ savepoint.rollback()
+ except:
+ # Mark the transaction as failed
+ self.transaction._saveCommitishError() # reraises!
def _invalidate_next(self):
self.valid = False
Modified: ZODB/branches/3.4/src/transaction/savepoint.txt
===================================================================
--- ZODB/branches/3.4/src/transaction/savepoint.txt 2005-04-24 15:26:37 UTC (rev 30146)
+++ ZODB/branches/3.4/src/transaction/savepoint.txt 2005-04-24 15:26:39 UTC (rev 30147)
@@ -219,3 +219,57 @@
...
TypeError: ('Savepoints unsupported', {'name': 'sam'})
+Failures
+--------
+
+If a failure occurs when creating or rolling back a savepoint, the
+transaction state will be uncertain and the transaction will become
+uncommitable. From that point on, most transaction operations,
+including commit, will fail until the transaction is aborted.
+
+In the previous example, we got an error when we tried to rollback the
+savepoint. If we try to commit the transaction, the commit will fail:
+
+ >>> transaction.commit() # doctest: +ELLIPSIS
+ Traceback (most recent call last):
+ ...
+ TransactionFailedError: An operation previously failed, with traceback:
+ ...
+ TypeError: ('Savepoints unsupported', {'name': 'sam'})
+ <BLANKLINE>
+
+We have to abort it to make any progress:
+
+ >>> transaction.abort()
+
+Similarly, in our earlier example, where we tried to take a savepoint
+with a data manager that didn't support savepoints:
+
+ >>> dm_no_sp['name'] = 'sally'
+ >>> dm['name'] = 'sally'
+ >>> savepoint = transaction.savepoint()
+ Traceback (most recent call last):
+ ...
+ TypeError: ('Savepoints unsupported', {'name': 'sue'})
+
+ >>> transaction.commit() # doctest: +ELLIPSIS
+ Traceback (most recent call last):
+ ...
+ TransactionFailedError: An operation previously failed, with traceback:
+ ...
+ TypeError: ('Savepoints unsupported', {'name': 'sue'})
+ <BLANKLINE>
+
+ >>> transaction.abort()
+
+After clearing the transaction with an abort, we can get on with new
+transactions:
+
+ >>> dm_no_sp['name'] = 'sally'
+ >>> dm['name'] = 'sally'
+ >>> transaction.commit()
+ >>> dm_no_sp['name']
+ 'sally'
+ >>> dm['name']
+ 'sally'
+
More information about the Zodb-checkins
mailing list