influxdb/tsdb/tsm1/reader_prefix_tree_test.go

121 lines
4.2 KiB
Go

package tsm1
import (
"bytes"
"fmt"
"reflect"
"testing"
"github.com/google/go-cmp/cmp"
)
func TestPrefixTree(t *testing.T) {
t.Run("Basic", func(t *testing.T) {
ranges := func(ns ...int64) (out []TimeRange) {
for _, n := range ns {
out = append(out, TimeRange{n, n})
}
return out
}
check := func(t *testing.T, tree *prefixTree, key string, exp []TimeRange) {
t.Helper()
got := tree.Search([]byte(key), nil)
if !reflect.DeepEqual(got, exp) {
t.Fatalf("bad search: %q:\n%v", key, cmp.Diff(got, exp))
}
}
tree := newPrefixTree()
tree.Append([]byte("abcdefghABCDEFGH"), ranges(1)...)
tree.Append([]byte("abcdefgh01234567"), ranges(2)...)
tree.Append([]byte("abcd"), ranges(3)...)
tree.Append([]byte("0123"), ranges(4)...)
tree.Append([]byte("abcdefghABCDEFGH-m1"), ranges(5)...)
tree.Append([]byte("abcdefghABCDEFGH-m1"), ranges(6)...)
tree.Append([]byte("abcdefgh01234567-m1"), ranges(7)...)
tree.Append([]byte("abcdefgh01234567-m1"), ranges(8)...)
tree.Append([]byte("abcdefgh"), ranges(9, 10)...)
check(t, tree, "abcd", ranges(3))
check(t, tree, "abcdefgh", ranges(3, 9, 10))
check(t, tree, "abcdefghABCDEFGH", ranges(3, 9, 10, 1))
check(t, tree, "abcdefghABCDEFGH-m1", ranges(3, 9, 10, 1, 5, 6))
check(t, tree, "abcdefgh01234567-m1", ranges(3, 9, 10, 2, 7, 8))
})
}
// Typical results on a 2018 MPB. Pay special attention to the
// 8 and 16 results as they are the most likely.
//
// BenchmarkPrefixTree/Append/0-8 300000000 5.93 ns/op
// BenchmarkPrefixTree/Append/4-8 20000000 93.7 ns/op
// BenchmarkPrefixTree/Append/8-8 100000000 12.9 ns/op
// BenchmarkPrefixTree/Append/12-8 20000000 100.0 ns/op
// BenchmarkPrefixTree/Append/16-8 100000000 20.4 ns/op
// BenchmarkPrefixTree/Append/20-8 20000000 111.0 ns/op
// BenchmarkPrefixTree/Append/24-8 50000000 28.5 ns/op
// BenchmarkPrefixTree/Append/28-8 20000000 118.0 ns/op
// BenchmarkPrefixTree/Append/32-8 50000000 35.8 ns/op
// BenchmarkPrefixTree/Search/Best/0-8 300000000 5.76 ns/op
// BenchmarkPrefixTree/Search/Best/4-8 20000000 102.0 ns/op
// BenchmarkPrefixTree/Search/Best/8-8 100000000 18.5 ns/op
// BenchmarkPrefixTree/Search/Best/12-8 20000000 116.0 ns/op
// BenchmarkPrefixTree/Search/Best/16-8 50000000 31.9 ns/op
// BenchmarkPrefixTree/Search/Best/20-8 10000000 131.0 ns/op
// BenchmarkPrefixTree/Search/Best/24-8 30000000 45.3 ns/op
// BenchmarkPrefixTree/Search/Best/28-8 10000000 142.0 ns/op
// BenchmarkPrefixTree/Search/Best/32-8 20000000 58.0 ns/op
// BenchmarkPrefixTree/Search/Worst/0-8 300000000 5.79 ns/op
// BenchmarkPrefixTree/Search/Worst/4-8 20000000 79.2 ns/op
// BenchmarkPrefixTree/Search/Worst/8-8 10000000 199.0 ns/op
// BenchmarkPrefixTree/Search/Worst/12-8 5000000 301.0 ns/op
// BenchmarkPrefixTree/Search/Worst/16-8 3000000 422.0 ns/op
// BenchmarkPrefixTree/Search/Worst/20-8 3000000 560.0 ns/op
// BenchmarkPrefixTree/Search/Worst/24-8 2000000 683.0 ns/op
// BenchmarkPrefixTree/Search/Worst/28-8 2000000 772.0 ns/op
// BenchmarkPrefixTree/Search/Worst/32-8 2000000 875.0 ns/op
func BenchmarkPrefixTree(b *testing.B) {
b.Run("Append", func(b *testing.B) {
run := func(b *testing.B, prefix []byte) {
tree := newPrefixTree()
for i := 0; i < b.N; i++ {
tree.Append(prefix)
}
}
for i := 0; i <= 32; i += 4 {
b.Run(fmt.Sprint(i), func(b *testing.B) { run(b, bytes.Repeat([]byte("0"), i)) })
}
})
b.Run("Search", func(b *testing.B) {
run := func(b *testing.B, worst bool) {
run := func(b *testing.B, key []byte) {
tree := newPrefixTree()
if worst {
for i := range key {
tree.Append(key[:i])
}
} else {
tree.Append(key)
}
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
tree.Search(key, nil)
}
}
for i := 0; i <= 32; i += 4 {
b.Run(fmt.Sprint(i), func(b *testing.B) { run(b, bytes.Repeat([]byte("0"), i)) })
}
}
b.Run("Best", func(b *testing.B) { run(b, false) })
b.Run("Worst", func(b *testing.B) { run(b, true) })
})
}