Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
W
wendelin.core
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
Joshua
wendelin.core
Commits
851636d1
Commit
851636d1
authored
Dec 11, 2019
by
Kirill Smelkov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
.
parent
416e9ccf
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
80 additions
and
6 deletions
+80
-6
zloadrace.py
zloadrace.py
+79
-6
zopenrace.py
zopenrace.py
+1
-0
No files found.
zloadrace.py
View file @
851636d1
...
@@ -2,20 +2,41 @@
...
@@ -2,20 +2,41 @@
"""Program zloadrace.py demonstrates concurrency bug in ZODB Connection.setstate()
"""Program zloadrace.py demonstrates concurrency bug in ZODB Connection.setstate()
that leads to XXX
that leads to XXX
XXX
XXX no, there is no load vs invalidation race on ZODB4 (ZODB3 is probably the same):
ZEO
---
ZEO server explicitly guarantees that it does not mix processing load
requests inside tpc_finish + send invalidations. This way if load is processed
after new commit, load reply is guranteed to come to client after invalidation
message. This was explicitly fixed by
https://github.com/zopefoundation/ZEO/commit/71eb1456
(search for callAsyncNoPoll there)
and later again by https://github.com/zopefoundation/ZEO/commit/94f275c3 .
NEO
---
XXX load vs invalidation race is there on ZODB4 and ZODB3, but on ZODB5 there is
XXX load vs invalidation race is there on ZODB4 and ZODB3, but on ZODB5 there is
another open vs invalidation race.
another open vs invalidation race.
"""
"""
from
__future__
import
print_function
from
ZODB
import
DB
from
ZODB
import
DB
import
transaction
import
transaction
from
persistent
import
Persistent
from
persistent
import
Persistent
from
wendelin.lib.testing
import
TestDB_ZEO
,
TestDB_NEO
from
wendelin.lib.testing
import
TestDB_ZEO
,
TestDB_NEO
from
golang
import
func
,
defer
from
golang
import
func
,
defer
,
chan
,
select
,
default
from
golang
import
sync
,
context
from
golang
import
sync
,
context
import
threading
from
ZODB.utils
import
u64
# PInt is persistent integer.
# PInt is persistent integer.
...
@@ -25,8 +46,8 @@ class PInt(Persistent):
...
@@ -25,8 +46,8 @@ class PInt(Persistent):
@
func
@
func
def
main
():
def
main
():
tdb
=
TestDB_ZEO
(
'<zeo>'
)
#
tdb = TestDB_ZEO('<zeo>')
#
tdb = TestDB_NEO('<neo>')
tdb
=
TestDB_NEO
(
'<neo>'
)
tdb
.
setup
()
tdb
.
setup
()
# XXX defer(tdb.teardown)
# XXX defer(tdb.teardown)
...
@@ -38,6 +59,9 @@ def main():
...
@@ -38,6 +59,9 @@ def main():
db1
=
DB
(
zstor1
)
db1
=
DB
(
zstor1
)
db2
=
DB
(
zstor2
)
db2
=
DB
(
zstor2
)
zstor1
.
app
.
poll_thread
.
name
=
'C1.poll'
zstor2
.
app
.
poll_thread
.
name
=
'C2.poll'
# XXX doc
# XXX doc
def
init
():
def
init
():
...
@@ -52,35 +76,64 @@ def main():
...
@@ -52,35 +76,64 @@ def main():
zconn
.
close
()
zconn
.
close
()
c2ready
=
chan
()
# c1 <- c2 "I'm ready to commit"
c2start
=
chan
()
# c1 -> c2 "go on to commit"
def
C1
(
ctx
,
N
):
def
C1
(
ctx
,
N
):
threading
.
current_thread
().
name
=
"C1"
def
c1
():
def
c1
():
transaction
.
begin
()
transaction
.
begin
()
zconn
=
db1
.
open
()
zconn
=
db1
.
open
()
print
(
'C1: (1) neo.app.last_tid = @%d'
%
u64
(
zstor1
.
app
.
last_tid
))
root
=
zconn
.
root
()
root
=
zconn
.
root
()
obj1
=
root
[
'obj1'
]
obj1
=
root
[
'obj1'
]
obj2
=
root
[
'obj2'
]
obj2
=
root
[
'obj2'
]
I
=
obj1
.
i
print
(
'C1: (2) neo.app.last_tid = @%d'
%
u64
(
zstor1
.
app
.
last_tid
))
print
(
'C1: (2) obj1.serial = @%d'
%
u64
(
obj1
.
_p_serial
))
c2ready
.
recv
()
c2start
.
send
(
1
)
import
time
time
.
sleep
(
0.5
)
# obj1 - reload it from zstor
# obj1 - reload it from zstor
# obj2 - get it from zconn cache
# obj2 - get it from zconn cache
for
i
in
range
(
10
*
N
):
#for i in range(N):
for
i
in
range
(
15
):
obj1
.
_p_invalidate
()
obj1
.
_p_invalidate
()
print
(
'C1: (X) neo.app.last_tid = @%d'
%
u64
(
zstor1
.
app
.
last_tid
))
# both objects must have the same values
# both objects must have the same values
i1
=
obj1
.
i
i1
=
obj1
.
i
i2
=
obj2
.
i
i2
=
obj2
.
i
print
(
'C1: (X) obj1.serial = @%d'
%
u64
(
obj1
.
_p_serial
))
print
(
'C1: (X) obj2.serial = @%d'
%
u64
(
obj2
.
_p_serial
))
if
i1
!=
i2
:
if
i1
!=
i2
:
raise
AssertionError
(
"C1: obj1.i (%d) != obj2.i (%d)"
%
(
i1
,
i2
))
raise
AssertionError
(
"C1: obj1.i (%d) != obj2.i (%d)"
%
(
i1
,
i2
))
if
i1
!=
I
:
raise
AssertionError
(
"C1: obj1.i (%d) mutated inside transaction (started with %d)"
%
(
i1
,
I
))
transaction
.
abort
()
transaction
.
abort
()
zconn
.
close
()
zconn
.
close
()
for
i
in
range
(
N
):
for
i
in
range
(
N
):
if
ready
(
ctx
.
done
()):
break
print
(
'C1.%d'
%
i
)
print
(
'C1.%d'
%
i
)
c1
()
c1
()
print
(
'C1.fin'
)
def
C2
(
ctx
,
N
):
def
C2
(
ctx
,
N
):
threading
.
current_thread
().
name
=
"C2"
def
c2
():
def
c2
():
transaction
.
begin
()
transaction
.
begin
()
zconn
=
db2
.
open
()
zconn
=
db2
.
open
()
...
@@ -92,24 +145,44 @@ def main():
...
@@ -92,24 +145,44 @@ def main():
obj2
.
i
+=
1
obj2
.
i
+=
1
assert
obj1
.
i
==
obj2
.
i
assert
obj1
.
i
==
obj2
.
i
c2ready
.
send
(
1
)
c2start
.
recv
()
transaction
.
commit
()
transaction
.
commit
()
zconn
.
close
()
zconn
.
close
()
for
i
in
range
(
N
):
for
i
in
range
(
N
):
if
ready
(
ctx
.
done
()):
break
print
(
'C2.%d'
%
i
)
print
(
'C2.%d'
%
i
)
c2
()
c2
()
print
(
'C2.fin'
)
init
()
init
()
import
time
time
.
sleep
(
2
)
print
()
N
=
100
N
=
100
0
wg
=
sync
.
WorkGroup
(
context
.
background
())
wg
=
sync
.
WorkGroup
(
context
.
background
())
wg
.
go
(
C1
,
N
)
wg
.
go
(
C1
,
N
)
wg
.
go
(
C2
,
N
)
wg
.
go
(
C2
,
N
)
wg
.
wait
()
wg
.
wait
()
# ready returns whether channel ch is ready.
def
ready
(
ch
):
_
,
_rx
=
select
(
default
,
# 0
ch
.
recv
,
# 1
)
if
_
==
0
:
return
False
return
True
if
__name__
==
'__main__'
:
if
__name__
==
'__main__'
:
main
()
main
()
zopenrace.py
View file @
851636d1
...
@@ -87,6 +87,7 @@ XXX but they do have load vs invalidation race.
...
@@ -87,6 +87,7 @@ XXX but they do have load vs invalidation race.
[2] https://github.com/zopefoundation/ZODB/blob/5.5.1-29-g0b3db5aee/src/ZODB/mvccadapter.py#L130-L139
[2] https://github.com/zopefoundation/ZODB/blob/5.5.1-29-g0b3db5aee/src/ZODB/mvccadapter.py#L130-L139
"""
"""
from
__future__
import
print_function
from
ZODB
import
DB
from
ZODB
import
DB
from
ZODB.MappingStorage
import
MappingStorage
from
ZODB.MappingStorage
import
MappingStorage
import
transaction
import
transaction
...
...
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