Commit 423f77be authored by Kirill Smelkov's avatar Kirill Smelkov

X wcfs: Goodby holeIdx

As a consequence rework treediff to work on key ranges instead of
individial keys.

Adjacency coverage gets wider, but that is ok, because in practice if
keys are added to a BTree - that means that something is added to
ZBigFile, and it is very likely that just added data will be accessed
again. In other words it means that wcfs will very likely track those
data on nearby future read access, so we don't loose anything if we
start to track those keys right at the beginning.

* t2: (74 commits)
  .
  .
  .
  .
  .
  .
  X kadj must be taken into account as kadj^δZ
  .
  .
  .
  .
  .
  .
  .
  .
  .
  .
  .
  .
  .
  ...
parents b0ca031f 006f001a
...@@ -26,7 +26,7 @@ import ( ...@@ -26,7 +26,7 @@ import (
"lab.nexedi.com/kirr/neo/go/zodb" "lab.nexedi.com/kirr/neo/go/zodb"
) )
const debugPPSet = false const tracePPSet = false
// PPTreeSubSet represents PP-connected subset of tree node objects. // PPTreeSubSet represents PP-connected subset of tree node objects.
// //
...@@ -131,14 +131,23 @@ func (S PPTreeSubSet) AddPath(path []zodb.Oid) { ...@@ -131,14 +131,23 @@ func (S PPTreeSubSet) AddPath(path []zodb.Oid) {
} }
} }
// ---- Union/Difference ---- // ---- Union/Difference/Intersetctior ----
// Union returns U = PP(A.leafs | B.leafs)
//
// In other words it returns sum of A and B.
func (A PPTreeSubSet) Union(B PPTreeSubSet) PPTreeSubSet {
U := A.Clone()
U.UnionInplace(B)
return U
}
// UnionInplace sets A = PP(A.leafs | B.leafs) // UnionInplace sets A = PP(A.leafs | B.leafs)
// //
// In other words it adds B nodes to A. // In other words it adds B nodes to A.
func (A PPTreeSubSet) UnionInplace(B PPTreeSubSet) { func (A PPTreeSubSet) UnionInplace(B PPTreeSubSet) {
if debugPPSet { if tracePPSet {
fmt.Printf("\n\nUnionInplace:\n") fmt.Printf("\n\nUnion:\n")
fmt.Printf(" A: %s\n", A) fmt.Printf(" A: %s\n", A)
fmt.Printf(" B: %s\n", B) fmt.Printf(" B: %s\n", B)
defer fmt.Printf("->U: %s\n", A) defer fmt.Printf("->U: %s\n", A)
...@@ -151,12 +160,22 @@ func (A PPTreeSubSet) UnionInplace(B PPTreeSubSet) { ...@@ -151,12 +160,22 @@ func (A PPTreeSubSet) UnionInplace(B PPTreeSubSet) {
A.xUnionInplace(B) A.xUnionInplace(B)
} }
// Difference returns D = PP(A.leafs \ B.leafs)
//
// In other words ... XXX
func (A PPTreeSubSet) Difference(B PPTreeSubSet) PPTreeSubSet {
D := A.Clone()
D.DifferenceInplace(B)
return D
}
// DifferenceInplace sets A = PP(A.leafs \ B.leafs) // DifferenceInplace sets A = PP(A.leafs \ B.leafs)
// //
// In other words it removes B nodes from A while still maintaining A as PP-connected. // In other words it removes B nodes from A while still maintaining A as PP-connected.
func (A PPTreeSubSet) DifferenceInplace(B PPTreeSubSet) { func (A PPTreeSubSet) DifferenceInplace(B PPTreeSubSet) {
if debugPPSet { if tracePPSet {
fmt.Printf("\n\nDifferenceInplace:\n") fmt.Printf("\n\nDifference:\n")
fmt.Printf(" A: %s\n", A) fmt.Printf(" A: %s\n", A)
fmt.Printf(" B: %s\n", B) fmt.Printf(" B: %s\n", B)
defer fmt.Printf("->D: %s\n", A) defer fmt.Printf("->D: %s\n", A)
...@@ -169,9 +188,11 @@ func (A PPTreeSubSet) DifferenceInplace(B PPTreeSubSet) { ...@@ -169,9 +188,11 @@ func (A PPTreeSubSet) DifferenceInplace(B PPTreeSubSet) {
A.xDifferenceInplace(B) A.xDifferenceInplace(B)
} }
// XXX Intersection
func (A PPTreeSubSet) xUnionInplace(B PPTreeSubSet) { func (A PPTreeSubSet) xUnionInplace(B PPTreeSubSet) {
if debugPPSet { if tracePPSet {
fmt.Printf("\n\n xUnionInplace:\n") fmt.Printf("\n\n xUnion:\n")
fmt.Printf(" a: %s\n", A) fmt.Printf(" a: %s\n", A)
fmt.Printf(" b: %s\n", B) fmt.Printf(" b: %s\n", B)
defer fmt.Printf(" ->u: %s\n", A) defer fmt.Printf(" ->u: %s\n", A)
...@@ -204,8 +225,8 @@ func (A PPTreeSubSet) xUnionInplace(B PPTreeSubSet) { ...@@ -204,8 +225,8 @@ func (A PPTreeSubSet) xUnionInplace(B PPTreeSubSet) {
} }
func (A PPTreeSubSet) xDifferenceInplace(B PPTreeSubSet) { func (A PPTreeSubSet) xDifferenceInplace(B PPTreeSubSet) {
if debugPPSet { if tracePPSet {
fmt.Printf("\n\n xDifferenceInplace:\n") fmt.Printf("\n\n xDifference:\n")
fmt.Printf(" a: %s\n", A) fmt.Printf(" a: %s\n", A)
fmt.Printf(" b: %s\n", B) fmt.Printf(" b: %s\n", B)
defer fmt.Printf(" ->d: %s\n", A) defer fmt.Printf(" ->d: %s\n", A)
...@@ -445,7 +466,7 @@ func (δ *ΔPPTreeSubSet) Reverse() { ...@@ -445,7 +466,7 @@ func (δ *ΔPPTreeSubSet) Reverse() {
// //
// See ΔPPTreeSubSet documentation for details. // See ΔPPTreeSubSet documentation for details.
func (S PPTreeSubSet) ApplyΔ(δ *ΔPPTreeSubSet) { func (S PPTreeSubSet) ApplyΔ(δ *ΔPPTreeSubSet) {
if debugPPSet { if tracePPSet {
fmt.Printf("\n\nApplyΔ\n") fmt.Printf("\n\nApplyΔ\n")
fmt.Printf(" A: %s\n", S) fmt.Printf(" A: %s\n", S)
fmt.Printf(" -: %s\n", δ.Del) fmt.Printf(" -: %s\n", δ.Del)
......
...@@ -82,10 +82,8 @@ func TestPPTreeSubSetOps(t *testing.T) { ...@@ -82,10 +82,8 @@ func TestPPTreeSubSetOps(t *testing.T) {
} }
for _, tt := range testv { for _, tt := range testv {
U := tt.A.Clone() U := tt.A.Union(tt.B)
U.UnionInplace(tt.B) D := tt.A.Difference(tt.B)
D := tt.A.Clone()
D.DifferenceInplace(tt.B)
if !U.Equal(tt.Union) { if !U.Equal(tt.Union) {
t.Errorf("Union:\n A: %s\n B: %s\n ->u: %s\n okU: %s\n", tt.A, tt.B, U, tt.Union) t.Errorf("Union:\n A: %s\n B: %s\n ->u: %s\n okU: %s\n", tt.A, tt.B, U, tt.Union)
......
// Copyright (C) 2021 Nexedi SA and Contributors.
// Kirill Smelkov <kirr@nexedi.com>
//
// This program is free software: you can Use, Study, Modify and Redistribute
// it under the terms of the GNU General Public License version 3, or (at your
// option) any later version, as published by the Free Software Foundation.
//
// You can also Link and Combine this program with other software covered by
// the terms of any of the Free Software licenses or any of the Open Source
// Initiative approved licenses and Convey the resulting work. Corresponding
// source of such a combination shall include the source code for all other
// software used.
//
// This program is distributed WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//
// See COPYING file for full licensing terms.
// See https://www.nexedi.com/licensing for rationale and options.
package xbtree
// set of [lo,hi) Key ranges.
import (
"fmt"
"sort"
)
const traceRangeSet = false
const debugRangeSet = false
// KeyRange represents [lo,hi) Key range.
type KeyRange struct {
lo Key
hi_ Key // NOTE _not_ hi) to avoid overflow at ∞; hi = hi_ + 1
}
// RangedKeySet is set of Keys with adjacent keys coaleced into Ranges.
//
// Zero value represents empty set.
type RangedKeySet struct {
// TODO rework to use BTree lo->hi_ instead if in practice in treediff,
// and other usage places, N(ranges) turns out to be not small
// (i.e. performance turns out to be not acceptable)
rangev []KeyRange // lo↑
}
// Has returns whether key k belongs to the range.
func (r *KeyRange) Has(k Key) bool {
return (r.lo <= k && k <= r.hi_)
}
// Add adds key k to the set.
func (S *RangedKeySet) Add(k Key) {
S.AddRange(KeyRange{lo: k, hi_: k})
}
// Del removes key k from the set.
func (S *RangedKeySet) Del(k Key) {
S.DelRange(KeyRange{lo: k, hi_: k})
}
// Has returns whether key k belongs to the set.
func (S *RangedKeySet) Has(k Key) bool {
return S.HasRange(KeyRange{lo: k, hi_: k})
}
// AddRange adds range r to the set.
func (S *RangedKeySet) AddRange(r KeyRange) {
if traceRangeSet {
fmt.Printf("\n\nAddRange:\n")
fmt.Printf(" S: %s\n", S)
fmt.Printf(" r: %s\n", r)
defer fmt.Printf("->u: %s\n", S)
}
S.verify()
defer S.verify()
// find first ilo: r.lo < [ilo].hi
l := len(S.rangev)
ilo := sort.Search(l, func(i int) bool {
return r.lo <= S.rangev[i].hi_
})
debugfRSet("\tilo: %d\n", ilo)
if ilo == l { // not found
S.rangev = append(S.rangev, r)
l++
debugfRSet("\tappend %s\t-> %s\n", r, S)
}
// find last jhi: [jhi].lo < r.hi
jhi := ilo
for ;; jhi++ {
if jhi == l {
break
}
if S.rangev[jhi].lo <= r.hi_ {
continue
}
break
}
debugfRSet("\tjhi: %d\n", jhi)
// entries in [ilo:jhi) ∈ [r.lo,r.hi) and should be merged into one
if (jhi - ilo) > 1 {
lo := S.rangev[ilo].lo
hi_ := S.rangev[jhi-1].hi_
S.rangev = append(
S.rangev[:ilo], append([]KeyRange{
KeyRange{lo, hi_}},
S.rangev[jhi:]...)...)
debugfRSet("\tmerge S[%d:%d]\t-> %s\n", ilo, jhi, S)
}
jhi = -1 // no longer valid
// if [r.lo,r.hi) was outside of any entry - create new entry
if r.hi_ < S.rangev[ilo].lo {
S.rangev = append(
S.rangev[:ilo], append([]KeyRange{
r},
S.rangev[ilo:]...)...)
debugfRSet("\tinsert %s\t-> %s\n", r, S)
}
// now we have covered entries merged as needed into [ilo]
// extend this entry if r coverage is wider
if r.lo < S.rangev[ilo].lo {
S.rangev[ilo].lo = r.lo
debugfRSet("\textend left\t-> %s\n", S)
}
if r.hi_ > S.rangev[ilo].hi_ {
S.rangev[ilo].hi_ = r.hi_
debugfRSet("\textend right\t-> %s\n", S)
}
// and check if we should merge it with right/left neighbours
if ilo+1 < len(S.rangev) { // right
if S.rangev[ilo].hi_+1 == S.rangev[ilo+1].lo {
S.rangev = append(
S.rangev[:ilo], append([]KeyRange{
KeyRange{S.rangev[ilo].lo, S.rangev[ilo+1].hi_}},
S.rangev[ilo+2:]...)...)
debugfRSet("\tmerge right\t-> %s\n", S)
}
}
if ilo > 0 { // left
if S.rangev[ilo-1].hi_+1 == S.rangev[ilo].lo {
S.rangev = append(
S.rangev[:ilo-1], append([]KeyRange{
KeyRange{S.rangev[ilo-1].lo, S.rangev[ilo].hi_}},
S.rangev[ilo+1:]...)...)
debugfRSet("\tmerge left\t-> %s\n", S)
}
}
// done
}
// DelRange removes range r from the set.
func (S *RangedKeySet) DelRange(r KeyRange) {
if traceRangeSet {
fmt.Printf("\n\nDelRange:\n")
fmt.Printf(" S: %s\n", S)
fmt.Printf(" r: %s\n", r)
defer fmt.Printf("->d: %s\n", S)
}
S.verify()
defer S.verify()
// find first ilo: r.lo < [ilo].hi
l := len(S.rangev)
ilo := sort.Search(l, func(i int) bool {
return r.lo <= S.rangev[i].hi_
})
debugfRSet("\tilo: %d\n", ilo)
if ilo == l { // not found
debugfRSet("\tnon-overlap right\n")
return
}
// find last jhi: [jhi].lo < r.hi
jhi := ilo
for ;; jhi++ {
if jhi == l {
break
}
if S.rangev[jhi].lo <= r.hi_ {
continue
}
break
}
debugfRSet("\tjhi: %d\n", jhi)
if jhi == 0 {
debugfRSet("\tnon-overlap left\n")
return
}
// [ilo+1:jhi-1] should be deleted
// [ilo] and [jhi-1] overlap with [r.lo,r.hi) - they shuold be deleted, or shrinked,
// or split+shrinked if ilo==jhi-1 and r is inside [ilo]
if jhi-ilo == 1 && S.rangev[ilo].lo < r.lo && r.hi_ < S.rangev[ilo].hi_ {
x := S.rangev[ilo]
S.rangev = append(
S.rangev[:ilo], append([]KeyRange{
x, x},
S.rangev[ilo+1:]...)...)
jhi++
debugfRSet("\tpresplit copy %s\t-> %s\n", x, S)
}
if S.rangev[ilo].lo < r.lo { // shrink left
S.rangev = append(
S.rangev[:ilo], append([]KeyRange{
KeyRange{S.rangev[ilo].lo, r.lo-1}},
S.rangev[ilo+1:]...)...)
ilo++
debugfRSet("\tshrink [%d] left\t-> %s\n", ilo, S)
}
if r.hi_ < S.rangev[jhi-1].hi_ { // shrink right
S.rangev = append(
S.rangev[:jhi-1], append([]KeyRange{
KeyRange{r.hi_+1, S.rangev[jhi-1].hi_}},
S.rangev[jhi:]...)...)
jhi--
debugfRSet("\tshrink [%d] right\t-> %s\n", jhi-1, S)
}
if (jhi - ilo) > 0 {
S.rangev = append(
S.rangev[:ilo],
S.rangev[jhi:]...)
debugfRSet("\tdelete S[%d:%d]\t-> %s\n", ilo, jhi, S)
}
// done
}
// HasRange returns whether all keys from range r belong to the set.
func (S *RangedKeySet) HasRange(r KeyRange) (yes bool) {
if traceRangeSet {
fmt.Printf("\n\nHasRange:\n")
fmt.Printf(" S: %s\n", S)
fmt.Printf(" r: %s\n", r)
defer func() {
fmt.Printf("->·: %v\n", yes)
}()
}
S.verify()
// find first ilo: r.lo < [ilo].hi
l := len(S.rangev)
ilo := sort.Search(l, func(i int) bool {
return r.lo <= S.rangev[i].hi_
})
debugfRSet("\tilo: %d\n", ilo)
if ilo == l { // not found
return false
}
// all keys from r are in S if r ∈ [ilo]
return (S.rangev[ilo].lo <= r.lo && r.hi_ <= S.rangev[ilo].hi_)
}
// Union returns RangedKeySet(A.keys | B.keys).
func (A *RangedKeySet) Union(B *RangedKeySet) *RangedKeySet {
U := A.Clone()
U.UnionInplace(B)
return U
}
// Difference returns RangedKeySet(A.keys \ B.keys).
func (A *RangedKeySet) Difference(B *RangedKeySet) *RangedKeySet {
D := A.Clone()
D.DifferenceInplace(B)
return D
}
// XXX Intersection
func (A *RangedKeySet) UnionInplace(B *RangedKeySet) {
A.verify()
B.verify()
defer A.verify()
// XXX dumb
for _, r := range B.rangev {
A.AddRange(r)
}
}
func (A *RangedKeySet) DifferenceInplace(B *RangedKeySet) {
A.verify()
B.verify()
defer A.verify()
// XXX dumb
for _, r := range B.rangev {
if len(A.rangev) == 0 {
break
}
A.DelRange(r)
}
}
// --------
// verify check RangedKeySet for internal consistency:
// - ranges must be not overlapping nor adjacent and ↑
func (S *RangedKeySet) verify() {
// XXX !debug -> return ?
var badv []string
badf := func(format string, argv ...interface{}) {
badv = append(badv, fmt.Sprintf(format, argv...))
}
defer func() {
if badv != nil {
emsg := fmt.Sprintf("S.verify: fail:\n\n")
for _, bad := range badv {
emsg += fmt.Sprintf("- %s\n", bad)
}
emsg += fmt.Sprintf("\nS: %s\n", S)
panic(emsg)
}
}()
hi_Prev := KeyMin
for i, r := range S.rangev {
hiPrev := hi_Prev + 1
if i > 0 && !(hiPrev < r.lo) { // NOTE not ≤ - adjacent ranges must be merged
badf("[%d]: !(hiPrev < r.lo)", i)
}
if !(r.lo <= r.hi_) {
badf("[%d]: !(r.lo <= r.hi_)", i)
}
hi_Prev = r.hi_
}
}
// Clone returns copy of the set.
func (orig *RangedKeySet) Clone() *RangedKeySet {
klon := &RangedKeySet{}
klon.rangev = append(klon.rangev, orig.rangev...)
return klon
}
// Empty returns whether the set is empty.
func (S *RangedKeySet) Empty() bool {
return len(S.rangev) == 0
}
// Equal returns whether A == B.
func (A *RangedKeySet) Equal(B *RangedKeySet) bool {
if len(A.rangev) != len(B.rangev) {
return false
}
for i, ra := range A.rangev {
rb := B.rangev[i]
if ra != rb {
return false
}
}
return true
}
// Clear removes all elements from the set.
func (S *RangedKeySet) Clear() {
S.rangev = nil
}
// AllRanges returns slice of all key ranges in the set.
// XXX -> iter?
func (S *RangedKeySet) AllRanges() /*readonly*/[]KeyRange {
return S.rangev
}
func (S RangedKeySet) String() string {
s := "{"
for i, r := range S.rangev {
if i > 0 {
s += " "
}
s += r.String()
}
s += "}"
return s
}
func (r KeyRange) String() string {
hi := r.hi_
if hi < KeyMax {
hi += 1
}
return fmt.Sprintf("[%s,%s)", kstr(r.lo), kstr(hi))
}
func debugfRSet(format string, argv ...interface{}) {
if !debugRangeSet {
return
}
fmt.Printf(format, argv...)
}
// Copyright (C) 2021 Nexedi SA and Contributors.
// Kirill Smelkov <kirr@nexedi.com>
//
// This program is free software: you can Use, Study, Modify and Redistribute
// it under the terms of the GNU General Public License version 3, or (at your
// option) any later version, as published by the Free Software Foundation.
//
// You can also Link and Combine this program with other software covered by
// the terms of any of the Free Software licenses or any of the Open Source
// Initiative approved licenses and Convey the resulting work. Corresponding
// source of such a combination shall include the source code for all other
// software used.
//
// This program is distributed WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//
// See COPYING file for full licensing terms.
// See https://www.nexedi.com/licensing for rationale and options.
package xbtree
import (
"testing"
)
func TestRangedKeySet(t *testing.T) {
const (
oo = KeyMax
noo = KeyMin
)
type testEntry struct {
A, B *RangedKeySet
Union *RangedKeySet
Difference *RangedKeySet
}
E := func(A, B, U, D *RangedKeySet) testEntry {
return testEntry{A, B, U, D}
}
// S is shorthand to create RangedKeySet, e.g. S(1,2, 4,5) will return {[1,2) [4,5)}
S := func(kv ...Key) *RangedKeySet {
l := len(kv)
if l % 2 != 0 {
panic("odd number of keys")
}
S := &RangedKeySet{}
for i := 0; i < l/2; i++ {
// construct .rangev directly, not via AddRange
lo := kv[2*i]
hi := kv[2*i+1]
hi_ := hi
if hi_ != oo {
hi_--
}
S.rangev = append(S.rangev, KeyRange{lo, hi_})
}
S.verify()
return S
}
testv := []testEntry{
E(
S(), // A
S(), // B
S(), // U
S()), // D
E(
S(1,2), // A
S(1,2), // B
S(1,2), // U
S()), // D
// adjacent [1,3) [3,5)
E(
S(1,3), // A
S(3,5), // B
S(1,5), // U
S(1,3)), // D
// overlapping [1,3) [2,4)
E(
S(1,3), // A
S(2,4), // B
S(1,4), // U
S(1,2)), // D
// [1,7) \ [3,5) -> [1,3) [5,7)
E(
S(1,7), // A
S(3,5), // B
S(1,7),
S(1,3, 5,7)),
// several ranges \ [-∞, ∞) -> ø
E(
S(1,3, 5,7, 11,100), // A
S(noo, oo), // B
S(noo, oo), // U
S()), // D
// [1,3) [5,7) + insert [3,5) -> [1,7)
E(
S(1,3, 5,7), // A
S(3,5), // B
S(1,7), // U
S(1,3, 5,7)), // D
// delete covering several ranges
// [-1,0) [1,3) [5,7) [9,11) [15,20) [100,200) \ [2,17)
E(
S(-1,0, 1,3, 5,7, 9,11, 15,20, 100,200), // A
S(2,17), // B
S(-1,0, 1,20, 100,200), // U
S(-1,0, 1,2, 17,20, 100,200)), // D
}
for _, tt := range testv {
A := tt.A
B := tt.B
U := A.Union(B)
D := A.Difference(B)
if !U.Equal(tt.Union) {
t.Errorf("Union:\n A: %s\n B: %s\n ->u: %s\n okU: %s\n", tt.A, tt.B, U, tt.Union)
}
if !D.Equal(tt.Difference) {
t.Errorf("Difference:\n A: %s\n B: %s\n ->d: %s\n okD: %s\n", tt.A, tt.B, D, tt.Difference)
}
// HasRange
assertHasRange(t, A.AllRanges(), A, true)
assertHasRange(t, B.AllRanges(), B, true)
assertHasRange(t, A.AllRanges(), U, true)
assertHasRange(t, B.AllRanges(), U, true)
Dab := D
Dba := B.Difference(A)
assertHasRange(t, Dab.AllRanges(), A, true)
assertHasRange(t, Dab.AllRanges(), B, false)
assertHasRange(t, Dba.AllRanges(), B, true)
assertHasRange(t, Dba.AllRanges(), A, false)
}
}
// assertHasRange asserts for all ranges from rangev that S.HasRange(r) == hasOK
func assertHasRange(t *testing.T, rangev []KeyRange, S *RangedKeySet, hasOK bool) {
t.Helper()
for _, r := range rangev {
has := S.HasRange(r)
if has != hasOK {
t.Errorf("HasRange:\n S: %s\n r: %s\n ->: %v\n ok: %v\n", S, r, has, hasOK)
}
}
}
This diff is collapsed.
...@@ -68,3 +68,15 @@ func nodePathToPath(nodePath []Node) (path []zodb.Oid) { ...@@ -68,3 +68,15 @@ func nodePathToPath(nodePath []Node) (path []zodb.Oid) {
} }
return path return path
} }
// kstr formats key as string.
func kstr(k Key) string {
if k == KeyMin {
return "-∞"
}
if k == KeyMax {
return "∞"
}
return fmt.Sprintf("%d", k)
}
...@@ -101,11 +101,6 @@ type ΔBtail struct { ...@@ -101,11 +101,6 @@ type ΔBtail struct {
// set of node that were requested to be tracked, but for which vδB was not yet rebuilt // set of node that were requested to be tracked, but for which vδB was not yet rebuilt
trackNew PPTreeSubSet trackNew PPTreeSubSet
// XXX root -> tracked holes
// XXX move -> ΔTtail ?
holeIdxByRoot map[zodb.Oid]treeSetKey
} }
...@@ -149,7 +144,6 @@ func NewΔBtail(at0 zodb.Tid, db *zodb.DB) *ΔBtail { ...@@ -149,7 +144,6 @@ func NewΔBtail(at0 zodb.Tid, db *zodb.DB) *ΔBtail {
byRoot: map[zodb.Oid]*ΔTtail{}, byRoot: map[zodb.Oid]*ΔTtail{},
trackSet: PPTreeSubSet{}, trackSet: PPTreeSubSet{},
trackNew: PPTreeSubSet{}, trackNew: PPTreeSubSet{},
holeIdxByRoot: map[zodb.Oid]treeSetKey{},
db: db, db: db,
} }
} }
...@@ -184,14 +178,6 @@ func (orig *ΔBtail) clone() *ΔBtail { ...@@ -184,14 +178,6 @@ func (orig *ΔBtail) clone() *ΔBtail {
klon.byRoot[root] = klonΔTtail klon.byRoot[root] = klonΔTtail
} }
// holeIdxByRoot
klon.holeIdxByRoot = make(map[zodb.Oid]treeSetKey, len(orig.holeIdxByRoot))
for root, origHoleIdx := range orig.holeIdxByRoot {
klonHoleIdx := treeSetKey{make(SetKey, len(origHoleIdx.SetKey))}
klonHoleIdx.Update(origHoleIdx.SetKey)
klon.holeIdxByRoot[root] = klonHoleIdx
}
return klon return klon
} }
...@@ -224,6 +210,7 @@ func (δBtail *ΔBtail) Tail() zodb.Tid { return δBtail.δZtail.Tail() } ...@@ -224,6 +210,7 @@ func (δBtail *ΔBtail) Tail() zodb.Tid { return δBtail.δZtail.Tail() }
// XXX path -> []oid ? // XXX path -> []oid ?
// //
// XXX catch cycles on add? // XXX catch cycles on add?
// XXX no need to pass keyPresent since holeIdx was removed
func (δBtail *ΔBtail) Track(key Key, keyPresent bool, nodePath []Node) error { // XXX Tree|Bucket; path[0] = root func (δBtail *ΔBtail) Track(key Key, keyPresent bool, nodePath []Node) error { // XXX Tree|Bucket; path[0] = root
path := nodePathToPath(nodePath) path := nodePathToPath(nodePath)
...@@ -241,21 +228,6 @@ func (δBtail *ΔBtail) track(key Key, keyPresent bool, path []zodb.Oid) error { ...@@ -241,21 +228,6 @@ func (δBtail *ΔBtail) track(key Key, keyPresent bool, path []zodb.Oid) error {
// track is track of path[-1] (i.e. leaf) // track is track of path[-1] (i.e. leaf)
// remember missing keys in track of leaf node (bucket or top-level ø tree)
holeIdx := δBtail.holeIdxFor(root)
if !keyPresent {
holeIdx.Add(key)
//track.holes.Add(key)
} else {
/*
if track.holes.Has(key) {
panicf("[%v] was previously requested to be tracked as ø", key)
}
*/
if holeIdx.Has(key) {
panicf("[%v] was previously requested to be tracked as ø", key)
}
}
// XXX hack - until rebuild is implemented // XXX hack - until rebuild is implemented
if XXX_killWhenRebuildWorks { if XXX_killWhenRebuildWorks {
...@@ -270,15 +242,6 @@ if XXX_killWhenRebuildWorks { ...@@ -270,15 +242,6 @@ if XXX_killWhenRebuildWorks {
return nil return nil
} }
func (δBtail *ΔBtail) holeIdxFor(root zodb.Oid) treeSetKey {
holeIdx, ok := δBtail.holeIdxByRoot[root]
if !ok {
holeIdx = treeSetKey{SetKey{}}
δBtail.holeIdxByRoot[root] = holeIdx
}
return holeIdx
}
// rebuild rebuilds ΔBtail taking trackNew requests into account. // rebuild rebuilds ΔBtail taking trackNew requests into account.
// XXX place // XXX place
func (δBtail *ΔBtail) rebuild() (err error) { func (δBtail *ΔBtail) rebuild() (err error) {
...@@ -332,9 +295,8 @@ func (δBtail *ΔBtail) rebuild() (err error) { ...@@ -332,9 +295,8 @@ func (δBtail *ΔBtail) rebuild() (err error) {
} }
for root, δtops := range δtopsByRoot { for root, δtops := range δtopsByRoot {
holeIdx := treeSetKey{SetKey{}} // XXX stub
// diff backwards curr -> prev // diff backwards curr -> prev
δT, δtrack, err := treediff(ctx, root, δtops, δZTC, trackNew, holeIdx, zconnCurr, zconnPrev) δT, δtrack, err := treediff(ctx, root, δtops, δZTC, trackNew, zconnCurr, zconnPrev)
if err != nil { if err != nil {
return err return err
} }
...@@ -428,7 +390,6 @@ if XXX_killWhenRebuildWorks { ...@@ -428,7 +390,6 @@ if XXX_killWhenRebuildWorks {
tracef("Update @%s -> @%s\n", δBtail.Head(), δZ.Tid) tracef("Update @%s -> @%s\n", δBtail.Head(), δZ.Tid)
tracef("δZ:\t%v\n", δZ.Changev) tracef("δZ:\t%v\n", δZ.Changev)
tracef("trackSet: %v\n", δBtail.trackSet) tracef("trackSet: %v\n", δBtail.trackSet)
tracef("holeIdxByRoot: %v\n", δBtail.holeIdxByRoot)
// XXX dup wrt rebuild? // XXX dup wrt rebuild?
...@@ -457,8 +418,7 @@ if XXX_killWhenRebuildWorks { ...@@ -457,8 +418,7 @@ if XXX_killWhenRebuildWorks {
} }
for root, δtops := range δtopsByRoot { for root, δtops := range δtopsByRoot {
holeIdx := δBtail.holeIdxByRoot[root] δT, δtrack, err := treediff(ctx, root, δtops, δZTC, δBtail.trackSet, zconnOld, zconnNew)
δT, δtrack, err := treediff(ctx, root, δtops, δZTC, δBtail.trackSet, holeIdx, zconnOld, zconnNew)
if err != nil { if err != nil {
return ΔB{}, err return ΔB{}, err
} }
......
This diff is collapsed.
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