Commit 042c5eeb authored by Kirill Smelkov's avatar Kirill Smelkov

.

parent 467ef54e
// 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 blib provides utilities related to BTrees.
package blib
import (
"fmt"
"math"
"lab.nexedi.com/kirr/neo/go/zodb/btree"
"lab.nexedi.com/nexedi/wendelin.core/wcfs/internal/set"
)
// XXX instead of generics
type Tree = btree.LOBTree
type Bucket = btree.LOBucket
type Node = btree.LONode
type TreeEntry = btree.LOEntry
type BucketEntry = btree.LOBucketEntry
type Key = int64
const KeyMax Key = math.MaxInt64
const KeyMin Key = math.MinInt64
type setOid = set.Oid
// kstr formats key as string.
func kstr(k Key) string {
if k == KeyMin {
return "-∞"
}
if k == KeyMax {
return "∞"
}
return fmt.Sprintf("%d", k)
}
func panicf(format string, argv ...interface{}) {
panic(fmt.Sprintf(format, argv...))
}
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
// See COPYING file for full licensing terms. // See COPYING file for full licensing terms.
// See https://www.nexedi.com/licensing for rationale and options. // See https://www.nexedi.com/licensing for rationale and options.
package xbtree package blib
// PP-connected subset of tree nodes. // PP-connected subset of tree nodes.
import ( import (
......
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
// See COPYING file for full licensing terms. // See COPYING file for full licensing terms.
// See https://www.nexedi.com/licensing for rationale and options. // See https://www.nexedi.com/licensing for rationale and options.
package xbtree package blib
import ( import (
"strings" "strings"
......
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
// See COPYING file for full licensing terms. // See COPYING file for full licensing terms.
// See https://www.nexedi.com/licensing for rationale and options. // See https://www.nexedi.com/licensing for rationale and options.
package xbtree package blib
// set of [lo,hi) Key ranges. // set of [lo,hi) Key ranges.
import ( import (
...@@ -30,8 +30,8 @@ const debugRangeSet = false ...@@ -30,8 +30,8 @@ const debugRangeSet = false
// KeyRange represents [lo,hi) Key range. // KeyRange represents [lo,hi) Key range.
type KeyRange struct { type KeyRange struct {
lo Key Lo Key
hi_ Key // NOTE _not_ hi) to avoid overflow at ∞; hi = hi_ + 1 Hi_ Key // NOTE _not_ hi) to avoid overflow at ∞; hi = hi_ + 1
} }
// RangedKeySet is set of Keys with adjacent keys coalesced into Ranges. // RangedKeySet is set of Keys with adjacent keys coalesced into Ranges.
...@@ -47,23 +47,23 @@ type RangedKeySet struct { ...@@ -47,23 +47,23 @@ type RangedKeySet struct {
// Has returns whether key k belongs to the range. // Has returns whether key k belongs to the range.
func (r *KeyRange) Has(k Key) bool { func (r *KeyRange) Has(k Key) bool {
return (r.lo <= k && k <= r.hi_) return (r.Lo <= k && k <= r.Hi_)
} }
// Add adds key k to the set. // Add adds key k to the set.
func (S *RangedKeySet) Add(k Key) { func (S *RangedKeySet) Add(k Key) {
S.AddRange(KeyRange{lo: k, hi_: k}) S.AddRange(KeyRange{Lo: k, Hi_: k})
} }
// Del removes key k from the set. // Del removes key k from the set.
func (S *RangedKeySet) Del(k Key) { func (S *RangedKeySet) Del(k Key) {
S.DelRange(KeyRange{lo: k, hi_: k}) S.DelRange(KeyRange{Lo: k, Hi_: k})
} }
// Has returns whether key k belongs to the set. // Has returns whether key k belongs to the set.
func (S *RangedKeySet) Has(k Key) bool { func (S *RangedKeySet) Has(k Key) bool {
return S.HasRange(KeyRange{lo: k, hi_: k}) return S.HasRange(KeyRange{Lo: k, Hi_: k})
} }
...@@ -79,10 +79,10 @@ func (S *RangedKeySet) AddRange(r KeyRange) { ...@@ -79,10 +79,10 @@ func (S *RangedKeySet) AddRange(r KeyRange) {
S.verify() S.verify()
defer S.verify() defer S.verify()
// find first ilo: r.lo < [ilo].hi // find first ilo: r.Lo < [ilo].hi
l := len(S.rangev) l := len(S.rangev)
ilo := sort.Search(l, func(i int) bool { ilo := sort.Search(l, func(i int) bool {
return r.lo <= S.rangev[i].hi_ return r.Lo <= S.rangev[i].Hi_
}) })
debugfRSet("\tilo: %d\n", ilo) debugfRSet("\tilo: %d\n", ilo)
...@@ -92,58 +92,58 @@ func (S *RangedKeySet) AddRange(r KeyRange) { ...@@ -92,58 +92,58 @@ func (S *RangedKeySet) AddRange(r KeyRange) {
debugfRSet("\tappend %s\t-> %s\n", r, S) debugfRSet("\tappend %s\t-> %s\n", r, S)
} }
// find last jhi: [jhi].lo < r.hi // find last jhi: [jhi].Lo < r.hi
jhi := ilo jhi := ilo
for ;; jhi++ { for ;; jhi++ {
if jhi == l { if jhi == l {
break break
} }
if S.rangev[jhi].lo <= r.hi_ { if S.rangev[jhi].Lo <= r.Hi_ {
continue continue
} }
break break
} }
debugfRSet("\tjhi: %d\n", jhi) debugfRSet("\tjhi: %d\n", jhi)
// entries in [ilo:jhi) ∈ [r.lo,r.hi) and should be merged into one // entries in [ilo:jhi) ∈ [r.Lo,r.hi) and should be merged into one
if (jhi - ilo) > 1 { if (jhi - ilo) > 1 {
lo := S.rangev[ilo].lo lo := S.rangev[ilo].Lo
hi_ := S.rangev[jhi-1].hi_ hi_ := S.rangev[jhi-1].Hi_
vReplaceSlice(&S.rangev, ilo,jhi, KeyRange{lo,hi_}) vReplaceSlice(&S.rangev, ilo,jhi, KeyRange{lo,hi_})
debugfRSet("\tmerge S[%d:%d]\t-> %s\n", ilo, jhi, S) debugfRSet("\tmerge S[%d:%d]\t-> %s\n", ilo, jhi, S)
} }
jhi = -1 // no longer valid jhi = -1 // no longer valid
// if [r.lo,r.hi) was outside of any entry - create new entry // if [r.lo,r.hi) was outside of any entry - create new entry
if r.hi_ < S.rangev[ilo].lo { if r.Hi_ < S.rangev[ilo].Lo {
vInsert(&S.rangev, ilo, r) vInsert(&S.rangev, ilo, r)
debugfRSet("\tinsert %s\t-> %s\n", r, S) debugfRSet("\tinsert %s\t-> %s\n", r, S)
} }
// now we have covered entries merged as needed into [ilo] // now we have covered entries merged as needed into [ilo]
// extend this entry if r coverage is wider // extend this entry if r coverage is wider
if r.lo < S.rangev[ilo].lo { if r.Lo < S.rangev[ilo].Lo {
S.rangev[ilo].lo = r.lo S.rangev[ilo].Lo = r.Lo
debugfRSet("\textend left\t-> %s\n", S) debugfRSet("\textend left\t-> %s\n", S)
} }
if r.hi_ > S.rangev[ilo].hi_ { if r.Hi_ > S.rangev[ilo].Hi_ {
S.rangev[ilo].hi_ = r.hi_ S.rangev[ilo].Hi_ = r.Hi_
debugfRSet("\textend right\t-> %s\n", S) debugfRSet("\textend right\t-> %s\n", S)
} }
// and check if we should merge it with right/left neighbours // and check if we should merge it with right/left neighbours
if ilo+1 < len(S.rangev) { // right if ilo+1 < len(S.rangev) { // right
if S.rangev[ilo].hi_+1 == S.rangev[ilo+1].lo { if S.rangev[ilo].Hi_+1 == S.rangev[ilo+1].Lo {
vReplaceSlice(&S.rangev, ilo,ilo+2, vReplaceSlice(&S.rangev, ilo,ilo+2,
KeyRange{S.rangev[ilo].lo, S.rangev[ilo+1].hi_}) KeyRange{S.rangev[ilo].Lo, S.rangev[ilo+1].Hi_})
debugfRSet("\tmerge right\t-> %s\n", S) debugfRSet("\tmerge right\t-> %s\n", S)
} }
} }
if ilo > 0 { // left if ilo > 0 { // left
if S.rangev[ilo-1].hi_+1 == S.rangev[ilo].lo { if S.rangev[ilo-1].Hi_+1 == S.rangev[ilo].Lo {
vReplaceSlice(&S.rangev, ilo-1,ilo+1, vReplaceSlice(&S.rangev, ilo-1,ilo+1,
KeyRange{S.rangev[ilo-1].lo, S.rangev[ilo].hi_}) KeyRange{S.rangev[ilo-1].Lo, S.rangev[ilo].Hi_})
debugfRSet("\tmerge left\t-> %s\n", S) debugfRSet("\tmerge left\t-> %s\n", S)
} }
} }
...@@ -163,10 +163,10 @@ func (S *RangedKeySet) DelRange(r KeyRange) { ...@@ -163,10 +163,10 @@ func (S *RangedKeySet) DelRange(r KeyRange) {
S.verify() S.verify()
defer S.verify() defer S.verify()
// find first ilo: r.lo < [ilo].hi // find first ilo: r.Lo < [ilo].hi
l := len(S.rangev) l := len(S.rangev)
ilo := sort.Search(l, func(i int) bool { ilo := sort.Search(l, func(i int) bool {
return r.lo <= S.rangev[i].hi_ return r.Lo <= S.rangev[i].Hi_
}) })
debugfRSet("\tilo: %d\n", ilo) debugfRSet("\tilo: %d\n", ilo)
...@@ -175,13 +175,13 @@ func (S *RangedKeySet) DelRange(r KeyRange) { ...@@ -175,13 +175,13 @@ func (S *RangedKeySet) DelRange(r KeyRange) {
return return
} }
// find last jhi: [jhi].lo < r.hi // find last jhi: [jhi].Lo < r.hi
jhi := ilo jhi := ilo
for ;; jhi++ { for ;; jhi++ {
if jhi == l { if jhi == l {
break break
} }
if S.rangev[jhi].lo <= r.hi_ { if S.rangev[jhi].Lo <= r.Hi_ {
continue continue
} }
break break
...@@ -196,19 +196,19 @@ func (S *RangedKeySet) DelRange(r KeyRange) { ...@@ -196,19 +196,19 @@ func (S *RangedKeySet) DelRange(r KeyRange) {
// [ilo+1:jhi-1] should be deleted // [ilo+1:jhi-1] should be deleted
// [ilo] and [jhi-1] overlap with [r.lo,r.hi) - they should be deleted, or shrinked, // [ilo] and [jhi-1] overlap with [r.lo,r.hi) - they should be deleted, or shrinked,
// or split+shrinked if ilo==jhi-1 and r is inside [ilo] // 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_ { if jhi-ilo == 1 && S.rangev[ilo].Lo < r.Lo && r.Hi_ < S.rangev[ilo].Hi_ {
x := S.rangev[ilo] x := S.rangev[ilo]
vInsert(&S.rangev, ilo, x) vInsert(&S.rangev, ilo, x)
jhi++ jhi++
debugfRSet("\tpresplit copy %s\t-> %s\n", x, S) debugfRSet("\tpresplit copy %s\t-> %s\n", x, S)
} }
if S.rangev[ilo].lo < r.lo { // shrink left if S.rangev[ilo].Lo < r.Lo { // shrink left
S.rangev[ilo] = KeyRange{S.rangev[ilo].lo, r.lo-1} S.rangev[ilo] = KeyRange{S.rangev[ilo].Lo, r.Lo-1}
ilo++ ilo++
debugfRSet("\tshrink [%d] left\t-> %s\n", ilo, S) debugfRSet("\tshrink [%d] left\t-> %s\n", ilo, S)
} }
if r.hi_ < S.rangev[jhi-1].hi_ { // shrink right if r.Hi_ < S.rangev[jhi-1].Hi_ { // shrink right
S.rangev[jhi-1] = KeyRange{r.hi_+1, S.rangev[jhi-1].hi_} S.rangev[jhi-1] = KeyRange{r.Hi_+1, S.rangev[jhi-1].Hi_}
jhi-- jhi--
debugfRSet("\tshrink [%d] right\t-> %s\n", jhi-1, S) debugfRSet("\tshrink [%d] right\t-> %s\n", jhi-1, S)
} }
...@@ -237,7 +237,7 @@ func (S *RangedKeySet) HasRange(r KeyRange) (yes bool) { ...@@ -237,7 +237,7 @@ func (S *RangedKeySet) HasRange(r KeyRange) (yes bool) {
// find first ilo: r.lo < [ilo].hi // find first ilo: r.lo < [ilo].hi
l := len(S.rangev) l := len(S.rangev)
ilo := sort.Search(l, func(i int) bool { ilo := sort.Search(l, func(i int) bool {
return r.lo <= S.rangev[i].hi_ return r.Lo <= S.rangev[i].Hi_
}) })
debugfRSet("\tilo: %d\n", ilo) debugfRSet("\tilo: %d\n", ilo)
...@@ -246,7 +246,7 @@ func (S *RangedKeySet) HasRange(r KeyRange) (yes bool) { ...@@ -246,7 +246,7 @@ func (S *RangedKeySet) HasRange(r KeyRange) (yes bool) {
} }
// all keys from r are in S if r ∈ [ilo] // all keys from r are in S if r ∈ [ilo]
return (S.rangev[ilo].lo <= r.lo && r.hi_ <= S.rangev[ilo].hi_) return (S.rangev[ilo].Lo <= r.Lo && r.Hi_ <= S.rangev[ilo].Hi_)
} }
...@@ -317,13 +317,13 @@ func (S *RangedKeySet) verify() { ...@@ -317,13 +317,13 @@ func (S *RangedKeySet) verify() {
hi_Prev := KeyMin hi_Prev := KeyMin
for i, r := range S.rangev { for i, r := range S.rangev {
hiPrev := hi_Prev + 1 hiPrev := hi_Prev + 1
if i > 0 && !(hiPrev < r.lo) { // NOTE not ≤ - adjacent ranges must be merged if i > 0 && !(hiPrev < r.Lo) { // NOTE not ≤ - adjacent ranges must be merged
badf("[%d]: !(hiPrev < r.lo)", i) badf("[%d]: !(hiPrev < r.lo)", i)
} }
if !(r.lo <= r.hi_) { if !(r.Lo <= r.Hi_) {
badf("[%d]: !(r.lo <= r.hi_)", i) badf("[%d]: !(r.lo <= r.hi_)", i)
} }
hi_Prev = r.hi_ hi_Prev = r.Hi_
} }
} }
...@@ -378,12 +378,12 @@ func (S RangedKeySet) String() string { ...@@ -378,12 +378,12 @@ func (S RangedKeySet) String() string {
func (r KeyRange) String() string { func (r KeyRange) String() string {
var shi string var shi string
if r.hi_ == KeyMax { if r.Hi_ == KeyMax {
shi = kstr(r.hi_) // ∞ shi = kstr(r.Hi_) // ∞
} else { } else {
shi = fmt.Sprintf("%d", r.hi_+1) shi = fmt.Sprintf("%d", r.Hi_+1)
} }
return fmt.Sprintf("[%s,%s)", kstr(r.lo), shi) return fmt.Sprintf("[%s,%s)", kstr(r.Lo), shi)
} }
......
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
// See COPYING file for full licensing terms. // See COPYING file for full licensing terms.
// See https://www.nexedi.com/licensing for rationale and options. // See https://www.nexedi.com/licensing for rationale and options.
package xbtree package blib
import ( import (
"testing" "testing"
......
...@@ -11,19 +11,20 @@ import ( ...@@ -11,19 +11,20 @@ import (
"lab.nexedi.com/kirr/neo/go/zodb/btree" "lab.nexedi.com/kirr/neo/go/zodb/btree"
"lab.nexedi.com/nexedi/wendelin.core/wcfs/internal/set" "lab.nexedi.com/nexedi/wendelin.core/wcfs/internal/set"
"lab.nexedi.com/nexedi/wendelin.core/wcfs/internal/xbtree/blib"
) )
// XXX instead of generics // XXX instead of generics
type Tree = btree.LOBTree type Tree = blib.Tree
type Bucket = btree.LOBucket type Bucket = blib.Bucket
type Node = btree.LONode type Node = blib.Node
type TreeEntry = btree.LOEntry type TreeEntry = blib.TreeEntry
type BucketEntry = btree.LOBucketEntry type BucketEntry = blib.BucketEntry
type Key = int64 type Key = blib.Key
const KeyMax Key = math.MaxInt64 const KeyMax = blib.KeyMax
const KeyMin Key = math.MinInt64 const KeyMin = blib.KeyMin
// value is assumed to be persistent reference. // value is assumed to be persistent reference.
// deletion is represented as VDEL. // deletion is represented as VDEL.
......
...@@ -24,6 +24,8 @@ import ( ...@@ -24,6 +24,8 @@ import (
"sort" "sort"
"lab.nexedi.com/kirr/neo/go/zodb" "lab.nexedi.com/kirr/neo/go/zodb"
"lab.nexedi.com/nexedi/wendelin.core/wcfs/internal/xbtree/blib"
) )
// RTree represents Tree node covering [lo, hi_] key range in its parent tree. // RTree represents Tree node covering [lo, hi_] key range in its parent tree.
...@@ -102,5 +104,5 @@ func (xkv RBucketSet) Flatten() map[Key]string { ...@@ -102,5 +104,5 @@ func (xkv RBucketSet) Flatten() map[Key]string {
} }
func (b *RBucket) String() string { func (b *RBucket) String() string {
return fmt.Sprintf("%sB%s{%s}", KeyRange{b.lo, b.hi_}, b.oid, kvtxt(b.kv)) return fmt.Sprintf("%sB%s{%s}", blib.KeyRange{b.lo, b.hi_}, b.oid, kvtxt(b.kv))
} }
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