Commit fa71d1df authored by Kirill Smelkov's avatar Kirill Smelkov

.

parent 943dfc75
...@@ -511,31 +511,33 @@ func xzgetBlkData(ctx context.Context, zconn *zodb.Connection, zblkOid zodb.Oid) ...@@ -511,31 +511,33 @@ func xzgetBlkData(ctx context.Context, zconn *zodb.Connection, zblkOid zodb.Oid)
return string(data) 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()
// xverifyΔBTail verifies how ΔBTail handles ZODB update for a tree with changes in between at1->at2. zconn, err := db.Open(ctx, &zodb.ConnOptions{At: at}); X(err)
return xzgetBlkData(ctx, zconn, zblkOid)
}
// xverifyΔBTail_Update verifies how ΔBTail handles ZODB update for a tree with changes in between t1->t2.
// //
// it is known that @at1 and @at2 the tree has xkv1 and xkv2 values correspondingly. // it is known that @at1 and @at2 the tree has xkv1 and xkv2 values correspondingly. XXX kill
// it is known that for at1->at2 ZODB-level change is δZ. // it is known that for at1->at2 ZODB-level change is δZ. XXX kill
// //
// kadjOK may be optionally provided. if kadjOK != nil computed adjacency // kadjOK may be optionally provided. if kadjOK != nil computed adjacency
// matrix is verified against it. // matrix is verified against it.
func xverifyΔBTail(t *testing.T, subj string, db *zodb.DB, treeRoot zodb.Oid, at1, at2 zodb.Tid, xkv1, xkv2 RBucketSet, δZ *zodb.EventCommit, kadjOK map[Key]SetKey) { func xverifyΔBTail_Update(t *testing.T, subj string, db *zodb.DB, treeRoot zodb.Oid, t1, t2 *tTreeCommit, kadjOK map[Key]SetKey) {
// 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 + ∞
allKeys := SetKey{}; allKeys.Add(kInf) // ∞ simulating ZBigFile.Size() query allKeys := allTestKeys(t1, t2)
maxk1 := -kInf; maxk2 := -kInf allKeyv := allKeys.SortedKeys()
for _, b := range xkv1 { for k := range b.kv {
allKeys.Add(k)
if k > maxk1 { maxk1 = k }
}}
for _, b := range xkv2 { for k := range b.kv {
allKeys.Add(k)
if k > maxk2 { maxk2 = k }
}}
allKeyv := allKeys.Elements()
sort.Slice(allKeyv, func(i, j int) bool {
return allKeyv[i] < allKeyv[j]
})
xkv1 := t1.xkv
xkv2 := t2.xkv
// kadj = {} k -> adjacent keys. if k is tracked -> changes to adjacents must be in δT. // kadj = {} k -> adjacent keys. if k is tracked -> changes to adjacents must be in δT.
kadj := map[Key]SetKey{} kadj := map[Key]SetKey{}
...@@ -595,13 +597,13 @@ func xverifyΔBTail(t *testing.T, subj string, db *zodb.DB, treeRoot zodb.Oid, a ...@@ -595,13 +597,13 @@ func xverifyΔBTail(t *testing.T, subj string, db *zodb.DB, treeRoot zodb.Oid, a
keys.Add(allKeyv[idx]) keys.Add(allKeyv[idx])
} }
xverifyΔBTail1(t, subj, db, treeRoot, at1,at2, xkv1,xkv2, δZ, keys, kadj) xverifyΔBTail_Update1(t, subj, db, treeRoot, t1.at,t2.at, xkv1,xkv2, t2.δZ, keys, kadj)
} }
} }
// xverifyΔBTail1 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ΔBTail1(t *testing.T, subj string, db *zodb.DB, treeRoot zodb.Oid, at1,at2 zodb.Tid, xkv1,xkv2 RBucketSet, δZ *zodb.EventCommit, initialTrackedKeys SetKey, kadj map[Key]SetKey) { 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, initialTrackedKeys SetKey, kadj map[Key]SetKey) {
X := exc.Raiseif X := exc.Raiseif
tracef("\n>>> Track=%s\n", initialTrackedKeys) tracef("\n>>> Track=%s\n", initialTrackedKeys)
...@@ -769,6 +771,85 @@ func xverifyΔBTail1(t *testing.T, subj string, db *zodb.DB, treeRoot zodb.Oid, ...@@ -769,6 +771,85 @@ func xverifyΔBTail1(t *testing.T, subj string, db *zodb.DB, treeRoot zodb.Oid,
} }
} }
// xverifyΔBtail_Get verifies δBtail.Get on series of vt ZODB changes.
// XXX
func xverifyΔBTail_Get(t *testing.T, subj string, db *zodb.DB, treeRoot zodb.Oid, vt ...*tTreeCommit) {
return
tkeys := allTestKeys(vt...)
tkeyv := tkeys.SortedKeys()
// verify t1->t2-> ... ->tn Track(keys) Get(keys, @at)
// for all combinations of tracked keys and at
for kidx := range IntSets(len(tkeyv)) {
keys := SetKey{}
for _, idx := range kidx {
keys.Add(tkeyv[idx])
}
xverifyΔBTail_Get1(t, subj, db, treeRoot, vt, keys)
}
}
func xverifyΔBTail_Get1(t *testing.T, subj string, db *zodb.DB, treeRoot zodb.Oid, vt []*tTreeCommit, keys SetKey) {
X := exc.Raiseif
// XXX subj here ?
// XXX tracked / ?
// t1->t2-> ... -> tn
δbtail := NewΔBtail(vt[0].at, db)
for i := 1; i < len(vt); i++ {
_, err := δbtail.Update(vt[i].δZ); X(err)
}
// Track(keys)
txn, ctx := transaction.New(context.Background())
defer txn.Abort()
zconn, err := db.Open(ctx, &zodb.ConnOptions{At: vt[len(vt)-1].at}); X(err)
xtree, err := zconn.Get(ctx, treeRoot); X(err)
ztree := xtree.(*Tree)
for k := range keys {
path := []Node{}
_, ok, err := ztree.VGet(ctx, k, func(node Node) {
path = append(path, node)
}); X(err)
err = δbtail.Track(k, ok, path); X(err)
}
// verify Get(k, @at) for all keys and @at
for i := 1; i < len(vt); i++ {
at := vt[i].at
for _, k := range keys.SortedKeys() {
vOid, ok, rev, revExact, err := δbtail.Get(ctx, ztree, k, at); X(err)
v := xzgetBlkDataAt(db, vOid, rev)
v_, ok_ := vt[i].xkv.Get(k).kv[k]
rev_, revExact_ := vt[i].at, false
for j := i-1; j >= 0; j-- {
v__ := vt[j].xkv.Get(k).kv[k]
if v__ != v_ {
rev_ = vt[j+1].at
revExact_ = true
break
}
rev_ = vt[j].at
}
if v == "" { v = DEL }
if v_ == "" { v_ = DEL }
if !(v == v_ && ok == ok_ && rev == rev_ && revExact == revExact_) {
t.Errorf("Get(%d, @%s) ->\nhave: %s, %v, @%s, %v\nwant: %s, %v, @%s, %v",
k, at,
v, ok, rev, revExact,
v_, ok_, rev_, revExact_)
}
}
}
}
// ΔBTestEntry represents one entry in ΔBTail tests. // ΔBTestEntry represents one entry in ΔBTail tests.
type ΔBTestEntry struct { type ΔBTestEntry struct {
...@@ -792,6 +873,15 @@ func ΔBTest(xtest interface{}) ΔBTestEntry { ...@@ -792,6 +873,15 @@ func ΔBTest(xtest interface{}) ΔBTestEntry {
return test return test
} }
// ΔBCommit represent test commit changing a tree XXX
type tTreeCommit struct {
tree string
at zodb.Tid
δZ *zodb.EventCommit // δZ.tid == at
xkv RBucketSet // full tree state as of @at
// XXX do we also need δkv ?
}
// 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) {
X := exc.Raiseif X := exc.Raiseif
...@@ -817,8 +907,8 @@ func testΔBTail(t *testing.T, testq chan ΔBTestEntry) { ...@@ -817,8 +907,8 @@ func testΔBTail(t *testing.T, testq chan ΔBTestEntry) {
err := db.Close(); X(err) err := db.Close(); X(err)
}() }()
// XCommitTree calls tg.Commit and returns δZ corresponding to committed transaction. // XCommitTree calls tg.Commit and returns tTreeCommit corresponding to committed transaction.
XCommitTree := func(tree string) *zodb.EventCommit { XCommitTree := func(tree string) *tTreeCommit {
defer exc.Contextf("commit %s", tree) defer exc.Contextf("commit %s", tree)
watchq := make(chan zodb.Event) watchq := make(chan zodb.Event)
...@@ -836,27 +926,42 @@ func testΔBTail(t *testing.T, testq chan ΔBTestEntry) { ...@@ -836,27 +926,42 @@ func testΔBTail(t *testing.T, testq chan ΔBTestEntry) {
if δZ.Tid != tid { if δZ.Tid != tid {
exc.Raisef("treegen -> %s ; watchq -> %s", tid, δZ) exc.Raisef("treegen -> %s ; watchq -> %s", tid, δZ)
} }
return δZ
xkv := XGetTree(db, δZ.Tid, tg.treeRoot)
return &tTreeCommit{
tree: tree,
at: δZ.Tid,
δZ: δZ,
xkv: xkv,
}
} }
at1 := tg.head var t0 *tTreeCommit
xkv1 := XGetTree(db, at1, tg.treeRoot) t1 := &tTreeCommit{
tree1 := "ø" // initial tree: "ø", // initial
at: tg.head,
δZ: nil, // XXX ok?
xkv: XGetTree(db, tg.head, tg.treeRoot),
}
for test := range testq { for test := range testq {
tree2 := test.tree t2 := XCommitTree(test.tree)
δZ := XCommitTree(tree2)
at2 := δZ.Tid
xkv2 := XGetTree(db, at2, tg.treeRoot)
subj := fmt.Sprintf("%s -> %s", tree1, tree2) // ΔBTail.Update
subj := fmt.Sprintf("%s -> %s", t1.tree, t2.tree)
tracef("\n\n\n**** %s ****\n\n", subj) tracef("\n\n\n**** %s ****\n\n", subj)
xverifyΔBTail(t, subj, db, tg.treeRoot, at1,at2, xkv1,xkv2, δZ, test.kadjOK) xverifyΔBTail_Update(t, subj, db, tg.treeRoot, t1,t2, test.kadjOK)
// XXX also verify ΔBtail.Get + SliceByRootRev // ΔBTail.Get
xverifyΔBTail_Get(t, "XXX", db, tg.treeRoot, t2)
xverifyΔBTail_Get(t, "XXX", db, tg.treeRoot, t1, t2)
if t0 != nil {
xverifyΔBTail_Get(t, "XXX", db, tg.treeRoot, t0, t1, t2)
}
// XXX ΔBTail.SliceByRootRev
at1 = at2 t0, t1 = t1, t2
xkv1 = xkv2
tree1 = tree2
} }
} }
...@@ -1299,6 +1404,18 @@ func xkvFlatten(xkv RBucketSet) map[Key]string { ...@@ -1299,6 +1404,18 @@ func xkvFlatten(xkv RBucketSet) map[Key]string {
return kv return kv
} }
// allTestKeys returns all keys from vt + ∞.
func allTestKeys(vt ...*tTreeCommit) SetKey {
allKeys := SetKey{}; allKeys.Add(kInf) // ∞ simulating ZBigFile.Size() query
for _, t := range vt {
for _, b := range t.xkv {
for k := range b.kv {
allKeys.Add(k)
}
}
}
return allKeys
}
// easies debugging / makes error output stable from run to run. // easies debugging / makes error output stable from run to run.
func (ks SetKey) SortedKeys() []Key { func (ks SetKey) SortedKeys() []Key {
......
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