VictoriaMetrics/lib/mergeset/encoding_test.go
Aliaksandr Valialkin af5bdb9254
lib/mergeset: remove superflouos sorting of inmemoryBlock.data at inmemoryBlock.sort()
There is no need to sort the underlying data according to sorted items there.
This should reduce cpu usage when registering new time series in `indexdb`.

Thanks to @ahfuzhang for the suggestion at https://github.com/VictoriaMetrics/VictoriaMetrics/issues/2245
2022-02-24 11:20:32 +02:00

183 lines
4.5 KiB
Go

package mergeset
import (
"math/rand"
"reflect"
"sort"
"sync"
"testing"
"testing/quick"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
)
func TestInmemoryBlockAdd(t *testing.T) {
var ib inmemoryBlock
for i := 0; i < 30; i++ {
var items []string
totalLen := 0
ib.Reset()
// Fill ib.
for j := 0; j < i*100+1; j++ {
s := getRandomBytes()
if !ib.Add(s) {
// ib is full.
break
}
items = append(items, string(s))
totalLen += len(s)
}
// Verify all the items are added.
if len(ib.items) != len(items) {
t.Fatalf("unexpected number of items added; got %d; want %d", len(ib.items), len(items))
}
if len(ib.data) != totalLen {
t.Fatalf("unexpected ib.data len; got %d; want %d", len(ib.data), totalLen)
}
data := ib.data
for j, it := range ib.items {
item := it.String(data)
if items[j] != item {
t.Fatalf("unexpected item at index %d out of %d, loop %d\ngot\n%X\nwant\n%X", j, len(items), i, item, items[j])
}
}
}
}
func TestInmemoryBlockSort(t *testing.T) {
var ib inmemoryBlock
for i := 0; i < 100; i++ {
var items []string
totalLen := 0
ib.Reset()
// Fill ib.
for j := 0; j < rand.Intn(1500); j++ {
s := getRandomBytes()
if !ib.Add(s) {
// ib is full.
break
}
items = append(items, string(s))
totalLen += len(s)
}
// Sort ib.
sort.Sort(&ib)
sort.Strings(items)
// Verify items are sorted.
if len(ib.items) != len(items) {
t.Fatalf("unexpected number of items added; got %d; want %d", len(ib.items), len(items))
}
if len(ib.data) != totalLen {
t.Fatalf("unexpected ib.data len; got %d; want %d", len(ib.data), totalLen)
}
data := ib.data
for j, it := range ib.items {
item := it.String(data)
if items[j] != item {
t.Fatalf("unexpected item at index %d out of %d, loop %d\ngot\n%X\nwant\n%X", j, len(items), i, item, items[j])
}
}
}
}
func TestInmemoryBlockMarshalUnmarshal(t *testing.T) {
var ib, ib2 inmemoryBlock
var sb storageBlock
var firstItem, commonPrefix []byte
var itemsLen uint32
var mt marshalType
for i := 0; i < 1000; i++ {
var items []string
totalLen := 0
ib.Reset()
// Fill ib.
itemsCount := 2 * (rand.Intn(i+1) + 1)
for j := 0; j < itemsCount/2; j++ {
s := getRandomBytes()
s = []byte("prefix " + string(s))
if !ib.Add(s) {
// ib is full.
break
}
items = append(items, string(s))
totalLen += len(s)
s = getRandomBytes()
if !ib.Add(s) {
// ib is full
break
}
items = append(items, string(s))
totalLen += len(s)
}
// Marshal ib.
sort.Strings(items)
firstItem, commonPrefix, itemsLen, mt = ib.MarshalUnsortedData(&sb, firstItem[:0], commonPrefix[:0], 0)
if int(itemsLen) != len(ib.items) {
t.Fatalf("unexpected number of items marshaled; got %d; want %d", itemsLen, len(ib.items))
}
firstItemExpected := ib.items[0].String(ib.data)
if string(firstItem) != firstItemExpected {
t.Fatalf("unexpected the first item\ngot\n%q\nwant\n%q", firstItem, firstItemExpected)
}
if err := checkMarshalType(mt); err != nil {
t.Fatalf("invalid mt: %s", err)
}
// Unmarshal ib.
if err := ib2.UnmarshalData(&sb, firstItem, commonPrefix, itemsLen, mt); err != nil {
t.Fatalf("cannot unmarshal data for firstItem=%q, commonPrefix=%q, itemsLen=%d, mt=%d: %s",
firstItem, commonPrefix, itemsLen, mt, err)
}
// Verify all the items are sorted and unmarshaled.
if len(ib2.items) != len(items) {
t.Fatalf("unexpected number of items unmarshaled; got %d; want %d", len(ib2.items), len(items))
}
if len(ib2.data) != totalLen {
t.Fatalf("unexpected ib.data len; got %d; want %d", len(ib2.data), totalLen)
}
for j := range items {
it2 := ib2.items[j]
item2 := it2.String(ib2.data)
if len(items[j]) != len(item2) {
t.Fatalf("items length mismatch at index %d out of %d, loop %d\ngot\n(len=%d) %X\nwant\n(len=%d) %X",
j, len(items), i, len(item2), item2, len(items[j]), items[j])
}
}
for j, it := range ib2.items {
item := it.String(ib2.data)
if items[j] != string(item) {
t.Fatalf("unexpected item at index %d out of %d, loop %d\ngot\n(len=%d) %X\nwant\n(len=%d) %X",
j, len(items), i, len(item), item, len(items[j]), items[j])
}
}
}
}
func getRandomBytes() []byte {
rndLock.Lock()
iv, ok := quick.Value(bytesType, rnd)
rndLock.Unlock()
if !ok {
logger.Panicf("error in quick.Value when generating random string")
}
return iv.Interface().([]byte)
}
var bytesType = reflect.TypeOf([]byte(nil))
var (
rnd = rand.New(rand.NewSource(1))
rndLock sync.Mutex
)