Ńň
4äKc @ s` d Z d e f d YZ d e f d YZ d Z e Z e d j o e i n d S( sf Sample objects for use in tests
$Id: test_SampleDataManager.py 112140 2010-05-07 15:29:36Z tseaver $
t DataManagerc B sP e Z d Z d Z d d Z d Z d Z d Z d Z d Z RS( sk Sample data manager
This class provides a trivial data-manager implementation and doc
strings to illustrate the the protocol and to provide a tool for
writing tests.
Our sample data manager has state that is updated through an inc
method and through transaction operations.
When we create a sample data manager:
>>> dm = DataManager()
It has two bits of state, state:
>>> dm.state
0
and delta:
>>> dm.delta
0
Both of which are initialized to 0. state is meant to model
committed state, while delta represents tentative changes within a
transaction. We change the state by calling inc:
>>> dm.inc()
which updates delta:
>>> dm.delta
1
but state isn't changed until we commit the transaction:
>>> dm.state
0
To commit the changes, we use 2-phase commit. We execute the first
stage by calling prepare. We need to pass a transation. Our
sample data managers don't really use the transactions for much,
so we'll be lazy and use strings for transactions:
>>> t1 = '1'
>>> dm.prepare(t1)
The sample data manager updates the state when we call prepare:
>>> dm.state
1
>>> dm.delta
1
This is mainly so we can detect some affect of calling the methods.
Now if we call commit:
>>> dm.commit(t1)
Our changes are"permanent". The state reflects the changes and the
delta has been reset to 0.
>>> dm.state
1
>>> dm.delta
0
c C s1 d | _ d | _ d | _ d | _ t | _ d S( Ni ( t statet spt Nonet transactiont deltat Falset prepared( t self( ( sL /usr/lib/python2.6/site-packages/transaction/tests/test_SampleDataManager.pyt __init__Y s
i c C s | i | 7_ d S( N( R ( R t n( ( sL /usr/lib/python2.6/site-packages/transaction/tests/test_SampleDataManager.pyt inc` s c C sO | i o t d n | i | t | _ | | _ | i | i 7_ d S( sŢ Prepare to commit data
>>> dm = DataManager()
>>> dm.inc()
>>> t1 = '1'
>>> dm.prepare(t1)
>>> dm.commit(t1)
>>> dm.state
1
>>> dm.inc()
>>> t2 = '2'
>>> dm.prepare(t2)
>>> dm.abort(t2)
>>> dm.state
1
It is en error to call prepare more than once without an intervening
commit or abort:
>>> dm.prepare(t1)
>>> dm.prepare(t1)
Traceback (most recent call last):
...
TypeError: Already prepared
>>> dm.prepare(t2)
Traceback (most recent call last):
...
TypeError: Already prepared
>>> dm.abort(t1)
If there was a preceeding savepoint, the transaction must match:
>>> rollback = dm.savepoint(t1)
>>> dm.prepare(t2)
Traceback (most recent call last):
,,,
TypeError: ('Transaction missmatch', '2', '1')
>>> dm.prepare(t1)
s Already preparedN( R t TypeErrort _checkTransactiont TrueR R R ( R R ( ( sL /usr/lib/python2.6/site-packages/transaction/tests/test_SampleDataManager.pyt preparec s -
c C s= | | i j o) | i d j o t d | | i n d S( Ns Transaction missmatch( R R R ( R R ( ( sL /usr/lib/python2.6/site-packages/transaction/tests/test_SampleDataManager.pyR
s c C s` | i | | i d j o
d | _ n | i o | i | i 8_ t | _ n d | _ d S( sâ Abort a transaction
The abort method can be called before two-phase commit to
throw away work done in the transaction:
>>> dm = DataManager()
>>> dm.inc()
>>> dm.state, dm.delta
(0, 1)
>>> t1 = '1'
>>> dm.abort(t1)
>>> dm.state, dm.delta
(0, 0)
The abort method also throws away work done in savepoints:
>>> dm.inc()
>>> r = dm.savepoint(t1)
>>> dm.inc()
>>> r = dm.savepoint(t1)
>>> dm.state, dm.delta
(0, 2)
>>> dm.abort(t1)
>>> dm.state, dm.delta
(0, 0)
If savepoints are used, abort must be passed the same
transaction:
>>> dm.inc()
>>> r = dm.savepoint(t1)
>>> t2 = '2'
>>> dm.abort(t2)
Traceback (most recent call last):
...
TypeError: ('Transaction missmatch', '2', '1')
>>> dm.abort(t1)
The abort method is also used to abort a two-phase commit:
>>> dm.inc()
>>> dm.state, dm.delta
(0, 1)
>>> dm.prepare(t1)
>>> dm.state, dm.delta
(1, 1)
>>> dm.abort(t1)
>>> dm.state, dm.delta
(0, 0)
Of course, the transactions passed to prepare and abort must
match:
>>> dm.prepare(t1)
>>> dm.abort(t2)
Traceback (most recent call last):
...
TypeError: ('Transaction missmatch', '2', '1')
>>> dm.abort(t1)
i N( R
R R R R R R ( R R ( ( sL /usr/lib/python2.6/site-packages/transaction/tests/test_SampleDataManager.pyt abort s A
c C sF | i p t d n | i | d | _ d | _ t | _ d S( s Complete two-phase commit
>>> dm = DataManager()
>>> dm.state
0
>>> dm.inc()
We start two-phase commit by calling prepare:
>>> t1 = '1'
>>> dm.prepare(t1)
We complete it by calling commit:
>>> dm.commit(t1)
>>> dm.state
1
It is an error ro call commit without calling prepare first:
>>> dm.inc()
>>> t2 = '2'
>>> dm.commit(t2)
Traceback (most recent call last):
...
TypeError: Not prepared to commit
>>> dm.prepare(t2)
>>> dm.commit(t2)
If course, the transactions given to prepare and commit must
be the same:
>>> dm.inc()
>>> t3 = '3'
>>> dm.prepare(t3)
>>> dm.commit(t2)
Traceback (most recent call last):
...
TypeError: ('Transaction missmatch', '2', '3')
s Not prepared to commiti N( R R R
R R R R ( R R ( ( sL /usr/lib/python2.6/site-packages/transaction/tests/test_SampleDataManager.pyt commitč s +
c C sI | i o t d n | i | | | _ | i d 7_ t | S( sŽ
Provide the ability to rollback transaction state
Savepoints provide a way to:
- Save partial transaction work. For some data managers, this
could allow resources to be used more efficiently.
- Provide the ability to revert state to a point in a
transaction without aborting the entire transaction. In
other words, savepoints support partial aborts.
Savepoints don't use two-phase commit. If there are errors in
setting or rolling back to savepoints, the application should
abort the containing transaction. This is *not* the
responsibility of the data manager.
Savepoints are always associated with a transaction. Any work
done in a savepoint's transaction is tentative until the
transaction is committed using two-phase commit.
>>> dm = DataManager()
>>> dm.inc()
>>> t1 = '1'
>>> r = dm.savepoint(t1)
>>> dm.state, dm.delta
(0, 1)
>>> dm.inc()
>>> dm.state, dm.delta
(0, 2)
>>> r.rollback()
>>> dm.state, dm.delta
(0, 1)
>>> dm.prepare(t1)
>>> dm.commit(t1)
>>> dm.state, dm.delta
(1, 0)
Savepoints must have the same transaction:
>>> r1 = dm.savepoint(t1)
>>> dm.state, dm.delta
(1, 0)
>>> dm.inc()
>>> dm.state, dm.delta
(1, 1)
>>> t2 = '2'
>>> r2 = dm.savepoint(t2)
Traceback (most recent call last):
...
TypeError: ('Transaction missmatch', '2', '1')
>>> r2 = dm.savepoint(t1)
>>> dm.inc()
>>> dm.state, dm.delta
(1, 2)
If we rollback to an earlier savepoint, we discard all work
done later:
>>> r1.rollback()
>>> dm.state, dm.delta
(1, 0)
and we can no longer rollback to the later savepoint:
>>> r2.rollback()
Traceback (most recent call last):
...
TypeError: ('Attempt to roll back to invalid save point', 3, 2)
We can roll back to a savepoint as often as we like:
>>> r1.rollback()
>>> r1.rollback()
>>> r1.rollback()
>>> dm.state, dm.delta
(1, 0)
>>> dm.inc()
>>> dm.inc()
>>> dm.inc()
>>> dm.state, dm.delta
(1, 3)
>>> r1.rollback()
>>> dm.state, dm.delta
(1, 0)
But we can't rollback to a savepoint after it has been
committed:
>>> dm.prepare(t1)
>>> dm.commit(t1)
>>> r1.rollback()
Traceback (most recent call last):
...
TypeError: Attempt to rollback stale rollback
s+ Can't get savepoint during two-phase commiti ( R R R
R R t Rollback( R R ( ( sL /usr/lib/python2.6/site-packages/transaction/tests/test_SampleDataManager.pyt savepoint s d
(
t __name__t
__module__t __doc__R R R R
R R R ( ( ( sL /usr/lib/python2.6/site-packages/transaction/tests/test_SampleDataManager.pyR s D 4 K 2R c B s e Z d Z d Z RS( c C s1 | | _ | i | _ | i | _ | i | _ d S( N( t dmR R R ( R R ( ( sL /usr/lib/python2.6/site-packages/transaction/tests/test_SampleDataManager.pyR s c C s} | i | i i j o t d n | i i | i j o t d | i | i i n | i | i _ | i | i _ d S( Ns" Attempt to rollback stale rollbacks* Attempt to roll back to invalid save point( R R R R R ( R ( ( sL /usr/lib/python2.6/site-packages/transaction/tests/test_SampleDataManager.pyt rollback s ( R R R R ( ( ( sL /usr/lib/python2.6/site-packages/transaction/tests/test_SampleDataManager.pyR
s c C s d d k l } | S( Ni˙˙˙˙( t DocTestSuite( t doctestR ( R ( ( sL /usr/lib/python2.6/site-packages/transaction/tests/test_SampleDataManager.pyt
test_suite s t __main__N( R t objectR R R t additional_testsR t unittestt main( ( ( sL /usr/lib/python2.6/site-packages/transaction/tests/test_SampleDataManager.pyt