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
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Nicolas Wavrant
ZODB
Commits
1867f7c4
Commit
1867f7c4
authored
Jan 07, 2003
by
Jeremy Hylton
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Rewrite tests to make sure they actually test the commit lock.
parent
4c2ed62d
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
144 additions
and
94 deletions
+144
-94
src/ZEO/tests/CommitLockTests.py
src/ZEO/tests/CommitLockTests.py
+144
-94
No files found.
src/ZEO/tests/CommitLockTests.py
View file @
1867f7c4
...
@@ -51,8 +51,7 @@ class WorkerThread(TestThread):
...
@@ -51,8 +51,7 @@ class WorkerThread(TestThread):
oid
=
self
.
storage
.
new_oid
()
oid
=
self
.
storage
.
new_oid
()
p
=
zodb_pickle
(
MinPO
(
"c"
))
p
=
zodb_pickle
(
MinPO
(
"c"
))
self
.
storage
.
store
(
oid
,
ZERO
,
p
,
''
,
self
.
trans
)
self
.
storage
.
store
(
oid
,
ZERO
,
p
,
''
,
self
.
trans
)
self
.
ready
.
set
()
self
.
myvote
()
self
.
storage
.
tpc_vote
(
self
.
trans
)
if
self
.
method
==
"tpc_finish"
:
if
self
.
method
==
"tpc_finish"
:
self
.
storage
.
tpc_finish
(
self
.
trans
)
self
.
storage
.
tpc_finish
(
self
.
trans
)
else
:
else
:
...
@@ -60,122 +59,173 @@ class WorkerThread(TestThread):
...
@@ -60,122 +59,173 @@ class WorkerThread(TestThread):
except
Disconnected
:
except
Disconnected
:
pass
pass
def
myvote
(
self
):
# The vote() call is synchronous, which makes it difficult to
# coordinate the action of multiple threads that all call
# vote(). This method sends the vote call, then sets the
# event saying vote was called, then waits for the vote
# response. It digs deep into the implementation of the client.
# This method is a replacement for:
# self.ready.set()
# self.storage.tpc_vote(self.trans)
rpc
=
self
.
storage
.
_server
.
rpc
msgid
=
rpc
.
_deferred_call
(
'vote'
,
self
.
storage
.
_serial
)
self
.
ready
.
set
()
rpc
.
_deferred_wait
(
msgid
)
self
.
storage
.
_check_serials
()
class
CommitLockTests
:
class
CommitLockTests
:
NUM_CLIENTS
=
5
# The commit lock tests verify that the storage successfully
# The commit lock tests verify that the storage successfully
# blocks and restarts transactions when there is content for a
# blocks and restarts transactions when there is contention for a
# single storage. There are a lot of cases to cover.
# single storage. There are a lot of cases to cover. transaction
# has finished.
# CommitLock1 checks the case where a single transaction delays
# The general flow of these tests is to start a transaction by
# other transactions before they actually block. IOW, by the time
# getting far enough into 2PC to acquire the commit lock. Then
# the other transactions get to the vote stage, the first
# begin one or more other connections that also want to commit.
# transaction has finished.
# This causes the commit lock code to be exercised. Once the
# other connections are started, the first transaction completes.
def
checkCommitLock1OnCommit
(
self
):
def
_cleanup
(
self
):
for
store
,
trans
in
self
.
_storages
:
store
.
tpc_abort
(
trans
)
store
.
close
()
self
.
_storages
=
[]
self
.
_storages
=
[]
try
:
self
.
_checkCommitLock
(
"tpc_finish"
,
self
.
_dosetup1
,
self
.
_dowork1
)
finally
:
self
.
_cleanup
()
def
checkCommitLock1OnAbort
(
self
):
def
_start_txn
(
self
):
self
.
_storages
=
[]
txn
=
Transaction
()
try
:
self
.
_storage
.
tpc_begin
(
txn
)
self
.
_checkCommitLock
(
"tpc_abort"
,
self
.
_dosetup1
,
self
.
_dowork1
)
oid
=
self
.
_storage
.
new_oid
()
finally
:
self
.
_storage
.
store
(
oid
,
ZERO
,
zodb_pickle
(
MinPO
(
1
)),
''
,
txn
)
return
oid
,
txn
def
checkCommitLockVoteFinish
(
self
):
oid
,
txn
=
self
.
_start_txn
()
self
.
_storage
.
tpc_vote
(
txn
)
self
.
_begin_threads
()
self
.
_storage
.
tpc_finish
(
txn
)
self
.
_storage
.
load
(
oid
,
''
)
self
.
_finish_threads
()
self
.
_dostore
()
self
.
_cleanup
()
self
.
_cleanup
()
def
checkCommitLock2OnCommit
(
self
):
def
checkCommitLockVoteAbort
(
self
):
self
.
_storages
=
[]
oid
,
txn
=
self
.
_start_txn
()
try
:
self
.
_storage
.
tpc_vote
(
txn
)
self
.
_checkCommitLock
(
"tpc_finish"
,
self
.
_dosetup2
,
self
.
_dowork2
)
finally
:
self
.
_begin_threads
()
self
.
_storage
.
tpc_abort
(
txn
)
self
.
_finish_threads
()
self
.
_dostore
()
self
.
_cleanup
()
self
.
_cleanup
()
def
checkCommitLock2OnAbort
(
self
):
def
checkCommitLockVoteClose
(
self
):
self
.
_storages
=
[]
oid
,
txn
=
self
.
_start_txn
()
try
:
self
.
_storage
.
tpc_vote
(
txn
)
self
.
_checkCommitLock
(
"tpc_abort"
,
self
.
_dosetup2
,
self
.
_dowork2
)
finally
:
self
.
_begin_threads
()
self
.
_storage
.
close
()
self
.
_finish_threads
()
self
.
_cleanup
()
self
.
_cleanup
()
def
_cleanup
(
self
):
def
_get_trans_id
(
self
):
for
store
,
trans
in
self
.
_storages
:
self
.
_dostore
()
store
.
tpc_abort
(
trans
)
L
=
self
.
_storage
.
undoInfo
()
store
.
close
()
return
L
[
0
][
'id'
]
self
.
_storages
=
[]
def
_checkCommitLock
(
self
,
method_name
,
dosetup
,
dowork
):
def
_begin_undo
(
self
,
trans_id
):
# check the commit lock when a client attemps a transaction,
rpc
=
self
.
_storage
.
_server
.
rpc
# but fails/exits before finishing the commit.
return
rpc
.
_deferred_call
(
'transactionalUndo'
,
trans_id
,
self
.
_storage
.
_serial
)
# The general flow of these tests is to start a transaction by
def
_finish_undo
(
self
,
msgid
):
# calling tpc_begin(). Then begin one or more other
return
self
.
_storage
.
_server
.
rpc
.
_deferred_wait
(
msgid
)
# connections that also want to commit. This causes the
# commit lock code to be exercised. Once the other
# connections are started, the first transaction completes.
# Either by commit or abort, depending on whether method_name
# is "tpc_finish."
# The tests are parameterized by method_name, dosetup(), and
# dowork(). The dosetup() function is called with a
# connectioned client storage, transaction, and timestamp.
# Any work it does occurs after the first transaction has
# started, but before it finishes. The dowork() function
# executes after the first transaction has completed.
# Start on transaction normally and get the lock.
t
=
Transaction
()
self
.
_storage
.
tpc_begin
(
t
)
oid
=
self
.
_storage
.
new_oid
()
self
.
_storage
.
store
(
oid
,
ZERO
,
zodb_pickle
(
MinPO
(
1
)),
''
,
t
)
self
.
_storage
.
tpc_vote
(
t
)
# Start a second transaction on a different connection without
def
checkCommitLockUndoFinish
(
self
):
# blocking the test thread.
trans_id
=
self
.
_get_trans_id
()
self
.
_storages
=
[]
oid
,
txn
=
self
.
_start_txn
()
for
i
in
range
(
4
):
msgid
=
self
.
_begin_undo
(
trans_id
)
storage2
=
self
.
_duplicate_client
()
t2
=
Transaction
()
self
.
_begin_threads
()
tid
=
self
.
_get_timestamp
()
dosetup
(
storage2
,
t2
,
tid
)
if
i
==
0
:
storage2
.
close
()
else
:
self
.
_storages
.
append
((
storage2
,
t2
))
if
method_name
==
"tpc_finish"
:
self
.
_finish_undo
(
msgid
)
self
.
_storage
.
tpc_finish
(
t
)
self
.
_storage
.
tpc_vote
(
txn
)
self
.
_storage
.
tpc_finish
(
txn
)
self
.
_storage
.
load
(
oid
,
''
)
self
.
_storage
.
load
(
oid
,
''
)
else
:
self
.
_storage
.
tpc_abort
(
t
)
dowork
(
method_name
)
self
.
_finish_threads
(
)
# Make sure the server is still responsive
self
.
_dostore
()
self
.
_dostore
()
self
.
_cleanup
()
def
_dosetup1
(
self
,
storage
,
trans
,
tid
):
def
checkCommitLockUndoAbort
(
self
):
storage
.
tpc_begin
(
trans
,
tid
)
trans_id
=
self
.
_get_trans_id
()
oid
,
txn
=
self
.
_start_txn
()
msgid
=
self
.
_begin_undo
(
trans_id
)
def
_dowork1
(
self
,
method_name
):
self
.
_begin_threads
()
for
store
,
trans
in
self
.
_storages
:
oid
=
store
.
new_oid
()
self
.
_finish_undo
(
msgid
)
store
.
store
(
oid
,
ZERO
,
zodb_pickle
(
MinPO
(
"c"
)),
''
,
trans
)
self
.
_storage
.
tpc_vote
(
txn
)
store
.
tpc_vote
(
trans
)
self
.
_storage
.
tpc_abort
(
txn
)
if
method_name
==
"tpc_finish"
:
store
.
tpc_finish
(
trans
)
self
.
_finish_threads
()
else
:
store
.
tpc_abort
(
trans
)
def
_dosetup2
(
self
,
storage
,
trans
,
tid
):
self
.
_dostore
()
self
.
_cleanup
()
def
checkCommitLockUndoClose
(
self
):
trans_id
=
self
.
_get_trans_id
()
oid
,
txn
=
self
.
_start_txn
()
msgid
=
self
.
_begin_undo
(
trans_id
)
self
.
_begin_threads
()
self
.
_finish_undo
(
msgid
)
self
.
_storage
.
tpc_vote
(
txn
)
self
.
_storage
.
close
()
self
.
_finish_threads
()
self
.
_cleanup
()
def
_begin_threads
(
self
):
# Start a second transaction on a different connection without
# blocking the test thread.
self
.
_storages
=
[]
self
.
_threads
=
[]
self
.
_threads
=
[]
t
=
WorkerThread
(
self
,
storage
,
trans
)
for
i
in
range
(
self
.
NUM_CLIENTS
):
storage
=
self
.
_duplicate_client
()
txn
=
Transaction
()
tid
=
self
.
_get_timestamp
()
t
=
WorkerThread
(
self
,
storage
,
txn
)
self
.
_threads
.
append
(
t
)
self
.
_threads
.
append
(
t
)
t
.
start
()
t
.
start
()
t
.
ready
.
wait
()
t
.
ready
.
wait
()
def
_dowork2
(
self
,
method_name
):
# Close on the connections abnormally to test server response
if
i
==
0
:
storage
.
close
()
else
:
self
.
_storages
.
append
((
storage
,
txn
))
def
_finish_threads
(
self
):
for
t
in
self
.
_threads
:
for
t
in
self
.
_threads
:
t
.
cleanup
()
t
.
cleanup
()
...
...
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