mirror of
https://github.com/dolthub/dolt.git
synced 2026-01-23 18:58:50 -06:00
219 lines
6.0 KiB
Go
219 lines
6.0 KiB
Go
// Copyright 2021 Dolthub, Inc.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package prolly
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/dolthub/dolt/go/store/prolly/message"
|
|
"github.com/dolthub/dolt/go/store/prolly/tree"
|
|
"github.com/dolthub/dolt/go/store/val"
|
|
)
|
|
|
|
func TestMutableMapReads(t *testing.T) {
|
|
scales := []int{
|
|
10,
|
|
100,
|
|
1000,
|
|
10_000,
|
|
}
|
|
|
|
for _, s := range scales {
|
|
name := fmt.Sprintf("test mutable map at scale %d", s)
|
|
t.Run(name, func(t *testing.T) {
|
|
|
|
mutableMap, tuples := makeMutableMap(t, s)
|
|
t.Run("get item from map", func(t *testing.T) {
|
|
testGet(t, mutableMap, tuples)
|
|
})
|
|
t.Run("iter all from map", func(t *testing.T) {
|
|
testIterAll(t, mutableMap, tuples)
|
|
})
|
|
t.Run("iter range", func(t *testing.T) {
|
|
testIterRange(t, mutableMap, tuples)
|
|
})
|
|
t.Run("iter prefix range", func(t *testing.T) {
|
|
testIterPrefixRange(t, mutableMap, tuples)
|
|
})
|
|
t.Run("iter ordinal range", func(t *testing.T) {
|
|
t.Skip("todo(andy)")
|
|
})
|
|
|
|
mutableIndex, idxTuples := makeMutableSecondaryIndex(t, s)
|
|
t.Run("iter prefix range", func(t *testing.T) {
|
|
testIterPrefixRange(t, mutableIndex, idxTuples)
|
|
})
|
|
|
|
mutableMap2, tuples2, deletes := deleteFromMutableMap(mutableMap.(*MutableMap), tuples)
|
|
t.Run("get item from map with deletes", func(t *testing.T) {
|
|
testMutableMapGetAndHas(t, mutableMap2, tuples2, deletes)
|
|
})
|
|
t.Run("iter all from map with deletes", func(t *testing.T) {
|
|
testIterAll(t, mutableMap2, tuples2)
|
|
})
|
|
t.Run("iter range with pending deletes", func(t *testing.T) {
|
|
testIterRange(t, mutableMap2, tuples2)
|
|
})
|
|
t.Run("iter ordinal range", func(t *testing.T) {
|
|
t.Skip("todo(andy)")
|
|
})
|
|
|
|
mutableIndex2, idxTuples2, _ := deleteFromMutableMap(mutableIndex.(*MutableMap), idxTuples)
|
|
t.Run("iter prefix range", func(t *testing.T) {
|
|
testIterPrefixRange(t, mutableIndex, idxTuples2)
|
|
})
|
|
|
|
prollyMap, err := mutableMap2.Map(context.Background())
|
|
require.NoError(t, err)
|
|
t.Run("get item from map after deletes applied", func(t *testing.T) {
|
|
testHas(t, prollyMap, tuples2)
|
|
})
|
|
t.Run("iter all from map after deletes applied", func(t *testing.T) {
|
|
testIterAll(t, prollyMap, tuples2)
|
|
})
|
|
t.Run("iter range after deletes applied", func(t *testing.T) {
|
|
testIterRange(t, prollyMap, tuples2)
|
|
})
|
|
t.Run("iter ordinal range", func(t *testing.T) {
|
|
t.Skip("todo(andy)")
|
|
})
|
|
|
|
prollyIndex, err := mutableIndex2.Map(context.Background())
|
|
require.NoError(t, err)
|
|
t.Run("iter prefix range", func(t *testing.T) {
|
|
testIterPrefixRange(t, prollyIndex, idxTuples2)
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestMutableMapFormat(t *testing.T) {
|
|
ctx := context.Background()
|
|
mutableMap, _ := makeMutableMap(t, 100)
|
|
s, err := debugFormat(ctx, mutableMap.(*MutableMap))
|
|
assert.NoError(t, err)
|
|
assert.NotEmpty(t, s)
|
|
}
|
|
|
|
func makeMutableMap(t *testing.T, count int) (testMap, [][2]val.Tuple) {
|
|
ctx := context.Background()
|
|
ns := tree.NewTestNodeStore()
|
|
|
|
kd := val.NewTupleDescriptor(
|
|
val.Type{Enc: val.Uint32Enc, Nullable: false},
|
|
)
|
|
vd := val.NewTupleDescriptor(
|
|
val.Type{Enc: val.Uint32Enc, Nullable: true},
|
|
val.Type{Enc: val.Uint32Enc, Nullable: true},
|
|
val.Type{Enc: val.Uint32Enc, Nullable: true},
|
|
)
|
|
|
|
tuples := tree.RandomTuplePairs(count, kd, vd, ns)
|
|
// 2/3 of tuples in Map
|
|
// 1/3 of tuples in memoryMap
|
|
clone := tree.CloneRandomTuples(tuples)
|
|
split := (count * 2) / 3
|
|
tree.ShuffleTuplePairs(clone)
|
|
|
|
mapTuples := clone[:split]
|
|
memTuples := clone[split:]
|
|
tree.SortTuplePairs(mapTuples, kd)
|
|
tree.SortTuplePairs(memTuples, kd)
|
|
|
|
serializer := message.NewProllyMapSerializer(vd, ns.Pool())
|
|
chunker, err := tree.NewEmptyChunker(ctx, ns, serializer)
|
|
require.NoError(t, err)
|
|
for _, pair := range mapTuples {
|
|
err = chunker.AddPair(ctx, tree.Item(pair[0]), tree.Item(pair[1]))
|
|
require.NoError(t, err)
|
|
}
|
|
root, err := chunker.Done(ctx)
|
|
require.NoError(t, err)
|
|
|
|
mut := newMutableMap(NewMap(root, ns, kd, vd))
|
|
|
|
for _, pair := range memTuples {
|
|
err = mut.Put(ctx, pair[0], pair[1])
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
return mut, tuples
|
|
}
|
|
|
|
func makeMutableSecondaryIndex(t *testing.T, count int) (testMap, [][2]val.Tuple) {
|
|
m, tuples := makeProllySecondaryIndex(t, count)
|
|
return newMutableMap(m.(Map)), tuples
|
|
}
|
|
|
|
func deleteFromMutableMap(mut *MutableMap, tt [][2]val.Tuple) (*MutableMap, [][2]val.Tuple, [][2]val.Tuple) {
|
|
count := len(tt)
|
|
testRand.Shuffle(count, func(i, j int) {
|
|
tt[i], tt[j] = tt[j], tt[i]
|
|
})
|
|
|
|
// delete 1/4 of tuples
|
|
deletes := tt[:count/4]
|
|
|
|
// re-sort the remaining tuples
|
|
remaining := tt[count/4:]
|
|
desc := keyDescFromMap(mut)
|
|
tree.SortTuplePairs(remaining, desc)
|
|
|
|
ctx := context.Background()
|
|
for _, kv := range deletes {
|
|
if err := mut.Delete(ctx, kv[0]); err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
return mut, remaining, deletes
|
|
}
|
|
|
|
func testMutableMapGetAndHas(t *testing.T, mut *MutableMap, tuples, deletes [][2]val.Tuple) {
|
|
ctx := context.Background()
|
|
for _, kv := range tuples {
|
|
ok, err := mut.Has(ctx, kv[0])
|
|
assert.True(t, ok)
|
|
require.NoError(t, err)
|
|
|
|
err = mut.Get(ctx, kv[0], func(key, val val.Tuple) (err error) {
|
|
assert.NotNil(t, kv[0])
|
|
assert.Equal(t, kv[0], key)
|
|
assert.Equal(t, kv[1], val)
|
|
return
|
|
})
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
for _, kv := range deletes {
|
|
ok, err := mut.Has(ctx, kv[0])
|
|
assert.False(t, ok)
|
|
require.NoError(t, err)
|
|
|
|
err = mut.Get(ctx, kv[0], func(key, value val.Tuple) (err error) {
|
|
assert.NotNil(t, kv[0])
|
|
assert.Equal(t, val.Tuple(nil), key)
|
|
assert.Equal(t, val.Tuple(nil), value)
|
|
return
|
|
})
|
|
require.NoError(t, err)
|
|
}
|
|
}
|