Commit f3a5dd3c authored by Kirill Smelkov's avatar Kirill Smelkov

.

parent 6dcfe755
...@@ -125,11 +125,11 @@ type ΔValue struct { ...@@ -125,11 +125,11 @@ type ΔValue struct {
// //
// δB: // δB:
// .rev↑ // .rev↑
// {} root -> {}(key, value) // {} root -> {}(key, value) XXX value -> δvalue
// //
// and atTail keeps set of k/v @tail for keys changed in (tail, head] // and atTail keeps set of k/v @tail for keys changed in (tail, head]
// //
// atTail: // atTail: XXX no need for atTail as we have δvalue.Old
// {} root -> {}(key, value) // {} root -> {}(key, value)
// //
// It covers only changes to keys from tracked subset of BTrees parts. // It covers only changes to keys from tracked subset of BTrees parts.
...@@ -183,6 +183,7 @@ type ΔBtail struct { ...@@ -183,6 +183,7 @@ type ΔBtail struct {
type nodeTrack struct { type nodeTrack struct {
parent zodb.Oid // parent node | InvalidOid for root parent zodb.Oid // parent node | InvalidOid for root
holes SetKey // missing keys tracked under this node; nil for !leaf holes SetKey // missing keys tracked under this node; nil for !leaf
// XXX move holes into separate ΔBtail..holeIdx
} }
// ΔB represents a change in BTrees space. // ΔB represents a change in BTrees space.
...@@ -206,7 +207,7 @@ type ΔTtail struct { ...@@ -206,7 +207,7 @@ type ΔTtail struct {
vδT []ΔTree // changes to tree keys; rev↑. covers keys ∈ tracked subset vδT []ΔTree // changes to tree keys; rev↑. covers keys ∈ tracked subset
// {}k/v @tail for keys that are changed in (tail, head]. // {}k/v @tail for keys that are changed in (tail, head].
KVAtTail map[Key]Value KVAtTail map[Key]Value // XXX not needed since vδT has ΔValue ?
// index for LastRevOf queries // index for LastRevOf queries
lastRevOf map[Key]zodb.Tid // {} key -> last lastRevOf map[Key]zodb.Tid // {} key -> last
...@@ -216,7 +217,7 @@ type ΔTtail struct { ...@@ -216,7 +217,7 @@ type ΔTtail struct {
// XXX -> ΔT ? // XXX -> ΔT ?
type ΔTree struct { type ΔTree struct {
Rev zodb.Tid Rev zodb.Tid
KV map[Key]Value KV map[Key]Value // XXX Value -> ΔValue ?
} }
// NewΔBtail creates new empty ΔBtail object. // NewΔBtail creates new empty ΔBtail object.
...@@ -682,32 +683,200 @@ func diffX(ctx context.Context, a, b Node, δZTC SetOid, trackIdx map[zodb.Oid]n ...@@ -682,32 +683,200 @@ func diffX(ctx context.Context, a, b Node, δZTC SetOid, trackIdx map[zodb.Oid]n
// δ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).
// //
// XXX trackIdx -> just pass δBtail? // XXX trackIdx -> just pass δBtail?
func diffT(ctx context.Context, a, b *Tree, δZTC SetOid, trackIdx map[zodb.Oid]nodeTrack) (δ map[Key]ΔValue, err error) { func diffT(ctx context.Context, A, B *Tree, δZTC SetOid, trackIdx map[zodb.Oid]nodeTrack) (δ map[Key]ΔValue, err error) {
tracef(" diffT %s %s\n", xidOf(a), xidOf(b)) tracef(" 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))
if a == nil { panic("a is nil") } if A == nil { panic("A is nil") }
if b == nil { panic("b is nil") } if B == nil { panic("B is nil") }
δ = map[Key]ΔValue{} δ = map[Key]ΔValue{}
defer tracef(" -> δ: %v\n", δ) defer tracef(" -> δ: %v\n", δ)
var av rangeSplit // nodes expanded from a // XXX maybe walk till a from root to get more precise initial range?
var bv rangeSplit // nodes expanded from b // XXX precise range as for a ?
// Aqueue := SetKey{} // "to process" keys on A atop := &nodeInRange{lo: KeyMin, hi_: KeyMax, node: A} // [-∞, ∞)
// Bqueue := SetKey{} // "to process" keys on B btop := &nodeInRange{lo: KeyMin, hi_: KeyMax, node: B} // [-∞, ∞)
// Adone := SetKey{} // "processed" keys on A Av := rangeSplit{atop} // nodes expanded from A
// Bdone := SetKey{} // "processed" keys on B Bv := rangeSplit{btop} // nodes expanded from B
// for phase 2:
Akqueue := SetKey{} // queue for keys in A to be processed for δ-
Bkqueue := SetKey{} // ----//---- in B for δ+
Akdone := SetKey{} // already processed keys in A
Bkdone := SetKey{} // ----//---- in B
// phase 1: expand A top-down driven by δZTC
// by default a node contributes to δ-
// a node ac does not contribute to δ- and can be skipped, if:
// - ac is not tracked, or
// - ac ∉ δZTC && ∃ bc from B: ac.oid == bc.oid (ac was not changed and stays in the tree)
Aq := [atop] // queue for A nodes that contribyte to δ-
for len(Aq) > 0 {
ra := Aq.pop()
err = ra.node.PActivate(ctx); /*X*/if err != nil { return nil, err }
defer ra.node.PDeactivate()
switch a := ra.node.(type) {
case *Bucket:
// a is bucket -> δ-
δA, err := diffB(ctx, a, nil); /*X*/if err != nil { return nil, err }
err = δMerge(δ, δA); /*X*/if err != nil { return nil, err }
// Bkqueue <- δA
for k := range δA {
Akdone.Add(k)
Bkqueue.Add(k)
}
// XXX ra.range -> Bqholes
ra.done = true
case *Tree:
// a is tree - expand it and queue children
// see for each children whether it can be skipped
// XXX if a is ø tree
av := a.Entryv()
for i, ae := range a.Entryv() {
ac := ae.Child()
_, tracked := trackIdx[ac.POid()]
if !tracked {
continue
}
if !δZTC.Has(ac.POid()) {
lo := av[i].Key()
hi_ := ra.hi_
if i+1 < len(av) {
hi_ = av[i+1].Key - 1
}
// XXX also check b's parents, as they could be already expanded?
bc, ok, err := Bv.tryGetToNode(ac.oid, lo, hi_, /*maxdepth*/2)
if err != nil { return nil, err }
if ok {
// ac can be skipped
// XXX ac.range \ bc.range -> Bqholes
continue
}
}
// ac cannot be skipped
Aq.push(ac)
}
}
}
// phase 2: reach consistency in between A and B.
// Every key removed in A has to be checked for whether it is present
// in B and contribute to δ+. In B, in turn, adding that key can add
// other keys to δ+. Those keys, in turn, have to be checked for
// whether they were present in A and contribute to δ-. For example:
//
// [ 2 4 ] [ 3 5 ]
// ↓ ↓ ↓ ↓ ↓ ↓
// |1| |23| |45| |12| |34| |56|
//
// if values for all keys change, tracked={1}, change to 1 adds
// * -B1, which queues B.1 and leads to
// * +B12, which queues A.2 and leads to
// * -B23, which queues B.3 and leads to
// * +B23, ...
for len(Bkqueue) > 0 {
for k := range Bkqueue {
b, err := Bv.GetToLeaf(ctx, k); /*X*/if err != nil { return nil, err }
// +bucket if that bucket is reached for the first time
if !b.done {
var δB map[Key]ΔValue
bbucket, ok := b.node.(*Bucket)
if ok { // !ok means ø tree
δB, err = diffB(ctx, nil, bbucket); /*X*/if err != nil { return nil, err }
}
// δ <- δB
err = δMerge(δ, δB); /*X*/if err != nil { return nil, err }
// Akqueue <- δB
for k_ := range δB {
Bkdone.Add(k_)
if !Akdone(k_) {
Akqueue.Add(k_)
}
}
b.done = true
}
// XXX k is not there -> hole
}
Bkqueue = SetKey{}
for k := range Akqueue {
a, err := Av.GetToLeaf(ctx, k); /*X*/if err != nil { return nil, err }
// -bucket if that bucket is reached for the first time
if !a.done {
var δA map[Key]ΔValue
abucket, ok := a.node.(*Bucket_
if !ok { // !ok means ø tree
δA, err := diffB(ctx, abucket, nil); /*X*/if err != nil { return nil, err }
}
// XXX also process holes?
// δ <- δA
err = δMerge(δ, δA); /*X*/if err != nil { return nil, err }
// Bkqueue <- δA
for k_ := range δA {
Akdone.Add(k_)
if !Bkdone.Has(k_) {
Bkqueue.Add(k_)
}
}
a.done = true
}
}
Akqueue = SetKey{}
}
Aq := [atop] // nodes in A that may contribute to δ
Bq := [] // ----//----
for len(Aq) > 0 {
a := Astk.pop()
// XXX activate(a)
baoverlap = []*nodeInRange // of all nodes in Bv that overlaps with a
for _, b := range baoverlap {
}
bn := Bv.Get(an.lo)
// XXX activate(bn)
bn.lo < an.lo // -> expand b if b is not bucket ; if b is bucket - b contributes; check also b followups that fit into a
(an.lo == bn.lo) && (an.hi_ == bn.hi_)
&& an.oid == bn.oid
// -> an/bn can contribute to δ only if an ∈ δZTC
}
// XXX precise range as for a ^^^ ?
btop := &nodeInRange{lo: KeyMin, hi_: KeyMax, node: b} // [-∞, ∞)
bv = rangeSplit{btop}
// initial phase: expand changed nodes in a till buckets; // initial phase: expand changed nodes in a till buckets;
// XXX changed buckets -> δ- // XXX changed buckets -> δ-
// XXX maybe walk till a from root to get more precise initial range?
atop := &nodeInRange{lo: KeyMin, hi_: KeyMax, node: a} // [-∞, ∞)
av = rangeSplit{atop}
Aqueue := []*nodeInRange{atop} // stack: "to process" nodes on A Aqueue := []*nodeInRange{atop} // stack: "to process" nodes on A
Bqueue := []*nodeInRange{} // stack: "to process" nodes on B Bqueue := []*nodeInRange{} // stack: "to process" nodes on B
......
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