Commit 84c589d6 authored by Kirill Smelkov's avatar Kirill Smelkov

.

parents 3bddfd4e 15a07c50
...@@ -407,6 +407,71 @@ func TestPrealloc(*testing.T) { ...@@ -407,6 +407,71 @@ func TestPrealloc(*testing.T) {
r.Close() r.Close()
} }
func TestSplitXOnEdge(t *testing.T) {
// verify how splitX works when splitting X for k pointing directly at split edge
tr := TreeNew(cmp)
// one index page with 2*kx+2 elements (last has .k=∞ so x.c=2*kx+1)
// which will splitX on next Set
for i := 0; i <= (2*kx + 1) * 2*kd; i++ {
// odd keys are left to be filled in second test
tr.Set(2*i, 2*i)
}
x0 := tr.r.(*x)
if x0.c != 2*kx+1 {
t.Fatalf("x0.c: %v ; expected %v", x0.c, 2*kx+1)
}
// set element with k directly at x0[kx].k
kedge := 2 * (kx + 1) * (2*kd)
if x0.x[kx].k != kedge {
t.Fatalf("edge key before splitX: %v ; expected %v", x0.x[kx].k, kedge)
}
tr.Set(kedge, 777)
// if splitX was wrong kedge:777 would land into wrong place with Get failing
v, ok := tr.Get(kedge)
if !(v==777 && ok) {
t.Fatalf("after splitX: Get(%v) -> %v, %v ; expected 777, true", v, ok)
}
// now check the same when splitted X has parent
xr := tr.r.(*x)
if xr.c != 1 { // second x comes with k=∞ with .c index
t.Fatalf("after splitX: xr.c: %v ; expected 1", xr.c)
}
if xr.x[0].ch != x0 {
t.Fatal("xr[0].ch is not x0")
}
for i := 0; i <= (2*kx) * kd; i++ {
tr.Set(2*i+1, 2*i+1)
}
// check x0 is in pre-splitX condition and still at the right place
if x0.c != 2*kx+1 {
t.Fatalf("x0.c: %v ; expected %v", x0.c, 2*kx+1)
}
if xr.x[0].ch != x0 {
t.Fatal("xr[0].ch is not x0")
}
// set element with k directly at x0[kx].k
kedge = (kx + 1) * (2*kd)
if x0.x[kx].k != kedge {
t.Fatalf("edge key before splitX: %v ; expected %v", x0.x[kx].k, kedge)
}
tr.Set(kedge, 888)
// if splitX was wrong kedge:888 would land into wrong place
v, ok = tr.Get(kedge)
if !(v==888 && ok) {
t.Fatalf("after splitX: Get(%v) -> %v, %v ; expected 888, true", v, ok)
}
}
func BenchmarkSetSeq1e3(b *testing.B) { func BenchmarkSetSeq1e3(b *testing.B) {
benchmarkSetSeq(b, 1e3) benchmarkSetSeq(b, 1e3)
} }
......
...@@ -771,6 +771,9 @@ func (t *Tree) Set(k interface{} /*K*/, v interface{} /*V*/) { ...@@ -771,6 +771,9 @@ func (t *Tree) Set(k interface{} /*K*/, v interface{} /*V*/) {
switch x := q.(type) { switch x := q.(type) {
case *x: case *x:
//hitPKmax = hitKmax //hitPKmax = hitKmax
if ok {
i++
}
if x.c > 2*kx { if x.c > 2*kx {
//dbg("splitX") //dbg("splitX")
...@@ -798,9 +801,9 @@ func (t *Tree) Set(k interface{} /*K*/, v interface{} /*V*/) { ...@@ -798,9 +801,9 @@ func (t *Tree) Set(k interface{} /*K*/, v interface{} /*V*/) {
p = x p = x
pi = i pi = i
if ok { //if ok {
pi++ // pi++
} //}
q = p.x[pi].ch q = p.x[pi].ch
if pi > 0 { if pi > 0 {
...@@ -879,13 +882,14 @@ func (t *Tree) Put(k interface{} /*K*/, upd func(oldV interface{} /*V*/, exists ...@@ -879,13 +882,14 @@ func (t *Tree) Put(k interface{} /*K*/, upd func(oldV interface{} /*V*/, exists
if ok { if ok {
switch x := q.(type) { switch x := q.(type) {
case *x: case *x:
i++
if x.c > 2*kx { if x.c > 2*kx {
panic("TODO") panic("TODO")
x, i, _, _ = t.splitX(p, x, pi, i) x, i, _, _ = t.splitX(p, x, pi, i)
} }
pi = i + 1 pi = i
p = x p = x
q = x.x[i+1].ch q = x.x[i].ch
continue continue
case *d: case *d:
oldV = x.d[i].v oldV = x.d[i].v
...@@ -982,36 +986,23 @@ func (t *Tree) splitX(p *x, q *x, pi int, i int) (*x, int, *x, int) { ...@@ -982,36 +986,23 @@ func (t *Tree) splitX(p *x, q *x, pi int, i int) (*x, int, *x, int) {
r.c = kx r.c = kx
if pi >= 0 { if pi >= 0 {
p.insert(pi, q.x[kx].k, r) p.insert(pi, q.x[kx].k, r)
q.x[kx].k = zk } else {
for i := range q.x[kx+1:] { p = newX(q).insert(0, q.x[kx].k, r)
q.x[kx+i+1] = zxe pi = 0
} t.r = p
switch {
case i < kx:
return q, i, p, pi
case i == kx:
return p, pi, p, -1
default: // i > kx
return r, i - kx - 1, p, pi + 1
}
} }
nr := newX(q).insert(0, q.x[kx].k, r)
t.r = nr
q.x[kx].k = zk q.x[kx].k = zk
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 {
switch { q = r
case i < kx: i -= kx + 1
return q, i, nr, 0 pi++
case i == kx:
return nr, 0, nr, -1
default: // i > kx
return r, i - kx - 1, nr, 1
} }
return q, i, p, pi
} }
func (t *Tree) underflow(p *x, q *d, pi int) { func (t *Tree) underflow(p *x, q *d, pi int) {
......
...@@ -620,13 +620,13 @@ func TestEnumeratorPrev(t *testing.T) { ...@@ -620,13 +620,13 @@ func TestEnumeratorPrev(t *testing.T) {
hit bool hit bool
keys []int keys []int
}{ }{
{5, false, []int{10}}, {5, false, []int{}},
{10, true, []int{10}}, {10, true, []int{10}},
{15, false, []int{20, 10}}, {15, false, []int{10}},
{20, true, []int{20, 10}}, {20, true, []int{20, 10}},
{25, false, []int{30, 20, 10}}, {25, false, []int{20, 10}},
{30, true, []int{30, 20, 10}}, {30, true, []int{30, 20, 10}},
{35, false, []int{}}, {35, false, []int{30, 20, 10}},
} }
for i, test := range table { for i, test := range table {
...@@ -683,6 +683,51 @@ func TestEnumeratorPrev(t *testing.T) { ...@@ -683,6 +683,51 @@ func TestEnumeratorPrev(t *testing.T) {
} }
} }
func TestEnumeratorPrevSanity(t *testing.T) {
// seeking within 3 keys: 10, 20, 30
table := []struct {
k int
hit bool
kOut int
vOut int
errOut error
}{
{10, true, 10, 100, nil},
{20, true, 20, 200, nil},
{30, true, 30, 300, nil},
{35, false, 30, 300, nil},
{25, false, 20, 200, nil},
{15, false, 10, 100, nil},
{5, false, 0, 0, io.EOF},
}
for i, test := range table {
r := TreeNew(cmp)
r.Set(10, 100)
r.Set(20, 200)
r.Set(30, 300)
en, hit := r.Seek(test.k)
if g, e := hit, test.hit; g != e {
t.Fatal(i, g, e)
}
k, v, err := en.Prev()
if g, e := err, test.errOut; g != e {
t.Fatal(i, g, e)
}
if g, e := k, test.kOut; g != e {
t.Fatal(i, g, e)
}
if g, e := v, test.vOut; g != e {
t.Fatal(i, g, e)
}
}
}
func BenchmarkSeekSeq1e3(b *testing.B) { func BenchmarkSeekSeq1e3(b *testing.B) {
benchmarkSeekSeq(b, 1e3) benchmarkSeekSeq(b, 1e3)
} }
......
...@@ -547,12 +547,13 @@ func (t *Tree) Set(k int, v int) { ...@@ -547,12 +547,13 @@ func (t *Tree) Set(k int, v int) {
if ok { if ok {
switch x := q.(type) { switch x := q.(type) {
case *x: case *x:
i++
if x.c > 2*kx { if x.c > 2*kx {
x, i = t.splitX(p, x, pi, i) x, i = t.splitX(p, x, pi, i)
} }
pi = i + 1 pi = i
p = x p = x
q = x.x[i+1].ch q = x.x[i].ch
continue continue
case *d: case *d:
x.d[i].v = v x.d[i].v = v
...@@ -614,12 +615,13 @@ func (t *Tree) Put(k int, upd func(oldV int, exists bool) (newV int, write bool) ...@@ -614,12 +615,13 @@ func (t *Tree) Put(k int, upd func(oldV int, exists bool) (newV int, write bool)
if ok { if ok {
switch x := q.(type) { switch x := q.(type) {
case *x: case *x:
i++
if x.c > 2*kx { if x.c > 2*kx {
x, i = t.splitX(p, x, pi, i) x, i = t.splitX(p, x, pi, i)
} }
pi = i + 1 pi = i
p = x p = x
q = x.x[i+1].ch q = x.x[i].ch
continue continue
case *d: case *d:
oldV = x.d[i].v oldV = x.d[i].v
...@@ -701,36 +703,20 @@ func (t *Tree) splitX(p *x, q *x, pi int, i int) (*x, int) { ...@@ -701,36 +703,20 @@ func (t *Tree) splitX(p *x, q *x, pi int, i int) (*x, int) {
r.c = kx r.c = kx
if pi >= 0 { if pi >= 0 {
p.insert(pi, q.x[kx].k, r) p.insert(pi, q.x[kx].k, r)
q.x[kx].k = zk } else {
for i := range q.x[kx+1:] { t.r = newX(q).insert(0, q.x[kx].k, r)
q.x[kx+i+1] = zxe
}
switch {
case i < kx:
return q, i
case i == kx:
return p, pi
default: // i > kx
return r, i - kx - 1
}
} }
nr := newX(q).insert(0, q.x[kx].k, r)
t.r = nr
q.x[kx].k = zk q.x[kx].k = zk
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 {
switch { q = r
case i < kx: i -= kx + 1
return q, i
case i == kx:
return nr, 0
default: // i > kx
return r, 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) {
......
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