Commit 93348d0f authored by Kirill Smelkov's avatar Kirill Smelkov

X Don't move data to new page on split if load is append-like

Else a lot of time is then spent moving data forth and back with memcpy
on further appends.
parent 4efd872d
......@@ -366,6 +366,12 @@ func (t *Tree) Delete(k interface{} /*K*/) (ok bool) {
}
}
// don't leave previously active data page with < 50% load
if t.hitD != nil && t.hitD.c < kd && t.hitP != nil {
//println("refill")
t.refill(t.hitP, t.hitD, t.hitPi)
}
// data page not quickly found - search and descent from root
pi := -1
var p *x
......@@ -744,6 +750,12 @@ func (t *Tree) Set(k interface{} /*K*/, v interface{} /*V*/) {
}
}
// don't leave previously active data page with < 50% load
if t.hitD != nil && t.hitD.c < kd && t.hitP != nil {
//println("refill")
t.refill(t.hitP, t.hitD, t.hitPi)
}
// data page not quickly found - search and descent from root
pi := -1
var p *x
......@@ -895,6 +907,12 @@ func (t *Tree) Put(k interface{} /*K*/, upd func(oldV interface{} /*V*/, exists
}
}
// don't leave previously active data page with < 50% load
if t.hitD != nil && t.hitD.c < kd && t.hitP != nil {
//println("refill")
t.refill(t.hitP, t.hitD, t.hitPi)
}
// data page not quickly found - search and descent from root
t.hitKminSet, t.hitKmaxSet = false, false // initially [-∞, +∞)
t.hitPKminSet, t.hitPKmaxSet = false, false
......@@ -984,13 +1002,19 @@ func (t *Tree) split(p *x, q *d, pi, i int, k interface{} /*K*/, v interface{} /
q.n = r
r.p = q
// don't copy on sequential bulk-set pattern
if i == 2*kd {
t.insert(r, 0, k, v)
} else {
copy(r.d[:], q.d[kd:2*kd])
for i := range q.d[kd:] {
q.d[kd+i] = zde
}
q.c = kd
r.c = kd
}
// XXX vs ^^^ (not adding elements)
if pi >= 0 {
p.insert(pi, r.d[0].k, r)
} else {
......@@ -1002,7 +1026,10 @@ func (t *Tree) split(p *x, q *d, pi, i int, k interface{} /*K*/, v interface{} /
}
if i > kd {
// XXX vvv try to merge with ^^^ t.insert(r, 0, k, v)
if i < 2*kd {
t.insert(r, i-kd, k, v)
}
t.setHitKmin(p.x[pi].k)
if pi+1 < p.c { // k=+∞ @p.c
t.setHitKmax(p.x[pi+1].k)
......@@ -1057,6 +1084,8 @@ func (t *Tree) underflow(p *x, q *d, pi int) {
t.ver++
l, r := p.siblings(pi)
// TODO don't move 1 elements for bulk-delete patterb (see split for bulk-set case)
if l != nil && l.c+q.c >= 2*kd {
l.mvR(q, 1)
p.x[pi-1].k = q.d[0].k
......@@ -1177,6 +1206,47 @@ func (t *Tree) underflowX(p *x, q *x, pi int, i int) (*x, int) {
return q, i
}
// refill refills data page to have >= 50% load taking data entries from siblings
// if siblings have not enough entries for such refill, the data page in question is concatenated into one of them.
// XXX naming -> fillup ?
func (t *Tree) refill(p *x, q *d, pi int) {
t.ver++
l, r := p.siblings(pi)
δl := 0
δr := 0
if l != nil {
δl = l.c - kd
}
if r != nil {
δr = r.c - kd
}
if q.c + δl + δr < kd {
// cannot refill - concatenate into l or r
if l != nil {
t.cat(p, l, q, pi-1)
} else {
t.cat(p, q, r, pi)
}
return
}
// refill from siblings
δ := kd - q.c
δl = δ * δl / (δl + δr)
δr = δ - δl
if δl != 0 {
l.mvR(q, δl)
p.x[pi-1].k = q.d[0].k
}
if δr != 0 {
q.mvL(r, δr)
p.x[pi].k = r.d[0].k
}
}
// ----------------------------------------------------------------- Enumerator
// Close recycles e to a pool for possible later reuse. No references to e
......
......@@ -366,6 +366,12 @@ func (t *Tree) Delete(k int) (ok bool) {
}
}
// don't leave previously active data page with < 50% load
if t.hitD != nil && t.hitD.c < kd && t.hitP != nil {
//println("refill")
t.refill(t.hitP, t.hitD, t.hitPi)
}
// data page not quickly found - search and descent from root
pi := -1
var p *x
......@@ -744,6 +750,12 @@ func (t *Tree) Set(k int, v int) {
}
}
// don't leave previously active data page with < 50% load
if t.hitD != nil && t.hitD.c < kd && t.hitP != nil {
//println("refill")
t.refill(t.hitP, t.hitD, t.hitPi)
}
// data page not quickly found - search and descent from root
pi := -1
var p *x
......@@ -895,6 +907,12 @@ func (t *Tree) Put(k int, upd func(oldV int, exists bool) (newV int, write bool)
}
}
// don't leave previously active data page with < 50% load
if t.hitD != nil && t.hitD.c < kd && t.hitP != nil {
//println("refill")
t.refill(t.hitP, t.hitD, t.hitPi)
}
// data page not quickly found - search and descent from root
t.hitKminSet, t.hitKmaxSet = false, false // initially [-∞, +∞)
t.hitPKminSet, t.hitPKmaxSet = false, false
......@@ -984,13 +1002,19 @@ func (t *Tree) split(p *x, q *d, pi, i int, k int, v int) {
q.n = r
r.p = q
// don't copy on sequential bulk-set pattern
if i == 2*kd {
t.insert(r, 0, k, v)
} else {
copy(r.d[:], q.d[kd:2*kd])
for i := range q.d[kd:] {
q.d[kd+i] = zde
}
q.c = kd
r.c = kd
}
// XXX vs ^^^ (not adding elements)
if pi >= 0 {
p.insert(pi, r.d[0].k, r)
} else {
......@@ -1002,7 +1026,10 @@ func (t *Tree) split(p *x, q *d, pi, i int, k int, v int) {
}
if i > kd {
// XXX vvv try to merge with ^^^ t.insert(r, 0, k, v)
if i < 2*kd {
t.insert(r, i-kd, k, v)
}
t.setHitKmin(p.x[pi].k)
if pi+1 < p.c { // k=+∞ @p.c
t.setHitKmax(p.x[pi+1].k)
......@@ -1057,6 +1084,8 @@ func (t *Tree) underflow(p *x, q *d, pi int) {
t.ver++
l, r := p.siblings(pi)
// TODO don't move 1 elements for bulk-delete patterb (see split for bulk-set case)
if l != nil && l.c+q.c >= 2*kd {
l.mvR(q, 1)
p.x[pi-1].k = q.d[0].k
......@@ -1177,6 +1206,47 @@ func (t *Tree) underflowX(p *x, q *x, pi int, i int) (*x, int) {
return q, i
}
// refill refills data page to have >= 50% load taking data entries from siblings
// if siblings have not enough entries for such refill, the data page in question is concatenated into one of them.
// XXX naming -> fillup ?
func (t *Tree) refill(p *x, q *d, pi int) {
t.ver++
l, r := p.siblings(pi)
δl := 0
δr := 0
if l != nil {
δl = l.c - kd
}
if r != nil {
δr = r.c - kd
}
if q.c + δl + δr < kd {
// cannot refill - concatenate into l or r
if l != nil {
t.cat(p, l, q, pi-1)
} else {
t.cat(p, q, r, pi)
}
return
}
// refill from siblings
δ := kd - q.c
δl = δ * δl / (δl + δr)
δr = δ - δl
if δl != 0 {
l.mvR(q, δl)
p.x[pi-1].k = q.d[0].k
}
if δr != 0 {
q.mvL(r, δr)
p.x[pi].k = r.d[0].k
}
}
// ----------------------------------------------------------------- Enumerator
// Close recycles e to a pool for possible later reuse. No references to e
......
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