Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Z
ZODB
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Kirill Smelkov
ZODB
Commits
f73688b1
Commit
f73688b1
authored
May 06, 2007
by
Jim Fulton
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Removed subtransaction support, which had been scheduled to go in 3.7.
parent
d245b891
Changes
4
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
24 additions
and
203 deletions
+24
-203
src/transaction/_manager.py
src/transaction/_manager.py
+5
-18
src/transaction/_transaction.py
src/transaction/_transaction.py
+2
-105
src/transaction/interfaces.py
src/transaction/interfaces.py
+6
-6
src/transaction/tests/test_transaction.py
src/transaction/tests/test_transaction.py
+11
-74
No files found.
src/transaction/_manager.py
View file @
f73688b1
...
@@ -89,24 +89,11 @@ class TransactionManager(object):
...
@@ -89,24 +89,11 @@ class TransactionManager(object):
def
doom
(
self
):
def
doom
(
self
):
return
self
.
get
().
doom
()
return
self
.
get
().
doom
()
def
commit
(
self
,
sub
=
_marker
):
def
commit
(
self
):
if
sub
is
_marker
:
return
self
.
get
().
commit
()
sub
=
None
else
:
def
abort
(
self
):
deprecated37
(
"subtransactions are deprecated; use "
return
self
.
get
().
abort
()
"transaction.savepoint() instead of "
"transaction.commit(1)"
)
return
self
.
get
().
commit
(
sub
,
deprecation_wng
=
False
)
def
abort
(
self
,
sub
=
_marker
):
if
sub
is
_marker
:
sub
=
None
else
:
deprecated37
(
"subtransactions are deprecated; use "
"sp.rollback() instead of "
"transaction.abort(1), where `sp` is the "
"corresponding savepoint captured earlier"
)
return
self
.
get
().
abort
(
sub
,
deprecation_wng
=
False
)
def
savepoint
(
self
,
optimistic
=
False
):
def
savepoint
(
self
,
optimistic
=
False
):
return
self
.
get
().
savepoint
(
optimistic
)
return
self
.
get
().
savepoint
(
optimistic
)
...
...
src/transaction/_transaction.py
View file @
f73688b1
...
@@ -27,54 +27,6 @@ resource manager and adds it to the list of resources. register() is
...
@@ -27,54 +27,6 @@ resource manager and adds it to the list of resources. register() is
for backwards compatibility. It takes a persistent object and
for backwards compatibility. It takes a persistent object and
registers its _p_jar attribute. TODO: explain adapter
registers its _p_jar attribute. TODO: explain adapter
Subtransactions
---------------
Note: Subtransactions are deprecated! Use savepoint/rollback instead.
A subtransaction applies the transaction notion recursively. It
allows a set of modifications within a transaction to be committed or
aborted as a group. A subtransaction is a strictly local activity;
its changes are not visible to any other database connection until the
top-level transaction commits. In addition to its use to organize a
large transaction, subtransactions can be used to optimize memory use.
ZODB must keep modified objects in memory until a transaction commits
and it can write the changes to the storage. A subtransaction uses a
temporary disk storage for its commits, allowing modified objects to
be flushed from memory when the subtransaction commits.
The commit() and abort() methods take an optional subtransaction
argument that defaults to false. If it is a true, the operation is
performed on a subtransaction.
Subtransactions add a lot of complexity to the transaction
implementation. Some resource managers support subtransactions, but
they are not required to. (ZODB Connection is the only standard
resource manager that supports subtransactions.) Resource managers
that do support subtransactions implement abort_sub() and commit_sub()
methods and support a second argument to tpc_begin().
The second argument to tpc_begin() indicates that a subtransaction
commit is beginning (if it is true). In a subtransaction, there is no
tpc_vote() call, because sub-transactions don't need 2-phase commit.
If a sub-transaction abort or commit fails, we can abort the outer
transaction. The tpc_finish() or tpc_abort() call applies just to
that subtransaction.
Once a resource manager is involved in a subtransaction, all
subsequent transactions will be treated as subtransactions until
abort_sub() or commit_sub() is called. abort_sub() will undo all the
changes of the subtransactions. commit_sub() will begin a top-level
transaction and store all the changes from subtransactions. After
commit_sub(), the transaction must still call tpc_vote() and
tpc_finish().
If the resource manager does not support subtransactions, nothing
happens when the subtransaction commits. Instead, the resource
manager is put on a list of managers to commit when the actual
top-level transaction commits. If this happens, it will not be
possible to abort subtransactions.
Two-phase commit
Two-phase commit
----------------
----------------
...
@@ -89,21 +41,6 @@ them.
...
@@ -89,21 +41,6 @@ them.
3. tpc_vote(txn)
3. tpc_vote(txn)
4. tpc_finish(txn)
4. tpc_finish(txn)
Subtransaction commit
---------------------
Note: Subtransactions are deprecated!
When a subtransaction commits, the protocol is different.
1. tpc_begin() is passed a second argument, which indicates that a
subtransaction is being committed.
2. tpc_vote() is not called.
Once a subtransaction has been committed, the top-level transaction
commit will start with a commit_sub() call instead of a tpc_begin()
call.
Before-commit hook
Before-commit hook
------------------
------------------
...
@@ -212,9 +149,6 @@ class Transaction(object):
...
@@ -212,9 +149,6 @@ class Transaction(object):
# savepoint to its index (see above).
# savepoint to its index (see above).
_savepoint2index
=
None
_savepoint2index
=
None
# Remember the savepoint for the last subtransaction.
_subtransaction_savepoint
=
None
# Meta data. ._extension is also metadata, but is initialized to an
# Meta data. ._extension is also metadata, but is initialized to an
# emtpy dict in __init__.
# emtpy dict in __init__.
user
=
""
user
=
""
...
@@ -372,29 +306,13 @@ class Transaction(object):
...
@@ -372,29 +306,13 @@ class Transaction(object):
assert
id
(
obj
)
not
in
map
(
id
,
adapter
.
objects
)
assert
id
(
obj
)
not
in
map
(
id
,
adapter
.
objects
)
adapter
.
objects
.
append
(
obj
)
adapter
.
objects
.
append
(
obj
)
def
commit
(
self
,
subtransaction
=
_marker
,
deprecation_wng
=
True
):
def
commit
(
self
):
if
self
.
status
is
Status
.
DOOMED
:
if
self
.
status
is
Status
.
DOOMED
:
raise
interfaces
.
DoomedTransaction
()
raise
interfaces
.
DoomedTransaction
()
if
subtransaction
is
_marker
:
subtransaction
=
0
elif
deprecation_wng
:
deprecated37
(
"subtransactions are deprecated; instead of "
"transaction.commit(1), use "
"transaction.savepoint(optimistic=True) in "
"contexts where a subtransaction abort will never "
"occur, or sp=transaction.savepoint() if later "
"rollback is possible and then sp.rollback() "
"instead of transaction.abort(1)"
)
if
self
.
_savepoint2index
:
if
self
.
_savepoint2index
:
self
.
_invalidate_all_savepoints
()
self
.
_invalidate_all_savepoints
()
if
subtransaction
:
# TODO deprecate subtransactions
self
.
_subtransaction_savepoint
=
self
.
savepoint
(
optimistic
=
True
)
return
if
self
.
status
is
Status
.
COMMITFAILED
:
if
self
.
status
is
Status
.
COMMITFAILED
:
self
.
_prior_operation_failed
()
# doesn't return
self
.
_prior_operation_failed
()
# doesn't return
...
@@ -546,28 +464,7 @@ class Transaction(object):
...
@@ -546,28 +464,7 @@ class Transaction(object):
self
.
log
.
error
(
"Error in tpc_abort() on manager %s"
,
self
.
log
.
error
(
"Error in tpc_abort() on manager %s"
,
rm
,
exc_info
=
sys
.
exc_info
())
rm
,
exc_info
=
sys
.
exc_info
())
def
abort
(
self
,
subtransaction
=
_marker
,
deprecation_wng
=
True
):
def
abort
(
self
):
if
subtransaction
is
_marker
:
subtransaction
=
0
elif
deprecation_wng
:
deprecated37
(
"subtransactions are deprecated; use "
"sp.rollback() instead of "
"transaction.abort(1), where `sp` is the "
"corresponding savepoint captured earlier"
)
if
subtransaction
:
# TODO deprecate subtransactions.
if
not
self
.
_subtransaction_savepoint
:
raise
interfaces
.
InvalidSavepointRollbackError
if
self
.
_subtransaction_savepoint
.
valid
:
self
.
_subtransaction_savepoint
.
rollback
()
# We're supposed to be able to call abort(1) multiple
# times without additional effect, so mark the subtxn
# savepoint invalid now.
self
.
_subtransaction_savepoint
.
transaction
=
None
assert
not
self
.
_subtransaction_savepoint
.
valid
return
if
self
.
_savepoint2index
:
if
self
.
_savepoint2index
:
self
.
_invalidate_all_savepoints
()
self
.
_invalidate_all_savepoints
()
...
...
src/transaction/interfaces.py
View file @
f73688b1
...
@@ -202,8 +202,8 @@ class ITransaction(zope.interface.Interface):
...
@@ -202,8 +202,8 @@ class ITransaction(zope.interface.Interface):
hooks. Applications should take care to avoid creating infinite loops
hooks. Applications should take care to avoid creating infinite loops
by recursively registering hooks.
by recursively registering hooks.
Hooks are called only for a top-level commit. A s
ubtransaction
Hooks are called only for a top-level commit. A s
avepoint
commit
does not call any hooks. If the transaction is aborted, hooks
does not call any hooks. If the transaction is aborted, hooks
are not called, and are discarded. Calling a hook "consumes" its
are not called, and are discarded. Calling a hook "consumes" its
registration too: hook registrations do not persist across
registration too: hook registrations do not persist across
transactions. If it's desired to call the same hook on every
transactions. If it's desired to call the same hook on every
...
@@ -231,8 +231,8 @@ class ITransaction(zope.interface.Interface):
...
@@ -231,8 +231,8 @@ class ITransaction(zope.interface.Interface):
hooks. Applications should take care to avoid creating infinite loops
hooks. Applications should take care to avoid creating infinite loops
by recursively registering hooks.
by recursively registering hooks.
Hooks are called only for a top-level commit. A
subtransaction
Hooks are called only for a top-level commit. A
commit or
savepoint creation does not call any hooks. If the
savepoint creation does not call any hooks. If the
transaction is aborted, hooks are not called, and are discarded.
transaction is aborted, hooks are not called, and are discarded.
Calling a hook "consumes" its registration too: hook registrations
Calling a hook "consumes" its registration too: hook registrations
do not persist across transactions. If it's desired to call the same
do not persist across transactions. If it's desired to call the same
...
@@ -269,8 +269,8 @@ class ITransaction(zope.interface.Interface):
...
@@ -269,8 +269,8 @@ class ITransaction(zope.interface.Interface):
hooks. Applications should take care to avoid creating infinite loops
hooks. Applications should take care to avoid creating infinite loops
by recursively registering hooks.
by recursively registering hooks.
Hooks are called only for a top-level commit. A
subtransaction
Hooks are called only for a top-level commit. A
commit or
savepoint creation does not call any hooks. Calling a
savepoint creation does not call any hooks. Calling a
hook "consumes" its registration: hook registrations do not
hook "consumes" its registration: hook registrations do not
persist across transactions. If it's desired to call the same
persist across transactions. If it's desired to call the same
hook on every transaction commit, then addAfterCommitHook() must be
hook on every transaction commit, then addAfterCommitHook() must be
...
...
src/transaction/tests/test_transaction.py
View file @
f73688b1
...
@@ -46,12 +46,6 @@ import transaction
...
@@ -46,12 +46,6 @@ import transaction
from
ZODB.utils
import
positive_id
from
ZODB.utils
import
positive_id
from
ZODB.tests.warnhook
import
WarningsHook
from
ZODB.tests.warnhook
import
WarningsHook
# deprecated37 remove when subtransactions go away
# Don't complain about subtxns in these tests.
warnings
.
filterwarnings
(
"ignore"
,
".*
\
n
subtransactions are deprecated"
,
DeprecationWarning
,
__name__
)
class
TransactionTests
(
unittest
.
TestCase
):
class
TransactionTests
(
unittest
.
TestCase
):
def
setUp
(
self
):
def
setUp
(
self
):
...
@@ -114,37 +108,6 @@ class TransactionTests(unittest.TestCase):
...
@@ -114,37 +108,6 @@ class TransactionTests(unittest.TestCase):
assert
self
.
nosub1
.
_p_jar
.
ctpc_finish
==
0
assert
self
.
nosub1
.
_p_jar
.
ctpc_finish
==
0
assert
self
.
nosub1
.
_p_jar
.
cabort
==
1
assert
self
.
nosub1
.
_p_jar
.
cabort
==
1
def
BUGtestNSJSubTransactionCommitAbort
(
self
):
"""
this reveals a bug in transaction.py
the nosub jar should not have tpc_finish
called on it till the containing txn
ends.
sub calling method commit
nosub calling method tpc_begin
sub calling method tpc_finish
nosub calling method tpc_finish
nosub calling method abort
sub calling method abort_sub
"""
self
.
sub1
.
modify
(
tracing
=
'sub'
)
self
.
nosub1
.
modify
(
tracing
=
'nosub'
)
self
.
transaction_manager
.
commit
(
1
)
assert
self
.
sub1
.
_p_jar
.
ctpc_finish
==
1
# bug, non sub trans jars are getting finished
# in a subtrans
assert
self
.
nosub1
.
_p_jar
.
ctpc_finish
==
0
self
.
transaction_manager
.
abort
()
assert
self
.
nosub1
.
_p_jar
.
cabort
==
1
assert
self
.
sub1
.
_p_jar
.
cabort_sub
==
1
### Failure Mode Tests
### Failure Mode Tests
#
#
...
@@ -158,7 +121,7 @@ class TransactionTests(unittest.TestCase):
...
@@ -158,7 +121,7 @@ class TransactionTests(unittest.TestCase):
def
testExceptionInAbort
(
self
):
def
testExceptionInAbort
(
self
):
self
.
sub1
.
_p_jar
=
SubTransaction
Jar
(
errors
=
'abort'
)
self
.
sub1
.
_p_jar
=
Basic
Jar
(
errors
=
'abort'
)
self
.
nosub1
.
modify
()
self
.
nosub1
.
modify
()
self
.
sub1
.
modify
(
nojar
=
1
)
self
.
sub1
.
modify
(
nojar
=
1
)
...
@@ -173,7 +136,7 @@ class TransactionTests(unittest.TestCase):
...
@@ -173,7 +136,7 @@ class TransactionTests(unittest.TestCase):
def
testExceptionInCommit
(
self
):
def
testExceptionInCommit
(
self
):
self
.
sub1
.
_p_jar
=
SubTransaction
Jar
(
errors
=
'commit'
)
self
.
sub1
.
_p_jar
=
Basic
Jar
(
errors
=
'commit'
)
self
.
nosub1
.
modify
()
self
.
nosub1
.
modify
()
self
.
sub1
.
modify
(
nojar
=
1
)
self
.
sub1
.
modify
(
nojar
=
1
)
...
@@ -188,7 +151,7 @@ class TransactionTests(unittest.TestCase):
...
@@ -188,7 +151,7 @@ class TransactionTests(unittest.TestCase):
def
testExceptionInTpcVote
(
self
):
def
testExceptionInTpcVote
(
self
):
self
.
sub1
.
_p_jar
=
SubTransaction
Jar
(
errors
=
'tpc_vote'
)
self
.
sub1
.
_p_jar
=
Basic
Jar
(
errors
=
'tpc_vote'
)
self
.
nosub1
.
modify
()
self
.
nosub1
.
modify
()
self
.
sub1
.
modify
(
nojar
=
1
)
self
.
sub1
.
modify
(
nojar
=
1
)
...
@@ -214,7 +177,7 @@ class TransactionTests(unittest.TestCase):
...
@@ -214,7 +177,7 @@ class TransactionTests(unittest.TestCase):
sub calling method tpc_abort
sub calling method tpc_abort
nosub calling method tpc_abort
nosub calling method tpc_abort
"""
"""
self
.
sub1
.
_p_jar
=
SubTransaction
Jar
(
errors
=
'tpc_begin'
)
self
.
sub1
.
_p_jar
=
Basic
Jar
(
errors
=
'tpc_begin'
)
self
.
nosub1
.
modify
()
self
.
nosub1
.
modify
()
self
.
sub1
.
modify
(
nojar
=
1
)
self
.
sub1
.
modify
(
nojar
=
1
)
...
@@ -228,8 +191,7 @@ class TransactionTests(unittest.TestCase):
...
@@ -228,8 +191,7 @@ class TransactionTests(unittest.TestCase):
assert
self
.
sub1
.
_p_jar
.
ctpc_abort
==
1
assert
self
.
sub1
.
_p_jar
.
ctpc_abort
==
1
def
testExceptionInTpcAbort
(
self
):
def
testExceptionInTpcAbort
(
self
):
self
.
sub1
.
_p_jar
=
SubTransactionJar
(
self
.
sub1
.
_p_jar
=
BasicJar
(
errors
=
(
'tpc_abort'
,
'tpc_vote'
))
errors
=
(
'tpc_abort'
,
'tpc_vote'
))
self
.
nosub1
.
modify
()
self
.
nosub1
.
modify
()
self
.
sub1
.
modify
(
nojar
=
1
)
self
.
sub1
.
modify
(
nojar
=
1
)
...
@@ -283,9 +245,9 @@ class DataObject:
...
@@ -283,9 +245,9 @@ class DataObject:
def
modify
(
self
,
nojar
=
0
,
tracing
=
0
):
def
modify
(
self
,
nojar
=
0
,
tracing
=
0
):
if
not
nojar
:
if
not
nojar
:
if
self
.
nost
:
if
self
.
nost
:
self
.
_p_jar
=
NoSubTransaction
Jar
(
tracing
=
tracing
)
self
.
_p_jar
=
Basic
Jar
(
tracing
=
tracing
)
else
:
else
:
self
.
_p_jar
=
SubTransaction
Jar
(
tracing
=
tracing
)
self
.
_p_jar
=
Basic
Jar
(
tracing
=
tracing
)
self
.
transaction_manager
.
get
().
join
(
self
.
_p_jar
)
self
.
transaction_manager
.
get
().
join
(
self
.
_p_jar
)
class
TestTxnException
(
Exception
):
class
TestTxnException
(
Exception
):
...
@@ -350,19 +312,6 @@ class BasicJar:
...
@@ -350,19 +312,6 @@ class BasicJar:
self
.
check
(
'tpc_finish'
)
self
.
check
(
'tpc_finish'
)
self
.
ctpc_finish
+=
1
self
.
ctpc_finish
+=
1
class
SubTransactionJar
(
BasicJar
):
def
abort_sub
(
self
,
txn
):
self
.
check
(
'abort_sub'
)
self
.
cabort_sub
=
1
def
commit_sub
(
self
,
txn
):
self
.
check
(
'commit_sub'
)
self
.
ccommit_sub
=
1
class
NoSubTransactionJar
(
BasicJar
):
pass
class
HoserJar
(
BasicJar
):
class
HoserJar
(
BasicJar
):
# The HoserJars coordinate their actions via the class variable
# The HoserJars coordinate their actions via the class variable
...
@@ -482,17 +431,13 @@ def test_beforeCommitHook():
...
@@ -482,17 +431,13 @@ def test_beforeCommitHook():
>>> log
>>> log
[]
[]
The hook is only called for a full commit, not for a savepoint or
The hook is only called for a full commit, not for a savepoint.
subtransaction.
>>> t = transaction.begin()
>>> t = transaction.begin()
>>> t.beforeCommitHook(hook, 'A', kw1='B')
>>> t.beforeCommitHook(hook, 'A', kw1='B')
>>> dummy = t.savepoint()
>>> dummy = t.savepoint()
>>> log
>>> log
[]
[]
>>> t.commit(subtransaction=True)
>>> log
[]
>>> t.commit()
>>> t.commit()
>>> log
>>> log
["arg 'A' kw1 'B' kw2 'no_kw2'"]
["arg 'A' kw1 'B' kw2 'no_kw2'"]
...
@@ -632,17 +577,13 @@ def test_addBeforeCommitHook():
...
@@ -632,17 +577,13 @@ def test_addBeforeCommitHook():
>>> log
>>> log
[]
[]
The hook is only called for a full commit, not for a savepoint or
The hook is only called for a full commit, not for a savepoint.
subtransaction.
>>> t = transaction.begin()
>>> t = transaction.begin()
>>> t.addBeforeCommitHook(hook, 'A', dict(kw1='B'))
>>> t.addBeforeCommitHook(hook, 'A', dict(kw1='B'))
>>> dummy = t.savepoint()
>>> dummy = t.savepoint()
>>> log
>>> log
[]
[]
>>> t.commit(subtransaction=True)
>>> log
[]
>>> t.commit()
>>> t.commit()
>>> log
>>> log
["arg 'A' kw1 'B' kw2 'no_kw2'"]
["arg 'A' kw1 'B' kw2 'no_kw2'"]
...
@@ -810,17 +751,13 @@ def test_addAfterCommitHook():
...
@@ -810,17 +751,13 @@ def test_addAfterCommitHook():
>>> log
>>> log
[]
[]
The hook is only called after a full commit, not for a savepoint or
The hook is only called after a full commit, not for a savepoint.
subtransaction.
>>> t = transaction.begin()
>>> t = transaction.begin()
>>> t.addAfterCommitHook(hook, 'A', dict(kw1='B'))
>>> t.addAfterCommitHook(hook, 'A', dict(kw1='B'))
>>> dummy = t.savepoint()
>>> dummy = t.savepoint()
>>> log
>>> log
[]
[]
>>> t.commit(subtransaction=True)
>>> log
[]
>>> t.commit()
>>> t.commit()
>>> log
>>> log
["True arg 'A' kw1 'B' kw2 'no_kw2'"]
["True arg 'A' kw1 'B' kw2 'no_kw2'"]
...
@@ -844,7 +781,7 @@ def test_addAfterCommitHook():
...
@@ -844,7 +781,7 @@ def test_addAfterCommitHook():
>>> class CommitFailure(Exception):
>>> class CommitFailure(Exception):
... pass
... pass
>>> class FailingDataManager:
>>> class FailingDataManager:
... def tpc_begin(self, txn
, sub=False
):
... def tpc_begin(self, txn):
... raise CommitFailure
... raise CommitFailure
... def abort(self, txn):
... def abort(self, txn):
... pass
... pass
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment