Commit 5aafa674 authored by Jan Mercl's avatar Jan Mercl

Lower GC presure by recycling things.

parent d2d7ab5c
.PHONY: all todo clean cover generic .PHONY: all todo clean cover generic mem nuke
testbin=b.test
all: editor all: editor
go build go build
...@@ -11,12 +13,6 @@ editor: ...@@ -11,12 +13,6 @@ editor:
go test -i go test -i
go test go test
todo:
@grep -n ^[[:space:]]*_[[:space:]]*=[[:space:]][[:alpha:]][[:alnum:]]* *.go || true
@grep -n TODO *.go || true
@grep -n BUG *.go || true
@grep -n println *.go || true
clean: clean:
@go clean @go clean
rm -f *~ rm -f *~
...@@ -31,3 +27,17 @@ generic: ...@@ -31,3 +27,17 @@ generic:
@# Intended use is to replace all textual occurrences of KEY or VALUE in @# Intended use is to replace all textual occurrences of KEY or VALUE in
@# the output with your desired types. @# the output with your desired types.
@sed -e 's|interface{}[^{]*/\*K\*/|KEY|g' -e 's|interface{}[^{]*/\*V\*/|VALUE|g' btree.go @sed -e 's|interface{}[^{]*/\*K\*/|KEY|g' -e 's|interface{}[^{]*/\*V\*/|VALUE|g' btree.go
mem:
go test -c
./$(testbin) -test.bench . -test.memprofile mem.out -test.memprofilerate 1
go tool pprof --lines --web --alloc_space $(testbin) mem.out
nuke: clean
rm -f *.test *.out
todo:
@grep -n ^[[:space:]]*_[[:space:]]*=[[:space:]][[:alpha:]][[:alnum:]]* *.go || true
@grep -n TODO *.go || true
@grep -n BUG *.go || true
@grep -n println *.go || true
// Copyright 2013 The Go Authors. All rights reserved. // Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
...@@ -279,6 +279,8 @@ func benchmarkSetSeq(b *testing.B, n int) { ...@@ -279,6 +279,8 @@ func benchmarkSetSeq(b *testing.B, n int) {
for j := 0; j < n; j++ { for j := 0; j < n; j++ {
r.Set(j, j) r.Set(j, j)
} }
b.StopTimer()
r.Close()
} }
b.StopTimer() b.StopTimer()
} }
...@@ -312,6 +314,7 @@ func benchmarkGetSeq(b *testing.B, n int) { ...@@ -312,6 +314,7 @@ func benchmarkGetSeq(b *testing.B, n int) {
} }
} }
b.StopTimer() b.StopTimer()
r.Close()
} }
func BenchmarkSetRnd1e3(b *testing.B) { func BenchmarkSetRnd1e3(b *testing.B) {
...@@ -345,6 +348,8 @@ func benchmarkSetRnd(b *testing.B, n int) { ...@@ -345,6 +348,8 @@ func benchmarkSetRnd(b *testing.B, n int) {
for _, v := range a { for _, v := range a {
r.Set(v, 0) r.Set(v, 0)
} }
b.StopTimer()
r.Close()
} }
b.StopTimer() b.StopTimer()
} }
...@@ -383,6 +388,7 @@ func benchmarkGetRnd(b *testing.B, n int) { ...@@ -383,6 +388,7 @@ func benchmarkGetRnd(b *testing.B, n int) {
} }
} }
b.StopTimer() b.StopTimer()
r.Close()
} }
func TestSetGet2(t *testing.T) { func TestSetGet2(t *testing.T) {
...@@ -557,19 +563,19 @@ func TestDelete1(t *testing.T) { ...@@ -557,19 +563,19 @@ func TestDelete1(t *testing.T) {
} }
} }
func benchmarkDelSeq1e3(b *testing.B) { func BenchmarkDelSeq1e3(b *testing.B) {
benchmarkDelSeq(b, 1e3) benchmarkDelSeq(b, 1e3)
} }
func benchmarkDelSeq1e4(b *testing.B) { func BenchmarkDelSeq1e4(b *testing.B) {
benchmarkDelSeq(b, 1e4) benchmarkDelSeq(b, 1e4)
} }
func benchmarkDelSeq1e5(b *testing.B) { func BenchmarkDelSeq1e5(b *testing.B) {
benchmarkDelSeq(b, 1e5) benchmarkDelSeq(b, 1e5)
} }
func benchmarkDelSeq1e6(b *testing.B) { func BenchmarkDelSeq1e6(b *testing.B) {
benchmarkDelSeq(b, 1e6) benchmarkDelSeq(b, 1e6)
} }
...@@ -624,6 +630,8 @@ func benchmarkDelRnd(b *testing.B, n int) { ...@@ -624,6 +630,8 @@ func benchmarkDelRnd(b *testing.B, n int) {
for _, v := range a { for _, v := range a {
r.Delete(v) r.Delete(v)
} }
b.StopTimer()
r.Close()
} }
b.StopTimer() b.StopTimer()
} }
...@@ -821,8 +829,11 @@ func benchmarkSeekSeq(b *testing.B, n int) { ...@@ -821,8 +829,11 @@ func benchmarkSeekSeq(b *testing.B, n int) {
debug.FreeOSMemory() debug.FreeOSMemory()
b.StartTimer() b.StartTimer()
for j := 0; j < n; j++ { for j := 0; j < n; j++ {
t.Seek(j) e, _ := t.Seek(j)
e.Close()
} }
b.StopTimer()
t.Close()
} }
b.StopTimer() b.StopTimer()
} }
...@@ -857,9 +868,12 @@ func benchmarkSeekRnd(b *testing.B, n int) { ...@@ -857,9 +868,12 @@ func benchmarkSeekRnd(b *testing.B, n int) {
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
for _, v := range a { for _, v := range a {
r.Seek(v) e, _ := r.Seek(v)
e.Close()
} }
} }
b.StopTimer()
r.Close()
} }
func BenchmarkNext1e3(b *testing.B) { func BenchmarkNext1e3(b *testing.B) {
...@@ -902,6 +916,8 @@ func benchmarkNext(b *testing.B, n int) { ...@@ -902,6 +916,8 @@ func benchmarkNext(b *testing.B, n int) {
b.Fatal(m) b.Fatal(m)
} }
} }
b.StopTimer()
t.Close()
} }
func BenchmarkPrev1e3(b *testing.B) { func BenchmarkPrev1e3(b *testing.B) {
......
This diff is collapsed.
.PHONY: all todo clean cover .PHONY: all todo clean cover mem
testbin=b.test
all: editor all: editor
go build go build
...@@ -10,6 +12,11 @@ editor: ...@@ -10,6 +12,11 @@ editor:
go test -i go test -i
go test go test
mem:
go test -c
./$(testbin) -test.bench . -test.memprofile mem.out -test.memprofilerate 1
go tool pprof --lines --web --alloc_space $(testbin) mem.out
todo: todo:
@grep -n ^[[:space:]]*_[[:space:]]*=[[:space:]][[:alpha:]][[:alnum:]]* *.go || true @grep -n ^[[:space:]]*_[[:space:]]*=[[:space:]][[:alpha:]][[:alnum:]]* *.go || true
@grep -n TODO *.go || true @grep -n TODO *.go || true
......
// Copyright 2013 The Go Authors. All rights reserved. // Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
...@@ -131,10 +131,6 @@ func TestSetGet1(t *testing.T) { ...@@ -131,10 +131,6 @@ func TestSetGet1(t *testing.T) {
} }
} }
func BenchmarkSetSeq1e2(b *testing.B) {
benchmarkSetSeq(b, 1e2)
}
func BenchmarkSetSeq1e3(b *testing.B) { func BenchmarkSetSeq1e3(b *testing.B) {
benchmarkSetSeq(b, 1e3) benchmarkSetSeq(b, 1e3)
} }
...@@ -161,14 +157,12 @@ func benchmarkSetSeq(b *testing.B, n int) { ...@@ -161,14 +157,12 @@ func benchmarkSetSeq(b *testing.B, n int) {
for j := 0; j < n; j++ { for j := 0; j < n; j++ {
r.Set(j, j) r.Set(j, j)
} }
b.StopTimer()
r.Close()
} }
b.StopTimer() b.StopTimer()
} }
func BenchmarkGetSeq1e2(b *testing.B) {
benchmarkGetSeq(b, 1e2)
}
func BenchmarkGetSeq1e3(b *testing.B) { func BenchmarkGetSeq1e3(b *testing.B) {
benchmarkGetSeq(b, 1e3) benchmarkGetSeq(b, 1e3)
} }
...@@ -198,10 +192,7 @@ func benchmarkGetSeq(b *testing.B, n int) { ...@@ -198,10 +192,7 @@ func benchmarkGetSeq(b *testing.B, n int) {
} }
} }
b.StopTimer() b.StopTimer()
} r.Close()
func BenchmarkSetRnd1e2(b *testing.B) {
benchmarkSetRnd(b, 1e2)
} }
func BenchmarkSetRnd1e3(b *testing.B) { func BenchmarkSetRnd1e3(b *testing.B) {
...@@ -235,14 +226,12 @@ func benchmarkSetRnd(b *testing.B, n int) { ...@@ -235,14 +226,12 @@ func benchmarkSetRnd(b *testing.B, n int) {
for _, v := range a { for _, v := range a {
r.Set(v, 0) r.Set(v, 0)
} }
b.StopTimer()
r.Close()
} }
b.StopTimer() b.StopTimer()
} }
func BenchmarkGetRnd1e2(b *testing.B) {
benchmarkGetRnd(b, 1e2)
}
func BenchmarkGetRnd1e3(b *testing.B) { func BenchmarkGetRnd1e3(b *testing.B) {
benchmarkGetRnd(b, 1e3) benchmarkGetRnd(b, 1e3)
} }
...@@ -277,6 +266,7 @@ func benchmarkGetRnd(b *testing.B, n int) { ...@@ -277,6 +266,7 @@ func benchmarkGetRnd(b *testing.B, n int) {
} }
} }
b.StopTimer() b.StopTimer()
r.Close()
} }
func TestSetGet2(t *testing.T) { func TestSetGet2(t *testing.T) {
...@@ -451,23 +441,19 @@ func TestDelete1(t *testing.T) { ...@@ -451,23 +441,19 @@ func TestDelete1(t *testing.T) {
} }
} }
func benchmarkDelSeq1e2(b *testing.B) { func BenchmarkDelSeq1e3(b *testing.B) {
benchmarkDelSeq(b, 1e2)
}
func benchmarkDelSeq1e3(b *testing.B) {
benchmarkDelSeq(b, 1e3) benchmarkDelSeq(b, 1e3)
} }
func benchmarkDelSeq1e4(b *testing.B) { func BenchmarkDelSeq1e4(b *testing.B) {
benchmarkDelSeq(b, 1e4) benchmarkDelSeq(b, 1e4)
} }
func benchmarkDelSeq1e5(b *testing.B) { func BenchmarkDelSeq1e5(b *testing.B) {
benchmarkDelSeq(b, 1e5) benchmarkDelSeq(b, 1e5)
} }
func benchmarkDelSeq1e6(b *testing.B) { func BenchmarkDelSeq1e6(b *testing.B) {
benchmarkDelSeq(b, 1e6) benchmarkDelSeq(b, 1e6)
} }
...@@ -484,14 +470,12 @@ func benchmarkDelSeq(b *testing.B, n int) { ...@@ -484,14 +470,12 @@ func benchmarkDelSeq(b *testing.B, n int) {
for j := 0; j < n; j++ { for j := 0; j < n; j++ {
r.Delete(j) r.Delete(j)
} }
b.StopTimer()
r.Close()
} }
b.StopTimer() b.StopTimer()
} }
func BenchmarkDelRnd1e2(b *testing.B) {
benchmarkDelRnd(b, 1e2)
}
func BenchmarkDelRnd1e3(b *testing.B) { func BenchmarkDelRnd1e3(b *testing.B) {
benchmarkDelRnd(b, 1e3) benchmarkDelRnd(b, 1e3)
} }
...@@ -526,6 +510,8 @@ func benchmarkDelRnd(b *testing.B, n int) { ...@@ -526,6 +510,8 @@ func benchmarkDelRnd(b *testing.B, n int) {
for _, v := range a { for _, v := range a {
r.Delete(v) r.Delete(v)
} }
b.StopTimer()
r.Close()
} }
b.StopTimer() b.StopTimer()
} }
...@@ -697,10 +683,6 @@ func TestEnumeratorPrev(t *testing.T) { ...@@ -697,10 +683,6 @@ func TestEnumeratorPrev(t *testing.T) {
} }
} }
func BenchmarkSeekSeq1e2(b *testing.B) {
benchmarkSeekSeq(b, 1e2)
}
func BenchmarkSeekSeq1e3(b *testing.B) { func BenchmarkSeekSeq1e3(b *testing.B) {
benchmarkSeekSeq(b, 1e3) benchmarkSeekSeq(b, 1e3)
} }
...@@ -727,16 +709,15 @@ func benchmarkSeekSeq(b *testing.B, n int) { ...@@ -727,16 +709,15 @@ func benchmarkSeekSeq(b *testing.B, n int) {
debug.FreeOSMemory() debug.FreeOSMemory()
b.StartTimer() b.StartTimer()
for j := 0; j < n; j++ { for j := 0; j < n; j++ {
t.Seek(j) e, _ := t.Seek(j)
e.Close()
} }
b.StopTimer()
t.Close()
} }
b.StopTimer() b.StopTimer()
} }
func BenchmarkSeekRnd1e2(b *testing.B) {
benchmarkSeekRnd(b, 1e2)
}
func BenchmarkSeekRnd1e3(b *testing.B) { func BenchmarkSeekRnd1e3(b *testing.B) {
benchmarkSeekRnd(b, 1e3) benchmarkSeekRnd(b, 1e3)
} }
...@@ -767,13 +748,12 @@ func benchmarkSeekRnd(b *testing.B, n int) { ...@@ -767,13 +748,12 @@ func benchmarkSeekRnd(b *testing.B, n int) {
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
for _, v := range a { for _, v := range a {
r.Seek(v) e, _ := r.Seek(v)
e.Close()
} }
} }
} b.StopTimer()
r.Close()
func BenchmarkNext1e2(b *testing.B) {
benchmarkNext(b, 1e2)
} }
func BenchmarkNext1e3(b *testing.B) { func BenchmarkNext1e3(b *testing.B) {
...@@ -816,10 +796,8 @@ func benchmarkNext(b *testing.B, n int) { ...@@ -816,10 +796,8 @@ func benchmarkNext(b *testing.B, n int) {
b.Fatal(m) b.Fatal(m)
} }
} }
} b.StopTimer()
t.Close()
func BenchmarkPrev1e2(b *testing.B) {
benchmarkPrev(b, 1e2)
} }
func BenchmarkPrev1e3(b *testing.B) { func BenchmarkPrev1e3(b *testing.B) {
...@@ -862,6 +840,8 @@ func benchmarkPrev(b *testing.B, n int) { ...@@ -862,6 +840,8 @@ func benchmarkPrev(b *testing.B, n int) {
b.Fatal(m) b.Fatal(m)
} }
} }
b.StopTimer()
t.Close()
} }
func TestSeekFirst0(t *testing.T) { func TestSeekFirst0(t *testing.T) {
......
// Copyright 2013 The Go Authors. All rights reserved. // Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
...@@ -8,10 +8,9 @@ package b ...@@ -8,10 +8,9 @@ package b
import ( import (
"fmt" "fmt"
"io" "io"
"sync"
) )
//TODO check vs orig initialize/finalize
const ( const (
kx = 32 //TODO benchmark tune this number if using custom key/value type(s). kx = 32 //TODO benchmark tune this number if using custom key/value type(s).
kd = 32 //TODO benchmark tune this number if using custom key/value type(s). kd = 32 //TODO benchmark tune this number if using custom key/value type(s).
...@@ -27,6 +26,29 @@ func init() { ...@@ -27,6 +26,29 @@ func init() {
} }
} }
var (
btDPool = sync.Pool{New: func() interface{} { return &d{} }}
btEPool = btEpool{sync.Pool{New: func() interface{} { return &Enumerator{} }}}
btTPool = btTpool{sync.Pool{New: func() interface{} { return &Tree{} }}}
btXPool = sync.Pool{New: func() interface{} { return &x{} }}
)
type btTpool struct{ sync.Pool }
func (p *btTpool) get(cmp Cmp) *Tree {
x := p.Get().(*Tree)
x.cmp = cmp
return x
}
type btEpool struct{ sync.Pool }
func (p *btEpool) get(err error, hit bool, i int, k int, q *d, t *Tree, ver int64) *Enumerator {
x := p.Get().(*Enumerator)
x.err, x.hit, x.i, x.k, x.q, x.t, x.ver = err, hit, i, k, q, t, ver
return x
}
type ( type (
// Cmp compares a and b. Return value is: // Cmp compares a and b. Return value is:
// //
...@@ -90,9 +112,11 @@ type ( ...@@ -90,9 +112,11 @@ type (
var ( // R/O zero values var ( // R/O zero values
zd d zd d
zde de zde de
ze Enumerator
zk int
zt Tree
zx x zx x
zxe xe zxe xe
zk int
) )
func clr(q interface{}) { func clr(q interface{}) {
...@@ -101,16 +125,18 @@ func clr(q interface{}) { ...@@ -101,16 +125,18 @@ func clr(q interface{}) {
for i := 0; i <= x.c; i++ { // Ch0 Sep0 ... Chn-1 Sepn-1 Chn for i := 0; i <= x.c; i++ { // Ch0 Sep0 ... Chn-1 Sepn-1 Chn
clr(x.x[i].ch) clr(x.x[i].ch)
} }
*x = zx // GC *x = zx
btXPool.Put(x)
case *d: case *d:
*x = zd // GC *x = zd
btDPool.Put(x)
} }
} }
// -------------------------------------------------------------------------- x // -------------------------------------------------------------------------- x
func newX(ch0 interface{}) *x { func newX(ch0 interface{}) *x {
r := &x{} r := btXPool.Get().(*x)
r.x[0].ch = ch0 r.x[0].ch = ch0
return r return r
} }
...@@ -172,7 +198,7 @@ func (l *d) mvR(r *d, c int) { ...@@ -172,7 +198,7 @@ func (l *d) mvR(r *d, c int) {
// TreeNew returns a newly created, empty Tree. The compare function is used // TreeNew returns a newly created, empty Tree. The compare function is used
// for key collation. // for key collation.
func TreeNew(cmp Cmp) *Tree { func TreeNew(cmp Cmp) *Tree {
return &Tree{cmp: cmp} return btTPool.get(cmp)
} }
// Clear removes all K/V pairs from the tree. // Clear removes all K/V pairs from the tree.
...@@ -186,6 +212,14 @@ func (t *Tree) Clear() { ...@@ -186,6 +212,14 @@ func (t *Tree) Clear() {
t.ver++ t.ver++
} }
// Close performs Clear and recycles t to a pool for possible later reuse. No
// references to t should exist or such references must not be used afterwards.
func (t *Tree) Close() {
t.Clear()
*t = zt
btTPool.Put(t)
}
func (t *Tree) cat(p *x, q, r *d, pi int) { func (t *Tree) cat(p *x, q, r *d, pi int) {
t.ver++ t.ver++
q.mvL(r, r.c) q.mvL(r, r.c)
...@@ -194,11 +228,21 @@ func (t *Tree) cat(p *x, q, r *d, pi int) { ...@@ -194,11 +228,21 @@ func (t *Tree) cat(p *x, q, r *d, pi int) {
} else { } else {
t.last = q t.last = q
} }
q.n = r.n //TODO recycle r q.n = r.n
*r = zd
btDPool.Put(r)
if p.c > 1 { if p.c > 1 {
p.extract(pi) p.extract(pi)
p.x[pi].ch = q p.x[pi].ch = q
} else { //TODO recycle r } else {
switch x := t.r.(type) {
case *x:
*x = zx
btXPool.Put(x)
case *d:
*x = zd
btDPool.Put(x)
}
t.r = q t.r = q
} }
} }
...@@ -208,7 +252,9 @@ func (t *Tree) catX(p, q, r *x, pi int) { ...@@ -208,7 +252,9 @@ func (t *Tree) catX(p, q, r *x, pi int) {
q.x[q.c].k = p.x[pi].k q.x[q.c].k = p.x[pi].k
copy(q.x[q.c+1:], r.x[:r.c]) copy(q.x[q.c+1:], r.x[:r.c])
q.c += r.c + 1 q.c += r.c + 1
q.x[q.c].ch = r.x[r.c].ch //TODO recycle r q.x[q.c].ch = r.x[r.c].ch
*r = zx
btXPool.Put(r)
if p.c > 1 { if p.c > 1 {
p.c-- p.c--
pc := p.c pc := p.c
...@@ -222,7 +268,15 @@ func (t *Tree) catX(p, q, r *x, pi int) { ...@@ -222,7 +268,15 @@ func (t *Tree) catX(p, q, r *x, pi int) {
return return
} }
t.r = q //TODO recycle r switch x := t.r.(type) {
case *x:
*x = zx
btXPool.Put(x)
case *d:
*x = zd
btDPool.Put(x)
}
t.r = q
} }
// Delete removes the k's KV pair, if it exists, in which case Delete returns // Delete removes the k's KV pair, if it exists, in which case Delete returns
...@@ -242,7 +296,7 @@ func (t *Tree) Delete(k int) (ok bool) { ...@@ -242,7 +296,7 @@ func (t *Tree) Delete(k int) (ok bool) {
switch x := q.(type) { switch x := q.(type) {
case *x: case *x:
if x.c < kx && q != t.r { if x.c < kx && q != t.r {
t.underflowX(p, &x, pi, &i) x, i = t.underflowX(p, x, pi, i)
} }
pi = i + 1 pi = i + 1
p = x p = x
...@@ -267,7 +321,7 @@ func (t *Tree) Delete(k int) (ok bool) { ...@@ -267,7 +321,7 @@ func (t *Tree) Delete(k int) (ok bool) {
switch x := q.(type) { switch x := q.(type) {
case *x: case *x:
if x.c < kx && q != t.r { if x.c < kx && q != t.r {
t.underflowX(p, &x, pi, &i) x, i = t.underflowX(p, x, pi, i)
} }
pi = i pi = i
p = x p = x
...@@ -424,7 +478,7 @@ func (t *Tree) overflow(p *x, q *d, pi, i int, k int, v int) { ...@@ -424,7 +478,7 @@ func (t *Tree) overflow(p *x, q *d, pi, i int, k int, v int) {
func (t *Tree) Seek(k int) (e *Enumerator, ok bool) { func (t *Tree) Seek(k int) (e *Enumerator, ok bool) {
q := t.r q := t.r
if q == nil { if q == nil {
e = &Enumerator{nil, false, 0, k, nil, t, t.ver} e = btEPool.get(nil, false, 0, k, nil, t, t.ver)
return return
} }
...@@ -436,16 +490,15 @@ func (t *Tree) Seek(k int) (e *Enumerator, ok bool) { ...@@ -436,16 +490,15 @@ func (t *Tree) Seek(k int) (e *Enumerator, ok bool) {
q = x.x[i+1].ch q = x.x[i+1].ch
continue continue
case *d: case *d:
e = &Enumerator{nil, ok, i, k, x, t, t.ver} return btEPool.get(nil, ok, i, k, x, t, t.ver), true
return
} }
} }
switch x := q.(type) { switch x := q.(type) {
case *x: case *x:
q = x.x[i].ch q = x.x[i].ch
case *d: case *d:
e = &Enumerator{nil, ok, i, k, x, t, t.ver} return btEPool.get(nil, ok, i, k, x, t, t.ver), false
return
} }
} }
} }
...@@ -458,7 +511,7 @@ func (t *Tree) SeekFirst() (e *Enumerator, err error) { ...@@ -458,7 +511,7 @@ func (t *Tree) SeekFirst() (e *Enumerator, err error) {
return nil, io.EOF return nil, io.EOF
} }
return &Enumerator{nil, true, 0, q.d[0].k, q, t, t.ver}, nil return btEPool.get(nil, true, 0, q.d[0].k, q, t, t.ver), nil
} }
// SeekLast returns an enumerator positioned on the last KV pair in the tree, // SeekLast returns an enumerator positioned on the last KV pair in the tree,
...@@ -469,7 +522,7 @@ func (t *Tree) SeekLast() (e *Enumerator, err error) { ...@@ -469,7 +522,7 @@ func (t *Tree) SeekLast() (e *Enumerator, err error) {
return nil, io.EOF return nil, io.EOF
} }
return &Enumerator{nil, true, q.c - 1, q.d[q.c-1].k, q, t, t.ver}, nil return btEPool.get(nil, true, q.c-1, q.d[q.c-1].k, q, t, t.ver), nil
} }
// Set sets the value associated with k. // Set sets the value associated with k.
...@@ -482,7 +535,7 @@ func (t *Tree) Set(k int, v int) { ...@@ -482,7 +535,7 @@ func (t *Tree) Set(k int, v int) {
var p *x var p *x
q := t.r q := t.r
if q == nil { if q == nil {
z := t.insert(&d{}, 0, k, v) z := t.insert(btDPool.Get().(*d), 0, k, v)
t.r, t.first, t.last = z, z, z t.r, t.first, t.last = z, z, z
return return
} }
...@@ -493,7 +546,7 @@ func (t *Tree) Set(k int, v int) { ...@@ -493,7 +546,7 @@ func (t *Tree) Set(k int, v int) {
switch x := q.(type) { switch x := q.(type) {
case *x: case *x:
if x.c > 2*kx { if x.c > 2*kx {
t.splitX(p, &x, pi, &i) x, i = t.splitX(p, x, pi, i)
} }
pi = i + 1 pi = i + 1
p = x p = x
...@@ -508,7 +561,7 @@ func (t *Tree) Set(k int, v int) { ...@@ -508,7 +561,7 @@ func (t *Tree) Set(k int, v int) {
switch x := q.(type) { switch x := q.(type) {
case *x: case *x:
if x.c > 2*kx { if x.c > 2*kx {
t.splitX(p, &x, pi, &i) x, i = t.splitX(p, x, pi, i)
} }
pi = i pi = i
p = x p = x
...@@ -549,7 +602,7 @@ func (t *Tree) Put(k int, upd func(oldV int, exists bool) (newV int, write bool) ...@@ -549,7 +602,7 @@ func (t *Tree) Put(k int, upd func(oldV int, exists bool) (newV int, write bool)
switch x := q.(type) { switch x := q.(type) {
case *x: case *x:
if x.c > 2*kx { if x.c > 2*kx {
t.splitX(p, &x, pi, &i) x, i = t.splitX(p, x, pi, i)
} }
pi = i + 1 pi = i + 1
p = x p = x
...@@ -570,7 +623,7 @@ func (t *Tree) Put(k int, upd func(oldV int, exists bool) (newV int, write bool) ...@@ -570,7 +623,7 @@ func (t *Tree) Put(k int, upd func(oldV int, exists bool) (newV int, write bool)
switch x := q.(type) { switch x := q.(type) {
case *x: case *x:
if x.c > 2*kx { if x.c > 2*kx {
t.splitX(p, &x, pi, &i) x, i = t.splitX(p, x, pi, i)
} }
pi = i pi = i
p = x p = x
...@@ -598,14 +651,14 @@ func (t *Tree) Put(k int, upd func(oldV int, exists bool) (newV int, write bool) ...@@ -598,14 +651,14 @@ func (t *Tree) Put(k int, upd func(oldV int, exists bool) (newV int, write bool)
return return
} }
z := t.insert(&d{}, 0, k, newV) z := t.insert(btDPool.Get().(*d), 0, k, newV)
t.r, t.first, t.last = z, z, z t.r, t.first, t.last = z, z, z
return return
} }
func (t *Tree) split(p *x, q *d, pi, i int, k int, v int) { func (t *Tree) split(p *x, q *d, pi, i int, k int, v int) {
t.ver++ t.ver++
r := &d{} r := btDPool.Get().(*d)
if q.n != nil { if q.n != nil {
r.n = q.n r.n = q.n
r.n.p = r r.n.p = r
...@@ -638,10 +691,9 @@ func (t *Tree) split(p *x, q *d, pi, i int, k int, v int) { ...@@ -638,10 +691,9 @@ func (t *Tree) split(p *x, q *d, pi, i int, k int, v int) {
t.insert(q, i, k, v) t.insert(q, i, k, v)
} }
func (t *Tree) splitX(p *x, pp **x, pi int, i *int) { func (t *Tree) splitX(p *x, q *x, pi int, i int) (*x, int) {
t.ver++ t.ver++
q := *pp r := btXPool.Get().(*x)
r := &x{}
copy(r.x[:], q.x[kx+1:]) copy(r.x[:], q.x[kx+1:])
q.c = kx q.c = kx
r.c = kx r.c = kx
...@@ -654,10 +706,11 @@ func (t *Tree) splitX(p *x, pp **x, pi int, i *int) { ...@@ -654,10 +706,11 @@ func (t *Tree) splitX(p *x, pp **x, pi int, i *int) {
for i := range q.x[kx+1:] { for i := range q.x[kx+1:] {
q.x[kx+i+1] = zxe q.x[kx+i+1] = zxe
} }
if *i > kx { if i > kx {
*pp = r q = r
*i -= kx + 1 i -= kx + 1
} }
return q, i
} }
func (t *Tree) underflow(p *x, q *d, pi int) { func (t *Tree) underflow(p *x, q *d, pi int) {
...@@ -678,10 +731,9 @@ func (t *Tree) underflow(p *x, q *d, pi int) { ...@@ -678,10 +731,9 @@ func (t *Tree) underflow(p *x, q *d, pi int) {
} }
} }
func (t *Tree) underflowX(p *x, pp **x, pi int, i *int) { func (t *Tree) underflowX(p *x, q *x, pi int, i int) (*x, int) {
t.ver++ t.ver++
var l, r *x var l, r *x
q := *pp
if pi >= 0 { if pi >= 0 {
if pi > 0 { if pi > 0 {
...@@ -698,10 +750,10 @@ func (t *Tree) underflowX(p *x, pp **x, pi int, i *int) { ...@@ -698,10 +750,10 @@ func (t *Tree) underflowX(p *x, pp **x, pi int, i *int) {
q.x[0].ch = l.x[l.c].ch q.x[0].ch = l.x[l.c].ch
q.x[0].k = p.x[pi-1].k q.x[0].k = p.x[pi-1].k
q.c++ q.c++
*i++ i++
l.c-- l.c--
p.x[pi-1].k = l.x[l.c].k p.x[pi-1].k = l.x[l.c].k
return return q, i
} }
if r != nil && r.c > kx { if r != nil && r.c > kx {
...@@ -715,21 +767,29 @@ func (t *Tree) underflowX(p *x, pp **x, pi int, i *int) { ...@@ -715,21 +767,29 @@ func (t *Tree) underflowX(p *x, pp **x, pi int, i *int) {
r.x[rc].ch = r.x[rc+1].ch r.x[rc].ch = r.x[rc+1].ch
r.x[rc].k = zk r.x[rc].k = zk
r.x[rc+1].ch = nil r.x[rc+1].ch = nil
return return q, i
} }
if l != nil { if l != nil {
*i += l.c + 1 i += l.c + 1
t.catX(p, l, q, pi-1) t.catX(p, l, q, pi-1)
*pp = l q = l
return return q, i
} }
t.catX(p, q, r, pi) t.catX(p, q, r, pi)
return q, i
} }
// ----------------------------------------------------------------- Enumerator // ----------------------------------------------------------------- Enumerator
// Close recycles e to a pool for possible later reuse. No references to e
// should exist or such references must not be used afterwards.
func (e *Enumerator) Close() {
*e = ze
btEPool.Put(e)
}
// Next returns the currently enumerated item, if it exists and moves to the // Next returns the currently enumerated item, if it exists and moves to the
// next item in the key collation order. If there is no item to return, err == // next item in the key collation order. If there is no item to return, err ==
// io.EOF is returned. // io.EOF is returned.
...@@ -747,6 +807,7 @@ func (e *Enumerator) Next() (k int, v int, err error) { ...@@ -747,6 +807,7 @@ func (e *Enumerator) Next() (k int, v int, err error) {
} }
*e = *f *e = *f
f.Close()
} }
if e.q == nil { if e.q == nil {
e.err, err = io.EOF, io.EOF e.err, err = io.EOF, io.EOF
...@@ -800,6 +861,7 @@ func (e *Enumerator) Prev() (k int, v int, err error) { ...@@ -800,6 +861,7 @@ func (e *Enumerator) Prev() (k int, v int, err error) {
} }
*e = *f *e = *f
f.Close()
} }
if e.q == nil { if e.q == nil {
e.err, err = io.EOF, io.EOF e.err, err = io.EOF, io.EOF
......
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