Commit 921e14fe authored by Tim Peters's avatar Tim Peters

Make the sample ResourceManager work more the way in which we

intend real implementations to work, and beefed up the tests
to match.  The collaboration also got a little simpler.
parent ab98a7ed
......@@ -124,13 +124,12 @@ Scenario
C3.regisiter(o3)
T.join(C3)
S1.rollback()
S2.rollback()
S2.discard()
T.discard()
C1.discard()
C2.discard()
C3.discard()
o3.invalidate()
S2.discard()
s21.discard() # roll back changes since previous, which is r11
C1.discard(s21)
o1.invalidate()
......
......@@ -409,11 +409,10 @@ class ISavePoint(zope.interface.Interface):
"""
def discard():
"""Discard changes saved by this savepoint.
"""Discard changes saved by and after this savepoint.
That means changes made since the immediately preceding
savepoint if one exists, or since the start of the transaction,
until this savepoint.
savepoint if one exists, or since the start of the transaction.
Once a savepoint has been discarded, it's an error to attempt
to rollback or discard it again.
......
......@@ -86,6 +86,7 @@ class ResourceManager(object):
self.transaction = None
self.delta = 0
self.txn_state = None
self.first_savepoint = None
def _check_state(self, *ok_states):
if self.txn_state not in ok_states:
......@@ -215,6 +216,9 @@ class ResourceManager(object):
self.transaction = None
self.prepared = False
self.txn_state = None
if self.first_savepoint is not None:
self.first_savepoint.invalidate()
self.first_savepoint = None
def tpc_abort(self, transaction):
"""Abort a transaction
......@@ -365,7 +369,7 @@ class ResourceManager(object):
>>> r2.rollback()
Traceback (most recent call last):
...
TypeError: ('Attempt to roll back to invalid save point', 3, 2)
ValueError: operation attempted on invalid SavePoint
We can roll back to a savepoint as often as we like:
......@@ -394,38 +398,69 @@ class ResourceManager(object):
>>> r1.rollback()
Traceback (most recent call last):
...
TypeError: Attempt to rollback stale rollback
ValueError: operation attempted on invalid SavePoint
"""
if self.txn_state is not None:
raise TypeError("Can't get savepoint during two-phase commit")
self._checkTransaction(transaction)
self.transaction = transaction
self.sp += 1
return SavePoint(self)
if self.first_savepoint is None:
savepoint = SavePoint(self, 0)
self.first_savepoint = savepoint
else:
savepoint = SavePoint(self, self.first_savepoint.delta)
self.first_savepoint.last_savepoint().next_savepoint = savepoint
return savepoint
def discard(self, transaction):
pass
if self.first_savepoint is None:
self.delta = 0
else:
self.delta = self.first_savepoint.last_savepoint().delta
class SavePoint(object):
def __init__(self, rm):
def __init__(self, rm, olddelta):
self.rm = rm
self.olddelta = olddelta
self.sp = rm.sp
self.delta = rm.delta
self.transaction = rm.transaction
self.next_savepoint = None
self.valid = True
def _valid_check(self):
if not self.valid:
raise ValueError("operation attempted on invalid SavePoint")
def rollback(self):
if self.transaction is not self.rm.transaction:
raise TypeError("Attempt to rollback stale rollback")
if self.rm.sp < self.sp:
raise TypeError("Attempt to roll back to invalid save point",
self.sp, self.rm.sp)
self.rm.sp = self.sp
self.rm.delta = self.delta
self._valid_check()
if self.next_savepoint is None:
self.rm.discard(self.transaction)
else:
self.next_savepoint.discard()
self.next_savepoint = None
def discard(self):
pass
self._valid_check()
if self.next_savepoint is None:
self.rm.discard(self.transaction)
else:
self.next_savepoint.discard()
self.rm.delta = self.olddelta
self.valid = False
def last_savepoint(self):
"""Return the last savepoint in the chain starting at self."""
while self.next_savepoint is not None:
self = self.next_savepoint
return self
def invalidate(self):
self.valid = False
if self.next_savepoint is not None:
self.next_savepoint.invalidate()
def test_suite():
from doctest import DocTestSuite
......
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