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) { ...@@ -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 // data page not quickly found - search and descent from root
pi := -1 pi := -1
var p *x var p *x
...@@ -744,6 +750,12 @@ func (t *Tree) Set(k interface{} /*K*/, v interface{} /*V*/) { ...@@ -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 // data page not quickly found - search and descent from root
pi := -1 pi := -1
var p *x var p *x
...@@ -895,6 +907,12 @@ func (t *Tree) Put(k interface{} /*K*/, upd func(oldV interface{} /*V*/, exists ...@@ -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 // data page not quickly found - search and descent from root
t.hitKminSet, t.hitKmaxSet = false, false // initially [-∞, +∞) t.hitKminSet, t.hitKmaxSet = false, false // initially [-∞, +∞)
t.hitPKminSet, t.hitPKmaxSet = false, false 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{} / ...@@ -984,13 +1002,19 @@ func (t *Tree) split(p *x, q *d, pi, i int, k interface{} /*K*/, v interface{} /
q.n = r q.n = r
r.p = q r.p = q
copy(r.d[:], q.d[kd:2*kd]) // don't copy on sequential bulk-set pattern
for i := range q.d[kd:] { if i == 2*kd {
q.d[kd+i] = zde 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
} }
q.c = kd
r.c = kd
// XXX vs ^^^ (not adding elements)
if pi >= 0 { if pi >= 0 {
p.insert(pi, r.d[0].k, r) p.insert(pi, r.d[0].k, r)
} else { } else {
...@@ -1002,7 +1026,10 @@ func (t *Tree) split(p *x, q *d, pi, i int, k interface{} /*K*/, v interface{} / ...@@ -1002,7 +1026,10 @@ func (t *Tree) split(p *x, q *d, pi, i int, k interface{} /*K*/, v interface{} /
} }
if i > kd { if i > kd {
t.insert(r, i-kd, k, v) // 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) t.setHitKmin(p.x[pi].k)
if pi+1 < p.c { // k=+∞ @p.c if pi+1 < p.c { // k=+∞ @p.c
t.setHitKmax(p.x[pi+1].k) t.setHitKmax(p.x[pi+1].k)
...@@ -1057,6 +1084,8 @@ func (t *Tree) underflow(p *x, q *d, pi int) { ...@@ -1057,6 +1084,8 @@ func (t *Tree) underflow(p *x, q *d, pi int) {
t.ver++ t.ver++
l, r := p.siblings(pi) 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 { if l != nil && l.c+q.c >= 2*kd {
l.mvR(q, 1) l.mvR(q, 1)
p.x[pi-1].k = q.d[0].k 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) { ...@@ -1177,6 +1206,47 @@ func (t *Tree) underflowX(p *x, q *x, pi int, i int) (*x, int) {
return q, i 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 // ----------------------------------------------------------------- Enumerator
// Close recycles e to a pool for possible later reuse. No references to e // 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) { ...@@ -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 // data page not quickly found - search and descent from root
pi := -1 pi := -1
var p *x var p *x
...@@ -744,6 +750,12 @@ func (t *Tree) Set(k int, v int) { ...@@ -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 // data page not quickly found - search and descent from root
pi := -1 pi := -1
var p *x var p *x
...@@ -895,6 +907,12 @@ func (t *Tree) Put(k int, upd func(oldV int, exists bool) (newV int, write bool) ...@@ -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 // data page not quickly found - search and descent from root
t.hitKminSet, t.hitKmaxSet = false, false // initially [-∞, +∞) t.hitKminSet, t.hitKmaxSet = false, false // initially [-∞, +∞)
t.hitPKminSet, t.hitPKmaxSet = false, false 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) { ...@@ -984,13 +1002,19 @@ func (t *Tree) split(p *x, q *d, pi, i int, k int, v int) {
q.n = r q.n = r
r.p = q r.p = q
copy(r.d[:], q.d[kd:2*kd]) // don't copy on sequential bulk-set pattern
for i := range q.d[kd:] { if i == 2*kd {
q.d[kd+i] = zde 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
} }
q.c = kd
r.c = kd
// XXX vs ^^^ (not adding elements)
if pi >= 0 { if pi >= 0 {
p.insert(pi, r.d[0].k, r) p.insert(pi, r.d[0].k, r)
} else { } else {
...@@ -1002,7 +1026,10 @@ func (t *Tree) split(p *x, q *d, pi, i int, k int, v int) { ...@@ -1002,7 +1026,10 @@ func (t *Tree) split(p *x, q *d, pi, i int, k int, v int) {
} }
if i > kd { if i > kd {
t.insert(r, i-kd, k, v) // 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) t.setHitKmin(p.x[pi].k)
if pi+1 < p.c { // k=+∞ @p.c if pi+1 < p.c { // k=+∞ @p.c
t.setHitKmax(p.x[pi+1].k) t.setHitKmax(p.x[pi+1].k)
...@@ -1057,6 +1084,8 @@ func (t *Tree) underflow(p *x, q *d, pi int) { ...@@ -1057,6 +1084,8 @@ func (t *Tree) underflow(p *x, q *d, pi int) {
t.ver++ t.ver++
l, r := p.siblings(pi) 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 { if l != nil && l.c+q.c >= 2*kd {
l.mvR(q, 1) l.mvR(q, 1)
p.x[pi-1].k = q.d[0].k 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) { ...@@ -1177,6 +1206,47 @@ func (t *Tree) underflowX(p *x, q *x, pi int, i int) (*x, int) {
return q, i 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 // ----------------------------------------------------------------- Enumerator
// Close recycles e to a pool for possible later reuse. No references to e // 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