Commit 37c2e806 authored by Kirill Smelkov's avatar Kirill Smelkov

X wcfs: Teach treediff to compute not only δtrack (set of nodes), but also δ for track-key coverage

This will, hopefully, be used to fix rebuild.

* t2:
  .
  .
  .
  .
  .
  .
  .
  X treediff ret += δtkeycov
  .
  .
parents 2c5f6517 175f92c9
...@@ -54,10 +54,11 @@ const tracePPSet = false ...@@ -54,10 +54,11 @@ const tracePPSet = false
type PPTreeSubSet map[zodb.Oid]*nodeInTree type PPTreeSubSet map[zodb.Oid]*nodeInTree
// nodeInTree represents tracking information about a node. // nodeInTree represents tracking information about a node.
// XXX -> treeNode ?
type nodeInTree struct { type nodeInTree struct {
parent zodb.Oid // parent node | InvalidOid for root parent zodb.Oid // parent node | InvalidOid for root
nchild int // number of direct children in PPTreeSubSet referring to this node nchild int // number of direct children in PPTreeSubSet referring to this node
// XXX + [lo,hi) range this node is coming under in its parent // XXX + [lo,hi) range this node is coming under in its parent XXX -> in its tree ?
} }
......
...@@ -398,11 +398,13 @@ func (S RangedKeySet) String() string { ...@@ -398,11 +398,13 @@ func (S RangedKeySet) String() string {
} }
func (r KeyRange) String() string { func (r KeyRange) String() string {
hi := r.hi_ var shi string
if hi < KeyMax { if r.hi_ == KeyMax {
hi += 1 shi = kstr(r.hi_) // ∞
} else {
shi = fmt.Sprintf("%d", r.hi_+1)
} }
return fmt.Sprintf("[%s,%s)", kstr(r.lo), kstr(hi)) return fmt.Sprintf("[%s,%s)", kstr(r.lo), shi)
} }
......
...@@ -82,6 +82,9 @@ import ( ...@@ -82,6 +82,9 @@ import (
"lab.nexedi.com/nexedi/wendelin.core/wcfs/internal/xzodb" "lab.nexedi.com/nexedi/wendelin.core/wcfs/internal/xzodb"
) )
const traceDiff = false
const debugDiff = false
// ΔValue represents change in value. // ΔValue represents change in value.
type ΔValue struct { type ΔValue struct {
Old Value Old Value
...@@ -318,18 +321,22 @@ func (rs rangeSplit) String() string { ...@@ -318,18 +321,22 @@ func (rs rangeSplit) String() string {
} }
// treediff computes δT/δtrack for tree/trackSet specified by root in between old..new. // treediff computes δT/δtrack/δtkeycov for tree/trackSet specified by root in between old..new.
// //
// δ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, err error) { 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) {
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)
tracef("\ntreediff %s δtops: %v δZTC: %v\n", root, δtops, δZTC)
defer tracef("\n")
δT = map[Key]ΔValue{} δT = map[Key]ΔValue{}
δtrack = &ΔPPTreeSubSet{Del: PPTreeSubSet{}, Add: PPTreeSubSet{}, δnchildNonLeafs: map[zodb.Oid]int{}}
δtkeycov = &RangedKeySet{}
tracefDiff("\ntreediff %s δtops: %v δZTC: %v\n", root, δtops, δZTC)
tracefDiff(" trackSet: %v\n", trackSet)
defer tracefDiff("\n-> δT: %v\nδtrack: %v\nδtkeycov: %v\n", δT, δtrack, δtkeycov)
δtrackv := []*ΔPPTreeSubSet{} δtrackv := []*ΔPPTreeSubSet{}
for top := range δtops { // XXX -> sorted? for top := range δtops { // XXX -> sorted?
...@@ -337,12 +344,12 @@ func treediff(ctx context.Context, root zodb.Oid, δtops SetOid, δZTC SetOid, t ...@@ -337,12 +344,12 @@ func treediff(ctx context.Context, root zodb.Oid, δtops SetOid, δZTC SetOid, t
b, err2 := zgetNodeOrNil(ctx, zconnNew, top) b, err2 := zgetNodeOrNil(ctx, zconnNew, top)
err := xerr.Merge(err1, err2) err := xerr.Merge(err1, err2)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, nil, err
} }
δtop, δtrackTop, err := diffX(ctx, a, b, δZTC, trackSet) δtop, δtrackTop, δtkeycovTop, err := diffX(ctx, a, b, δZTC, trackSet)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, nil, err
} }
// FIXME -> merge (VDEL vs add) // FIXME -> merge (VDEL vs add)
...@@ -350,22 +357,23 @@ func treediff(ctx context.Context, root zodb.Oid, δtops SetOid, δZTC SetOid, t ...@@ -350,22 +357,23 @@ func treediff(ctx context.Context, root zodb.Oid, δtops SetOid, δZTC SetOid, t
// -> assert that keys from different δtop do not overlap // -> assert that keys from different δtop do not overlap
// DEL k -> Tkextra += k // DEL k -> Tkextra += k
// +k -> Tkextra -= k // +k -> Tkextra -= k
tracef("-> δtop: %v\n", δtop) debugfDiff("-> δtop: %v\n", δtop)
tracef("-> δtrackTop: %v\n", δtrackTop) debugfDiff("-> δtrackTop: %v\n", δtrackTop)
debugfDiff("-> δtkeycovTop: %v\n", δtkeycovTop)
for k,δv := range δtop { for k,δv := range δtop {
δT[k] = δv δT[k] = δv
} }
δtrackv = append(δtrackv, δtrackTop) δtrackv = append(δtrackv, δtrackTop)
δtkeycov.UnionInplace(δtkeycovTop)
} }
// adjust trackSet by merge(δtrackTops) // adjust trackSet by merge(δtrackTops)
δtrack = &ΔPPTreeSubSet{Del: PPTreeSubSet{}, Add: PPTreeSubSet{}, δnchildNonLeafs: map[zodb.Oid]int{}}
for _, δ := range δtrackv { for _, δ := range δtrackv {
δtrack.Update(δ) δtrack.Update(δ)
} }
return δT, δtrack, nil return δT, δtrack, δtkeycov, nil
} }
// diffX computes difference in between two revisions of a tree's subtree. // diffX computes difference in between two revisions of a tree's subtree.
...@@ -379,7 +387,9 @@ func treediff(ctx context.Context, root zodb.Oid, δtops SetOid, δZTC SetOid, t ...@@ -379,7 +387,9 @@ func treediff(ctx context.Context, root zodb.Oid, δtops SetOid, δZTC SetOid, t
// //
// δtrack is trackSet δ that needs to be applied to trackSet to keep it // δtrack is trackSet δ that needs to be applied to trackSet to keep it
// consistent with b (= a + δ). // consistent with b (= a + δ).
func diffX(ctx context.Context, a, b Node, δZTC SetOid, trackSet PPTreeSubSet) (δ map[Key]ΔValue, δtrack *ΔPPTreeSubSet, err error) { //
// δ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) {
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?
} }
...@@ -408,7 +418,7 @@ func diffX(ctx context.Context, a, b Node, δZTC SetOid, trackSet PPTreeSubSet) ...@@ -408,7 +418,7 @@ func diffX(ctx context.Context, a, b Node, δZTC SetOid, trackSet PPTreeSubSet)
panicf("BUG: a.oid != b.oid ; a: %s b: %s", a.POid(), b.POid()) panicf("BUG: a.oid != b.oid ; a: %s b: %s", a.POid(), b.POid())
} }
if !((aT != nil && bT != nil) || (aB != nil && bB != nil)) { if !((aT != nil && bT != nil) || (aB != nil && bB != nil)) {
return nil, nil, fmt.Errorf("object %s: type mutated %s -> %s", a.POid(), return nil, nil, nil, fmt.Errorf("object %s: type mutated %s -> %s", a.POid(),
zodb.ClassOf(a), zodb.ClassOf(b)) zodb.ClassOf(a), zodb.ClassOf(b))
} }
} }
...@@ -420,8 +430,9 @@ func diffX(ctx context.Context, a, b Node, δZTC SetOid, trackSet PPTreeSubSet) ...@@ -420,8 +430,9 @@ func diffX(ctx context.Context, a, b Node, δZTC SetOid, trackSet PPTreeSubSet)
δ, err := diffB(ctx, aB, bB) δ, err := diffB(ctx, aB, bB)
if δ != nil { if δ != nil {
δtrack = &ΔPPTreeSubSet{} δtrack = &ΔPPTreeSubSet{}
δtkeycov = &RangedKeySet{}
} }
return δ, δtrack, err return δ, δtrack, δtkeycov, err
} }
} }
...@@ -429,16 +440,21 @@ func diffX(ctx context.Context, a, b Node, δZTC SetOid, trackSet PPTreeSubSet) ...@@ -429,16 +440,21 @@ 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, err error) { func diffT(ctx context.Context, A, B *Tree, δZTC SetOid, trackSet PPTreeSubSet) (δ map[Key]ΔValue, δtrack *ΔPPTreeSubSet, δtkeycov *RangedKeySet, err error) {
tracef(" 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 = &ΔPPTreeSubSet{Del: PPTreeSubSet{}, Add: PPTreeSubSet{}, δnchildNonLeafs: map[zodb.Oid]int{}} δtrack = &ΔPPTreeSubSet{Del: PPTreeSubSet{}, Add: PPTreeSubSet{}, δnchildNonLeafs: map[zodb.Oid]int{}}
defer tracef(" -> δ: %v\n", δ) δtkeycov = &RangedKeySet{}
defer func() {
tracefDiff(" -> δ: %v\n", δ)
tracefDiff(" -> δtrack: %v\n", δtrack)
tracefDiff(" -> δtkeycov: %v\n", δtkeycov)
}()
if A == nil && B == nil { if A == nil && B == nil {
return δ, δtrack, nil // ø changes return δ, δtrack, δtkeycov, nil // ø changes
} }
// assert A.oid == B.oid // assert A.oid == B.oid
...@@ -451,21 +467,61 @@ func diffT(ctx context.Context, A, B *Tree, δZTC SetOid, trackSet PPTreeSubSet) ...@@ -451,21 +467,61 @@ func diffT(ctx context.Context, A, B *Tree, δZTC SetOid, trackSet PPTreeSubSet)
} }
var ABoid zodb.Oid var ABoid zodb.Oid
var AB *Tree
if A != nil { if A != nil {
ABoid = A.POid() ABoid = A.POid()
AB = A
} }
if B != nil { if B != nil {
ABoid = B.POid() ABoid = B.POid()
AB = B
} }
// path prefix to A and B // path prefix to A and B
ABpath := trackSet.Path(ABoid) ABpath := trackSet.Path(ABoid)
// key coverage for A and B
ABlo := KeyMin
ABhi_ := KeyMax
node := AB
ABcov:
for i := len(ABpath)-2; i >= 0; i-- {
xparent, err := node.PJar().Get(ctx, ABpath[i]); /*X*/if err != nil { return nil,nil,nil, err }
parent := xparent.(*Tree) // must succeed
// find node in parent children and constrain ABlo/ABhi accordingly
entryv := parent.Entryv()
for j, entry := range entryv {
if entry.Child() == node {
// parent.entry[j] points to node
// [i].Key ≤ [i].Child.*.Key < [i+1].Key
klo := entryv[j].Key()
khi_ := KeyMax
if j+1 < len(entryv) {
khi_ = entryv[j+1].Key() - 1
}
if klo > ABlo {
ABlo = klo
}
if khi_ < ABhi_ {
ABhi_ = khi_
}
node = parent
continue ABcov
}
}
panicf("BUG: T%s points to T%s as parent in trackSet, but not found in T%s children", node.POid(), parent.POid(), parent.POid())
}
if A == nil || B == nil { if A == nil || B == nil {
// top of the subtree must stay in the tracking set even if the subtree is removed // top of the subtree must stay in the tracking set even if the subtree is removed
// this way, if later, the subtree will be recreated, that change won't be missed // this way, if later, the subtree will be recreated, that change won't be missed
δtrack.Del.AddPath(ABpath) δtrack.Del.AddPath(ABpath)
δtrack.Add.AddPath(ABpath) δtrack.Add.AddPath(ABpath)
// δtkeycov stays ø
} }
// A|B == nil -> artificial empty tree // A|B == nil -> artificial empty tree
...@@ -479,10 +535,9 @@ func diffT(ctx context.Context, A, B *Tree, δZTC SetOid, trackSet PPTreeSubSet) ...@@ -479,10 +535,9 @@ func diffT(ctx context.Context, A, B *Tree, δZTC SetOid, trackSet PPTreeSubSet)
} }
// initial split ranges for A and B // initial split ranges for A and B
// XXX maybe walk till a from root to get more precise initial range?
prefix := ABpath[:len(ABpath)-1] prefix := ABpath[:len(ABpath)-1]
atop := &nodeInRange{prefix: prefix, lo: KeyMin, hi_: KeyMax, node: A} // [-∞, ∞) atop := &nodeInRange{prefix: prefix, lo: ABlo, hi_: ABhi_, node: A} // [-∞, ∞)
btop := &nodeInRange{prefix: prefix, lo: KeyMin, hi_: KeyMax, node: B} // [-∞, ∞) btop := &nodeInRange{prefix: prefix, lo: ABlo, hi_: ABhi_, node: B} // [-∞, ∞)
Av := rangeSplit{atop} // nodes expanded from A Av := rangeSplit{atop} // nodes expanded from A
Bv := rangeSplit{btop} // nodes expanded from B Bv := rangeSplit{btop} // nodes expanded from B
...@@ -496,7 +551,7 @@ func diffT(ctx context.Context, A, B *Tree, δZTC SetOid, trackSet PPTreeSubSet) ...@@ -496,7 +551,7 @@ func diffT(ctx context.Context, A, B *Tree, δZTC SetOid, trackSet PPTreeSubSet)
δtodo := &RangedKeySet{} δtodo := &RangedKeySet{}
δtodo.AddRange(r) δtodo.AddRange(r)
δtodo.DifferenceInplace(Akdone) δtodo.DifferenceInplace(Akdone)
tracef(" Akq <- %s\n", δtodo) debugfDiff(" Akq <- %s\n", δtodo)
Akqueue.UnionInplace(δtodo) Akqueue.UnionInplace(δtodo)
} }
} }
...@@ -505,7 +560,7 @@ func diffT(ctx context.Context, A, B *Tree, δZTC SetOid, trackSet PPTreeSubSet) ...@@ -505,7 +560,7 @@ func diffT(ctx context.Context, A, B *Tree, δZTC SetOid, trackSet PPTreeSubSet)
δtodo := &RangedKeySet{} δtodo := &RangedKeySet{}
δtodo.AddRange(r) δtodo.AddRange(r)
δtodo.DifferenceInplace(Bkdone) δtodo.DifferenceInplace(Bkdone)
tracef(" Bkq <- %s\n", δtodo) debugfDiff(" Bkq <- %s\n", δtodo)
Bkqueue.UnionInplace(δtodo) Bkqueue.UnionInplace(δtodo)
} }
} }
...@@ -516,6 +571,10 @@ func diffT(ctx context.Context, A, B *Tree, δZTC SetOid, trackSet PPTreeSubSet) ...@@ -516,6 +571,10 @@ func diffT(ctx context.Context, A, B *Tree, δZTC SetOid, trackSet PPTreeSubSet)
BtrackSet.AddPath(ABpath) BtrackSet.AddPath(ABpath)
} }
// δtkeycov will be = BAdd \ ADel
δtkeycovADel := &RangedKeySet{}
δtkeycovBAdd := &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 δ-
// a node ac does not contribute to δ- and can be skipped, if: // a node ac does not contribute to δ- and can be skipped, if:
...@@ -523,30 +582,37 @@ func diffT(ctx context.Context, A, B *Tree, δZTC SetOid, trackSet PPTreeSubSet) ...@@ -523,30 +582,37 @@ func diffT(ctx context.Context, A, B *Tree, δZTC SetOid, trackSet PPTreeSubSet)
// - ac ∉ δZTC && ∃ bc from B: ac.oid == bc.oid (ac+ac.children were not changed, and ac stays in the tree) // - ac ∉ δZTC && ∃ bc from B: ac.oid == bc.oid (ac+ac.children were not changed, and ac stays in the tree)
Aq := []*nodeInRange{atop} // queue for A nodes that contribute to δ- Aq := []*nodeInRange{atop} // queue for A nodes that contribute to δ-
for len(Aq) > 0 { for len(Aq) > 0 {
tracef("\n") debugfDiff("\n")
tracef(" aq: %v\n", Aq) debugfDiff(" aq: %v\n", Aq)
tracef(" av: %s\n", Av) debugfDiff(" av: %s\n", Av)
tracef(" bv: %s\n", Bv) debugfDiff(" bv: %s\n", Bv)
ra := pop(&Aq) ra := pop(&Aq)
err = ra.node.PActivate(ctx); /*X*/if err != nil { return nil,nil, err } err = ra.node.PActivate(ctx); /*X*/if err != nil { return nil,nil,nil, err }
defer ra.node.PDeactivate() defer ra.node.PDeactivate()
tracef(" a: %s\n", ra) debugfDiff(" a: %s\n", ra)
switch a := ra.node.(type) { switch a := ra.node.(type) {
case *Bucket: case *Bucket:
// a is bucket -> δ- // a is bucket -> δ-
δA, err := diffB(ctx, a, nil); /*X*/if err != nil { return 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, err } err = δMerge(δ, δA); /*X*/if err != nil { return nil,nil,nil, err }
ar := KeyRange{ra.lo, ra.hi_}
δtrack.Del.AddPath(ra.Path()) δtrack.Del.AddPath(ra.Path())
δtkeycovADel.AddRange(ar)
debugfDiff(" δtrack - %s %v\n", ar, ra.Path())
// Bkqueue <- ra.range // Bkqueue <- ra.range
Bktodo(KeyRange{ra.lo, ra.hi_}) Bktodo(ar)
ra.done = true ra.done = true
case *Tree: case *Tree:
// empty tree - only queue holes covered by it // empty tree - only queue holes covered by it
if len(a.Entryv()) == 0 { if len(a.Entryv()) == 0 {
Bktodo(KeyRange{ra.lo, ra.hi_}) ar := KeyRange{ra.lo, ra.hi_}
δtrack.Del.AddPath(ra.Path())
δtkeycovADel.AddRange(ar)
debugfDiff(" δtrack - %s %v\n", ar, ra.Path())
Bktodo(ar)
continue continue
} }
...@@ -578,7 +644,7 @@ func diffT(ctx context.Context, A, B *Tree, δZTC SetOid, trackSet PPTreeSubSet) ...@@ -578,7 +644,7 @@ func diffT(ctx context.Context, A, B *Tree, δZTC SetOid, trackSet PPTreeSubSet)
if !ok { if !ok {
break // bucket break // bucket
} }
err = bloT.PActivate(ctx); /*X*/if err != nil { return nil,nil, err } err = bloT.PActivate(ctx); /*X*/if err != nil { return nil,nil,nil, err }
defer bloT.PDeactivate() defer bloT.PDeactivate()
if len(bloT.Entryv()) == 0 { if len(bloT.Entryv()) == 0 {
...@@ -608,6 +674,16 @@ func diffT(ctx context.Context, A, B *Tree, δZTC SetOid, trackSet PPTreeSubSet) ...@@ -608,6 +674,16 @@ func diffT(ctx context.Context, A, B *Tree, δZTC SetOid, trackSet PPTreeSubSet)
δtrack.Add.AddPath(bpath) δtrack.Add.AddPath(bpath)
if nc := at.nchild; nc != 0 { if nc := at.nchild; nc != 0 {
δtrack.δnchildNonLeafs[acOid] = nc δtrack.δnchildNonLeafs[acOid] = nc
// XXX debugDiff δtrack [) ...
} else {
// adjust δtkeycov only if it was leaf bucket
ar := KeyRange{ac.lo, ac.hi_}
bc := Bv.Get(ac.lo)
br := KeyRange{bc.lo, bc.hi_}
δtkeycovADel.AddRange(ar)
δtkeycovBAdd.AddRange(br)
debugfDiff(" δtrack - %s %v KKK\n", ar, apath)
debugfDiff(" δtrack + %s %v KKK\n", br, bpath)
} }
} }
...@@ -636,14 +712,14 @@ func diffT(ctx context.Context, A, B *Tree, δZTC SetOid, trackSet PPTreeSubSet) ...@@ -636,14 +712,14 @@ func diffT(ctx context.Context, A, B *Tree, δZTC SetOid, trackSet PPTreeSubSet)
// * +B12, which queues A.2 and leads to // * +B12, which queues A.2 and leads to
// * -B23, which queues B.3 and leads to // * -B23, which queues B.3 and leads to
// * +B23, ... // * +B23, ...
tracef("\nphase 2:\n") debugfDiff("\nphase 2:\n")
for { for {
tracef("\n") debugfDiff("\n")
tracef(" av: %s\n", Av) debugfDiff(" av: %s\n", Av)
tracef(" bv: %s\n", Bv) debugfDiff(" bv: %s\n", Bv)
tracef("\n") debugfDiff("\n")
tracef(" Bkq: %s\n", Bkqueue) debugfDiff(" Bkq: %s\n", Bkqueue)
if Bkqueue.Empty() { if Bkqueue.Empty() {
break break
} }
...@@ -651,22 +727,24 @@ func diffT(ctx context.Context, A, B *Tree, δZTC SetOid, trackSet PPTreeSubSet) ...@@ -651,22 +727,24 @@ func diffT(ctx context.Context, A, B *Tree, δZTC SetOid, trackSet PPTreeSubSet)
for _, r := range Bkqueue.AllRanges() { for _, r := range Bkqueue.AllRanges() {
lo := r.lo lo := r.lo
for { for {
b, err := Bv.GetToLeaf(ctx, lo); /*X*/if err != nil { return nil,nil, err } b, err := Bv.GetToLeaf(ctx, lo); /*X*/if err != nil { return nil,nil,nil, err }
tracef(" B k%d -> %s\n", lo, b) debugfDiff(" B k%d -> %s\n", lo, b)
// +bucket if that bucket is reached for the first time // +bucket if that bucket is reached for the first time
if !b.done { if !b.done {
var δB map[Key]ΔValue var δB map[Key]ΔValue
bbucket, ok := b.node.(*Bucket) bbucket, ok := b.node.(*Bucket)
if ok { // !ok means ø tree if ok { // !ok means ø tree
δB, err = diffB(ctx, nil, bbucket); /*X*/if err != nil { return nil,nil, err } δB, err = diffB(ctx, nil, bbucket); /*X*/if err != nil { return nil,nil,nil, err }
} }
// δ <- δB // δ <- δB
err = δMerge(δ, δB); /*X*/if err != nil { return nil,nil, err } err = δMerge(δ, δB); /*X*/if err != nil { return nil,nil,nil, err }
br := KeyRange{b.lo, b.hi_}
δtrack.Add.AddPath(b.Path()) δtrack.Add.AddPath(b.Path())
δtkeycovBAdd.AddRange(br)
debugfDiff(" δtrack + %s %v\n", br, b.Path())
// Akqueue <- δB // Akqueue <- δB
br := KeyRange{b.lo, b.hi_}
Bkdone.AddRange(br) Bkdone.AddRange(br)
Aktodo(br) Aktodo(br)
...@@ -683,27 +761,35 @@ func diffT(ctx context.Context, A, B *Tree, δZTC SetOid, trackSet PPTreeSubSet) ...@@ -683,27 +761,35 @@ func diffT(ctx context.Context, A, B *Tree, δZTC SetOid, trackSet PPTreeSubSet)
} }
Bkqueue.Clear() Bkqueue.Clear()
tracef("\n") debugfDiff("\n")
tracef(" Akq: %s\n", Akqueue) debugfDiff(" Akq: %s\n", Akqueue)
for _, r := range Akqueue.AllRanges() { for _, r := range Akqueue.AllRanges() {
lo := r.lo lo := r.lo
for { for {
a, err := Av.GetToLeaf(ctx, lo); /*X*/if err != nil { return nil,nil, err } a, err := Av.GetToLeaf(ctx, lo); /*X*/if err != nil { return nil,nil,nil, err }
tracef(" A k%d -> %s\n", lo, a) debugfDiff(" A k%d -> %s\n", lo, a)
// -bucket if that bucket is reached for the first time // -bucket if that bucket is reached for the first time
if !a.done { if !a.done {
var δA map[Key]ΔValue var δA map[Key]ΔValue
abucket, ok := a.node.(*Bucket) abucket, ok := a.node.(*Bucket)
if ok { // !ok means ø tree if ok { // !ok means ø tree
δA, err = diffB(ctx, abucket, nil); /*X*/if err != nil { return nil,nil, err } δA, err = diffB(ctx, abucket, nil); /*X*/if err != nil { return nil,nil,nil, err }
} }
// δ <- δA // δ <- δA
err = δMerge(δ, δA); /*X*/if err != nil { return 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
ar := KeyRange{a.lo, a.hi_}
_, tracked := trackSet[a.node.POid()]
if tracked {
δtkeycovADel.AddRange(ar)
debugfDiff(" δtrack - %s %v\n", ar, a.Path())
} else {
debugfDiff(" δtrack - [) %v\n", a.Path())
}
// Bkqueue <- a.range // Bkqueue <- a.range
ar := KeyRange{a.lo, a.hi_}
Akdone.AddRange(ar) Akdone.AddRange(ar)
Bktodo(ar) Bktodo(ar)
...@@ -720,15 +806,16 @@ func diffT(ctx context.Context, A, B *Tree, δZTC SetOid, trackSet PPTreeSubSet) ...@@ -720,15 +806,16 @@ func diffT(ctx context.Context, A, B *Tree, δZTC SetOid, trackSet PPTreeSubSet)
Akqueue.Clear() Akqueue.Clear()
} }
return δ, δtrack, nil δtkeycov = δtkeycovBAdd.Difference(δtkeycovADel)
return δ, δtrack, δtkeycov, nil
} }
// δMerge merges changes from δ2 into δ. // δMerge merges changes from δ2 into δ.
// δ is total-building diff, while δ2 is diff from comparing some subnodes. // δ is total-building diff, while δ2 is diff from comparing some subnodes.
func δMerge(δ, δ2 map[Key]ΔValue) error { func δMerge(δ, δ2 map[Key]ΔValue) error {
tracef(" δmerge %v <- %v\n", δ, δ2) debugfDiff(" δmerge %v <- %v\n", δ, δ2)
defer tracef(" -> %v\n", δ) defer debugfDiff(" -> %v\n", δ)
// merge δ <- δ2 // merge δ <- δ2
for k, δv2 := range δ2 { for k, δv2 := range δ2 {
...@@ -773,7 +860,7 @@ func δMerge(δ, δ2 map[Key]ΔValue) error { ...@@ -773,7 +860,7 @@ func δMerge(δ, δ2 map[Key]ΔValue) error {
δv.New = δv2.New δv.New = δv2.New
} }
tracef(" [%v] merge %s %s -> %s\n", k, δv1, δv2, δv) debugfDiff(" [%v] merge %s %s -> %s\n", k, δv1, δv2, δv)
if δv.Old != δv.New { if δv.Old != δv.New {
δ[k] = δv δ[k] = δv
} else { } else {
...@@ -787,7 +874,7 @@ func δMerge(δ, δ2 map[Key]ΔValue) error { ...@@ -787,7 +874,7 @@ func δMerge(δ, δ2 map[Key]ΔValue) error {
// diffB computes difference in between two buckets. // diffB computes difference in between two buckets.
// see diffX for details. // see diffX for details.
func diffB(ctx context.Context, a, b *Bucket) (δ map[Key]ΔValue, err error) { func diffB(ctx context.Context, a, b *Bucket) (δ map[Key]ΔValue, err error) {
tracef(" diffB %s %s\n", xidOf(a), xidOf(b)) tracefDiff(" diffB %s %s\n", xidOf(a), xidOf(b))
defer xerr.Contextf(&err, "diffB %s %s", xidOf(a), xidOf(b)) defer xerr.Contextf(&err, "diffB %s %s", xidOf(a), xidOf(b))
// XXX oid can be InvalidOid for T/B... (i.e. B is part of T and is not yet committed separately) // XXX oid can be InvalidOid for T/B... (i.e. B is part of T and is not yet committed separately)
...@@ -805,9 +892,9 @@ func diffB(ctx context.Context, a, b *Bucket) (δ map[Key]ΔValue, err error) { ...@@ -805,9 +892,9 @@ func diffB(ctx context.Context, a, b *Bucket) (δ map[Key]ΔValue, err error) {
} }
δ = map[Key]ΔValue{} δ = map[Key]ΔValue{}
defer tracef(" -> δb: %v\n", δ) defer tracefDiff(" -> δb: %v\n", δ)
//tracef(" av: %v", av) //debugfDiff(" av: %v", av)
//tracef(" bv: %v", bv) //debugfDiff(" bv: %v", bv)
for len(av) > 0 || len(bv) > 0 { for len(av) > 0 || len(bv) > 0 {
ka, va := KeyMax, VDEL ka, va := KeyMax, VDEL
...@@ -904,11 +991,7 @@ func xidOf(obj zodb.IPersistent) string { ...@@ -904,11 +991,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 = "*" }
hi := rn.hi_ return fmt.Sprintf("%s%s%s", done, KeyRange{rn.lo, rn.hi_}, vnode(rn.node))
if hi < KeyMax {
hi += 1
}
return fmt.Sprintf("%s[%s,%s)%s", done, kstr(rn.lo), kstr(hi), vnode(rn.node))
} }
// push pushes element to node stack. // push pushes element to node stack.
...@@ -961,3 +1044,15 @@ func vnode(node Node) string { ...@@ -961,3 +1044,15 @@ func vnode(node Node) string {
} }
return kind + node.POid().String() return kind + node.POid().String()
} }
func tracefDiff(format string, argv ...interface{}) {
if traceDiff {
fmt.Printf(format, argv...)
}
}
func debugfDiff(format string, argv ...interface{}) {
if debugDiff {
fmt.Printf(format, argv...)
}
}
...@@ -36,13 +36,6 @@ type SetOid = set.SetOid ...@@ -36,13 +36,6 @@ type SetOid = set.SetOid
const debug = false
func tracef(format string, argv ...interface{}) {
if debug {
fmt.Printf(format, argv...)
}
}
// nodePathToPath converts path from []Node to []Oid. // nodePathToPath converts path from []Node to []Oid.
// XXX place = ? // XXX place = ?
func nodePathToPath(nodePath []Node) (path []zodb.Oid) { func nodePathToPath(nodePath []Node) (path []zodb.Oid) {
......
...@@ -22,6 +22,7 @@ package xbtree ...@@ -22,6 +22,7 @@ package xbtree
import ( import (
"context" "context"
"fmt"
"sort" "sort"
"strings" "strings"
...@@ -36,6 +37,10 @@ import ( ...@@ -36,6 +37,10 @@ import (
// TODO kill this after rebuild is finished // TODO kill this after rebuild is finished
const XXX_killWhenRebuildWorks = true const XXX_killWhenRebuildWorks = true
const traceΔBtail = false
const debugΔBtail = false
// ΔBtail represents tail of revisional changes to BTrees. // ΔBtail represents tail of revisional changes to BTrees.
// //
// It semantically consists of // It semantically consists of
...@@ -99,7 +104,7 @@ type ΔBtail struct { ...@@ -99,7 +104,7 @@ type ΔBtail struct {
// set of tracked nodes as of @head state. // set of tracked nodes as of @head state.
trackSet PPTreeSubSet trackSet PPTreeSubSet
// set of node that were requested to be tracked, but for which vδB was not yet rebuilt // set of nodes that were requested to be tracked, but for which vδB was not yet rebuilt
trackNew PPTreeSubSet trackNew PPTreeSubSet
} }
...@@ -217,18 +222,19 @@ func (δBtail *ΔBtail) Track(key Key, keyPresent bool, nodePath []Node) error { ...@@ -217,18 +222,19 @@ func (δBtail *ΔBtail) Track(key Key, keyPresent bool, nodePath []Node) error {
pathv := []string{} pathv := []string{}
for _, node := range nodePath { pathv = append(pathv, vnode(node)) } for _, node := range nodePath { pathv = append(pathv, vnode(node)) }
tracef("Track [%v] %s\n", key, strings.Join(pathv, " -> ")) tracefΔBtail("\nTrack [%v] %s\n", key, strings.Join(pathv, " -> "))
return δBtail.track(key, keyPresent, path) return δBtail.track(key, keyPresent, path)
} }
func (δBtail *ΔBtail) track(key Key, keyPresent bool, path []zodb.Oid) error { func (δBtail *ΔBtail) track(key Key, keyPresent bool, path []zodb.Oid) error {
// XXX locking
root := path[0] root := path[0]
δBtail.trackNew.AddPath(path) δBtail.trackNew.AddPath(path)
// track is track of path[-1] (i.e. leaf) // track is track of path[-1] (i.e. leaf)
// XXX hack - until rebuild is implemented // XXX hack - until rebuild is implemented
if XXX_killWhenRebuildWorks { if XXX_killWhenRebuildWorks {
_, ok := δBtail.byRoot[root] _, ok := δBtail.byRoot[root]
...@@ -248,6 +254,10 @@ func (δBtail *ΔBtail) rebuild() (err error) { ...@@ -248,6 +254,10 @@ func (δBtail *ΔBtail) rebuild() (err error) {
defer xerr.Context(&err, "ΔBtail rebuild") defer xerr.Context(&err, "ΔBtail rebuild")
// XXX locking // XXX locking
tracefΔBtail("\nRebuild @%s .. @%s\n", δBtail.Tail(), δBtail.Head())
tracefΔBtail("trackSet: %v\n", δBtail.trackSet)
tracefΔBtail("trackNew: %v\n", δBtail.trackNew)
trackNew := δBtail.trackNew trackNew := δBtail.trackNew
δBtail.trackNew = PPTreeSubSet{} δBtail.trackNew = PPTreeSubSet{}
...@@ -272,11 +282,11 @@ func (δBtail *ΔBtail) rebuild() (err error) { ...@@ -272,11 +282,11 @@ func (δBtail *ΔBtail) rebuild() (err error) {
δZTC, δtopsByRoot := δZConnectTracked(δZ.Changev, trackNew) δZTC, δtopsByRoot := δZConnectTracked(δZ.Changev, trackNew)
tracef("\nrebuild @%s <- @%s\n", atPrev, δZ.Rev) debugfΔBtail("\n rebuild @%s <- @%s\n", atPrev, δZ.Rev)
tracef("δZ:\t%v\n", δZ.Changev) debugfΔBtail(" δZ:\t%v\n", δZ.Changev)
tracef("trackNew: %v\n", trackNew) debugfΔBtail(" trackNew: %v\n", trackNew)
tracef("trackSet: %v\n", δBtail.trackSet) // XXX needed? debugfΔBtail(" trackSet: %v\n", δBtail.trackSet) // XXX needed?
defer tracef("\n\n") defer debugfΔBtail("\n\n")
// XXX len(δtopsByRoot) == 0 -> skip // XXX len(δtopsByRoot) == 0 -> skip
...@@ -296,12 +306,15 @@ func (δBtail *ΔBtail) rebuild() (err error) { ...@@ -296,12 +306,15 @@ func (δBtail *ΔBtail) rebuild() (err error) {
for root, δtops := range δtopsByRoot { for root, δtops := range δtopsByRoot {
// diff backwards curr -> prev // diff backwards curr -> prev
δT, δtrack, err := treediff(ctx, root, δtops, δZTC, trackNew, zconnCurr, zconnPrev) δT, δtrack, δtkeycov, err := treediff(ctx, root, δtops, δZTC, trackNew, zconnCurr, zconnPrev)
if err != nil { if err != nil {
return err return err
} }
tracef("-> root<%s> δkv*: %v δtrack*: %v\n", root, δT, δtrack) // FIXME use δtkeycov to recompute track coverage
_ = δtkeycov
debugfΔBtail(" -> root<%s> δkv*: %v δtrack*: %v\n", root, δT, δtrack)
trackNew.ApplyΔ(δtrack) trackNew.ApplyΔ(δtrack)
vδtrack = append([]*ΔPPTreeSubSet{δtrack}, vδtrack...) vδtrack = append([]*ΔPPTreeSubSet{δtrack}, vδtrack...)
...@@ -371,9 +384,24 @@ func (δBtail *ΔBtail) rebuild() (err error) { ...@@ -371,9 +384,24 @@ func (δBtail *ΔBtail) rebuild() (err error) {
// //
// TODO optionally accept zconnOld/zconnNew from client // TODO optionally accept zconnOld/zconnNew from client
func (δBtail *ΔBtail) Update(δZ *zodb.EventCommit) (_ ΔB, err error) { func (δBtail *ΔBtail) Update(δZ *zodb.EventCommit) (_ ΔB, err error) {
δB, _, err := δBtail._Update(δZ)
return δB, err
}
// _Update serves Update and also returns δtkeycov from treediff for testing.
type _ΔTrackKeyCov struct {
ByRoot map[zodb.Oid]*RangedKeySet // {} root -> δtrackedKeys (always grow)
}
func (δBtail *ΔBtail) _Update(δZ *zodb.EventCommit) (_ ΔB, δTKeyCov _ΔTrackKeyCov, err error) {
headOld := δBtail.Head() headOld := δBtail.Head()
defer xerr.Contextf(&err, "ΔBtail update %s -> %s", headOld, δZ.Tid) defer xerr.Contextf(&err, "ΔBtail update %s -> %s", headOld, δZ.Tid)
tracefΔBtail("\nUpdate @%s -> @%s δZ: %v\n", δBtail.Head(), δZ.Tid, δZ.Changev)
tracefΔBtail("trackSet: %v\n", δBtail.trackSet)
tracefΔBtail("trackNew: %v\n", δBtail.trackNew)
δTKeyCov = _ΔTrackKeyCov{ByRoot: make(map[zodb.Oid]*RangedKeySet)}
if XXX_killWhenRebuildWorks { if XXX_killWhenRebuildWorks {
// XXX hack - until vvv is reenabled // XXX hack - until vvv is reenabled
δBtail.trackSet.UnionInplace(δBtail.trackNew) δBtail.trackSet.UnionInplace(δBtail.trackNew)
...@@ -383,14 +411,10 @@ if XXX_killWhenRebuildWorks { ...@@ -383,14 +411,10 @@ if XXX_killWhenRebuildWorks {
// update .trackSet and vδB from .trackNew // update .trackSet and vδB from .trackNew
err = δBtail.rebuild() err = δBtail.rebuild()
if err != nil { if err != nil {
return ΔB{}, err return ΔB{}, δTKeyCov, err
} }
} }
tracef("Update @%s -> @%s\n", δBtail.Head(), δZ.Tid)
tracef("δZ:\t%v\n", δZ.Changev)
tracef("trackSet: %v\n", δBtail.trackSet)
// XXX dup wrt rebuild? // XXX dup wrt rebuild?
δBtail.δZtail.Append(δZ.Tid, δZ.Changev) δBtail.δZtail.Append(δZ.Tid, δZ.Changev)
...@@ -401,7 +425,7 @@ if XXX_killWhenRebuildWorks { ...@@ -401,7 +425,7 @@ if XXX_killWhenRebuildWorks {
// skip opening DB connections if there is no change to any tree node // skip opening DB connections if there is no change to any tree node
if len(δtopsByRoot) == 0 { if len(δtopsByRoot) == 0 {
return δB, nil return δB, δTKeyCov, nil
} }
// open ZODB connections corresponding to "old" and "new" states // open ZODB connections corresponding to "old" and "new" states
...@@ -410,20 +434,20 @@ if XXX_killWhenRebuildWorks { ...@@ -410,20 +434,20 @@ if XXX_killWhenRebuildWorks {
defer txn.Abort() defer txn.Abort()
zconnOld, err := δBtail.db.Open(ctx, &zodb.ConnOptions{At: headOld}) zconnOld, err := δBtail.db.Open(ctx, &zodb.ConnOptions{At: headOld})
if err != nil { if err != nil {
return ΔB{}, err return ΔB{}, δTKeyCov, err
} }
zconnNew, err := δBtail.db.Open(ctx, &zodb.ConnOptions{At: δZ.Tid}) zconnNew, err := δBtail.db.Open(ctx, &zodb.ConnOptions{At: δZ.Tid})
if err != nil { if err != nil {
return ΔB{}, err return ΔB{}, δTKeyCov, err
} }
for root, δtops := range δtopsByRoot { for root, δtops := range δtopsByRoot {
δT, δtrack, err := treediff(ctx, root, δtops, δZTC, δBtail.trackSet, zconnOld, zconnNew) δT, δtrack, δtkeycov, err := treediff(ctx, root, δtops, δZTC, δBtail.trackSet, zconnOld, zconnNew)
if err != nil { if err != nil {
return ΔB{}, err return ΔB{}, δTKeyCov, err
} }
tracef("\n-> root<%s> δkv: %v δtrack: %v\n", root, δT, δtrack) tracefΔBtail("\n-> root<%s> δkv: %v δtrack: %v δtkeycov: %v\n", root, δT, δtrack, δtkeycov)
if len(δT) > 0 { // an object might be resaved without change if len(δT) > 0 { // an object might be resaved without change
δB.ByRoot[root] = δT δB.ByRoot[root] = δT
...@@ -441,9 +465,10 @@ if XXX_killWhenRebuildWorks { ...@@ -441,9 +465,10 @@ if XXX_killWhenRebuildWorks {
} }
δBtail.trackSet.ApplyΔ(δtrack) δBtail.trackSet.ApplyΔ(δtrack)
δTKeyCov.ByRoot[root] = δtkeycov
} }
return δB, nil return δB, δTKeyCov, nil
} }
...@@ -563,3 +588,16 @@ func (δBtail *ΔBtail) SliceByRootRev(root zodb.Oid, lo, hi zodb.Tid) /*readonl ...@@ -563,3 +588,16 @@ func (δBtail *ΔBtail) SliceByRootRev(root zodb.Oid, lo, hi zodb.Tid) /*readonl
func (δBtail *ΔBtail) ΔZtail() /*readonly*/*zodb.ΔTail { func (δBtail *ΔBtail) ΔZtail() /*readonly*/*zodb.ΔTail {
return δBtail.δZtail return δBtail.δZtail
} }
func tracefΔBtail(format string, argv ...interface{}) {
if traceΔBtail {
fmt.Printf(format, argv...)
}
}
func debugfΔBtail(format string, argv ...interface{}) {
if debugΔBtail {
fmt.Printf(format, argv...)
}
}
...@@ -300,11 +300,19 @@ func (rbs RBucketSet) coverage() string { ...@@ -300,11 +300,19 @@ func (rbs RBucketSet) coverage() string {
return s return s
} }
// trackSet returns what should be ΔBtree.trackSet for specified tracked key set. // trackSet returns what should be ΔBtree.trackSet coverage for specified tracked key set.
func (rbs RBucketSet) trackSet(tracked SetKey) PPTreeSubSet { func (rbs RBucketSet) trackSet(tracked SetKey) PPTreeSubSet {
trackSet := PPTreeSubSet{} trackSet, _ := rbs.trackSetWithCov(tracked)
return trackSet
}
// trackSetWithCov returns what should be ΔBtree.trackSet and its key coverage for specified tracked key set.
func (rbs RBucketSet) trackSetWithCov(tracked SetKey) (trackSet PPTreeSubSet, keyCover *RangedKeySet) {
trackSet = PPTreeSubSet{}
keyCover = &RangedKeySet{}
for k := range tracked { for k := range tracked {
kb := rbs.Get(k) kb := rbs.Get(k)
keyCover.AddRange(KeyRange{kb.lo, kb.hi_})
// 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
...@@ -345,7 +353,7 @@ func (rbs RBucketSet) trackSet(tracked SetKey) PPTreeSubSet { ...@@ -345,7 +353,7 @@ func (rbs RBucketSet) trackSet(tracked SetKey) PPTreeSubSet {
p = p.parent p = p.parent
} }
} }
return trackSet return trackSet, keyCover
} }
...@@ -666,7 +674,7 @@ func xverifyΔBTail_Update(t *testing.T, subj string, db *zodb.DB, treeRoot zodb ...@@ -666,7 +674,7 @@ func xverifyΔBTail_Update(t *testing.T, subj string, db *zodb.DB, treeRoot zodb
// 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, at1,at2 zodb.Tid, xkv1,xkv2 RBucketSet, δZ *zodb.EventCommit, d12 map[Key]Δstring, initialTrackedKeys SetKey, kadj KAdjMatrix) { func xverifyΔBTail_Update1(t *testing.T, subj string, db *zodb.DB, treeRoot zodb.Oid, at1,at2 zodb.Tid, xkv1,xkv2 RBucketSet, δZ *zodb.EventCommit, d12 map[Key]Δstring, initialTrackedKeys SetKey, kadj KAdjMatrix) {
X := exc.Raiseif X := exc.Raiseif
tracef("\n>>> Track=%s\n", initialTrackedKeys) // t.Logf("\n>>> Track=%s\n", initialTrackedKeys)
var TrackedδZ SetKey = nil var TrackedδZ SetKey = nil
var kadjTrackedδZ SetKey = nil var kadjTrackedδZ SetKey = nil
...@@ -780,21 +788,18 @@ func xverifyΔBTail_Update1(t *testing.T, subj string, db *zodb.DB, treeRoot zod ...@@ -780,21 +788,18 @@ func xverifyΔBTail_Update1(t *testing.T, subj string, db *zodb.DB, treeRoot zod
// verify δbtail.trackSet against @at1 // verify δbtail.trackSet against @at1
// trackSet1 = xkv1[tracked1] // trackSet1 = xkv1[tracked1]
trackSet1 := xkv1.trackSet(initialTrackedKeys) trackSet1, tkeyCov1 := xkv1.trackSetWithCov(initialTrackedKeys)
// if !reflect.DeepEqual(trackSet1, δbtail.trackSet) {
// badf("δbtail.trackSet1 wrong:\n\thave: %v\n\twant: %v", δbtail.trackSet, trackSet1)
// }
if !δbtail.trackSet.Equal(ø) { if !δbtail.trackSet.Equal(ø) {
badf("δbtail.trackSet1 wrong:\n\thave: %v\n\twant: %v", δbtail.trackSet, ø) badf("δbtail.trackSet1 wrong:\n\thave: %v\n\twant: %v", δbtail.trackSet, ø)
} }
if !δbtail.trackNew.Equal(trackSet1) { if !δbtail.trackNew.Equal(trackSet1) {
badf("δbtail.trackNew1 wrong:\n\thave: %v\n\twant: %v", δbtail.trackNew, trackSet1) badf("δbtail.trackNew1 wrong:\n\thave: %v\n\twant: %v", δbtail.trackNew, trackSet1)
} }
// δbtail.assertTrack(t, "1", /*ø*/PPTreeSubSet{}, trackSet1) // δbtail.assertTrack(t, "1", ø, trackSet1)
// δB <- δZ // δB <- δZ
δB, err := δbtail.Update(δZ); X(err) δB, δTKeyCov, err := δbtail._Update(δZ); X(err)
if δB.Rev != δZ.Tid { if δB.Rev != δZ.Tid {
badf("δB: rev != δZ.Tid ; rev=%s δZ.Tid=%s", δB.Rev, δZ.Tid) badf("δB: rev != δZ.Tid ; rev=%s δZ.Tid=%s", δB.Rev, δZ.Tid)
return return
...@@ -802,17 +807,14 @@ func xverifyΔBTail_Update1(t *testing.T, subj string, db *zodb.DB, treeRoot zod ...@@ -802,17 +807,14 @@ func xverifyΔBTail_Update1(t *testing.T, subj string, db *zodb.DB, treeRoot zod
// verify δbtail.trackSet against @at2 // verify δbtail.trackSet against @at2
// trackSet2 = xkv2[tracked2] ( = xkv2[kadj[tracked1]] // trackSet2 = xkv2[tracked2] ( = xkv2[kadj[tracked1]]
trackSet2 := xkv2.trackSet(initialTrackedKeys.Union(kadjTrackedδZ)) trackSet2, tkeyCov2 := xkv2.trackSetWithCov(initialTrackedKeys.Union(kadjTrackedδZ))
// if !reflect.DeepEqual(trackSet2, δbtail.trackSet) {
// badf("δbtail.trackSet2 wrong:\n\thave: %v\n\twant: %v", δbtail.trackSet, trackSet2)
// }
if !δbtail.trackSet.Equal(trackSet2) { if !δbtail.trackSet.Equal(trackSet2) {
badf("δbtail.trackSet2 wrong:\n\thave: %v\n\twant: %v", δbtail.trackSet, trackSet2) badf("δbtail.trackSet2 wrong:\n\thave: %v\n\twant: %v", δbtail.trackSet, trackSet2)
} }
if !δbtail.trackNew.Equal(ø) { if !δbtail.trackNew.Equal(ø) {
badf("δbtail.trackNew2 wrong:\n\thave: %v\n\twant: %v", δbtail.trackNew, ø) badf("δbtail.trackNew2 wrong:\n\thave: %v\n\twant: %v", δbtail.trackNew, ø)
} }
// δbtail.assertTrack(t, "2", trackSet2, /*ø*/PPTreeSubSet{}) // δbtail.assertTrack(t, "2", trackSet2, ø)
// assert δB.ByRoot == {treeRoot -> ...} if δTok != ø // assert δB.ByRoot == {treeRoot -> ...} if δTok != ø
...@@ -833,6 +835,13 @@ func xverifyΔBTail_Update1(t *testing.T, subj string, db *zodb.DB, treeRoot zod ...@@ -833,6 +835,13 @@ func xverifyΔBTail_Update1(t *testing.T, subj string, db *zodb.DB, treeRoot zod
return return
} }
// assert δtkeycov == δ(tkeyCov1, tkeyCov2)
δtkeycovOK := tkeyCov2.Difference(tkeyCov1)
δtkeycov := δTKeyCov.ByRoot[treeRoot]
if !δtkeycov.Equal(δtkeycovOK) {
badf("δtkeycov wrong:\nhave: %s\nwant: %s", δtkeycov, δtkeycovOK)
}
// δT <- δB // δT <- δB
δToid := δB.ByRoot[treeRoot] // {} k -> δoid δToid := δB.ByRoot[treeRoot] // {} k -> δoid
...@@ -1354,7 +1363,7 @@ func testΔBTail(t *testing.T, testq chan ΔBTestEntry) { ...@@ -1354,7 +1363,7 @@ func testΔBTail(t *testing.T, testq chan ΔBTestEntry) {
t2.prev = t1 // XXX ----//---- t2.prev = t1 // XXX ----//----
subj := fmt.Sprintf("%s -> %s", t1.tree, t2.tree) subj := fmt.Sprintf("%s -> %s", t1.tree, t2.tree)
tracef("\n\n\n**** %s ****\n\n", subj) // t.Logf("\n\n\n**** %s ****\n\n", subj)
// KAdj // KAdj
if kadjOK := test.kadjOK; kadjOK != nil { if kadjOK := test.kadjOK; kadjOK != nil {
...@@ -1938,12 +1947,7 @@ func sortedKeys(kv map[Key]Δstring) []Key { ...@@ -1938,12 +1947,7 @@ func sortedKeys(kv map[Key]Δstring) []Key {
} }
func (b *RBucket) String() string { func (b *RBucket) String() string {
// XXX dup wrt nodeInRange.String return fmt.Sprintf("%sB%s{%s}", KeyRange{b.lo, b.hi_}, b.oid, kvtxt(b.kv))
hi := b.hi_
if hi < KeyMax {
hi += 1
}
return fmt.Sprintf("[%s,%s)B%s{%s}", kstr(b.lo), kstr(hi), b.oid, kvtxt(b.kv))
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment