Commit f65f775b authored by Kirill Smelkov's avatar Kirill Smelkov

X wcfs/xbtree: treediff(ø, b)

parent 5324547c
......@@ -131,32 +131,6 @@ func (S PPTreeSubSet) AddPath(path []zodb.Oid) {
}
}
// AddNodePath is a convenience wrapper to call AddPath starting from Nodes instead of Oids.
func (S PPTreeSubSet) AddNodePath(path []Node) {
// assert path = Tree Tree ... Tree Bucket
l := len(path)
switch {
case l == 0:
panic("empty path")
case l == 1:
// must be empty Tree
_ = path[0].(*Tree)
default:
// must be Tree Tree ... Tree Bucket
for _, node := range path[:l-1] {
_ = node.(*Tree)
}
_ = path[l-1].(*Bucket)
}
oidv := make([]zodb.Oid, l)
for i, node := range path {
oidv[i] = node.POid()
}
S.AddPath(oidv)
}
// ---- Union/Difference ----
// UnionInplace sets A = PP(A.leafs | B.leafs)
......
......@@ -468,12 +468,18 @@ func diffT(ctx context.Context, A, B *Tree, δZTC SetOid, trackSet PPTreeSubSet,
δtrack = &ΔPPTreeSubSet{Del: PPTreeSubSet{}, Add: PPTreeSubSet{}, δnchildNonLeafs: map[zodb.Oid]int{}}
defer tracef(" -> δ: %v\n", δ)
if A==nil && B==nil {
panic("TODO: verify it is covered by tests")
if A == nil && B == nil {
return δ, δtrack, nil // ø changes
}
// XXX A!=nil && B!=nil -> assert A.POid() == B.POid()
// assert A.oid == B.oid
if A != nil && B != nil {
Aoid := A.POid()
Boid := B.POid()
if Aoid != Boid {
panicf("A.oid (%s) != B.oid (%s)", Aoid, Boid)
}
}
var ABoid zodb.Oid
if A != nil {
......@@ -493,10 +499,12 @@ func diffT(ctx context.Context, A, B *Tree, δZTC SetOid, trackSet PPTreeSubSet,
δtrack.Add.AddPath(ABpath)
}
if A == nil { panic("A is nil") } // TODO -> art. ø tree
// A|B == nil -> artificial empty tree
if A == nil {
A = zodb.NewPersistent(reflect.TypeOf(Tree{}), /*jar*/nil).(*Tree)
}
Bempty := false
if B == nil {
// artificial empty tree
B = zodb.NewPersistent(reflect.TypeOf(Tree{}), /*jar*/nil).(*Tree)
Bempty = true
}
......
......@@ -42,3 +42,29 @@ func tracef(format string, argv ...interface{}) {
fmt.Printf(format, argv...)
}
}
// nodePathToPath converts path from []Node to []Oid.
// XXX place = ?
func nodePathToPath(nodePath []Node) (path []zodb.Oid) {
// assert nodePath = Tree Tree ... Tree Bucket
l := len(nodePath)
switch {
case l == 0:
panic("empty path")
case l == 1:
// must be empty Tree
_ = nodePath[0].(*Tree)
default:
// must be Tree Tree ... Tree Bucket
for _, node := range nodePath[:l-1] {
_ = node.(*Tree)
}
_ = nodePath[l-1].(*Bucket)
}
path = make([]zodb.Oid, l)
for i, node := range nodePath {
path[i] = node.POid()
}
return path
}
......@@ -224,15 +224,20 @@ func (δBtail *ΔBtail) Tail() zodb.Tid { return δBtail.δZtail.Tail() }
// XXX path -> []oid ?
//
// XXX catch cycles on add?
func (δBtail *ΔBtail) Track(key Key, keyPresent bool, path []Node) error { // XXX Tree|Bucket; path[0] = root
// XXX assert Tree Tree ... Tree Bucket XXX AddNodePath does that
root := path[0].(*Tree).POid()
func (δBtail *ΔBtail) Track(key Key, keyPresent bool, nodePath []Node) error { // XXX Tree|Bucket; path[0] = root
path := nodePathToPath(nodePath)
pathv := []string{}
for _, node := range path { pathv = append(pathv, vnode(node)) }
for _, node := range nodePath { pathv = append(pathv, vnode(node)) }
tracef("Track [%v] %s\n", key, strings.Join(pathv, " -> "))
δBtail.trackNew.AddNodePath(path)
return δBtail.track(key, keyPresent, path)
}
func (δBtail *ΔBtail) track(key Key, keyPresent bool, path []zodb.Oid) error {
root := path[0]
δBtail.trackNew.AddPath(path)
// track is track of path[-1] (i.e. leaf)
......
......@@ -608,11 +608,6 @@ func xverifyΔBTail_Update(t *testing.T, subj string, db *zodb.DB, treeRoot zodb
// 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) {
if t1.tree == DEL {
// Track(k) -> Update ; requires that tree exists at Track time
t.Skip("Track(tree1) needs tree1 to exist") // XXX just limit trackKeys to ø instead ?
}
allKeys := allTestKeys(t1, t2)
allKeyv := allKeys.SortedElements()
......@@ -668,13 +663,29 @@ func xverifyΔBTail_Update1(t *testing.T, subj string, db *zodb.DB, treeRoot zod
zconn, err := db.Open(ctx, &zodb.ConnOptions{At: at1}); X(err)
δbtail := NewΔBtail(zconn.At(), db)
xtree, err := zconn.Get(ctx, treeRoot); X(err)
ztree := xtree.(*Tree)
xtree, err := zgetNodeOrNil(ctx, zconn, treeRoot); X(err)
var ztree *Tree // = nil if treeRoot was deleted
if xtree != nil {
ztree = xtree.(*Tree)
}
kadjTracked = SetKey{} // kadj[Tracked] (all keys adjacent to tracked keys)
for k := range initialTrackedKeys {
if ztree != nil {
_, ok, path, err := ZTreeGetBlkData(ctx, ztree, k); X(err)
err = δbtail.Track(k, ok, path); X(err)
} else {
// if treeRoot is deleted - add it to tracked set with every key
// being a hole. This aligns with the following situation
//
// T1 -> ø -> T2
//
// where after T1->ø, even though the tree becomes deleted, its root
// continues to be tracked and all keys migrate to holes in the
// tracking set. By aligning initial state to the same as after
// T1->ø, we test what will happen on ø->T2.
err = δbtail.track(k, false, []zodb.Oid{treeRoot}); X(err)
}
kadjTracked.Update(kadj[k])
}
......
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