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
Labels
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Commits
Open sidebar
Kirill Smelkov
wendelin.core
Commits
5c299054
Commit
5c299054
authored
Jun 27, 2019
by
Kirill Smelkov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
.
parent
6adc53bd
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
86 additions
and
11 deletions
+86
-11
wcfs/wcfs.go
wcfs/wcfs.go
+64
-8
wcfs/wcfs_test.py
wcfs/wcfs_test.py
+22
-3
No files found.
wcfs/wcfs.go
View file @
5c299054
...
...
@@ -512,6 +512,10 @@ type Head struct {
// head/watch opens
// XXX protected by ... zheadMu ?
wlinkTab
map
[
*
WatchLink
]
struct
{}
// waiters for zconn.At to become ≥ their at.
hwaitMu
sync
.
Mutex
// zheadMu.W | zheadMu.R + hwaitMu
hwait
map
[
hwaiter
]
struct
{}
// set{(at, ready)}
}
// /(head|<rev>)/bigfile/ - served by BigFileDir.
...
...
@@ -520,12 +524,12 @@ type BigFileDir struct {
head
*
Head
// parent head/ or @<rev>/
// {} oid -> <bigfileX>
fileMu
sync
.
Mutex
fileMu
sync
.
Mutex
// XXX doc zheadMu.W | ... ?
fileTab
map
[
zodb
.
Oid
]
*
BigFile
// δ tail of tracked BTree nodes of all BigFiles + -> which file
// (used only for head/, not revX/)
δFmu
sync
.
RWMutex
δFmu
sync
.
RWMutex
// XXX doc zheadMu.W | ... ?
δFtail
*
ΔFtail
}
...
...
@@ -556,7 +560,7 @@ type BigFile struct {
//
// Being a staging area for data to enter OS cache, loading has to be
// consulted/invalidated whenever wcfs logic needs to consult/invalidate OS cache.
loadMu
sync
.
Mutex
loadMu
sync
.
Mutex
// XXX doc zheadMu.W | ... ?
loading
map
[
int64
]
*
blkLoadState
// #blk -> {... blkdata}
// watches attached to this file.
...
...
@@ -665,8 +669,8 @@ func (_ *zodbCacheControl) PCacheClassify(obj zodb.IPersistent) zodb.PCachePolic
// -------- zhead lock/wait --------
// XXX needed?
// TODO head.zheadMu -> special mutex with Lock(ctx) so that Lock wait could be canceled
func
(
head
*
Head
)
zheadRLock
()
{
head
.
zheadMu
.
RLock
()
}
func
(
head
*
Head
)
zheadRUnlock
()
{
head
.
zheadMu
.
RUnlock
()
}
func
(
head
*
Head
)
zheadLock
()
{
head
.
zheadMu
.
Lock
()
}
...
...
@@ -924,6 +928,54 @@ retry:
// XXX δFtail.ForgetPast(...)
// XXX for f in δF: f.δtail.ForgetPast(...)
// notify zhead.At waiters
for
w
:=
range
head
.
hwait
{
if
w
.
at
<=
δZ
.
Tid
{
delete
(
head
.
hwait
,
w
)
close
(
w
.
ready
)
}
}
}
// hwaiter represents someone waiting for zhead to become ≥ at.
type
hwaiter
struct
{
at
zodb
.
Tid
ready
chan
struct
{}
}
// zheadWait waits till head.zconn.At becomes ≥ at.
//
// It returns error either if db is down or ctx is canceled. XXX db -> wcfs?
func
(
head
*
Head
)
zheadWait
(
ctx
context
.
Context
,
at
zodb
.
Tid
)
(
err
error
)
{
defer
xerr
.
Contextf
(
&
err
,
"wait zhead ≥ %s"
,
at
)
if
head
.
rev
!=
0
{
panic
(
"must be called only for head/, not @revX/"
)
}
// check if zhead is already ≥ at
head
.
zheadMu
.
RLock
()
if
head
.
zconn
.
At
()
>=
at
{
head
.
zheadMu
.
RUnlock
()
return
}
// no - we have to wait for it
ready
:=
make
(
chan
struct
{})
head
.
hwaitMu
.
Lock
()
head
.
hwait
[
hwaiter
{
at
,
ready
}]
=
struct
{}{}
head
.
hwaitMu
.
Unlock
()
head
.
zheadMu
.
RUnlock
()
select
{
case
<-
ctx
.
Done
()
:
return
ctx
.
Err
()
case
<-
ready
:
return
nil
// ok - zhead.At went ≥ at
}
}
// invalidateBlk invalidates 1 file block in kernel cache.
...
...
@@ -1430,15 +1482,18 @@ func (wlink *WatchLink) setupWatch(ctx context.Context, foid zodb.Oid, at zodb.T
// check at >= w.at
// XXX we might want to allow going back in history if we need it.
if
!
(
at
>=
w
.
at
)
{
return
fmt
.
Errorf
(
"going back
ZZ
history is forbidden"
)
return
fmt
.
Errorf
(
"going back
in
history is forbidden"
)
}
// XXX locking
err
=
head
.
zheadWait
(
ctx
,
at
)
if
err
!=
nil
{
return
err
}
// XXX locking
headAt
:=
head
.
zconn
.
At
()
// XXX wait head.zconn.At() ≥ at
// XXX <~> f.δtail.Head() ≥ at (?)
if
at
<
bfdir
.
δFtail
.
Tail
()
{
return
fmt
.
Errorf
(
"too far away back from head/at (@%s); δt = %s"
,
headAt
,
headAt
.
Time
()
.
Sub
(
at
.
Time
()
.
Time
))
...
...
@@ -2148,6 +2203,7 @@ func main() {
rev
:
0
,
zconn
:
zhead
,
wlinkTab
:
make
(
map
[
*
WatchLink
]
struct
{}),
hwait
:
make
(
map
[
hwaiter
]
struct
{}),
}
wnode
:=
&
WatchNode
{
...
...
wcfs/wcfs_test.py
View file @
5c299054
...
...
@@ -34,6 +34,7 @@ from persistent.timestamp import TimeStamp
from
ZODB.utils
import
z64
,
u64
,
p64
import
sys
,
os
,
os
.
path
,
subprocess
,
threading
,
inspect
,
traceback
,
re
from
thread
import
get_ident
as
gettid
from
time
import
gmtime
from
errno
import
EINVAL
from
golang
import
go
,
chan
,
select
,
func
,
defer
,
default
...
...
@@ -208,6 +209,11 @@ class tDB:
t
.
_files
=
set
()
t
.
_wlinks
=
set
()
# ID of the thread which created tDB
# ( transaction plays dirty games with threading.local and we have to
# check the thread is the same when .root is used )
t
.
_maintid
=
gettid
()
# prepare initail objects for test: zfile, nonzfile
t
.
root
[
'!file'
]
=
t
.
nonzfile
=
Persistent
()
t
.
root
[
'zfile'
]
=
t
.
zfile
=
ZBigFile
(
blksize
)
...
...
@@ -266,11 +272,15 @@ class tDB:
assert
changeDelta
is
not
None
t
.
change
(
zf
,
changeDelta
)
# we'll verify that all changed objects come from the same ZODB connection
zconns
=
set
()
# perform modifications scheduled by change.
# use !wcfs mode so that we prepare data independently of wcfs code paths.
dF
=
DF
()
for
zf
,
zfDelta
in
t
.
_changed
.
items
():
dfile
=
DFile
()
zconns
.
add
(
zf
.
_p_jar
)
zfh
=
zf
.
fileh_open
(
_use_wcfs
=
False
)
for
blk
,
data
in
zfDelta
.
iteritems
():
dfile
.
ddata
[
blk
]
=
data
...
...
@@ -279,9 +289,18 @@ class tDB:
memcpy
(
vma
,
data
)
dF
.
byfile
[
zf
]
=
dfile
assert
len
(
zconns
)
in
(
0
,
1
)
# either nothing to commit or all from the same zconn
if
len
(
zconns
)
==
1
:
zconn
=
zconns
.
pop
()
root
=
zconn
.
root
()
else
:
# no objects to commit
root
=
t
.
root
assert
gettid
()
==
t
.
_maintid
# perform the commit. NOTE there is no clean way to retrieve tid of
# just committed transaction - we use last._p_serial as workaround.
t
.
root
[
'_last'
]
=
last
=
Persistent
()
root
[
'_last'
]
=
last
=
Persistent
()
last
.
_p_changed
=
1
transaction
.
commit
()
head
=
tAt
(
t
,
last
.
_p_serial
)
...
...
@@ -1456,7 +1475,7 @@ def test_wcfs_watch_setup_ahead():
f
=
t
.
open
(
zf
)
at1
=
t
.
commit
(
zf
,
{
2
:
'c1'
})
f
.
assertData
([
''
,
'
'
,
'c1'
])
f
.
assertData
([
''
,
'
x'
,
'c1'
])
# NOTE #1 not accessed
wg
=
sync
.
WorkGroup
(
timeout
())
dt
=
100
*
time
.
millisecond
...
...
@@ -1491,7 +1510,7 @@ def test_wcfs_watch_setup_ahead():
time
.
sleep
(
10
*
dt
)
committing
.
close
()
at2
=
t
.
commit
(
zf
,
{
2
:
'c
2'
})
at2
=
t
.
commit
(
zf
,
{
1
:
'b
2'
})
assert
tidtime
(
at2
)
-
tidtime
(
at1
)
>=
10
*
dt
wg
.
go
(
_
)
...
...
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