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

.

parents 3bddfd4e 15a07c50
......@@ -407,6 +407,71 @@ func TestPrealloc(*testing.T) {
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) {
benchmarkSetSeq(b, 1e3)
}
......
......@@ -771,6 +771,9 @@ func (t *Tree) Set(k interface{} /*K*/, v interface{} /*V*/) {
switch x := q.(type) {
case *x:
//hitPKmax = hitKmax
if ok {
i++
}
if x.c > 2*kx {
//dbg("splitX")
......@@ -798,9 +801,9 @@ func (t *Tree) Set(k interface{} /*K*/, v interface{} /*V*/) {
p = x
pi = i
if ok {
pi++
}
//if ok {
// pi++
//}
q = p.x[pi].ch
if pi > 0 {
......@@ -879,13 +882,14 @@ func (t *Tree) Put(k interface{} /*K*/, upd func(oldV interface{} /*V*/, exists
if ok {
switch x := q.(type) {
case *x:
i++
if x.c > 2*kx {
panic("TODO")
x, i, _, _ = t.splitX(p, x, pi, i)
}
pi = i + 1
pi = i
p = x
q = x.x[i+1].ch
q = x.x[i].ch
continue
case *d:
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) {
r.c = kx
if pi >= 0 {
p.insert(pi, q.x[kx].k, r)
q.x[kx].k = zk
for i := range q.x[kx+1:] {
q.x[kx+i+1] = zxe
}
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
}
} else {
p = newX(q).insert(0, q.x[kx].k, r)
pi = 0
t.r = p
}
nr := newX(q).insert(0, q.x[kx].k, r)
t.r = nr
q.x[kx].k = zk
for i := range q.x[kx+1:] {
q.x[kx+i+1] = zxe
}
switch {
case i < kx:
return q, i, nr, 0
case i == kx:
return nr, 0, nr, -1
default: // i > kx
return r, i - kx - 1, nr, 1
if i > kx {
q = r
i -= kx + 1
pi++
}
return q, i, p, pi
}
func (t *Tree) underflow(p *x, q *d, pi int) {
......
......@@ -620,13 +620,13 @@ func TestEnumeratorPrev(t *testing.T) {
hit bool
keys []int
}{
{5, false, []int{10}},
{5, false, []int{}},
{10, true, []int{10}},
{15, false, []int{20, 10}},
{15, false, []int{10}},
{20, true, []int{20, 10}},
{25, false, []int{30, 20, 10}},
{25, false, []int{20, 10}},
{30, true, []int{30, 20, 10}},
{35, false, []int{}},
{35, false, []int{30, 20, 10}},
}
for i, test := range table {
......@@ -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) {
benchmarkSeekSeq(b, 1e3)
}
......
......@@ -547,12 +547,13 @@ func (t *Tree) Set(k int, v int) {
if ok {
switch x := q.(type) {
case *x:
i++
if x.c > 2*kx {
x, i = t.splitX(p, x, pi, i)
}
pi = i + 1
pi = i
p = x
q = x.x[i+1].ch
q = x.x[i].ch
continue
case *d:
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)
if ok {
switch x := q.(type) {
case *x:
i++
if x.c > 2*kx {
x, i = t.splitX(p, x, pi, i)
}
pi = i + 1
pi = i
p = x
q = x.x[i+1].ch
q = x.x[i].ch
continue
case *d:
oldV = x.d[i].v
......@@ -701,36 +703,20 @@ func (t *Tree) splitX(p *x, q *x, pi int, i int) (*x, int) {
r.c = kx
if pi >= 0 {
p.insert(pi, q.x[kx].k, r)
q.x[kx].k = zk
for i := range q.x[kx+1:] {
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
}
} else {
t.r = newX(q).insert(0, q.x[kx].k, r)
}
nr := newX(q).insert(0, q.x[kx].k, r)
t.r = nr
q.x[kx].k = zk
for i := range q.x[kx+1:] {
q.x[kx+i+1] = zxe
}
switch {
case i < kx:
return q, i
case i == kx:
return nr, 0
default: // i > kx
return r, i - kx - 1
if i > kx {
q = r
i -= kx + 1
}
return q, i
}
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