Commit 024dde83 authored by Kirill Smelkov's avatar Kirill Smelkov

.

parent 190617f5
......@@ -760,6 +760,76 @@ func (δTtail *ΔTtail) forgetPast(revCut zodb.Tid) {
}
// GetAt tries to retrieve root[key]@at from δBtail data.
//
// If δBtail has δB entry that covers root[key]@at, corresponding value
// (VDEL means deletion) and valueExact=true are returned. If δBtail data
// allows to determine revision of root[key]@at value, corresponding revision
// and revExact=true are returned. If revision of root[key]@at cannot be
// determined (rev=δBtail.Tail, revExact=false) are returned.
//
// If δBtail has no δB entry that covers root[key]@at, return is
//
// (value=VDEL, valueExact=false, rev=δBtail.Tail, revExact=false)
//
// .rev and exact=true are returned:
//
// (δB[root/key].δvalue.New, δB.rev, exact=true)
//
// If δBtail has no δB entry for root[key] with .rev ≤ @at, return is
//
// (VDEL, δBtail.Tail, exact=false)
//
// key must be tracked
// at must ∈ (tail, head]
func (δBtail *ΔBtail) GetAt(root zodb.Oid, key Key, at zodb.Tid) (value Value, rev zodb.Tid, valueExact, revExact bool, err error) {
defer xerr.Contextf(&err, "δBtail: root<%s>: get %d @%s", root, key, at)
// XXX key not tracked -> panic
tail := δBtail.Tail()
head := δBtail.Head()
if !(tail < at && at <= head) {
panicf("at out of bounds: at: @%s, (tail, head] = (@%s, @%s]", at, tail, head)
}
// XXX locking
value = VDEL
valueExact = false
rev = tail
revExact = false
err = δBtail.rebuild1IfNeeded(root)
if err != nil {
return value, rev, valueExact, revExact, err
}
δTtail := δBtail.vδTbyRoot[root]
if δTtail == nil {
panicf("δBtail: root<%s> not tracked", root)
}
// XXX -> index lastXXXOf(key) | linear scan ↓ looking for change <= at
for i := len(δTtail.vδT)-1; i >= 0; i-- {
δT := δTtail.vδT[i]
δvalue, ok_ := δT.ΔKV[key]
if ok_ {
valueExact = true
if δT.Rev > at {
value = δvalue.Old
} else {
value = δvalue.New
rev = δT.Rev
revExact = true
break
}
}
}
return value, rev, valueExact, revExact, nil
}
// XXX kill
// Get returns root[key] as of @at database state plus revision that changed it.
//
// if revExact=False - rev is upper estimate for the revision.
......@@ -768,7 +838,7 @@ func (δTtail *ΔTtail) forgetPast(revCut zodb.Tid) {
// at must ∈ (tail, head]
//
// XXX root -> Oid ?
func (δBtail *ΔBtail) GetAt(ctx context.Context, root *Tree, key Key, at zodb.Tid) (value Value, ok bool, rev zodb.Tid, revExact bool, err error) {
func (δBtail *ΔBtail) XXGetAt(ctx context.Context, root *Tree, key Key, at zodb.Tid) (value Value, ok bool, rev zodb.Tid, revExact bool, err error) {
rootOid := root.POid()
defer xerr.Contextf(&err, "δBtail: root<%s>: get %d @%s", rootOid, key, at)
// XXX key not tracked -> panic
......
......@@ -390,9 +390,9 @@ func (bf *zBigFileState) PySetState(pystate interface{}) (err error) {
return fmt.Errorf("blksize: must be > 0; got %d", blksize)
}
blktab, ok := t[1].(*btree.LOBTree)
if !ok {
return fmt.Errorf("blktab: expect LOBTree; got %s", xzodb.TypeOf(t[1]))
blktab, err := vBlktab(t[1])
if err != nil {
return err
}
bf.blksize = blksize
......@@ -437,9 +437,9 @@ func (bf *ZBigFile) LoadBlk(ctx context.Context, blk int64) (_ []byte, treePath
return make([]byte, bf.blksize), treePath, nil, blkRevMax, nil
}
zblk, ok = xzblk.(ZBlk)
if !ok {
return nil, nil, nil, 0, fmt.Errorf("expect ZBlk*; got %s", xzodb.TypeOf(xzblk))
zblk, err = vZBlk(xzblk)
if err != nil {
return nil, nil, nil, 0, err
}
blkdata, zblkrev, err := zblk.LoadBlkData(ctx)
......@@ -493,6 +493,23 @@ func (bf *ZBigFile) Size(ctx context.Context) (_ int64, treePath []btree.LONode,
return size, treePath, nil
}
// vZBlk checks and converts xzblk to a ZBlk object.
func vZBlk(xzblk interface{}) (ZBlk, error) {
zblk, ok := xzblk.(ZBlk)
if !ok {
return nil, fmt.Errorf("expect ZBlk*; got %s", xzodb.TypeOf(xzblk))
}
return zblk, nil
}
// vBlktab checks and converts xblktab to LOBTree object.
func vBlktab(xblktab interface{}) (*btree.LOBTree, error) {
blktab, ok := xblktab.(*btree.LOBTree)
if !ok {
return nil, fmt.Errorf("blktab: expect LOBTree; got %s", xzodb.TypeOf(xblktab))
}
return blktab, nil
}
// ----------------------------------------
......
......@@ -67,7 +67,7 @@ type setOid = set.Oid
// .ForgetPast(revCut) - forget changes past revCut
// .SliceByRev(lo, hi) -> []δF - query for all files changes with rev ∈ (lo, hi]
// .SliceByFileRev(file, lo, hi) -> []δfile - query for changes of file with rev ∈ (lo, hi]
// .LastBlkRev(file, #blk, at) - query for what is last revision that changed
// .BlkRevAt(file, #blk, at) - query for what is last revision that changed
// file[#blk] as of @at database state.
//
// where δfile represents a change to one file
......@@ -708,27 +708,161 @@ func (δFtail *ΔFtail) SliceByFileRev(zfile *ZBigFile, lo, hi zodb.Tid) /*reado
return vδf
}
// XXX rename -> BlkRevAt
// BlkRevAt returns last revision that changed file[blk] as of @at database state.
//
// if exact=False - what is returned is only an upper bound for last block revision.
//
// zf must be any checkout from (tail, head]
// at must ∈ (tail, head]
// blk must be tracked
//
// XXX +ctx, error rebuild []δF here
func (δFtail *ΔFtail) BlkRevAt(ctx context.Context, zf *ZBigFile, blk int64, at zodb.Tid) (_ zodb.Tid, exact bool) {
rev, exact, err := δFtail._BlkRevAt(ctx, zf, blk, at)
if err != nil {
panic(err) // XXX
}
return rev, exact
}
func (δFtail *ΔFtail) _BlkRevAt(ctx context.Context, zf *ZBigFile, blk int64, at zodb.Tid) (_ zodb.Tid, exact bool, err error) {
defer xerr.Contextf(&err, "blkrev f<%s> #%d @%s", zf.POid(), blk, at)
//fmt.Printf("\nblkrev #%d @%s\n", blk, at)
// assert at ∈ (tail, head]
tail := δFtail.Tail()
head := δFtail.Head()
if !(tail < at && at <= head) {
panicf("at out of bounds: at: @%s, (tail, head] = (@%s, @%s]", at, tail, head)
}
// assert zf.at ∈ (tail, head]
zconn := zf.PJar()
zconnAt := zconn.At()
if !(tail < zconnAt && zconnAt <= head) {
panicf("zconn.at out of bounds: zconn.at: @%s, (tail, head] = (@%s, @%s]", zconnAt, tail, head)
}
// XXX locking
δftail, err := δFtail.rebuildIfNeeded(zf.POid())
if err != nil {
return zodb.InvalidTid, false, err
}
// find epoch that covers at and associated blktab root/object
vδE := δftail.vδE
//fmt.Printf(" vδE: %v\n", vδE)
l := len(vδE)
i := sort.Search(l, func(i int) bool {
return at < vδE[i].Rev
})
// vδE[i] is next epoch
// vδE[i-1] is epoch that covers at
// root
var root zodb.Oid
if i == l {
root = δftail.root
} else {
root = vδE[i].oldRoot
}
// epoch
var epoch zodb.Tid
i--
if i < 0 {
// i<0 - first epoch (no explicit start) - use δFtail.tail as lo
epoch = δFtail.Tail()
} else {
epoch = vδE[i].Rev
}
//fmt.Printf(" epoch: @%s root: %s\n", epoch, root)
if root == xbtree.VDEL {
return epoch, true, nil
}
zblk, tabRev, zblkExact, tabRevExact, err := δFtail.δBtail.GetAt(root, blk, at)
//fmt.Printf(" GetAt #%d @%s -> %s(%v), @%s(%v)\n", blk, at, zblk, zblkExact, tabRev, tabRevExact)
if err != nil {
return zodb.InvalidTid, false, err
}
if tabRev < epoch {
tabRev = epoch
tabRevExact = true
}
// if δBtail does not have entry that covers root[blk] - get it
// through zconn that has any .at ∈ (tail, head].
if !zblkExact {
xblktab, err := zconn.Get(ctx, root)
if err != nil {
return zodb.InvalidTid, false, err
}
blktab, err := vBlktab(xblktab)
if err != nil {
return zodb.InvalidTid, false, err
}
xzblkObj, ok, err := blktab.Get(ctx, blk)
if err != nil {
return zodb.InvalidTid, false, err
}
if !ok {
zblk = xbtree.VDEL
} else {
zblkObj, err := vZBlk(xzblkObj)
if err != nil {
return zodb.InvalidTid, false, fmt.Errorf("blktab<%s>[#%d]: %s", root, blk, err)
}
zblk = zblkObj.POid()
}
}
// block was removed
if zblk == xbtree.VDEL {
return tabRev, tabRevExact, nil
}
// blktab[blk] was changed to point to a zblk @tabRev.
// blk revision is max rev and when zblk changed last in (rev, at] range.
zblkRev, zblkRevExact := δFtail.δBtail.ΔZtail().LastRevOf(zblk, at)
//fmt.Printf(" ZRevOf %s @%s -> @%s, %v\n", zblk, at, zblkRev, zblkRevExact)
if zblkRev > tabRev {
return zblkRev, zblkRevExact, nil
} else {
return tabRev, tabRevExact, nil
}
}
// XXX kill
// LastBlkRev returns last revision that changed file[blk] as of @at database state.
//
// if exact=False - what is returned is only an upper bound for last block revision.
//
// zf must be from @head
// zf must be from @head.
// at must ∈ (tail, head]
// blk must be tracked
//
// XXX +ctx, error rebuild []δF here
func (δFtail *ΔFtail) LastBlkRev(ctx context.Context, zf *ZBigFile, blk int64, at zodb.Tid) (_ zodb.Tid, exact bool) {
rev, exact, err := δFtail._LastBlkRev(ctx, zf, blk, at)
func (δFtail *ΔFtail) __LastBlkRev(ctx context.Context, zf *ZBigFile, blk int64, at zodb.Tid) (_ zodb.Tid, exact bool) {
rev, exact, err := δFtail.___LastBlkRev(ctx, zf, blk, at)
if err != nil {
panic(err) // XXX
}
return rev, exact
}
func (δFtail *ΔFtail) _LastBlkRev(ctx context.Context, zf *ZBigFile, blk int64, at zodb.Tid) (_ zodb.Tid, exact bool, err error) {
func (δFtail *ΔFtail) ___LastBlkRev(ctx context.Context, zf *ZBigFile, blk int64, at zodb.Tid) (_ zodb.Tid, exact bool, err error) {
defer xerr.Contextf(&err, "blkrev f<%s> #%d @%s", zf.POid(), blk, at)
//fmt.Printf("\nblkrev #%d @%s\n", blk, at)
// XXX assert at ∈ (tail, head]
// XXX assert zf.at == head (!)
// XXX locking
δftail, err := δFtail.rebuildIfNeeded(zf.POid())
......@@ -780,7 +914,7 @@ func (δFtail *ΔFtail) _LastBlkRev(ctx context.Context, zf *ZBigFile, blk int64
//fmt.Printf(" epoch: @%s root: %s\n", epoch, root)
// get to rootObj (NOTE @head, because it is ΔBtail.GetAt requirement)
// get to rootObj (NOTE @head, because it is ΔBtail.GetAt requirement) XXX
if rootObj == nil && root != xbtree.VDEL {
zconn := zf.PJar()
xrootObj, err := zconn.Get(ctx, root)
......@@ -800,7 +934,7 @@ func (δFtail *ΔFtail) _LastBlkRev(ctx context.Context, zf *ZBigFile, blk int64
var tabRev zodb.Tid
var tabRevExact, ok bool
if rootObj != nil {
zblkOid, ok, tabRev, tabRevExact, err = δFtail.δBtail.GetAt(ctx, rootObj, blk, at)
zblkOid, ok, tabRev, tabRevExact, err = δFtail.δBtail.XXGetAt(ctx, rootObj, blk, at)
//fmt.Printf(" GetAt #%d @%s -> %s, %v, @%s, %v\n", blk, at, zblkOid, ok, tabRev, tabRevExact)
if err != nil {
return zodb.InvalidTid, false, err
......
......@@ -543,7 +543,7 @@ func testΔFtail(t_ *testing.T, testq chan ΔFTestEntry) {
}
// LastBlkRev
// BlkRevAt
blkv := []int64{} // all blocks
if l := len(vδf); l > 0 {
......@@ -560,7 +560,7 @@ func testΔFtail(t_ *testing.T, testq chan ΔFTestEntry) {
at := vδf[j].Rev
blkRev := blkRevAt[at]
for _, blk := range blkv {
rev, exact := δFtail.LastBlkRev(ctx, zfile, blk, at)
rev, exact := δFtail.BlkRevAt(ctx, zfile, blk, at)
revOK, ok := blkRev[blk]
if !ok {
k := len(epochv) - 1
......
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