Airat Arifullin
221203beeb
All checks were successful
ci/woodpecker/push/pre-commit Pipeline was successful
* Replace panics in unit tests by require.NoError and t.Fatalf Signed-off-by: Airat Arifullin <a.arifullin@yadro.com>
234 lines
6.5 KiB
Go
234 lines
6.5 KiB
Go
package blobstor
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"testing"
|
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/blobovniczatree"
|
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/common"
|
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/fstree"
|
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/memstore"
|
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/internal/testutil"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
// The storages to benchmark. Each storage has a description and a function which returns the actual
|
|
// storage along with a cleanup function.
|
|
var storages = []struct {
|
|
desc string
|
|
create func(*testing.B) (common.Storage, func())
|
|
}{
|
|
{
|
|
desc: "memstore",
|
|
create: func(*testing.B) (common.Storage, func()) {
|
|
return memstore.New(), func() {}
|
|
},
|
|
},
|
|
{
|
|
desc: "fstree_nosync",
|
|
create: func(b *testing.B) (common.Storage, func()) {
|
|
dir, err := os.MkdirTemp(os.TempDir(), "fstree_nosync")
|
|
if err != nil {
|
|
b.Fatalf("creating fstree_nosync root path: %v", err)
|
|
}
|
|
cleanup := func() { os.RemoveAll(dir) }
|
|
return fstree.New(
|
|
fstree.WithPath(dir),
|
|
fstree.WithDepth(2),
|
|
fstree.WithDirNameLen(2),
|
|
fstree.WithNoSync(true),
|
|
), cleanup
|
|
},
|
|
},
|
|
{
|
|
desc: "fstree",
|
|
create: func(b *testing.B) (common.Storage, func()) {
|
|
dir, err := os.MkdirTemp(os.TempDir(), "fstree")
|
|
if err != nil {
|
|
b.Fatalf("creating fstree root path: %v", err)
|
|
}
|
|
cleanup := func() { os.RemoveAll(dir) }
|
|
return fstree.New(
|
|
fstree.WithPath(dir),
|
|
fstree.WithDepth(2),
|
|
fstree.WithDirNameLen(2),
|
|
), cleanup
|
|
},
|
|
},
|
|
{
|
|
desc: "blobovniczatree",
|
|
create: func(b *testing.B) (common.Storage, func()) {
|
|
dir, err := os.MkdirTemp(os.TempDir(), "blobovniczatree")
|
|
if err != nil {
|
|
b.Fatalf("creating blobovniczatree root path: %v", err)
|
|
}
|
|
cleanup := func() { os.RemoveAll(dir) }
|
|
return blobovniczatree.NewBlobovniczaTree(
|
|
blobovniczatree.WithRootPath(dir),
|
|
), cleanup
|
|
},
|
|
},
|
|
}
|
|
|
|
func BenchmarkSubstorageReadPerf(b *testing.B) {
|
|
readTests := []struct {
|
|
desc string
|
|
size int
|
|
objGen func() testutil.ObjectGenerator
|
|
addrGen func() testutil.AddressGenerator
|
|
}{
|
|
{
|
|
desc: "seq100",
|
|
size: 10000,
|
|
objGen: func() testutil.ObjectGenerator { return &testutil.SeqObjGenerator{ObjSize: 100} },
|
|
addrGen: func() testutil.AddressGenerator { return &testutil.SeqAddrGenerator{MaxID: 100} },
|
|
},
|
|
{
|
|
desc: "rand100",
|
|
size: 10000,
|
|
objGen: func() testutil.ObjectGenerator { return &testutil.SeqObjGenerator{ObjSize: 100} },
|
|
addrGen: func() testutil.AddressGenerator { return testutil.RandAddrGenerator(10000) },
|
|
},
|
|
}
|
|
for _, tt := range readTests {
|
|
for _, stEntry := range storages {
|
|
b.Run(fmt.Sprintf("%s-%s", stEntry.desc, tt.desc), func(b *testing.B) {
|
|
objGen := tt.objGen()
|
|
st, cleanup := stEntry.create(b)
|
|
|
|
require.NoError(b, st.Open(false))
|
|
require.NoError(b, st.Init())
|
|
|
|
// Fill database
|
|
for i := 0; i < tt.size; i++ {
|
|
obj := objGen.Next()
|
|
addr := testutil.AddressFromObject(b, obj)
|
|
raw, err := obj.Marshal()
|
|
require.NoError(b, err)
|
|
if _, err := st.Put(common.PutPrm{
|
|
Address: addr,
|
|
RawData: raw,
|
|
}); err != nil {
|
|
b.Fatalf("writing entry: %v", err)
|
|
}
|
|
}
|
|
|
|
// Benchmark reading
|
|
addrGen := tt.addrGen()
|
|
b.ResetTimer()
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
for pb.Next() {
|
|
_, err := st.Get(common.GetPrm{Address: addrGen.Next()})
|
|
require.NoError(b, err)
|
|
}
|
|
})
|
|
|
|
require.NoError(b, st.Close())
|
|
cleanup()
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
func BenchmarkSubstorageWritePerf(b *testing.B) {
|
|
generators := []struct {
|
|
desc string
|
|
create func() testutil.ObjectGenerator
|
|
}{
|
|
{desc: "rand10", create: func() testutil.ObjectGenerator { return &testutil.RandObjGenerator{ObjSize: 10} }},
|
|
{desc: "rand100", create: func() testutil.ObjectGenerator { return &testutil.RandObjGenerator{ObjSize: 100} }},
|
|
{desc: "rand1000", create: func() testutil.ObjectGenerator { return &testutil.RandObjGenerator{ObjSize: 1000} }},
|
|
{desc: "overwrite10", create: func() testutil.ObjectGenerator { return &testutil.OverwriteObjGenerator{ObjSize: 10, MaxObjects: 100} }},
|
|
{desc: "overwrite100", create: func() testutil.ObjectGenerator { return &testutil.OverwriteObjGenerator{ObjSize: 100, MaxObjects: 100} }},
|
|
{desc: "overwrite1000", create: func() testutil.ObjectGenerator {
|
|
return &testutil.OverwriteObjGenerator{ObjSize: 1000, MaxObjects: 100}
|
|
}},
|
|
}
|
|
|
|
for _, genEntry := range generators {
|
|
for _, stEntry := range storages {
|
|
b.Run(fmt.Sprintf("%s-%s", stEntry.desc, genEntry.desc), func(b *testing.B) {
|
|
gen := genEntry.create()
|
|
st, cleanup := stEntry.create(b)
|
|
|
|
require.NoError(b, st.Open(false))
|
|
require.NoError(b, st.Init())
|
|
|
|
b.ResetTimer()
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
for pb.Next() {
|
|
obj := gen.Next()
|
|
addr := testutil.AddressFromObject(b, obj)
|
|
raw, err := obj.Marshal()
|
|
require.NoError(b, err)
|
|
if _, err := st.Put(common.PutPrm{
|
|
Address: addr,
|
|
RawData: raw,
|
|
}); err != nil {
|
|
b.Fatalf("writing entry: %v", err)
|
|
}
|
|
}
|
|
})
|
|
|
|
require.NoError(b, st.Close())
|
|
cleanup()
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
func BenchmarkSubstorageIteratePerf(b *testing.B) {
|
|
iterateTests := []struct {
|
|
desc string
|
|
size int
|
|
objGen func() testutil.ObjectGenerator
|
|
}{
|
|
{
|
|
desc: "rand100",
|
|
size: 10000,
|
|
objGen: func() testutil.ObjectGenerator { return &testutil.RandObjGenerator{ObjSize: 100} },
|
|
},
|
|
}
|
|
for _, tt := range iterateTests {
|
|
for _, stEntry := range storages {
|
|
b.Run(fmt.Sprintf("%s-%s", stEntry.desc, tt.desc), func(b *testing.B) {
|
|
objGen := tt.objGen()
|
|
st, cleanup := stEntry.create(b)
|
|
|
|
require.NoError(b, st.Open(false))
|
|
require.NoError(b, st.Init())
|
|
|
|
// Fill database
|
|
for i := 0; i < tt.size; i++ {
|
|
obj := objGen.Next()
|
|
addr := testutil.AddressFromObject(b, obj)
|
|
raw, err := obj.Marshal()
|
|
require.NoError(b, err)
|
|
if _, err := st.Put(common.PutPrm{
|
|
Address: addr,
|
|
RawData: raw,
|
|
}); err != nil {
|
|
b.Fatalf("writing entry: %v", err)
|
|
}
|
|
}
|
|
|
|
// Benchmark iterate
|
|
cnt := 0
|
|
b.ResetTimer()
|
|
_, err := st.Iterate(common.IteratePrm{
|
|
Handler: func(elem common.IterationElement) error {
|
|
cnt++
|
|
return nil
|
|
},
|
|
})
|
|
require.NoError(b, err)
|
|
require.Equal(b, tt.size, cnt)
|
|
b.StopTimer()
|
|
|
|
require.NoError(b, st.Close())
|
|
cleanup()
|
|
})
|
|
}
|
|
}
|
|
}
|