Commit 66c20069 authored by Kirill Smelkov's avatar Kirill Smelkov

.

parent a1f0152e
......@@ -250,13 +250,45 @@ func (tg *AllStructsSrv) AllStructs(kv1, kv2 map[Key]string, maxdepth, maxsplit,
}
// RBucket represents Bucket node covering [lo, hi) key range in its Tree.
type RBucket struct {
lo, hi Key
kv map[Key]string // bucket's k->v; values were ZBlk objects whose data is loaded instead.
}
// RBucketSet represents set of buckets covering whole [-∞,∞) range.
type RBucketSet []*RBucket // k↑
// Get returns RBucket which covers key k.
func (rbs RBucketSet) Get(k Key) *RBucket {
i := sort.Search(len(rbs), func(i int) bool {
return rbs[i].hi > k
})
if i == len(rbs) {
panic(fmt.Sprintf("BUG: key %v not covered", k))
}
rb := rbs[i]
if !(rb.lo <= k && k < rb.hi) {
panic(fmt.Sprintf("BUG: get(%v) -> [%v, %v)", k, rb.lo, rb.hi))
}
return rb
}
// XGetTree loads Tree from zurl@at->obj<root>.
// Tree values must be ZBlk whose data is returned instead of references to ZBlk objects.
// The tree is returned structured by buckets as
// {} k -> {k->v}
// where key k points to {k->v} that represents k's bucket.
func XGetTree(db *zodb.DB, at zodb.Tid, root zodb.Oid) map[Key]map[Key]string {
//
// [] [lo,hi){k->v} k↑
//
// XXX kill where key k points to {k->v} that represents k's bucket.
//func XGetTree(db *zodb.DB, at zodb.Tid, root zodb.Oid) map[Key]map[Key]string {
//func XGetTree(db *zodb.DB, at zodb.Tid, root zodb.Oid) map[Key]*RBucket {
func XGetTree(db *zodb.DB, at zodb.Tid, root zodb.Oid) RBucketSet {
defer exc.Contextf("%s: @%s: get tree %s", db.Storage().URL(), at, root)
X := exc.Raiseif
......@@ -270,10 +302,68 @@ func XGetTree(db *zodb.DB, at zodb.Tid, root zodb.Oid) map[Key]map[Key]string {
exc.Raisef("expected %s, got %s", typeOf(ztree), typeOf(xztree))
}
// XXX better load through direct nodes traversal, not via bucket.next?
// (firstbucket and .next are secondary and might be broken)
rbucketv := RBucketSet{}
xwalkDFS(ctx, -kInf, kInf, ztree, func(rb *RBucket) {
rbucketv = append(rbucketv, rb)
})
return rbucketv
}
// xwalkDFS walks ztree in depth-first order emitting bvisit callback on visited bucket nodes.
func xwalkDFS(ctx context.Context, lo, hi Key, ztree *Tree, bvisit func(*RBucket)) {
X := exc.Raiseif
err := ztree.PActivate(ctx); X(err)
defer ztree.PDeactivate()
// [i].Key ≤ [i].Child.*.Key < [i+1].Key i ∈ [0, len([]))
//
// [0].Key = -∞ ; always returned so
// [len(ev)].Key = +∞ ; should be assumed so
ev := ztree.Entryv()
for i := range ev {
xlo := lo; if i > 0 { xlo = ev[i].Key() }
xhi := hi; if i+1 < len(ev) { xhi = ev[i+1].Key() }
tchild, ok := ev[i].Child().(*Tree)
if ok {
xwalkDFS(ctx, xlo, xhi, tchild, bvisit)
continue
}
zbucket := ev[i].Child().(*Bucket)
err = zbucket.PActivate(ctx); X(err)
defer zbucket.PDeactivate()
bkv := make(map[Key]string)
bentryv := zbucket.Entryv()
for _, __ := range bentryv {
k := __.Key()
xv := __.Value()
zv, ok := xv.(zBlk)
if !ok {
exc.Raisef("[%d] -> %s; want ZBlk", k, typeOf(xv))
}
data, _, err := zv.loadBlkData(ctx); X(err)
bkv[k] = string(data)
}
bvisit(&RBucket{xlo, xhi, bkv})
}
}
/*
err = ztree.PActivate(ctx); X(err)
defer ztree.PDeactivate()
// XXX better load through direct nodes traversal, not via bucket.next?
// (firstbucket and .next are secondary and might be broken)
zbucket := ztree.FirstBucket()
xkv := make(map[Key]map[Key]string)
......@@ -282,7 +372,12 @@ func XGetTree(db *zodb.DB, at zodb.Tid, root zodb.Oid) map[Key]map[Key]string {
defer zbucket.PDeactivate()
bkv := make(map[Key]string)
for _, __ := range zbucket.Entryv() {
bentryv := zbucket.Entryv()
if len(bentryv) == 0 {
exc.Raisef("bucket %s is empty", zbucket.POid())
}
for _, __ := range bentryv {
k := __.Key()
xv := __.Value()
zv, ok := xv.(zBlk)
......@@ -294,6 +389,10 @@ func XGetTree(db *zodb.DB, at zodb.Tid, root zodb.Oid) map[Key]map[Key]string {
bkv[k] = string(data)
}
path :=
bentryv[0].Key()
bentryv[len(bentryv)-1].Key()
for k := range bkv {
xkv[k] = bkv
}
......@@ -303,6 +402,7 @@ func XGetTree(db *zodb.DB, at zodb.Tid, root zodb.Oid) map[Key]map[Key]string {
return xkv
}
*/
// XGetKV translates {k -> <oid>} to {k -> ZBlk(oid).data} according to db@at snapshot.
func XGetKV(db *zodb.DB, at zodb.Tid, kvOid map[Key]Value) map[Key]string {
......@@ -329,18 +429,25 @@ func XGetKV(db *zodb.DB, at zodb.Tid, kvOid map[Key]Value) map[Key]string {
return kv
}
/*
// XGetBucket retrurns Bucket corresponding to root[k].
func XGetBucket(db *zodb.DB, at zodb.Tid, root zodb.Oid) ... {
// XXX kill -> amend XGetTree
}
*/
// xverifyΔBTail verifies how ΔBTail handles ZODB update for a tree with changes in between at1->at2.
//
// it is known that @at1 and @at2 the tree has xkv1 and xkv2 values correspondingly.
// it is known that for at1->at2 ZODB-level change is δZ.
func xverifyΔBTail(t *testing.T, subj string, db *zodb.DB, treeRoot zodb.Oid, at1, at2 zodb.Tid, xkv1, xkv2 map[Key]map[Key]string, δZ *zodb.EventCommit) {
func xverifyΔBTail(t *testing.T, subj string, db *zodb.DB, treeRoot zodb.Oid, at1, at2 zodb.Tid, xkv1, xkv2 RBucketSet, δZ *zodb.EventCommit) { // XXX +kadjOK
d12 := kvdiff(xkvFlatten(xkv1), xkvFlatten(xkv2))
// verify transition at1->at2 for all initial states of tracked {keys} from kv1 + kv2 + ∞
allKeys := SetKey{}; allKeys.Add(kInf) // inf, simulating ZBigFile.Size() query
for k := range xkv1 { allKeys.Add(k) }
for k := range xkv2 { allKeys.Add(k) }
for _, b := range xkv1 { for k := range b.kv { allKeys.Add(k) }}
for _, b := range xkv2 { for k := range b.kv { allKeys.Add(k) }}
allKeyv := allKeys.Elements()
sort.Slice(allKeyv, func(i, j int) bool {
return allKeyv[i] < allKeyv[j]
......@@ -350,9 +457,31 @@ func xverifyΔBTail(t *testing.T, subj string, db *zodb.DB, treeRoot zodb.Oid, a
// it must be present in δB if maxkey tracking is requested.
maxKey := -kInf
if l := len(allKeyv); l > 0 {
maxKey = allKeyv[l-1]
maxKey = allKeyv[l-1] // FIXME always returns kInf -> rework to be real maxkey
}
// {} k -> adjacent keys. if k is tracked -> changes to adjacents must be in δT.
kadj := map[Key]SetKey{}
for k := range allKeys {
ka := SetKey{}
if k == kInf {
// XXX update with
// xkv1[maxk1]
// xkv2[maxk2]
} else {
kb := xkv1.Get(k)
for k := range kb.kv { ka.Add(k) }
//// XXX correct?
//ka.Update(xkv1[k])
//ka.Update(xkv2[k])
}
kadj[k] = ka
}
for kidx := range IntSets(len(allKeyv)) {
keys := SetKey{}
for _, idx := range kidx {
......@@ -802,10 +931,10 @@ func TestKVTxt(t *testing.T) {
}
// xkvFlatten converts xkv with bucket structure into regular dict.
func xkvFlatten(xkv map[Key]map[Key]string) map[Key]string {
func xkvFlatten(xkv RBucketSet) map[Key]string {
kv := make(map[Key]string)
for _, bkv := range xkv {
for k,v := range bkv {
for _, b := range xkv {
for k,v := range b.kv {
kv[k] = v
}
}
......
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