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
11c95175
Commit
11c95175
authored
Jul 01, 2021
by
Kirill Smelkov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
.
parent
042c5eeb
Changes
11
Show whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
340 additions
and
272 deletions
+340
-272
wcfs/internal/xbtree/blib/pptreesubset.go
wcfs/internal/xbtree/blib/pptreesubset.go
+3
-3
wcfs/internal/xbtree/treediff.go
wcfs/internal/xbtree/treediff.go
+34
-33
wcfs/internal/xbtree/xbtree.go
wcfs/internal/xbtree/xbtree.go
+0
-2
wcfs/internal/xbtree/xbtreetest/init/init.go
wcfs/internal/xbtree/xbtreetest/init/init.go
+105
-0
wcfs/internal/xbtree/xbtreetest/rtree.go
wcfs/internal/xbtree/xbtreetest/rtree.go
+16
-16
wcfs/internal/xbtree/xbtreetest/treeenv.go
wcfs/internal/xbtree/xbtreetest/treeenv.go
+40
-35
wcfs/internal/xbtree/xbtreetest/xbtreetest.go
wcfs/internal/xbtree/xbtreetest/xbtreetest.go
+12
-9
wcfs/internal/xbtree/xbtreetest/zdata.go
wcfs/internal/xbtree/xbtreetest/zdata.go
+68
-0
wcfs/internal/xbtree/δbtail.go
wcfs/internal/xbtree/δbtail.go
+17
-16
wcfs/internal/xbtree/δbtail_test.go
wcfs/internal/xbtree/δbtail_test.go
+44
-79
wcfs/internal/xbtree/δbtail_x_test.go
wcfs/internal/xbtree/δbtail_x_test.go
+1
-79
No files found.
wcfs/internal/xbtree/blib/pptreesubset.go
View file @
11c95175
...
@@ -102,7 +102,7 @@ func (S PPTreeSubSet) AddPath(path []zodb.Oid) {
...
@@ -102,7 +102,7 @@ func (S PPTreeSubSet) AddPath(path []zodb.Oid) {
// normalize path: remove embedded bucket and check whether it was an
// normalize path: remove embedded bucket and check whether it was an
// artificial empty tree.
// artificial empty tree.
path
=
n
ormPath
(
path
)
path
=
N
ormPath
(
path
)
// go through path and add nodes to the set
// go through path and add nodes to the set
parent
:=
zodb
.
InvalidOid
parent
:=
zodb
.
InvalidOid
...
@@ -132,11 +132,11 @@ func (S PPTreeSubSet) AddPath(path []zodb.Oid) {
...
@@ -132,11 +132,11 @@ func (S PPTreeSubSet) AddPath(path []zodb.Oid) {
}
}
}
}
//
n
ormPath normalizes path.
//
N
ormPath normalizes path.
//
//
// It removes embedded buckets and artificial empty trees.
// It removes embedded buckets and artificial empty trees.
// Returned slice is subslice of path and aliases its memory.
// Returned slice is subslice of path and aliases its memory.
func
n
ormPath
(
path
[]
zodb
.
Oid
)
[]
zodb
.
Oid
{
func
N
ormPath
(
path
[]
zodb
.
Oid
)
[]
zodb
.
Oid
{
l
:=
len
(
path
)
l
:=
len
(
path
)
// don't keep track of artificial empty tree
// don't keep track of artificial empty tree
...
...
wcfs/internal/xbtree/treediff.go
View file @
11c95175
...
@@ -80,6 +80,7 @@ import (
...
@@ -80,6 +80,7 @@ import (
"lab.nexedi.com/kirr/neo/go/zodb"
"lab.nexedi.com/kirr/neo/go/zodb"
"lab.nexedi.com/nexedi/wendelin.core/wcfs/internal/xzodb"
"lab.nexedi.com/nexedi/wendelin.core/wcfs/internal/xzodb"
"lab.nexedi.com/nexedi/wendelin.core/wcfs/internal/xbtree/blib"
)
)
const
traceDiff
=
false
const
traceDiff
=
false
...
@@ -113,7 +114,7 @@ func (δv ΔValue) String() string {
...
@@ -113,7 +114,7 @@ func (δv ΔValue) String() string {
// for example for e.g. t₀->t₁->b₂ if δZ/T={t₀ b₂} -> δZ/TC=δZ/T+{t₁}
// for example for e.g. t₀->t₁->b₂ if δZ/T={t₀ b₂} -> δZ/TC=δZ/T+{t₁}
//
//
// δtopsByRoot = {} root -> {top changed nodes in that tree}
// δtopsByRoot = {} root -> {top changed nodes in that tree}
func
δZConnectTracked
(
δZv
[]
zodb
.
Oid
,
T
PPTreeSubSet
)
(
δZTC
setOid
,
δtopsByRoot
map
[
zodb
.
Oid
]
setOid
)
{
func
δZConnectTracked
(
δZv
[]
zodb
.
Oid
,
T
blib
.
PPTreeSubSet
)
(
δZTC
setOid
,
δtopsByRoot
map
[
zodb
.
Oid
]
setOid
)
{
δZ
:=
setOid
{};
for
_
,
δ
:=
range
δZv
{
δZ
.
Add
(
δ
)
}
δZ
:=
setOid
{};
for
_
,
δ
:=
range
δZv
{
δZ
.
Add
(
δ
)
}
δZTC
=
setOid
{}
δZTC
=
setOid
{}
δtopsByRoot
=
map
[
zodb
.
Oid
]
setOid
{}
δtopsByRoot
=
map
[
zodb
.
Oid
]
setOid
{}
...
@@ -338,18 +339,18 @@ func (rs rangeSplit) String() string {
...
@@ -338,18 +339,18 @@ func (rs rangeSplit) String() string {
// δtops is set of top nodes for changed subtrees.
// δtops is set of top nodes for changed subtrees.
// δZTC is connected(δZ/T) - connected closure for subset of δZ(old..new) that
// δZTC is connected(δZ/T) - connected closure for subset of δZ(old..new) that
// touches tracked nodes of T.
// touches tracked nodes of T.
func
treediff
(
ctx
context
.
Context
,
root
zodb
.
Oid
,
δtops
setOid
,
δZTC
setOid
,
trackSet
PPTreeSubSet
,
zconnOld
,
zconnNew
*
zodb
.
Connection
)
(
δT
map
[
Key
]
ΔValue
,
δtrack
*
ΔPPTreeSubSet
,
δtkeycov
*
RangedKeySet
,
err
error
)
{
func
treediff
(
ctx
context
.
Context
,
root
zodb
.
Oid
,
δtops
setOid
,
δZTC
setOid
,
trackSet
blib
.
PPTreeSubSet
,
zconnOld
,
zconnNew
*
zodb
.
Connection
)
(
δT
map
[
Key
]
ΔValue
,
δtrack
*
blib
.
ΔPPTreeSubSet
,
δtkeycov
*
blib
.
RangedKeySet
,
err
error
)
{
defer
xerr
.
Contextf
(
&
err
,
"treediff %s..%s %s"
,
zconnOld
.
At
(),
zconnNew
.
At
(),
root
)
defer
xerr
.
Contextf
(
&
err
,
"treediff %s..%s %s"
,
zconnOld
.
At
(),
zconnNew
.
At
(),
root
)
δT
=
map
[
Key
]
ΔValue
{}
δT
=
map
[
Key
]
ΔValue
{}
δtrack
=
NewΔPPTreeSubSet
()
δtrack
=
blib
.
NewΔPPTreeSubSet
()
δtkeycov
=
&
RangedKeySet
{}
δtkeycov
=
&
blib
.
RangedKeySet
{}
tracefDiff
(
"
\n
treediff %s δtops: %v δZTC: %v
\n
"
,
root
,
δtops
,
δZTC
)
tracefDiff
(
"
\n
treediff %s δtops: %v δZTC: %v
\n
"
,
root
,
δtops
,
δZTC
)
tracefDiff
(
" trackSet: %v
\n
"
,
trackSet
)
tracefDiff
(
" trackSet: %v
\n
"
,
trackSet
)
defer
tracefDiff
(
"
\n
-> δT: %v
\n
δtrack: %v
\n
δtkeycov: %v
\n
"
,
δT
,
δtrack
,
δtkeycov
)
defer
tracefDiff
(
"
\n
-> δT: %v
\n
δtrack: %v
\n
δtkeycov: %v
\n
"
,
δT
,
δtrack
,
δtkeycov
)
δtrackv
:=
[]
*
ΔPPTreeSubSet
{}
δtrackv
:=
[]
*
blib
.
ΔPPTreeSubSet
{}
for
top
:=
range
δtops
{
// XXX -> sorted?
for
top
:=
range
δtops
{
// XXX -> sorted?
a
,
err1
:=
zgetNodeOrNil
(
ctx
,
zconnOld
,
top
)
a
,
err1
:=
zgetNodeOrNil
(
ctx
,
zconnOld
,
top
)
...
@@ -401,7 +402,7 @@ func treediff(ctx context.Context, root zodb.Oid, δtops setOid, δZTC setOid, t
...
@@ -401,7 +402,7 @@ func treediff(ctx context.Context, root zodb.Oid, δtops setOid, δZTC setOid, t
// consistent with b (= a + δ).
// consistent with b (= a + δ).
//
//
// δtkeycov represents how δtrack grows (always grows) tracking set key coverage.
// δtkeycov represents how δtrack grows (always grows) tracking set key coverage.
func
diffX
(
ctx
context
.
Context
,
a
,
b
Node
,
δZTC
setOid
,
trackSet
PPTreeSubSet
)
(
δ
map
[
Key
]
ΔValue
,
δtrack
*
ΔPPTreeSubSet
,
δtkeycov
*
RangedKeySet
,
err
error
)
{
func
diffX
(
ctx
context
.
Context
,
a
,
b
Node
,
δZTC
setOid
,
trackSet
blib
.
PPTreeSubSet
)
(
δ
map
[
Key
]
ΔValue
,
δtrack
*
blib
.
ΔPPTreeSubSet
,
δtkeycov
*
blib
.
RangedKeySet
,
err
error
)
{
if
a
==
nil
&&
b
==
nil
{
if
a
==
nil
&&
b
==
nil
{
panic
(
"BUG: both a & b == nil"
)
// XXX -> not a bug e.g. for `ø ø T` sequence?
panic
(
"BUG: both a & b == nil"
)
// XXX -> not a bug e.g. for `ø ø T` sequence?
}
}
...
@@ -438,11 +439,11 @@ func diffX(ctx context.Context, a, b Node, δZTC setOid, trackSet PPTreeSubSet)
...
@@ -438,11 +439,11 @@ func diffX(ctx context.Context, a, b Node, δZTC setOid, trackSet PPTreeSubSet)
if
isT
{
if
isT
{
return
diffT
(
ctx
,
aT
,
bT
,
δZTC
,
trackSet
)
return
diffT
(
ctx
,
aT
,
bT
,
δZTC
,
trackSet
)
}
else
{
}
else
{
var
δtrack
*
ΔPPTreeSubSet
var
δtrack
*
blib
.
ΔPPTreeSubSet
δ
,
err
:=
diffB
(
ctx
,
aB
,
bB
)
δ
,
err
:=
diffB
(
ctx
,
aB
,
bB
)
if
δ
!=
nil
{
if
δ
!=
nil
{
δtrack
=
NewΔPPTreeSubSet
()
δtrack
=
blib
.
NewΔPPTreeSubSet
()
δtkeycov
=
&
RangedKeySet
{}
δtkeycov
=
&
blib
.
RangedKeySet
{}
}
}
return
δ
,
δtrack
,
δtkeycov
,
err
return
δ
,
δtrack
,
δtkeycov
,
err
}
}
...
@@ -452,13 +453,13 @@ func diffX(ctx context.Context, a, b Node, δZTC setOid, trackSet PPTreeSubSet)
...
@@ -452,13 +453,13 @@ func diffX(ctx context.Context, a, b Node, δZTC setOid, trackSet PPTreeSubSet)
//
//
// a, b point to top of subtrees @old and @new revisions.
// a, b point to top of subtrees @old and @new revisions.
// δZTC is connected set of objects covering δZT (objects changed in this tree in old..new).
// δZTC is connected set of objects covering δZT (objects changed in this tree in old..new).
func
diffT
(
ctx
context
.
Context
,
A
,
B
*
Tree
,
δZTC
setOid
,
trackSet
PPTreeSubSet
)
(
δ
map
[
Key
]
ΔValue
,
δtrack
*
ΔPPTreeSubSet
,
δtkeycov
*
RangedKeySet
,
err
error
)
{
func
diffT
(
ctx
context
.
Context
,
A
,
B
*
Tree
,
δZTC
setOid
,
trackSet
blib
.
PPTreeSubSet
)
(
δ
map
[
Key
]
ΔValue
,
δtrack
*
blib
.
ΔPPTreeSubSet
,
δtkeycov
*
blib
.
RangedKeySet
,
err
error
)
{
tracefDiff
(
" diffT %s %s
\n
"
,
xidOf
(
A
),
xidOf
(
B
))
tracefDiff
(
" diffT %s %s
\n
"
,
xidOf
(
A
),
xidOf
(
B
))
defer
xerr
.
Contextf
(
&
err
,
"diffT %s %s"
,
xidOf
(
A
),
xidOf
(
B
))
defer
xerr
.
Contextf
(
&
err
,
"diffT %s %s"
,
xidOf
(
A
),
xidOf
(
B
))
δ
=
map
[
Key
]
ΔValue
{}
δ
=
map
[
Key
]
ΔValue
{}
δtrack
=
NewΔPPTreeSubSet
()
δtrack
=
blib
.
NewΔPPTreeSubSet
()
δtkeycov
=
&
RangedKeySet
{}
δtkeycov
=
&
blib
.
RangedKeySet
{}
defer
func
()
{
defer
func
()
{
tracefDiff
(
" -> δ: %v
\n
"
,
δ
)
tracefDiff
(
" -> δ: %v
\n
"
,
δ
)
tracefDiff
(
" -> δtrack: %v
\n
"
,
δtrack
)
tracefDiff
(
" -> δtrack: %v
\n
"
,
δtrack
)
...
@@ -564,22 +565,22 @@ ABcov:
...
@@ -564,22 +565,22 @@ ABcov:
Bv
:=
rangeSplit
{
btop
}
// nodes expanded from B
Bv
:=
rangeSplit
{
btop
}
// nodes expanded from B
// for phase 2:
// for phase 2:
Akqueue
:=
&
RangedKeySet
{}
// queue for keys in A to be processed for δ-
Akqueue
:=
&
blib
.
RangedKeySet
{}
// queue for keys in A to be processed for δ-
Bkqueue
:=
&
RangedKeySet
{}
// ----//---- in B for δ+
Bkqueue
:=
&
blib
.
RangedKeySet
{}
// ----//---- in B for δ+
Akdone
:=
&
RangedKeySet
{}
// already processed keys in A
Akdone
:=
&
blib
.
RangedKeySet
{}
// already processed keys in A
Bkdone
:=
&
RangedKeySet
{}
// ----//---- in B
Bkdone
:=
&
blib
.
RangedKeySet
{}
// ----//---- in B
Aktodo
:=
func
(
r
KeyRange
)
{
Aktodo
:=
func
(
r
blib
.
KeyRange
)
{
if
!
Akdone
.
HasRange
(
r
)
{
if
!
Akdone
.
HasRange
(
r
)
{
δtodo
:=
&
RangedKeySet
{}
δtodo
:=
&
blib
.
RangedKeySet
{}
δtodo
.
AddRange
(
r
)
δtodo
.
AddRange
(
r
)
δtodo
.
DifferenceInplace
(
Akdone
)
δtodo
.
DifferenceInplace
(
Akdone
)
debugfDiff
(
" Akq <- %s
\n
"
,
δtodo
)
debugfDiff
(
" Akq <- %s
\n
"
,
δtodo
)
Akqueue
.
UnionInplace
(
δtodo
)
Akqueue
.
UnionInplace
(
δtodo
)
}
}
}
}
Bktodo
:=
func
(
r
KeyRange
)
{
Bktodo
:=
func
(
r
blib
.
KeyRange
)
{
if
!
Bkdone
.
HasRange
(
r
)
{
if
!
Bkdone
.
HasRange
(
r
)
{
δtodo
:=
&
RangedKeySet
{}
δtodo
:=
&
blib
.
RangedKeySet
{}
δtodo
.
AddRange
(
r
)
δtodo
.
AddRange
(
r
)
δtodo
.
DifferenceInplace
(
Bkdone
)
δtodo
.
DifferenceInplace
(
Bkdone
)
debugfDiff
(
" Bkq <- %s
\n
"
,
δtodo
)
debugfDiff
(
" Bkq <- %s
\n
"
,
δtodo
)
...
@@ -595,8 +596,8 @@ ABcov:
...
@@ -595,8 +596,8 @@ ABcov:
}
}
// δtkeycov will be = BAdd \ ADel
// δtkeycov will be = BAdd \ ADel
δtkeycovADel
:=
&
RangedKeySet
{}
δtkeycovADel
:=
&
blib
.
RangedKeySet
{}
δtkeycovBAdd
:=
&
RangedKeySet
{}
δtkeycovBAdd
:=
&
blib
.
RangedKeySet
{}
// phase 1: expand A top->down driven by δZTC.
// phase 1: expand A top->down driven by δZTC.
// by default a node contributes to δ-
// by default a node contributes to δ-
...
@@ -620,7 +621,7 @@ ABcov:
...
@@ -620,7 +621,7 @@ ABcov:
// a is bucket -> δ-
// a is bucket -> δ-
δA
,
err
:=
diffB
(
ctx
,
a
,
nil
);
/*X*/
if
err
!=
nil
{
return
nil
,
nil
,
nil
,
err
}
δA
,
err
:=
diffB
(
ctx
,
a
,
nil
);
/*X*/
if
err
!=
nil
{
return
nil
,
nil
,
nil
,
err
}
err
=
δMerge
(
δ
,
δA
);
/*X*/
if
err
!=
nil
{
return
nil
,
nil
,
nil
,
err
}
err
=
δMerge
(
δ
,
δA
);
/*X*/
if
err
!=
nil
{
return
nil
,
nil
,
nil
,
err
}
ar
:=
KeyRange
{
ra
.
lo
,
ra
.
hi_
}
ar
:=
blib
.
KeyRange
{
ra
.
lo
,
ra
.
hi_
}
δtrack
.
Del
.
AddPath
(
ra
.
Path
())
δtrack
.
Del
.
AddPath
(
ra
.
Path
())
δtkeycovADel
.
AddRange
(
ar
)
δtkeycovADel
.
AddRange
(
ar
)
debugfDiff
(
" δtrack - %s %v
\n
"
,
ar
,
ra
.
Path
())
debugfDiff
(
" δtrack - %s %v
\n
"
,
ar
,
ra
.
Path
())
...
@@ -632,7 +633,7 @@ ABcov:
...
@@ -632,7 +633,7 @@ ABcov:
case
*
Tree
:
case
*
Tree
:
// empty tree - queue holes covered by it
// empty tree - queue holes covered by it
if
len
(
a
.
Entryv
())
==
0
{
if
len
(
a
.
Entryv
())
==
0
{
ar
:=
KeyRange
{
ra
.
lo
,
ra
.
hi_
}
ar
:=
blib
.
KeyRange
{
ra
.
lo
,
ra
.
hi_
}
δtrack
.
Del
.
AddPath
(
ra
.
Path
())
δtrack
.
Del
.
AddPath
(
ra
.
Path
())
δtkeycovADel
.
AddRange
(
ar
)
δtkeycovADel
.
AddRange
(
ar
)
debugfDiff
(
" δtrack - %s %v
\n
"
,
ar
,
ra
.
Path
())
debugfDiff
(
" δtrack - %s %v
\n
"
,
ar
,
ra
.
Path
())
...
@@ -691,8 +692,8 @@ ABcov:
...
@@ -691,8 +692,8 @@ ABcov:
}
}
if
found
{
if
found
{
// ac can be skipped if key coverage stays the same
// ac can be skipped if key coverage stays the same
ar
:=
KeyRange
{
ac
.
lo
,
ac
.
hi_
}
ar
:=
blib
.
KeyRange
{
ac
.
lo
,
ac
.
hi_
}
br
:=
KeyRange
{
bc
.
lo
,
bc
.
hi_
}
br
:=
blib
.
KeyRange
{
bc
.
lo
,
bc
.
hi_
}
if
ar
==
br
{
if
ar
==
br
{
// adjust trackSet since path to the node could have changed
// adjust trackSet since path to the node could have changed
apath
:=
ac
.
Path
()
apath
:=
ac
.
Path
()
...
@@ -744,7 +745,7 @@ ABcov:
...
@@ -744,7 +745,7 @@ ABcov:
}
}
for
_
,
r
:=
range
Bkqueue
.
AllRanges
()
{
for
_
,
r
:=
range
Bkqueue
.
AllRanges
()
{
lo
:=
r
.
l
o
lo
:=
r
.
L
o
for
{
for
{
b
,
err
:=
Bv
.
GetToLeaf
(
ctx
,
lo
);
/*X*/
if
err
!=
nil
{
return
nil
,
nil
,
nil
,
err
}
b
,
err
:=
Bv
.
GetToLeaf
(
ctx
,
lo
);
/*X*/
if
err
!=
nil
{
return
nil
,
nil
,
nil
,
err
}
debugfDiff
(
" B k%d -> %s
\n
"
,
lo
,
b
)
debugfDiff
(
" B k%d -> %s
\n
"
,
lo
,
b
)
...
@@ -758,7 +759,7 @@ ABcov:
...
@@ -758,7 +759,7 @@ ABcov:
// δ <- δB
// δ <- δB
err
=
δMerge
(
δ
,
δB
);
/*X*/
if
err
!=
nil
{
return
nil
,
nil
,
nil
,
err
}
err
=
δMerge
(
δ
,
δB
);
/*X*/
if
err
!=
nil
{
return
nil
,
nil
,
nil
,
err
}
br
:=
KeyRange
{
b
.
lo
,
b
.
hi_
}
br
:=
blib
.
KeyRange
{
b
.
lo
,
b
.
hi_
}
δtrack
.
Add
.
AddPath
(
b
.
Path
())
δtrack
.
Add
.
AddPath
(
b
.
Path
())
δtkeycovBAdd
.
AddRange
(
br
)
δtkeycovBAdd
.
AddRange
(
br
)
debugfDiff
(
" δtrack + %s %v
\n
"
,
br
,
b
.
Path
())
debugfDiff
(
" δtrack + %s %v
\n
"
,
br
,
b
.
Path
())
...
@@ -771,7 +772,7 @@ ABcov:
...
@@ -771,7 +772,7 @@ ABcov:
}
}
// continue with next right bucket until r coverage is complete
// continue with next right bucket until r coverage is complete
if
r
.
h
i_
<=
b
.
hi_
{
if
r
.
H
i_
<=
b
.
hi_
{
break
break
}
}
lo
=
b
.
hi_
+
1
lo
=
b
.
hi_
+
1
...
@@ -782,7 +783,7 @@ ABcov:
...
@@ -782,7 +783,7 @@ ABcov:
debugfDiff
(
"
\n
"
)
debugfDiff
(
"
\n
"
)
debugfDiff
(
" Akq: %s
\n
"
,
Akqueue
)
debugfDiff
(
" Akq: %s
\n
"
,
Akqueue
)
for
_
,
r
:=
range
Akqueue
.
AllRanges
()
{
for
_
,
r
:=
range
Akqueue
.
AllRanges
()
{
lo
:=
r
.
l
o
lo
:=
r
.
L
o
for
{
for
{
a
,
err
:=
Av
.
GetToLeaf
(
ctx
,
lo
);
/*X*/
if
err
!=
nil
{
return
nil
,
nil
,
nil
,
err
}
a
,
err
:=
Av
.
GetToLeaf
(
ctx
,
lo
);
/*X*/
if
err
!=
nil
{
return
nil
,
nil
,
nil
,
err
}
debugfDiff
(
" A k%d -> %s
\n
"
,
lo
,
a
)
debugfDiff
(
" A k%d -> %s
\n
"
,
lo
,
a
)
...
@@ -798,7 +799,7 @@ ABcov:
...
@@ -798,7 +799,7 @@ ABcov:
err
=
δMerge
(
δ
,
δA
);
/*X*/
if
err
!=
nil
{
return
nil
,
nil
,
nil
,
err
}
err
=
δMerge
(
δ
,
δA
);
/*X*/
if
err
!=
nil
{
return
nil
,
nil
,
nil
,
err
}
δtrack
.
Del
.
AddPath
(
a
.
Path
())
δtrack
.
Del
.
AddPath
(
a
.
Path
())
// NOTE adjust δtkeycovADel only if a was originally tracked
// NOTE adjust δtkeycovADel only if a was originally tracked
ar
:=
KeyRange
{
a
.
lo
,
a
.
hi_
}
ar
:=
blib
.
KeyRange
{
a
.
lo
,
a
.
hi_
}
_
,
tracked
:=
trackSet
[
a
.
node
.
POid
()]
_
,
tracked
:=
trackSet
[
a
.
node
.
POid
()]
if
tracked
{
if
tracked
{
δtkeycovADel
.
AddRange
(
ar
)
δtkeycovADel
.
AddRange
(
ar
)
...
@@ -815,7 +816,7 @@ ABcov:
...
@@ -815,7 +816,7 @@ ABcov:
}
}
// continue with next right bucket until r coverage is complete
// continue with next right bucket until r coverage is complete
if
r
.
h
i_
<=
a
.
hi_
{
if
r
.
H
i_
<=
a
.
hi_
{
break
break
}
}
lo
=
a
.
hi_
+
1
lo
=
a
.
hi_
+
1
...
@@ -1009,7 +1010,7 @@ func xidOf(obj zodb.IPersistent) string {
...
@@ -1009,7 +1010,7 @@ func xidOf(obj zodb.IPersistent) string {
func
(
rn
*
nodeInRange
)
String
()
string
{
func
(
rn
*
nodeInRange
)
String
()
string
{
done
:=
" "
;
if
rn
.
done
{
done
=
"*"
}
done
:=
" "
;
if
rn
.
done
{
done
=
"*"
}
return
fmt
.
Sprintf
(
"%s%s%s"
,
done
,
KeyRange
{
rn
.
lo
,
rn
.
hi_
},
vnode
(
rn
.
node
))
return
fmt
.
Sprintf
(
"%s%s%s"
,
done
,
blib
.
KeyRange
{
rn
.
lo
,
rn
.
hi_
},
vnode
(
rn
.
node
))
}
}
// push pushes element to node stack.
// push pushes element to node stack.
...
...
wcfs/internal/xbtree/xbtree.go
View file @
11c95175
...
@@ -5,10 +5,8 @@ package xbtree
...
@@ -5,10 +5,8 @@ package xbtree
import
(
import
(
"fmt"
"fmt"
"math"
"lab.nexedi.com/kirr/neo/go/zodb"
"lab.nexedi.com/kirr/neo/go/zodb"
"lab.nexedi.com/kirr/neo/go/zodb/btree"
"lab.nexedi.com/nexedi/wendelin.core/wcfs/internal/set"
"lab.nexedi.com/nexedi/wendelin.core/wcfs/internal/set"
"lab.nexedi.com/nexedi/wendelin.core/wcfs/internal/xbtree/blib"
"lab.nexedi.com/nexedi/wendelin.core/wcfs/internal/xbtree/blib"
...
...
wcfs/internal/xbtree/xbtreetest/init/init.go
0 → 100644
View file @
11c95175
// Copyright (C) 2020-2021 Nexedi SA and Contributors.
// Kirill Smelkov <kirr@nexedi.com>
//
// This program is free software: you can Use, Study, Modify and Redistribute
// it under the terms of the GNU General Public License version 3, or (at your
// option) any later version, as published by the Free Software Foundation.
//
// You can also Link and Combine this program with other software covered by
// the terms of any of the Free Software licenses or any of the Open Source
// Initiative approved licenses and Convey the resulting work. Corresponding
// source of such a combination shall include the source code for all other
// software used.
//
// This program is distributed WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//
// See COPYING file for full licensing terms.
// See https://www.nexedi.com/licensing for rationale and options.
// Package xbtreetest/init (ex imported from package A) should be imported in
// addition to xbtreetest (from package A_test) to initialize xbtreetest at runtime.
package
init
// ZBlk-related part of δbtail_test
import
(
"context"
"fmt"
"lab.nexedi.com/kirr/go123/xerr"
"lab.nexedi.com/kirr/neo/go/zodb"
"lab.nexedi.com/nexedi/wendelin.core/wcfs/internal/xbtree"
"lab.nexedi.com/nexedi/wendelin.core/wcfs/internal/xzodb"
"lab.nexedi.com/nexedi/wendelin.core/wcfs/internal/zdata"
)
type
Tree
=
xbtree
.
Tree
type
Node
=
xbtree
.
Node
type
Key
=
xbtree
.
Key
type
ZBlk
=
zdata
.
ZBlk
// ztreeGetBlk returns ztree[k] and tree path that lead to this block.
// XXX +return blkRevMax and use it ?
func
ztreeGetBlk
(
ctx
context
.
Context
,
ztree
*
Tree
,
k
Key
)
(
zblk
ZBlk
,
ok
bool
,
path
[]
Node
,
err
error
)
{
path
=
[]
Node
{}
xzblk
,
ok
,
err
:=
ztree
.
VGet
(
ctx
,
k
,
func
(
node
Node
)
{
path
=
append
(
path
,
node
)
})
if
err
!=
nil
{
return
nil
,
false
,
nil
,
err
}
if
ok
{
zblk
,
ok
=
xzblk
.
(
ZBlk
)
if
!
ok
{
return
nil
,
false
,
nil
,
fmt
.
Errorf
(
"expect ZBlk*; got %s"
,
xzodb
.
TypeOf
(
xzblk
))
// XXX errctx
}
}
return
zblk
,
ok
,
path
,
nil
}
func
init
()
{
xbtree
.
ZTreeGetBlkData
=
ZTreeGetBlkData
xbtree
.
ZGetBlkData
=
ZGetBlkData
}
// ZTreeGetBlkData returns block data from block pointed to by ztree[k].
func
ZTreeGetBlkData
(
ctx
context
.
Context
,
ztree
*
Tree
,
k
Key
)
(
data
string
,
ok
bool
,
path
[]
Node
,
err
error
)
{
defer
xerr
.
Contextf
(
&
err
,
"@%s: tree<%s>: get blkdata from [%d]"
,
ztree
.
PJar
()
.
At
(),
ztree
.
POid
(),
k
)
zblk
,
ok
,
path
,
err
:=
ztreeGetBlk
(
ctx
,
ztree
,
k
)
if
err
!=
nil
||
!
ok
{
return
""
,
ok
,
path
,
err
}
bdata
,
_
,
err
:=
zblk
.
LoadBlkData
(
ctx
)
if
err
!=
nil
{
return
""
,
false
,
nil
,
err
}
return
string
(
bdata
),
true
,
path
,
nil
}
// ZGetBlkData loads block data from ZBlk object specified by its oid.
func
ZGetBlkData
(
ctx
context
.
Context
,
zconn
*
zodb
.
Connection
,
zblkOid
zodb
.
Oid
)
(
data
string
,
err
error
)
{
defer
xerr
.
Contextf
(
&
err
,
"@%s: get blkdata from obj %s"
,
zconn
.
At
(),
zblkOid
)
xblk
,
err
:=
zconn
.
Get
(
ctx
,
zblkOid
)
if
err
!=
nil
{
return
""
,
err
}
zblk
,
ok
:=
xblk
.
(
ZBlk
)
if
!
ok
{
return
""
,
fmt
.
Errorf
(
"expect ZBlk*; got %s"
,
xzodb
.
TypeOf
(
xblk
))
}
bdata
,
_
,
err
:=
zblk
.
LoadBlkData
(
ctx
)
if
err
!=
nil
{
return
""
,
err
}
return
string
(
bdata
),
nil
}
wcfs/internal/xbtree/xbtreetest/rtree.go
View file @
11c95175
...
@@ -31,27 +31,27 @@ import (
...
@@ -31,27 +31,27 @@ import (
// RTree represents Tree node covering [lo, hi_] key range in its parent tree.
// RTree represents Tree node covering [lo, hi_] key range in its parent tree.
// XXX actually no coverage here -> kill? -> change to just `path []zodb.Oid` in RBucket?
// XXX actually no coverage here -> kill? -> change to just `path []zodb.Oid` in RBucket?
type
RTree
struct
{
type
RTree
struct
{
o
id
zodb
.
Oid
O
id
zodb
.
Oid
p
arent
*
RTree
P
arent
*
RTree
// XXX +children?
// XXX +children?
}
}
// RBucket represents Bucket node covering [lo, hi_] key range in its Tree.
// RBucket represents Bucket node covering [lo, hi_] key range in its Tree.
// NOTE it is not [lo,hi) but [lo,hi_] instead to avoid overflow at KeyMax.
// NOTE it is not [lo,hi) but [lo,hi_] instead to avoid overflow at KeyMax.
type
RBucket
struct
{
type
RBucket
struct
{
o
id
zodb
.
Oid
O
id
zodb
.
Oid
p
arent
*
RTree
P
arent
*
RTree
lo
,
hi_
Key
// XXX -> KeyRange ?
Keycov
blib
.
KeyRange
kv
map
[
Key
]
string
// bucket's k->v; values were ZBlk objects whose data is loaded instead.
KV
map
[
Key
]
string
// bucket's k->v; values were ZBlk objects whose data is loaded instead.
}
}
// Path returns path to this bucket from tree root.
// Path returns path to this bucket from tree root.
func
(
rb
*
RBucket
)
Path
()
[]
zodb
.
Oid
{
func
(
rb
*
RBucket
)
Path
()
[]
zodb
.
Oid
{
path
:=
[]
zodb
.
Oid
{
rb
.
o
id
}
path
:=
[]
zodb
.
Oid
{
rb
.
O
id
}
p
:=
rb
.
p
arent
p
:=
rb
.
P
arent
for
p
!=
nil
{
for
p
!=
nil
{
path
=
append
([]
zodb
.
Oid
{
p
.
o
id
},
path
...
)
path
=
append
([]
zodb
.
Oid
{
p
.
O
id
},
path
...
)
p
=
p
.
p
arent
p
=
p
.
P
arent
}
}
return
path
return
path
}
}
...
@@ -63,15 +63,15 @@ type RBucketSet []*RBucket // k↑
...
@@ -63,15 +63,15 @@ type RBucketSet []*RBucket // k↑
// Get returns RBucket which covers key k.
// Get returns RBucket which covers key k.
func
(
rbs
RBucketSet
)
Get
(
k
Key
)
*
RBucket
{
func
(
rbs
RBucketSet
)
Get
(
k
Key
)
*
RBucket
{
i
:=
sort
.
Search
(
len
(
rbs
),
func
(
i
int
)
bool
{
i
:=
sort
.
Search
(
len
(
rbs
),
func
(
i
int
)
bool
{
return
k
<=
rbs
[
i
]
.
h
i_
return
k
<=
rbs
[
i
]
.
Keycov
.
H
i_
})
})
if
i
==
len
(
rbs
)
{
if
i
==
len
(
rbs
)
{
panicf
(
"BUG: key %v not covered; coverage: %s"
,
k
,
rbs
.
coverage
())
panicf
(
"BUG: key %v not covered; coverage: %s"
,
k
,
rbs
.
coverage
())
}
}
rb
:=
rbs
[
i
]
rb
:=
rbs
[
i
]
if
!
(
rb
.
lo
<=
k
&&
k
<=
rb
.
h
i_
)
{
if
!
(
rb
.
Keycov
.
Lo
<=
k
&&
k
<=
rb
.
Keycov
.
H
i_
)
{
panicf
(
"BUG: get(%v) ->
[%v, %v]; coverage: %s"
,
k
,
rb
.
lo
,
rb
.
hi_
,
rbs
.
coverage
())
panicf
(
"BUG: get(%v) ->
%s; coverage: %s"
,
k
,
rb
.
Keycov
,
rbs
.
coverage
())
}
}
return
rb
return
rb
...
@@ -87,7 +87,7 @@ func (rbs RBucketSet) coverage() string {
...
@@ -87,7 +87,7 @@ func (rbs RBucketSet) coverage() string {
if
s
!=
""
{
if
s
!=
""
{
s
+=
" "
s
+=
" "
}
}
s
+=
fmt
.
Sprintf
(
"
[%v, %v]"
,
rb
.
lo
,
rb
.
hi_
)
s
+=
fmt
.
Sprintf
(
"
%s"
,
rb
.
Keycov
)
}
}
return
s
return
s
}
}
...
@@ -96,7 +96,7 @@ func (rbs RBucketSet) coverage() string {
...
@@ -96,7 +96,7 @@ func (rbs RBucketSet) coverage() string {
func
(
xkv
RBucketSet
)
Flatten
()
map
[
Key
]
string
{
func
(
xkv
RBucketSet
)
Flatten
()
map
[
Key
]
string
{
kv
:=
make
(
map
[
Key
]
string
)
kv
:=
make
(
map
[
Key
]
string
)
for
_
,
b
:=
range
xkv
{
for
_
,
b
:=
range
xkv
{
for
k
,
v
:=
range
b
.
kv
{
for
k
,
v
:=
range
b
.
KV
{
kv
[
k
]
=
v
kv
[
k
]
=
v
}
}
}
}
...
@@ -104,5 +104,5 @@ func (xkv RBucketSet) Flatten() map[Key]string {
...
@@ -104,5 +104,5 @@ func (xkv RBucketSet) Flatten() map[Key]string {
}
}
func
(
b
*
RBucket
)
String
()
string
{
func
(
b
*
RBucket
)
String
()
string
{
return
fmt
.
Sprintf
(
"%sB%s{%s}"
,
b
lib
.
KeyRange
{
b
.
lo
,
b
.
hi_
},
b
.
oid
,
kvtxt
(
b
.
kv
))
return
fmt
.
Sprintf
(
"%sB%s{%s}"
,
b
.
Keycov
,
b
.
Oid
,
kvtxt
(
b
.
KV
))
}
}
wcfs/internal/xbtree/xbtreetest/treeenv.go
View file @
11c95175
...
@@ -18,7 +18,7 @@
...
@@ -18,7 +18,7 @@
// See https://www.nexedi.com/licensing for rationale and options.
// See https://www.nexedi.com/licensing for rationale and options.
package
xbtreetest
package
xbtreetest
// T
reeEnv
+ friends
// T + friends
import
(
import
(
"context"
"context"
...
@@ -28,14 +28,15 @@ import (
...
@@ -28,14 +28,15 @@ import (
"lab.nexedi.com/kirr/neo/go/transaction"
"lab.nexedi.com/kirr/neo/go/transaction"
"lab.nexedi.com/kirr/neo/go/zodb"
"lab.nexedi.com/kirr/neo/go/zodb"
"lab.nexedi.com/nexedi/wendelin.core/wcfs/internal/xbtree/blib"
"lab.nexedi.com/nexedi/wendelin.core/wcfs/internal/xzodb"
"lab.nexedi.com/nexedi/wendelin.core/wcfs/internal/xzodb"
)
)
//
tTreeEnv
is tree-based testing environment.
//
T
is tree-based testing environment.
//
//
// It combines TreeSrv and client side access to ZODB with committed trees.
// It combines TreeSrv and client side access to ZODB with committed trees.
// It should be created it via
tNewTreeEnv
().
// It should be created it via
NewT
().
type
tTreeEnv
struct
{
type
T
struct
{
*
testing
.
T
*
testing
.
T
work
string
// working directory
work
string
// working directory
...
@@ -44,13 +45,13 @@ type tTreeEnv struct {
...
@@ -44,13 +45,13 @@ type tTreeEnv struct {
db
*
zodb
.
DB
db
*
zodb
.
DB
// all committed trees
// all committed trees
commitv
[]
*
tTree
Commit
commitv
[]
*
Commit
}
}
//
tTree
Commit represent test commit changing a tree.
// Commit represent test commit changing a tree.
type
tTree
Commit
struct
{
type
Commit
struct
{
tree
string
// the tree in topology-encoding
tree
string
// the tree in topology-encoding
prev
*
tTreeCommit
// previous commit
prev
*
Commit
// previous commit
at
zodb
.
Tid
// commit revision
at
zodb
.
Tid
// commit revision
δZ
*
zodb
.
EventCommit
// raw ZODB changes; δZ.tid == at
δZ
*
zodb
.
EventCommit
// raw ZODB changes; δZ.tid == at
xkv
RBucketSet
// full tree state as of @at
xkv
RBucketSet
// full tree state as of @at
...
@@ -59,12 +60,12 @@ type tTreeCommit struct {
...
@@ -59,12 +60,12 @@ type tTreeCommit struct {
// δzblkData map[zodb.Oid]Δstring // full diff for zblkData against parent XXX ?
// δzblkData map[zodb.Oid]Δstring // full diff for zblkData against parent XXX ?
}
}
//
tNewTreeEnv creates new tTreeEnv
.
//
NewT creates new T
.
func
tNewTreeEnv
(
t
*
testing
.
T
)
*
tTreeEnv
{
func
NewT
(
t
*
testing
.
T
)
*
T
{
X
:=
exc
.
Raiseif
X
:=
exc
.
Raiseif
t
.
Helper
()
t
.
Helper
()
tt
:=
&
tTreeEnv
{
T
:
t
}
tt
:=
&
T
{
T
:
t
}
var
err
error
var
err
error
work
:=
t
.
TempDir
()
work
:=
t
.
TempDir
()
...
@@ -91,7 +92,7 @@ func tNewTreeEnv(t *testing.T) *tTreeEnv {
...
@@ -91,7 +92,7 @@ func tNewTreeEnv(t *testing.T) *tTreeEnv {
})
})
head
:=
tt
.
treeSrv
.
head
head
:=
tt
.
treeSrv
.
head
t1
:=
&
tTree
Commit
{
t1
:=
&
Commit
{
tree
:
"T/B:"
,
// treegen.py creates the tree as initially empty
tree
:
"T/B:"
,
// treegen.py creates the tree as initially empty
prev
:
nil
,
prev
:
nil
,
at
:
head
,
at
:
head
,
...
@@ -100,7 +101,7 @@ func tNewTreeEnv(t *testing.T) *tTreeEnv {
...
@@ -100,7 +101,7 @@ func tNewTreeEnv(t *testing.T) *tTreeEnv {
δZ
:
nil
,
δZ
:
nil
,
δxkv
:
nil
,
δxkv
:
nil
,
}
}
tt
.
commitv
=
[]
*
tTree
Commit
{
t1
}
tt
.
commitv
=
[]
*
Commit
{
t1
}
return
tt
return
tt
}
}
...
@@ -115,17 +116,18 @@ func (_ *tZODBCacheEverything) PCacheClassify(_ zodb.IPersistent) zodb.PCachePol
...
@@ -115,17 +116,18 @@ func (_ *tZODBCacheEverything) PCacheClassify(_ zodb.IPersistent) zodb.PCachePol
}
}
// Root returns OID of root tree node.
// Root returns OID of root tree node.
func
(
t
*
tTreeEnv
)
Root
()
zodb
.
Oid
{
func
(
t
*
T
)
Root
()
zodb
.
Oid
{
return
t
.
treeSrv
.
treeRoot
return
t
.
treeSrv
.
treeRoot
}
}
// Head returns most-recently committed tree.
// Head returns most-recently committed tree.
func
(
t
*
tTreeEnv
)
Head
()
*
tTree
Commit
{
func
(
t
*
T
)
Head
()
*
Commit
{
return
t
.
commitv
[
len
(
t
.
commitv
)
-
1
]
return
t
.
commitv
[
len
(
t
.
commitv
)
-
1
]
}
}
// CommitTree calls t.treeSrv.Commit and returns tTreeCommit corresponding to committed transaction.
// CommitTree calls t.treeSrv.Commit and returns Commit corresponding to committed transaction.
func
(
t
*
tTreeEnv
)
CommitTree
(
tree
string
)
*
tTreeCommit
{
// XXX naming -> Commit ?
func
(
t
*
T
)
CommitTree
(
tree
string
)
*
Commit
{
// TODO X = FatalIf
// TODO X = FatalIf
X
:=
exc
.
Raiseif
X
:=
exc
.
Raiseif
defer
exc
.
Contextf
(
"commit %s"
,
tree
)
defer
exc
.
Contextf
(
"commit %s"
,
tree
)
...
@@ -164,19 +166,18 @@ func (t *tTreeEnv) CommitTree(tree string) *tTreeCommit {
...
@@ -164,19 +166,18 @@ func (t *tTreeEnv) CommitTree(tree string) *tTreeCommit {
// it comes to ->T2.
// it comes to ->T2.
xkv
=
RBucketSet
{
xkv
=
RBucketSet
{
&
RBucket
{
&
RBucket
{
o
id
:
zodb
.
InvalidOid
,
O
id
:
zodb
.
InvalidOid
,
p
arent
:
&
RTree
{
P
arent
:
&
RTree
{
o
id
:
t
.
Root
(),
// NOTE oid is not InvalidOid
O
id
:
t
.
Root
(),
// NOTE oid is not InvalidOid
p
arent
:
nil
,
P
arent
:
nil
,
},
},
lo
:
KeyMin
,
Keycov
:
blib
.
KeyRange
{
KeyMin
,
KeyMax
},
hi_
:
KeyMax
,
KV
:
map
[
Key
]
string
{},
kv
:
map
[
Key
]
string
{},
},
},
}
}
}
}
ttree
:=
&
tTree
Commit
{
ttree
:=
&
Commit
{
tree
:
tree
,
tree
:
tree
,
at
:
δZ
.
Tid
,
at
:
δZ
.
Tid
,
δZ
:
δZ
,
δZ
:
δZ
,
...
@@ -244,7 +245,7 @@ func xGetBlkDataTab(db *zodb.DB, at zodb.Tid) map[zodb.Oid]string {
...
@@ -244,7 +245,7 @@ func xGetBlkDataTab(db *zodb.DB, at zodb.Tid) map[zodb.Oid]string {
// xgetBlkData loads blk data for ZBlk<oid> @t.at
// xgetBlkData loads blk data for ZBlk<oid> @t.at
//
//
// For speed the load is done via preloaded t.blkDataTab instead of access to the DB.
// For speed the load is done via preloaded t.blkDataTab instead of access to the DB.
func
(
t
*
tTree
Commit
)
xgetBlkData
(
oid
zodb
.
Oid
)
string
{
func
(
t
*
Commit
)
xgetBlkData
(
oid
zodb
.
Oid
)
string
{
if
oid
==
VDEL
{
if
oid
==
VDEL
{
return
DEL
return
DEL
}
}
...
@@ -282,15 +283,14 @@ func xGetTree(db *zodb.DB, at zodb.Tid, root zodb.Oid) RBucketSet {
...
@@ -282,15 +283,14 @@ func xGetTree(db *zodb.DB, at zodb.Tid, root zodb.Oid) RBucketSet {
})
})
if
len
(
rbucketv
)
==
0
{
// empty tree -> [-∞,∞){}
if
len
(
rbucketv
)
==
0
{
// empty tree -> [-∞,∞){}
etree
:=
&
RTree
{
etree
:=
&
RTree
{
o
id
:
root
,
O
id
:
root
,
p
arent
:
nil
,
P
arent
:
nil
,
}
}
ebucket
:=
&
RBucket
{
ebucket
:=
&
RBucket
{
oid
:
zodb
.
InvalidOid
,
Oid
:
zodb
.
InvalidOid
,
parent
:
etree
,
Parent
:
etree
,
lo
:
KeyMin
,
Keycov
:
blib
.
KeyRange
{
KeyMin
,
KeyMax
},
hi_
:
KeyMax
,
KV
:
map
[
Key
]
string
{},
kv
:
map
[
Key
]
string
{},
}
}
rbucketv
=
RBucketSet
{
ebucket
}
rbucketv
=
RBucketSet
{
ebucket
}
}
}
...
@@ -307,7 +307,7 @@ func _xwalkDFS(ctx context.Context, lo, hi_ Key, ztree *Tree, rparent *RTree, bv
...
@@ -307,7 +307,7 @@ func _xwalkDFS(ctx context.Context, lo, hi_ Key, ztree *Tree, rparent *RTree, bv
err
:=
ztree
.
PActivate
(
ctx
);
X
(
err
)
err
:=
ztree
.
PActivate
(
ctx
);
X
(
err
)
defer
ztree
.
PDeactivate
()
defer
ztree
.
PDeactivate
()
rtree
:=
&
RTree
{
oid
:
ztree
.
POid
(),
p
arent
:
rparent
}
rtree
:=
&
RTree
{
Oid
:
ztree
.
POid
(),
P
arent
:
rparent
}
// [i].Key ≤ [i].Child.*.Key < [i+1].Key i ∈ [0, len([]))
// [i].Key ≤ [i].Child.*.Key < [i+1].Key i ∈ [0, len([]))
//
//
...
@@ -346,7 +346,12 @@ func _xwalkDFS(ctx context.Context, lo, hi_ Key, ztree *Tree, rparent *RTree, bv
...
@@ -346,7 +346,12 @@ func _xwalkDFS(ctx context.Context, lo, hi_ Key, ztree *Tree, rparent *RTree, bv
}
}
b
:=
&
RBucket
{
oid
:
zbucket
.
POid
(),
parent
:
rtree
,
lo
:
xlo
,
hi_
:
xhi_
,
kv
:
bkv
}
b
:=
&
RBucket
{
Oid
:
zbucket
.
POid
(),
Parent
:
rtree
,
Keycov
:
blib
.
KeyRange
{
xlo
,
xhi_
},
KV
:
bkv
,
}
bvisit
(
b
)
bvisit
(
b
)
}
}
}
}
...
...
wcfs/internal/xbtree/xbtreetest/xbtreetest.go
View file @
11c95175
...
@@ -23,24 +23,27 @@ package xbtreetest
...
@@ -23,24 +23,27 @@ package xbtreetest
import
(
import
(
"fmt"
"fmt"
"math"
"lab.nexedi.com/kirr/neo/go/zodb"
"lab.nexedi.com/kirr/neo/go/zodb"
"lab.nexedi.com/kirr/neo/go/zodb/btree"
"lab.nexedi.com/nexedi/wendelin.core/wcfs/internal/set"
"lab.nexedi.com/nexedi/wendelin.core/wcfs/internal/set"
// "lab.nexedi.com/nexedi/wendelin.core/wcfs/internal/xbtree
"
"lab.nexedi.com/nexedi/wendelin.core/wcfs/internal/xbtree/blib
"
)
)
// XXX dup from xbtree (to avoid import cycle)
// XXX instead of generics
type
Tree
=
btree
.
LOBTree
type
Tree
=
blib
.
Tree
type
Bucket
=
btree
.
LOBucket
type
Bucket
=
blib
.
Bucket
type
Node
=
blib
.
Node
type
TreeEntry
=
blib
.
TreeEntry
type
BucketEntry
=
blib
.
BucketEntry
type
Key
=
blib
.
Key
const
KeyMax
=
blib
.
KeyMax
const
KeyMin
=
blib
.
KeyMin
type
Key
=
int64
const
KeyMax
Key
=
math
.
MaxInt64
const
KeyMin
Key
=
math
.
MinInt64
type
setKey
=
set
.
I64
type
setKey
=
set
.
I64
// XXX dup from xbtree (to avoid import cycle)
const
VDEL
=
zodb
.
InvalidOid
const
VDEL
=
zodb
.
InvalidOid
...
...
wcfs/internal/xbtree/xbtreetest/zdata.go
0 → 100644
View file @
11c95175
// Copyright (C) 2020-2021 Nexedi SA and Contributors.
// Kirill Smelkov <kirr@nexedi.com>
//
// This program is free software: you can Use, Study, Modify and Redistribute
// it under the terms of the GNU General Public License version 3, or (at your
// option) any later version, as published by the Free Software Foundation.
//
// You can also Link and Combine this program with other software covered by
// the terms of any of the Free Software licenses or any of the Open Source
// Initiative approved licenses and Convey the resulting work. Corresponding
// source of such a combination shall include the source code for all other
// software used.
//
// This program is distributed WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//
// See COPYING file for full licensing terms.
// See https://www.nexedi.com/licensing for rationale and options.
package
xbtreetest
// access to ZBlk data
import
(
"context"
"lab.nexedi.com/kirr/go123/exc"
"lab.nexedi.com/kirr/neo/go/transaction"
"lab.nexedi.com/kirr/neo/go/zodb"
_
"lab.nexedi.com/kirr/neo/go/zodb/wks"
)
// ZBlk-related functions are imported at runtime by package xbtreetest/init
var
(
ZTreeGetBlkData
func
(
context
.
Context
,
*
Tree
,
Key
)
(
string
,
bool
,
[]
Node
,
error
)
ZGetBlkData
func
(
context
.
Context
,
*
zodb
.
Connection
,
zodb
.
Oid
)
(
string
,
error
)
)
func
zassertInitDone
()
{
if
ZTreeGetBlkData
==
nil
{
panic
(
"xbtreetest/zdata not initialized -> import xbtreetest/init to fix"
)
}
}
// xzgetBlkData loads block data from ZBlk object specified by its oid.
func
xzgetBlkData
(
ctx
context
.
Context
,
zconn
*
zodb
.
Connection
,
zblkOid
zodb
.
Oid
)
string
{
zassertInitDone
()
X
:=
exc
.
Raiseif
if
zblkOid
==
VDEL
{
return
DEL
}
data
,
err
:=
ZGetBlkData
(
ctx
,
zconn
,
zblkOid
);
X
(
err
)
return
string
(
data
)
}
// xzgetBlkDataAt loads block data from ZBlk object specified by oid@at.
func
xzgetBlkDataAt
(
db
*
zodb
.
DB
,
zblkOid
zodb
.
Oid
,
at
zodb
.
Tid
)
string
{
zassertInitDone
()
X
:=
exc
.
Raiseif
txn
,
ctx
:=
transaction
.
New
(
context
.
Background
())
defer
txn
.
Abort
()
zconn
,
err
:=
db
.
Open
(
ctx
,
&
zodb
.
ConnOptions
{
At
:
at
});
X
(
err
)
return
xzgetBlkData
(
ctx
,
zconn
,
zblkOid
)
}
wcfs/internal/xbtree/δbtail.go
View file @
11c95175
...
@@ -30,6 +30,7 @@ import (
...
@@ -30,6 +30,7 @@ import (
"lab.nexedi.com/kirr/neo/go/transaction"
"lab.nexedi.com/kirr/neo/go/transaction"
"lab.nexedi.com/kirr/neo/go/zodb"
"lab.nexedi.com/kirr/neo/go/zodb"
"lab.nexedi.com/nexedi/wendelin.core/wcfs/internal/xbtree/blib"
"lab.nexedi.com/nexedi/wendelin.core/wcfs/internal/xtail"
"lab.nexedi.com/nexedi/wendelin.core/wcfs/internal/xtail"
)
)
...
@@ -96,7 +97,7 @@ type ΔBtail struct {
...
@@ -96,7 +97,7 @@ type ΔBtail struct {
// For this set all vδT are fully computed.
// For this set all vδT are fully computed.
// The set of nodes that were requested to be tracked, but were not yet
// The set of nodes that were requested to be tracked, but were not yet
// taken into account, is kept in ΔTtail.trackNew & co.
// taken into account, is kept in ΔTtail.trackNew & co.
trackSet
PPTreeSubSet
trackSet
blib
.
PPTreeSubSet
// set of trees for which .trackNew is non-empty
// set of trees for which .trackNew is non-empty
trackNewRoots
setOid
trackNewRoots
setOid
...
@@ -114,7 +115,7 @@ type ΔTtail struct {
...
@@ -114,7 +115,7 @@ type ΔTtail struct {
// set of nodes that were requested to be tracked in this tree, but for
// set of nodes that were requested to be tracked in this tree, but for
// which vδT was not yet rebuilt
// which vδT was not yet rebuilt
trackNew
PPTreeSubSet
trackNew
blib
.
PPTreeSubSet
// XXX + trackNewKeys RangedKeySet
// XXX + trackNewKeys RangedKeySet
// {}k/v @tail for keys that are changed in (tail, head].
// {}k/v @tail for keys that are changed in (tail, head].
...
@@ -158,7 +159,7 @@ func NewΔBtail(at0 zodb.Tid, db *zodb.DB) *ΔBtail {
...
@@ -158,7 +159,7 @@ func NewΔBtail(at0 zodb.Tid, db *zodb.DB) *ΔBtail {
δZtail
:
zodb
.
NewΔTail
(
at0
),
δZtail
:
zodb
.
NewΔTail
(
at0
),
vδBroots
:
nil
,
vδBroots
:
nil
,
vδTbyRoot
:
map
[
zodb
.
Oid
]
*
ΔTtail
{},
vδTbyRoot
:
map
[
zodb
.
Oid
]
*
ΔTtail
{},
trackSet
:
PPTreeSubSet
{},
trackSet
:
blib
.
PPTreeSubSet
{},
trackNewRoots
:
setOid
{},
trackNewRoots
:
setOid
{},
db
:
db
,
db
:
db
,
}
}
...
@@ -167,7 +168,7 @@ func NewΔBtail(at0 zodb.Tid, db *zodb.DB) *ΔBtail {
...
@@ -167,7 +168,7 @@ func NewΔBtail(at0 zodb.Tid, db *zodb.DB) *ΔBtail {
// newΔTtail creates new empty ΔTtail object.
// newΔTtail creates new empty ΔTtail object.
func
newΔTtail
()
*
ΔTtail
{
func
newΔTtail
()
*
ΔTtail
{
return
&
ΔTtail
{
return
&
ΔTtail
{
trackNew
:
PPTreeSubSet
{},
trackNew
:
blib
.
PPTreeSubSet
{},
KVAtTail
:
make
(
map
[
Key
]
Value
),
KVAtTail
:
make
(
map
[
Key
]
Value
),
lastRevOf
:
make
(
map
[
Key
]
zodb
.
Tid
),
lastRevOf
:
make
(
map
[
Key
]
zodb
.
Tid
),
}
}
...
@@ -271,7 +272,7 @@ func (δBtail *ΔBtail) track(key Key, path []zodb.Oid) error {
...
@@ -271,7 +272,7 @@ func (δBtail *ΔBtail) track(key Key, path []zodb.Oid) error {
// empty artificial tree. We need to do the normalization because we
// empty artificial tree. We need to do the normalization because we
// later check whether leaf path[-1] ∈ trackSet and without
// later check whether leaf path[-1] ∈ trackSet and without
// normalization path[-1] can be InvalidOid.
// normalization path[-1] can be InvalidOid.
path
=
n
ormPath
(
path
)
path
=
blib
.
N
ormPath
(
path
)
if
len
(
path
)
==
0
{
if
len
(
path
)
==
0
{
return
nil
// empty tree
return
nil
// empty tree
}
}
...
@@ -334,7 +335,7 @@ func (δBtail *ΔBtail) rebuildAll() (err error) {
...
@@ -334,7 +335,7 @@ func (δBtail *ΔBtail) rebuildAll() (err error) {
// - set of revisions for which new entries in .vδT have been created.
// - set of revisions for which new entries in .vδT have been created.
//
//
// XXX place
// XXX place
func
(
δTtail
*
ΔTtail
)
rebuild
(
root
zodb
.
Oid
,
δZtail
*
zodb
.
ΔTail
,
db
*
zodb
.
DB
)
(
δtrackSet
PPTreeSubSet
,
δrevSet
setTid
,
err
error
)
{
func
(
δTtail
*
ΔTtail
)
rebuild
(
root
zodb
.
Oid
,
δZtail
*
zodb
.
ΔTail
,
db
*
zodb
.
DB
)
(
δtrackSet
blib
.
PPTreeSubSet
,
δrevSet
setTid
,
err
error
)
{
defer
xerr
.
Context
(
&
err
,
"ΔTtail rebuild"
)
defer
xerr
.
Context
(
&
err
,
"ΔTtail rebuild"
)
// XXX locking
// XXX locking
...
@@ -342,7 +343,7 @@ func (δTtail *ΔTtail) rebuild(root zodb.Oid, δZtail *zodb.ΔTail, db *zodb.DB
...
@@ -342,7 +343,7 @@ func (δTtail *ΔTtail) rebuild(root zodb.Oid, δZtail *zodb.ΔTail, db *zodb.DB
tracefΔBtail
(
"trackNew: %v
\n
"
,
δTtail
.
trackNew
)
tracefΔBtail
(
"trackNew: %v
\n
"
,
δTtail
.
trackNew
)
trackNew
:=
δTtail
.
trackNew
trackNew
:=
δTtail
.
trackNew
δTtail
.
trackNew
=
PPTreeSubSet
{}
δTtail
.
trackNew
=
blib
.
PPTreeSubSet
{}
if
len
(
trackNew
)
==
0
{
if
len
(
trackNew
)
==
0
{
return
nil
,
nil
,
nil
return
nil
,
nil
,
nil
...
@@ -353,7 +354,7 @@ func (δTtail *ΔTtail) rebuild(root zodb.Oid, δZtail *zodb.ΔTail, db *zodb.DB
...
@@ -353,7 +354,7 @@ func (δTtail *ΔTtail) rebuild(root zodb.Oid, δZtail *zodb.ΔTail, db *zodb.DB
// go backwards and merge vδT <- treediff(lo..hi/trackNew)
// go backwards and merge vδT <- treediff(lo..hi/trackNew)
vδZ
:=
δZtail
.
Data
()
vδZ
:=
δZtail
.
Data
()
for
{
for
{
δtkeycov
:=
&
RangedKeySet
{}
// all keys coming into tracking set during this lo<-hi scan
δtkeycov
:=
&
blib
.
RangedKeySet
{}
// all keys coming into tracking set during this lo<-hi scan
trackNewCur
:=
trackNew
.
Clone
()
// trackNew adjusted as of when going to i<- entry
trackNewCur
:=
trackNew
.
Clone
()
// trackNew adjusted as of when going to i<- entry
for
i
:=
len
(
vδZ
)
-
1
;
i
>=
0
;
i
--
{
for
i
:=
len
(
vδZ
)
-
1
;
i
>=
0
;
i
--
{
δZ
:=
vδZ
[
i
]
δZ
:=
vδZ
[
i
]
...
@@ -411,7 +412,7 @@ func (δTtail *ΔTtail) rebuild(root zodb.Oid, δZtail *zodb.ΔTail, db *zodb.DB
...
@@ -411,7 +412,7 @@ func (δTtail *ΔTtail) rebuild(root zodb.Oid, δZtail *zodb.ΔTail, db *zodb.DB
// widenTrackNew widens trackNew to cover δtkeycov.
// widenTrackNew widens trackNew to cover δtkeycov.
// XXX -> widenTrackSet?
// XXX -> widenTrackSet?
func
widenTrackNew
(
trackNew
PPTreeSubSet
,
δtkeycov
*
RangedKeySet
,
root
zodb
.
Oid
,
at
zodb
.
Tid
,
db
*
zodb
.
DB
)
(
err
error
)
{
func
widenTrackNew
(
trackNew
blib
.
PPTreeSubSet
,
δtkeycov
*
blib
.
RangedKeySet
,
root
zodb
.
Oid
,
at
zodb
.
Tid
,
db
*
zodb
.
DB
)
(
err
error
)
{
// XXX errctx, debug
// XXX errctx, debug
defer
xerr
.
Contextf
(
&
err
,
"widenTrackNew tree<%s> @%s +%s"
,
root
,
at
,
δtkeycov
)
defer
xerr
.
Contextf
(
&
err
,
"widenTrackNew tree<%s> @%s +%s"
,
root
,
at
,
δtkeycov
)
...
@@ -430,13 +431,13 @@ func widenTrackNew(trackNew PPTreeSubSet, δtkeycov *RangedKeySet, root zodb.Oid
...
@@ -430,13 +431,13 @@ func widenTrackNew(trackNew PPTreeSubSet, δtkeycov *RangedKeySet, root zodb.Oid
top
:=
&
nodeInRange
{
prefix
:
nil
,
lo
:
KeyMin
,
hi_
:
KeyMax
,
node
:
tree
}
top
:=
&
nodeInRange
{
prefix
:
nil
,
lo
:
KeyMin
,
hi_
:
KeyMax
,
node
:
tree
}
V
:=
rangeSplit
{
top
}
V
:=
rangeSplit
{
top
}
for
_
,
r
:=
range
δtkeycov
.
AllRanges
()
{
for
_
,
r
:=
range
δtkeycov
.
AllRanges
()
{
lo
:=
r
.
l
o
lo
:=
r
.
L
o
for
{
for
{
b
,
err
:=
V
.
GetToLeaf
(
ctx
,
lo
);
/*X*/
if
err
!=
nil
{
return
err
}
b
,
err
:=
V
.
GetToLeaf
(
ctx
,
lo
);
/*X*/
if
err
!=
nil
{
return
err
}
trackNew
.
AddPath
(
b
.
Path
())
trackNew
.
AddPath
(
b
.
Path
())
// continue with next right bucket until r coverage is complete
// continue with next right bucket until r coverage is complete
if
r
.
h
i_
<=
b
.
hi_
{
if
r
.
H
i_
<=
b
.
hi_
{
break
break
}
}
lo
=
b
.
hi_
+
1
lo
=
b
.
hi_
+
1
...
@@ -450,7 +451,7 @@ func widenTrackNew(trackNew PPTreeSubSet, δtkeycov *RangedKeySet, root zodb.Oid
...
@@ -450,7 +451,7 @@ func widenTrackNew(trackNew PPTreeSubSet, δtkeycov *RangedKeySet, root zodb.Oid
//
//
// δtrackNew/δtkeycov represents how trackNew changes when going through `atPrev <- δZ.Rev` .
// δtrackNew/δtkeycov represents how trackNew changes when going through `atPrev <- δZ.Rev` .
// newRevEntry indicates whether δZ.Rev was not there before in .vδT and new corresponding δT entry was created.
// newRevEntry indicates whether δZ.Rev was not there before in .vδT and new corresponding δT entry was created.
func
(
δTtail
*
ΔTtail
)
rebuild1
(
atPrev
zodb
.
Tid
,
δZ
zodb
.
ΔRevEntry
,
trackNew
PPTreeSubSet
,
db
*
zodb
.
DB
)
(
δtrackNew
*
ΔPPTreeSubSet
,
δtkeycov
*
RangedKeySet
,
newRevEntry
bool
,
err
error
)
{
func
(
δTtail
*
ΔTtail
)
rebuild1
(
atPrev
zodb
.
Tid
,
δZ
zodb
.
ΔRevEntry
,
trackNew
blib
.
PPTreeSubSet
,
db
*
zodb
.
DB
)
(
δtrackNew
*
blib
.
ΔPPTreeSubSet
,
δtkeycov
*
blib
.
RangedKeySet
,
newRevEntry
bool
,
err
error
)
{
defer
xerr
.
Contextf
(
&
err
,
"rebuild1 %s<-%s"
,
atPrev
,
δZ
.
Rev
)
defer
xerr
.
Contextf
(
&
err
,
"rebuild1 %s<-%s"
,
atPrev
,
δZ
.
Rev
)
debugfΔBtail
(
"
\n
rebuild1 @%s <- @%s
\n
"
,
atPrev
,
δZ
.
Rev
)
debugfΔBtail
(
"
\n
rebuild1 @%s <- @%s
\n
"
,
atPrev
,
δZ
.
Rev
)
...
@@ -467,7 +468,7 @@ func (δTtail *ΔTtail) rebuild1(atPrev zodb.Tid, δZ zodb.ΔRevEntry, trackNew
...
@@ -467,7 +468,7 @@ func (δTtail *ΔTtail) rebuild1(atPrev zodb.Tid, δZ zodb.ΔRevEntry, trackNew
// skip opening DB connections if there is no change to this tree
// skip opening DB connections if there is no change to this tree
if
len
(
δtopsByRoot
)
==
0
{
if
len
(
δtopsByRoot
)
==
0
{
return
NewΔPPTreeSubSet
(),
&
RangedKeySet
{},
false
,
nil
return
blib
.
NewΔPPTreeSubSet
(),
&
blib
.
RangedKeySet
{},
false
,
nil
}
}
if
len
(
δtopsByRoot
)
!=
1
{
if
len
(
δtopsByRoot
)
!=
1
{
...
@@ -560,7 +561,7 @@ func (δBtail *ΔBtail) Update(δZ *zodb.EventCommit) (_ ΔB, err error) {
...
@@ -560,7 +561,7 @@ func (δBtail *ΔBtail) Update(δZ *zodb.EventCommit) (_ ΔB, err error) {
// δtkeycov1 != ø -> rebuild δTtail with trackNew ~= δtkeycov1
// δtkeycov1 != ø -> rebuild δTtail with trackNew ~= δtkeycov1
if
!
δT1
.
δtkeycov1
.
Empty
()
&&
δBtail
.
δZtail
.
Len
()
>
1
{
if
!
δT1
.
δtkeycov1
.
Empty
()
&&
δBtail
.
δZtail
.
Len
()
>
1
{
trackNew
:=
PPTreeSubSet
{}
trackNew
:=
blib
.
PPTreeSubSet
{}
err
:=
widenTrackNew
(
trackNew
,
δT1
.
δtkeycov1
,
root
,
δBtail
.
Head
(),
δBtail
.
db
)
err
:=
widenTrackNew
(
trackNew
,
δT1
.
δtkeycov1
,
root
,
δBtail
.
Head
(),
δBtail
.
db
)
if
err
!=
nil
{
if
err
!=
nil
{
return
ΔB
{},
err
return
ΔB
{},
err
...
@@ -611,8 +612,8 @@ type _ΔBUpdate1 struct {
...
@@ -611,8 +612,8 @@ type _ΔBUpdate1 struct {
ByRoot
map
[
zodb
.
Oid
]
*
_ΔTUpdate1
ByRoot
map
[
zodb
.
Oid
]
*
_ΔTUpdate1
}
}
type
_ΔTUpdate1
struct
{
type
_ΔTUpdate1
struct
{
δtkeycov1
*
RangedKeySet
// {} root -> δtrackedKeys after first treediff (always grow)
δtkeycov1
*
blib
.
RangedKeySet
// {} root -> δtrackedKeys after first treediff (always grow)
δtrack
*
ΔPPTreeSubSet
// XXX kill (not used)
δtrack
*
blib
.
ΔPPTreeSubSet
// XXX kill (not used)
}
}
func
(
δBtail
*
ΔBtail
)
_Update1
(
δZ
*
zodb
.
EventCommit
)
(
δB1
_ΔBUpdate1
,
err
error
)
{
func
(
δBtail
*
ΔBtail
)
_Update1
(
δZ
*
zodb
.
EventCommit
)
(
δB1
_ΔBUpdate1
,
err
error
)
{
headOld
:=
δBtail
.
Head
()
headOld
:=
δBtail
.
Head
()
...
...
wcfs/internal/xbtree/δbtail_test.go
View file @
11c95175
...
@@ -44,17 +44,11 @@ package xbtree
...
@@ -44,17 +44,11 @@ package xbtree
// - to generate set of random tree topologies that all correspond to particular {k->v} dict.
// - to generate set of random tree topologies that all correspond to particular {k->v} dict.
import
(
import
(
"bufio"
"context"
"flag"
"flag"
"fmt"
"fmt"
"io"
"math"
"math"
"math/rand"
"math/rand"
"os"
"os/exec"
"reflect"
"reflect"
"regexp"
"sort"
"sort"
"strings"
"strings"
"testing"
"testing"
...
@@ -62,16 +56,18 @@ import (
...
@@ -62,16 +56,18 @@ import (
"lab.nexedi.com/kirr/go123/exc"
"lab.nexedi.com/kirr/go123/exc"
"lab.nexedi.com/kirr/go123/xerr"
"lab.nexedi.com/kirr/go123/xerr"
"lab.nexedi.com/kirr/neo/go/transaction"
"lab.nexedi.com/kirr/neo/go/zodb"
"lab.nexedi.com/kirr/neo/go/zodb"
_
"lab.nexedi.com/kirr/neo/go/zodb/wks"
"lab.nexedi.com/nexedi/wendelin.core/wcfs/internal/xbtree/blib"
"lab.nexedi.com/nexedi/wendelin.core/wcfs/internal/xbtree/xbtreetest"
"lab.nexedi.com/nexedi/wendelin.core/wcfs/internal/xbtree/xbtreetest"
// "lab.nexedi.com/nexedi/wendelin.core/wcfs/internal/xzodb"
// "lab.nexedi.com/nexedi/wendelin.core/wcfs/internal/xzodb"
)
)
type
Δstring
=
xbtreetest
.
Δstring
// trackSet returns what should be ΔBtail.trackSet coverage for specified tracked key set.
// trackSet returns what should be ΔBtail.trackSet coverage for specified tracked key set.
func
(
rbs
RBucketSet
)
trackSet
(
tracked
setKey
)
PPTreeSubSet
{
func
(
rbs
xbtreetest
.
RBucketSet
)
trackSet
(
tracked
setKey
)
blib
.
PPTreeSubSet
{
// nil = don't compute keyCover
// nil = don't compute keyCover
// (trackSet is called from inside hot inner loop of rebuild test)
// (trackSet is called from inside hot inner loop of rebuild test)
trackSet
:=
rbs
.
_trackSetWithCov
(
tracked
,
nil
)
trackSet
:=
rbs
.
_trackSetWithCov
(
tracked
,
nil
)
...
@@ -79,23 +75,23 @@ func (rbs RBucketSet) trackSet(tracked setKey) PPTreeSubSet {
...
@@ -79,23 +75,23 @@ func (rbs RBucketSet) trackSet(tracked setKey) PPTreeSubSet {
}
}
// trackSetWithCov returns what should be ΔBtail.trackSet and its key coverage for specified tracked key set.
// trackSetWithCov returns what should be ΔBtail.trackSet and its key coverage for specified tracked key set.
func
(
rbs
RBucketSet
)
trackSetWithCov
(
tracked
setKey
)
(
trackSet
PPTreeSubSet
,
keyCover
*
RangedKeySet
)
{
func
(
rbs
xbtreetest
.
RBucketSet
)
trackSetWithCov
(
tracked
setKey
)
(
trackSet
blib
.
PPTreeSubSet
,
keyCover
*
blib
.
RangedKeySet
)
{
keyCover
=
&
RangedKeySet
{}
keyCover
=
&
blib
.
RangedKeySet
{}
trackSet
=
rbs
.
_trackSetWithCov
(
tracked
,
keyCover
)
trackSet
=
rbs
.
_trackSetWithCov
(
tracked
,
keyCover
)
return
trackSet
,
keyCover
return
trackSet
,
keyCover
}
}
func
(
rbs
RBucketSet
)
_trackSetWithCov
(
tracked
setKey
,
outKeyCover
*
RangedKeySet
)
(
trackSet
PPTreeSubSet
)
{
func
(
rbs
xbtreetest
.
RBucketSet
)
_trackSetWithCov
(
tracked
setKey
,
outKeyCover
*
blib
.
RangedKeySet
)
(
trackSet
blib
.
PPTreeSubSet
)
{
trackSet
=
PPTreeSubSet
{}
trackSet
=
blib
.
PPTreeSubSet
{}
for
k
:=
range
tracked
{
for
k
:=
range
tracked
{
kb
:=
rbs
.
Get
(
k
)
kb
:=
rbs
.
Get
(
k
)
if
outKeyCover
!=
nil
{
if
outKeyCover
!=
nil
{
outKeyCover
.
AddRange
(
KeyRange
{
kb
.
lo
,
kb
.
hi_
}
)
outKeyCover
.
AddRange
(
kb
.
Keycov
)
}
}
// trackSet explicitly records only regular buckets.
// trackSet explicitly records only regular buckets.
// embedded buckets all have oid=zodb.InvalidOid and would lead to z
// embedded buckets all have oid=zodb.InvalidOid and would lead to z
newNode
:=
false
newNode
:=
false
if
kb
.
o
id
!=
zodb
.
InvalidOid
{
if
kb
.
O
id
!=
zodb
.
InvalidOid
{
track
,
already
:=
trackSet
[
kb
.
oid
]
track
,
already
:=
trackSet
[
kb
.
oid
]
if
!
already
{
if
!
already
{
track
=
&
nodeInTree
{
parent
:
kb
.
parent
.
oid
,
nchild
:
0
}
track
=
&
nodeInTree
{
parent
:
kb
.
parent
.
oid
,
nchild
:
0
}
...
@@ -138,7 +134,7 @@ func (rbs RBucketSet) _trackSetWithCov(tracked setKey, outKeyCover *RangedKeySet
...
@@ -138,7 +134,7 @@ func (rbs RBucketSet) _trackSetWithCov(tracked setKey, outKeyCover *RangedKeySet
// XGetδKV translates {k -> δ<oid>} to {k -> δ(ZBlk(oid).data)} according to t1..t2 db snapshots.
// XGetδKV translates {k -> δ<oid>} to {k -> δ(ZBlk(oid).data)} according to t1..t2 db snapshots.
func
XGetδKV
(
t1
,
t2
*
tTree
Commit
,
δkvOid
map
[
Key
]
ΔValue
)
map
[
Key
]
Δstring
{
func
XGetδKV
(
t1
,
t2
*
xbtreetest
.
Commit
,
δkvOid
map
[
Key
]
ΔValue
)
map
[
Key
]
Δstring
{
δkv
:=
make
(
map
[
Key
]
Δstring
,
len
(
δkvOid
))
δkv
:=
make
(
map
[
Key
]
Δstring
,
len
(
δkvOid
))
for
k
,
δvOid
:=
range
δkvOid
{
for
k
,
δvOid
:=
range
δkvOid
{
δkv
[
k
]
=
Δstring
{
δkv
[
k
]
=
Δstring
{
...
@@ -217,7 +213,7 @@ func (kadjA KAdjMatrix) Mul(kadjB KAdjMatrix) KAdjMatrix {
...
@@ -217,7 +213,7 @@ func (kadjA KAdjMatrix) Mul(kadjB KAdjMatrix) KAdjMatrix {
// This set of keys defaults to allTestKeys(t1,t2).
// This set of keys defaults to allTestKeys(t1,t2).
//
//
// KAdj itself is verified by testΔBTail on entries with .kadjOK set.
// KAdj itself is verified by testΔBTail on entries with .kadjOK set.
func
KAdj
(
t1
,
t2
*
tTree
Commit
,
keysv
...
setKey
)
(
kadj
KAdjMatrix
)
{
func
KAdj
(
t1
,
t2
*
xbtreetest
.
Commit
,
keysv
...
setKey
)
(
kadj
KAdjMatrix
)
{
// assert KAdj(A,B) == KAdj(B,A)
// assert KAdj(A,B) == KAdj(B,A)
kadj12
:=
_KAdj
(
t1
,
t2
,
keysv
...
)
kadj12
:=
_KAdj
(
t1
,
t2
,
keysv
...
)
kadj21
:=
_KAdj
(
t2
,
t1
,
keysv
...
)
kadj21
:=
_KAdj
(
t2
,
t1
,
keysv
...
)
...
@@ -235,7 +231,7 @@ func debugfKAdj(format string, argv ...interface{}) {
...
@@ -235,7 +231,7 @@ func debugfKAdj(format string, argv ...interface{}) {
}
}
}
}
func
_KAdj
(
t1
,
t2
*
tTree
Commit
,
keysv
...
setKey
)
(
kadj
KAdjMatrix
)
{
func
_KAdj
(
t1
,
t2
*
xbtreetest
.
Commit
,
keysv
...
setKey
)
(
kadj
KAdjMatrix
)
{
var
keys
setKey
var
keys
setKey
switch
len
(
keysv
)
{
switch
len
(
keysv
)
{
case
0
:
case
0
:
...
@@ -261,10 +257,10 @@ func _KAdj(t1, t2 *tTreeCommit, keysv ...setKey) (kadj KAdjMatrix) {
...
@@ -261,10 +257,10 @@ func _KAdj(t1, t2 *tTreeCommit, keysv ...setKey) (kadj KAdjMatrix) {
adj1
:=
setKey
{}
adj1
:=
setKey
{}
adj2
:=
setKey
{}
adj2
:=
setKey
{}
q1
:=
&
RangedKeySet
{};
q1
.
Add
(
k
)
q1
:=
&
blib
.
RangedKeySet
{};
q1
.
Add
(
k
)
q2
:=
&
RangedKeySet
{};
q2
.
Add
(
k
)
q2
:=
&
blib
.
RangedKeySet
{};
q2
.
Add
(
k
)
done1
:=
&
RangedKeySet
{}
done1
:=
&
blib
.
RangedKeySet
{}
done2
:=
&
RangedKeySet
{}
done2
:=
&
blib
.
RangedKeySet
{}
debugfKAdj
(
"
\n
k%s
\n
"
,
kstr
(
k
))
debugfKAdj
(
"
\n
k%s
\n
"
,
kstr
(
k
))
for
!
q1
.
Empty
()
||
!
q2
.
Empty
()
{
for
!
q1
.
Empty
()
||
!
q2
.
Empty
()
{
...
@@ -281,10 +277,10 @@ func _KAdj(t1, t2 *tTreeCommit, keysv ...setKey) (kadj KAdjMatrix) {
...
@@ -281,10 +277,10 @@ func _KAdj(t1, t2 *tTreeCommit, keysv ...setKey) (kadj KAdjMatrix) {
debugfKAdj
(
" adj1 += %s
\t
-> %s
\n
"
,
kstr
(
k_
),
adj1
)
debugfKAdj
(
" adj1 += %s
\t
-> %s
\n
"
,
kstr
(
k_
),
adj1
)
}
}
}
}
b1r
:=
KeyRange
{
b1
.
lo
,
b1
.
hi_
}
b1r
:=
blib
.
KeyRange
{
b1
.
lo
,
b1
.
hi_
}
done1
.
AddRange
(
b1r
)
done1
.
AddRange
(
b1r
)
// q2 |= (b1.keyrange \ done2)
// q2 |= (b1.keyrange \ done2)
δq2
:=
&
RangedKeySet
{}
δq2
:=
&
blib
.
RangedKeySet
{}
δq2
.
AddRange
(
b1r
)
δq2
.
AddRange
(
b1r
)
δq2
.
DifferenceInplace
(
done2
)
δq2
.
DifferenceInplace
(
done2
)
q2
.
UnionInplace
(
δq2
)
q2
.
UnionInplace
(
δq2
)
...
@@ -310,10 +306,10 @@ func _KAdj(t1, t2 *tTreeCommit, keysv ...setKey) (kadj KAdjMatrix) {
...
@@ -310,10 +306,10 @@ func _KAdj(t1, t2 *tTreeCommit, keysv ...setKey) (kadj KAdjMatrix) {
debugfKAdj
(
" adj2 += %s
\t
-> %s
\n
"
,
kstr
(
k_
),
adj2
)
debugfKAdj
(
" adj2 += %s
\t
-> %s
\n
"
,
kstr
(
k_
),
adj2
)
}
}
}
}
b2r
:=
KeyRange
{
b2
.
lo
,
b2
.
hi_
}
b2r
:=
blib
.
KeyRange
{
b2
.
lo
,
b2
.
hi_
}
done2
.
AddRange
(
b2r
)
done2
.
AddRange
(
b2r
)
// q1 |= (b2.keyrange \ done1)
// q1 |= (b2.keyrange \ done1)
δq1
:=
&
RangedKeySet
{}
δq1
:=
&
blib
.
RangedKeySet
{}
δq1
.
AddRange
(
b2r
)
δq1
.
AddRange
(
b2r
)
δq1
.
DifferenceInplace
(
done1
)
δq1
.
DifferenceInplace
(
done1
)
q1
.
UnionInplace
(
δq1
)
q1
.
UnionInplace
(
δq1
)
...
@@ -343,7 +339,7 @@ func _KAdj(t1, t2 *tTreeCommit, keysv ...setKey) (kadj KAdjMatrix) {
...
@@ -343,7 +339,7 @@ func _KAdj(t1, t2 *tTreeCommit, keysv ...setKey) (kadj KAdjMatrix) {
// the cycling phase of update, that is responsible to recompute older
// the cycling phase of update, that is responsible to recompute older
// entries when key coverage grows, is exercised by
// entries when key coverage grows, is exercised by
// xverifyΔBTail_rebuild.
// xverifyΔBTail_rebuild.
func
xverifyΔBTail_Update
(
t
*
testing
.
T
,
subj
string
,
db
*
zodb
.
DB
,
treeRoot
zodb
.
Oid
,
t1
,
t2
*
tTree
Commit
)
{
func
xverifyΔBTail_Update
(
t
*
testing
.
T
,
subj
string
,
db
*
zodb
.
DB
,
treeRoot
zodb
.
Oid
,
t1
,
t2
*
xbtreetest
.
Commit
)
{
// verify transition at1->at2 for all initial states of tracked {keys} from kv1 + kv2 + ∞
// verify transition at1->at2 for all initial states of tracked {keys} from kv1 + kv2 + ∞
t
.
Run
(
fmt
.
Sprintf
(
"Update/%s→%s"
,
t1
.
tree
,
t2
.
tree
),
func
(
t
*
testing
.
T
)
{
t
.
Run
(
fmt
.
Sprintf
(
"Update/%s→%s"
,
t1
.
tree
,
t2
.
tree
),
func
(
t
*
testing
.
T
)
{
...
@@ -370,7 +366,7 @@ func xverifyΔBTail_Update(t *testing.T, subj string, db *zodb.DB, treeRoot zodb
...
@@ -370,7 +366,7 @@ func xverifyΔBTail_Update(t *testing.T, subj string, db *zodb.DB, treeRoot zodb
// xverifyΔBTail_Update1 verifies how ΔBTail handles ZODB update at1->at2 from initial
// xverifyΔBTail_Update1 verifies how ΔBTail handles ZODB update at1->at2 from initial
// tracked state defined by initialTrackedKeys.
// tracked state defined by initialTrackedKeys.
func
xverifyΔBTail_Update1
(
t
*
testing
.
T
,
subj
string
,
db
*
zodb
.
DB
,
treeRoot
zodb
.
Oid
,
t1
,
t2
*
tTree
Commit
,
initialTrackedKeys
setKey
,
kadj
KAdjMatrix
)
{
func
xverifyΔBTail_Update1
(
t
*
testing
.
T
,
subj
string
,
db
*
zodb
.
DB
,
treeRoot
zodb
.
Oid
,
t1
,
t2
*
xbtreetest
.
Commit
,
initialTrackedKeys
setKey
,
kadj
KAdjMatrix
)
{
X
:=
exc
.
Raiseif
X
:=
exc
.
Raiseif
//t.Logf("\n>>> Track=%s\n", initialTrackedKeys)
//t.Logf("\n>>> Track=%s\n", initialTrackedKeys)
...
@@ -423,7 +419,7 @@ func xverifyΔBTail_Update1(t *testing.T, subj string, db *zodb.DB, treeRoot zod
...
@@ -423,7 +419,7 @@ func xverifyΔBTail_Update1(t *testing.T, subj string, db *zodb.DB, treeRoot zod
if
oid2
==
zodb
.
InvalidOid
{
// embedded bucket
if
oid2
==
zodb
.
InvalidOid
{
// embedded bucket
oid2
=
leaf2
.
parent
.
oid
oid2
=
leaf2
.
parent
.
oid
}
}
if
δZset
.
Has
(
oid1
)
||
δZset
.
Has
(
oid2
)
||
(
KeyRange
{
leaf1
.
lo
,
leaf1
.
hi_
}
!=
KeyRange
{
leaf2
.
lo
,
leaf2
.
hi_
})
{
if
δZset
.
Has
(
oid1
)
||
δZset
.
Has
(
oid2
)
||
(
blib
.
KeyRange
{
leaf1
.
lo
,
leaf1
.
hi_
}
!=
blib
.
KeyRange
{
leaf2
.
lo
,
leaf2
.
hi_
})
{
TrackedδZ
.
Add
(
k
)
TrackedδZ
.
Add
(
k
)
}
}
}
}
...
@@ -452,7 +448,7 @@ func xverifyΔBTail_Update1(t *testing.T, subj string, db *zodb.DB, treeRoot zod
...
@@ -452,7 +448,7 @@ func xverifyΔBTail_Update1(t *testing.T, subj string, db *zodb.DB, treeRoot zod
}
}
}
}
ø
:=
PPTreeSubSet
{}
ø
:=
blib
.
PPTreeSubSet
{}
// trackSet1 = xkv1[tracked1]
// trackSet1 = xkv1[tracked1]
// trackSet2 = xkv2[tracked2] ( = xkv2[kadj[tracked1]]
// trackSet2 = xkv2[tracked2] ( = xkv2[kadj[tracked1]]
...
@@ -477,7 +473,7 @@ func xverifyΔBTail_Update1(t *testing.T, subj string, db *zodb.DB, treeRoot zod
...
@@ -477,7 +473,7 @@ func xverifyΔBTail_Update1(t *testing.T, subj string, db *zodb.DB, treeRoot zod
// assert δtkeycov == δ(tkeyCov1, tkeyCov2)
// assert δtkeycov == δ(tkeyCov1, tkeyCov2)
δtkeycovOK
:=
tkeyCov2
.
Difference
(
tkeyCov1
)
δtkeycovOK
:=
tkeyCov2
.
Difference
(
tkeyCov1
)
δtkeycov
:=
&
RangedKeySet
{}
δtkeycov
:=
&
blib
.
RangedKeySet
{}
if
__
,
ok
:=
δB1
.
ByRoot
[
treeRoot
];
ok
{
if
__
,
ok
:=
δB1
.
ByRoot
[
treeRoot
];
ok
{
δtkeycov
=
__
.
δtkeycov1
δtkeycov
=
__
.
δtkeycov1
}
}
...
@@ -558,7 +554,7 @@ func xverifyΔBTail_Update1(t *testing.T, subj string, db *zodb.DB, treeRoot zod
...
@@ -558,7 +554,7 @@ func xverifyΔBTail_Update1(t *testing.T, subj string, db *zodb.DB, treeRoot zod
// assertTrack verifies state of .trackSet and ΔTtail.trackNew.
// assertTrack verifies state of .trackSet and ΔTtail.trackNew.
// it assumes that only one tree root is being tracked.
// it assumes that only one tree root is being tracked.
// XXX place
// XXX place
func
(
δBtail
*
ΔBtail
)
assertTrack
(
t
*
testing
.
T
,
subj
string
,
trackSetOK
PPTreeSubSet
,
trackNewOK
PPTreeSubSet
)
{
func
(
δBtail
*
ΔBtail
)
assertTrack
(
t
*
testing
.
T
,
subj
string
,
trackSetOK
blib
.
PPTreeSubSet
,
trackNewOK
blib
.
PPTreeSubSet
)
{
t
.
Helper
()
t
.
Helper
()
if
!
δBtail
.
trackSet
.
Equal
(
trackSetOK
)
{
if
!
δBtail
.
trackSet
.
Equal
(
trackSetOK
)
{
t
.
Errorf
(
"%s: trackSet:
\n\t
have: %v
\n\t
want: %v"
,
subj
,
δBtail
.
trackSet
,
trackSetOK
)
t
.
Errorf
(
"%s: trackSet:
\n\t
have: %v
\n\t
want: %v"
,
subj
,
δBtail
.
trackSet
,
trackSetOK
)
...
@@ -605,7 +601,7 @@ func (δBtail *ΔBtail) assertTrack(t *testing.T, subj string, trackSetOK PPTree
...
@@ -605,7 +601,7 @@ func (δBtail *ΔBtail) assertTrack(t *testing.T, subj string, trackSetOK PPTree
// t1->t2 further exercises incremental rebuild.
// t1->t2 further exercises incremental rebuild.
//
//
// It also exercises rebuild phase of ΔBtail.Update.
// It also exercises rebuild phase of ΔBtail.Update.
func
xverifyΔBTail_rebuild
(
t
*
testing
.
T
,
db
*
zodb
.
DB
,
treeRoot
zodb
.
Oid
,
t0
,
t1
,
t2
*
tTree
Commit
)
{
func
xverifyΔBTail_rebuild
(
t
*
testing
.
T
,
db
*
zodb
.
DB
,
treeRoot
zodb
.
Oid
,
t0
,
t1
,
t2
*
xbtreetest
.
Commit
)
{
t
.
Run
(
fmt
.
Sprintf
(
"rebuild/%s→%s"
,
t0
.
tree
,
t1
.
tree
),
func
(
t
*
testing
.
T
)
{
t
.
Run
(
fmt
.
Sprintf
(
"rebuild/%s→%s"
,
t0
.
tree
,
t1
.
tree
),
func
(
t
*
testing
.
T
)
{
tAllKeys
:=
allTestKeys
(
t0
,
t1
,
t2
)
tAllKeys
:=
allTestKeys
(
t0
,
t1
,
t2
)
tAllKeyv
:=
tAllKeys
.
SortedElements
()
tAllKeyv
:=
tAllKeys
.
SortedElements
()
...
@@ -628,7 +624,7 @@ func xverifyΔBTail_rebuild(t *testing.T, db *zodb.DB, treeRoot zodb.Oid, t0, t1
...
@@ -628,7 +624,7 @@ func xverifyΔBTail_rebuild(t *testing.T, db *zodb.DB, treeRoot zodb.Oid, t0, t1
// kadj210 = kadj10·kadj21
// kadj210 = kadj10·kadj21
kadj210
:=
kadj10
.
Mul
(
kadj21
)
kadj210
:=
kadj10
.
Mul
(
kadj21
)
ø
:=
PPTreeSubSet
{}
ø
:=
blib
.
PPTreeSubSet
{}
// verify t0 -> t1 Track(keys1) Rebuild -> t2 Track(keys2) Rebuild
// verify t0 -> t1 Track(keys1) Rebuild -> t2 Track(keys2) Rebuild
// for all combinations of keys1 and keys2
// for all combinations of keys1 and keys2
...
@@ -790,10 +786,10 @@ func xverifyΔBTail_rebuild(t *testing.T, db *zodb.DB, treeRoot zodb.Oid, t0, t1
...
@@ -790,10 +786,10 @@ func xverifyΔBTail_rebuild(t *testing.T, db *zodb.DB, treeRoot zodb.Oid, t0, t1
}
}
// xverifyΔBTail_rebuild_U verifies ΔBtail state after Update(ti->tj).
// xverifyΔBTail_rebuild_U verifies ΔBtail state after Update(ti->tj).
func
xverifyΔBTail_rebuild_U
(
t
*
testing
.
T
,
δbtail
*
ΔBtail
,
treeRoot
zodb
.
Oid
,
ti
,
tj
*
tTreeCommit
,
xat
map
[
zodb
.
Tid
]
string
,
trackSet
PPTreeSubSet
,
vδTok
...
map
[
Key
]
Δstring
)
{
func
xverifyΔBTail_rebuild_U
(
t
*
testing
.
T
,
δbtail
*
ΔBtail
,
treeRoot
zodb
.
Oid
,
ti
,
tj
*
xbtreetest
.
Commit
,
xat
map
[
zodb
.
Tid
]
string
,
trackSet
blib
.
PPTreeSubSet
,
vδTok
...
map
[
Key
]
Δstring
)
{
t
.
Helper
()
t
.
Helper
()
X
:=
exc
.
Raiseif
X
:=
exc
.
Raiseif
ø
:=
PPTreeSubSet
{}
ø
:=
blib
.
PPTreeSubSet
{}
subj
:=
fmt
.
Sprintf
(
"after Update(@%s→@%s)"
,
xat
[
ti
.
at
],
xat
[
tj
.
at
])
subj
:=
fmt
.
Sprintf
(
"after Update(@%s→@%s)"
,
xat
[
ti
.
at
],
xat
[
tj
.
at
])
...
@@ -835,9 +831,9 @@ func xverifyΔBTail_rebuild_U(t *testing.T, δbtail *ΔBtail, treeRoot zodb.Oid,
...
@@ -835,9 +831,9 @@ func xverifyΔBTail_rebuild_U(t *testing.T, δbtail *ΔBtail, treeRoot zodb.Oid,
}
}
// xverifyΔBTail_rebuild_TR verifies ΔBtail state after Track(keys) + rebuild.
// xverifyΔBTail_rebuild_TR verifies ΔBtail state after Track(keys) + rebuild.
func
xverifyΔBTail_rebuild_TR
(
t
*
testing
.
T
,
δbtail
*
ΔBtail
,
tj
*
tTreeCommit
,
treeRoot
zodb
.
Oid
,
xat
map
[
zodb
.
Tid
]
string
,
keys
setKey
,
trackSet
PPTreeSubSet
,
trackNew
,
trackSetAfterRebuild
PPTreeSubSet
,
vδTok
...
map
[
Key
]
Δstring
)
{
func
xverifyΔBTail_rebuild_TR
(
t
*
testing
.
T
,
δbtail
*
ΔBtail
,
tj
*
xbtreetest
.
Commit
,
treeRoot
zodb
.
Oid
,
xat
map
[
zodb
.
Tid
]
string
,
keys
setKey
,
trackSet
blib
.
PPTreeSubSet
,
trackNew
,
trackSetAfterRebuild
blib
.
PPTreeSubSet
,
vδTok
...
map
[
Key
]
Δstring
)
{
t
.
Helper
()
t
.
Helper
()
ø
:=
PPTreeSubSet
{}
ø
:=
blib
.
PPTreeSubSet
{}
// Track(keys)
// Track(keys)
xtrackKeys
(
δbtail
,
tj
,
keys
)
xtrackKeys
(
δbtail
,
tj
,
keys
)
...
@@ -858,14 +854,14 @@ func xverifyΔBTail_rebuild_TR(t *testing.T, δbtail *ΔBtail, tj *tTreeCommit,
...
@@ -858,14 +854,14 @@ func xverifyΔBTail_rebuild_TR(t *testing.T, δbtail *ΔBtail, tj *tTreeCommit,
// assertΔTtail verifies state of ΔTtail that corresponds to treeRoot in δbtail.
// assertΔTtail verifies state of ΔTtail that corresponds to treeRoot in δbtail.
// it also verifies that δbtail.vδBroots matches ΔTtail data.
// it also verifies that δbtail.vδBroots matches ΔTtail data.
func
assertΔTtail
(
t
*
testing
.
T
,
subj
string
,
δbtail
*
ΔBtail
,
tj
*
tTree
Commit
,
treeRoot
zodb
.
Oid
,
xat
map
[
zodb
.
Tid
]
string
,
vδTok
...
map
[
Key
]
Δstring
)
{
func
assertΔTtail
(
t
*
testing
.
T
,
subj
string
,
δbtail
*
ΔBtail
,
tj
*
xbtreetest
.
Commit
,
treeRoot
zodb
.
Oid
,
xat
map
[
zodb
.
Tid
]
string
,
vδTok
...
map
[
Key
]
Δstring
)
{
t
.
Helper
()
t
.
Helper
()
// XXX +KVAtTail, +lastRevOf
// XXX +KVAtTail, +lastRevOf
l
:=
len
(
vδTok
)
l
:=
len
(
vδTok
)
var
vatOK
[]
zodb
.
Tid
var
vatOK
[]
zodb
.
Tid
var
vδTok_
[]
map
[
Key
]
Δstring
var
vδTok_
[]
map
[
Key
]
Δstring
at2t
:=
map
[
zodb
.
Tid
]
*
tTree
Commit
{
tj
.
at
:
tj
}
at2t
:=
map
[
zodb
.
Tid
]
*
xbtreetest
.
Commit
{
tj
.
at
:
tj
}
t0
:=
tj
t0
:=
tj
for
i
:=
0
;
i
<
l
;
i
++
{
for
i
:=
0
;
i
<
l
;
i
++
{
// empty vδTok entries means they should be absent in vδT
// empty vδTok entries means they should be absent in vδT
...
@@ -933,7 +929,7 @@ func assertΔTtail(t *testing.T, subj string, δbtail *ΔBtail, tj *tTreeCommit,
...
@@ -933,7 +929,7 @@ func assertΔTtail(t *testing.T, subj string, δbtail *ΔBtail, tj *tTreeCommit,
// xtrackKeys issues δbtail.Track requests for tree[keys].
// xtrackKeys issues δbtail.Track requests for tree[keys].
// XXX place
// XXX place
func
xtrackKeys
(
δbtail
*
ΔBtail
,
t
*
tTree
Commit
,
keys
setKey
)
{
func
xtrackKeys
(
δbtail
*
ΔBtail
,
t
*
xbtreetest
.
Commit
,
keys
setKey
)
{
X
:=
exc
.
Raiseif
X
:=
exc
.
Raiseif
head
:=
δbtail
.
Head
()
head
:=
δbtail
.
Head
()
if
head
!=
t
.
at
{
if
head
!=
t
.
at
{
...
@@ -960,7 +956,7 @@ func xtrackKeys(δbtail *ΔBtail, t *tTreeCommit, keys setKey) {
...
@@ -960,7 +956,7 @@ func xtrackKeys(δbtail *ΔBtail, t *tTreeCommit, keys setKey) {
// XXX
// XXX
// XXX kill
// XXX kill
/*
/*
func ___xverifyΔBTail_GetAt(t *testing.T, db *zodb.DB, treeRoot zodb.Oid, vt ...*
tTree
Commit) {
func ___xverifyΔBTail_GetAt(t *testing.T, db *zodb.DB, treeRoot zodb.Oid, vt ...*
xbtreetest.
Commit) {
subj := vt[0].tree
subj := vt[0].tree
for _, t := range vt[1:] {
for _, t := range vt[1:] {
subj += "→" + t.tree
subj += "→" + t.tree
...
@@ -993,7 +989,7 @@ func ___xverifyΔBTail_GetAt(t *testing.T, db *zodb.DB, treeRoot zodb.Oid, vt ..
...
@@ -993,7 +989,7 @@ func ___xverifyΔBTail_GetAt(t *testing.T, db *zodb.DB, treeRoot zodb.Oid, vt ..
})
})
}
}
func xverifyΔBTail_GetAt1(t *testing.T, db *zodb.DB, treeRoot zodb.Oid, vt []*
tTree
Commit, xat map[zodb.Tid]string, keys setKey) {
func xverifyΔBTail_GetAt1(t *testing.T, db *zodb.DB, treeRoot zodb.Oid, vt []*
xbtreetest.
Commit, xat map[zodb.Tid]string, keys setKey) {
X := exc.Raiseif
X := exc.Raiseif
// t1->t2-> ... -> tn
// t1->t2-> ... -> tn
...
@@ -1081,9 +1077,9 @@ func ΔBTest(xtest interface{}) ΔBTestEntry {
...
@@ -1081,9 +1077,9 @@ func ΔBTest(xtest interface{}) ΔBTestEntry {
// testΔBTail verifies ΔBTail on sequence of tree topologies coming from testq.
// testΔBTail verifies ΔBTail on sequence of tree topologies coming from testq.
func
testΔBTail
(
t_
*
testing
.
T
,
testq
chan
ΔBTestEntry
)
{
func
testΔBTail
(
t_
*
testing
.
T
,
testq
chan
ΔBTestEntry
)
{
t
:=
tNewTreeEnv
(
t_
)
t
:=
xbtreetest
.
NewT
(
t_
)
var
t0
*
tTree
Commit
var
t0
*
xbtreetest
.
Commit
for
test
:=
range
testq
{
for
test
:=
range
testq
{
t1
:=
t
.
Head
()
t1
:=
t
.
Head
()
t2
:=
t
.
CommitTree
(
test
.
tree
)
t2
:=
t
.
CommitTree
(
test
.
tree
)
...
@@ -1563,7 +1559,7 @@ func TestΔBTailAllStructs(t *testing.T) {
...
@@ -1563,7 +1559,7 @@ func TestΔBTailAllStructs(t *testing.T) {
func
TestΔBtailForget
(
t_
*
testing
.
T
)
{
func
TestΔBtailForget
(
t_
*
testing
.
T
)
{
t
:=
tNewTreeEnv
(
t_
)
t
:=
xbtreetest
.
NewT
(
t_
)
X
:=
exc
.
Raiseif
X
:=
exc
.
Raiseif
t0
:=
t
.
CommitTree
(
"T/B:"
)
t0
:=
t
.
CommitTree
(
"T/B:"
)
...
@@ -1602,7 +1598,7 @@ func TestΔBtailForget(t_ *testing.T) {
...
@@ -1602,7 +1598,7 @@ func TestΔBtailForget(t_ *testing.T) {
func
TestΔBtailClone
(
t_
*
testing
.
T
)
{
func
TestΔBtailClone
(
t_
*
testing
.
T
)
{
// ΔBtail.Clone had bug that aliased klon data to orig
// ΔBtail.Clone had bug that aliased klon data to orig
t
:=
tNewTreeEnv
(
t_
)
t
:=
xbtreetest
.
NewT
(
t_
)
X
:=
exc
.
Raiseif
X
:=
exc
.
Raiseif
t0
:=
t
.
CommitTree
(
"T2/B1:a-B2:b"
)
t0
:=
t
.
CommitTree
(
"T2/B1:a-B2:b"
)
...
@@ -1678,7 +1674,7 @@ func TestIntSets(t *testing.T) {
...
@@ -1678,7 +1674,7 @@ func TestIntSets(t *testing.T) {
// allTestKeys returns all keys from vt + ∞.
// allTestKeys returns all keys from vt + ∞.
func
allTestKeys
(
vt
...*
tTree
Commit
)
setKey
{
func
allTestKeys
(
vt
...*
xbtreetest
.
Commit
)
setKey
{
allKeys
:=
setKey
{};
allKeys
.
Add
(
KeyMax
)
// ∞ simulating ZBigFile.Size() query
allKeys
:=
setKey
{};
allKeys
.
Add
(
KeyMax
)
// ∞ simulating ZBigFile.Size() query
for
_
,
t
:=
range
vt
{
for
_
,
t
:=
range
vt
{
for
_
,
b
:=
range
t
.
xkv
{
for
_
,
b
:=
range
t
.
xkv
{
...
@@ -1738,34 +1734,3 @@ func δTEqual(δa, δb map[Key]Δstring) bool {
...
@@ -1738,34 +1734,3 @@ func δTEqual(δa, δb map[Key]Δstring) bool {
}
}
return
true
return
true
}
}
// ----------------------------------------
// ZBlk-related functions are imported at runtime by δbtail_x_test
var
(
ZTreeGetBlkData
func
(
context
.
Context
,
*
Tree
,
Key
)
(
string
,
bool
,
[]
Node
,
error
)
ZGetBlkData
func
(
context
.
Context
,
*
zodb
.
Connection
,
zodb
.
Oid
)
(
string
,
error
)
)
// xzgetBlkData loads block data from ZBlk object specified by its oid.
func
xzgetBlkData
(
ctx
context
.
Context
,
zconn
*
zodb
.
Connection
,
zblkOid
zodb
.
Oid
)
string
{
X
:=
exc
.
Raiseif
if
zblkOid
==
VDEL
{
return
DEL
}
data
,
err
:=
ZGetBlkData
(
ctx
,
zconn
,
zblkOid
);
X
(
err
)
return
string
(
data
)
}
// xzgetBlkDataAt loads block data from ZBlk object specified by oid@at.
func
xzgetBlkDataAt
(
db
*
zodb
.
DB
,
zblkOid
zodb
.
Oid
,
at
zodb
.
Tid
)
string
{
X
:=
exc
.
Raiseif
txn
,
ctx
:=
transaction
.
New
(
context
.
Background
())
defer
txn
.
Abort
()
zconn
,
err
:=
db
.
Open
(
ctx
,
&
zodb
.
ConnOptions
{
At
:
at
});
X
(
err
)
return
xzgetBlkData
(
ctx
,
zconn
,
zblkOid
)
}
wcfs/internal/xbtree/δbtail_x_test.go
View file @
11c95175
...
@@ -18,85 +18,7 @@
...
@@ -18,85 +18,7 @@
// See https://www.nexedi.com/licensing for rationale and options.
// See https://www.nexedi.com/licensing for rationale and options.
package
xbtree_test
package
xbtree_test
// ZBlk-related part of δbtail_test
import
(
import
(
"context"
_
"lab.nexedi.com/nexedi/wendelin.core/wcfs/internal/xbtree/xbtreetest/init"
"fmt"
"lab.nexedi.com/kirr/go123/xerr"
"lab.nexedi.com/kirr/neo/go/zodb"
"lab.nexedi.com/nexedi/wendelin.core/wcfs/internal/xbtree"
"lab.nexedi.com/nexedi/wendelin.core/wcfs/internal/xzodb"
"lab.nexedi.com/nexedi/wendelin.core/wcfs/internal/zdata"
)
)
type
Tree
=
xbtree
.
Tree
type
Node
=
xbtree
.
Node
type
Key
=
xbtree
.
Key
type
ZBlk
=
zdata
.
ZBlk
// ztreeGetBlk returns ztree[k] and tree path that lead to this block.
// XXX +return blkRevMax and use it ?
func
ztreeGetBlk
(
ctx
context
.
Context
,
ztree
*
Tree
,
k
Key
)
(
zblk
ZBlk
,
ok
bool
,
path
[]
Node
,
err
error
)
{
path
=
[]
Node
{}
xzblk
,
ok
,
err
:=
ztree
.
VGet
(
ctx
,
k
,
func
(
node
Node
)
{
path
=
append
(
path
,
node
)
})
if
err
!=
nil
{
return
nil
,
false
,
nil
,
err
}
if
ok
{
zblk
,
ok
=
xzblk
.
(
ZBlk
)
if
!
ok
{
return
nil
,
false
,
nil
,
fmt
.
Errorf
(
"expect ZBlk*; got %s"
,
xzodb
.
TypeOf
(
xzblk
))
// XXX errctx
}
}
return
zblk
,
ok
,
path
,
nil
}
func
init
()
{
xbtree
.
ZTreeGetBlkData
=
ZTreeGetBlkData
xbtree
.
ZGetBlkData
=
ZGetBlkData
}
// ZTreeGetBlkData returns block data from block pointed to by ztree[k].
func
ZTreeGetBlkData
(
ctx
context
.
Context
,
ztree
*
Tree
,
k
Key
)
(
data
string
,
ok
bool
,
path
[]
Node
,
err
error
)
{
defer
xerr
.
Contextf
(
&
err
,
"@%s: tree<%s>: get blkdata from [%d]"
,
ztree
.
PJar
()
.
At
(),
ztree
.
POid
(),
k
)
zblk
,
ok
,
path
,
err
:=
ztreeGetBlk
(
ctx
,
ztree
,
k
)
if
err
!=
nil
||
!
ok
{
return
""
,
ok
,
path
,
err
}
bdata
,
_
,
err
:=
zblk
.
LoadBlkData
(
ctx
)
if
err
!=
nil
{
return
""
,
false
,
nil
,
err
}
return
string
(
bdata
),
true
,
path
,
nil
}
// ZGetBlkData loads block data from ZBlk object specified by its oid.
func
ZGetBlkData
(
ctx
context
.
Context
,
zconn
*
zodb
.
Connection
,
zblkOid
zodb
.
Oid
)
(
data
string
,
err
error
)
{
defer
xerr
.
Contextf
(
&
err
,
"@%s: get blkdata from obj %s"
,
zconn
.
At
(),
zblkOid
)
xblk
,
err
:=
zconn
.
Get
(
ctx
,
zblkOid
)
if
err
!=
nil
{
return
""
,
err
}
zblk
,
ok
:=
xblk
.
(
ZBlk
)
if
!
ok
{
return
""
,
fmt
.
Errorf
(
"expect ZBlk*; got %s"
,
xzodb
.
TypeOf
(
xblk
))
}
bdata
,
_
,
err
:=
zblk
.
LoadBlkData
(
ctx
)
if
err
!=
nil
{
return
""
,
err
}
return
string
(
bdata
),
nil
}
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