diff --git a/pkg/local_object_storage/metabase/delete_test.go b/pkg/local_object_storage/metabase/delete_test.go new file mode 100644 index 00000000..712fbcbf --- /dev/null +++ b/pkg/local_object_storage/metabase/delete_test.go @@ -0,0 +1,66 @@ +package meta + +import ( + "os" + "testing" + + "github.com/nspcc-dev/neofs-api-go/pkg/object" + "github.com/stretchr/testify/require" + "go.etcd.io/bbolt" +) + +func BenchmarkDB_Delete(b *testing.B) { + path := "delete_test.db" + + bdb, err := bbolt.Open(path, 0600, nil) + require.NoError(b, err) + + defer func() { + bdb.Close() + os.Remove(path) + }() + + db := NewDB(bdb) + + var existingAddr *object.Address + + for i := 0; i < 10; i++ { + obj := generateObject(b, testPrm{}) + + existingAddr = obj.Address() + + require.NoError(b, db.Put(obj)) + } + + b.Run("existing address", func(b *testing.B) { + b.ReportAllocs() + b.ResetTimer() + + for i := 0; i < b.N; i++ { + err := db.Delete(existingAddr) + + b.StopTimer() + require.NoError(b, err) + b.StartTimer() + } + }) + + b.Run("non-existing address", func(b *testing.B) { + b.ReportAllocs() + b.ResetTimer() + + for i := 0; i < b.N; i++ { + b.StopTimer() + addr := object.NewAddress() + addr.SetContainerID(testCID()) + addr.SetObjectID(testOID()) + b.StartTimer() + + err := db.Delete(addr) + + b.StopTimer() + require.NoError(b, err) + b.StartTimer() + } + }) +} diff --git a/pkg/local_object_storage/metabase/get_test.go b/pkg/local_object_storage/metabase/get_test.go new file mode 100644 index 00000000..1d6dab77 --- /dev/null +++ b/pkg/local_object_storage/metabase/get_test.go @@ -0,0 +1,66 @@ +package meta + +import ( + "os" + "testing" + + "github.com/nspcc-dev/neofs-api-go/pkg/object" + "github.com/stretchr/testify/require" + "go.etcd.io/bbolt" +) + +func BenchmarkDB_Get(b *testing.B) { + path := "get_test.db" + + bdb, err := bbolt.Open(path, 0600, nil) + require.NoError(b, err) + + defer func() { + bdb.Close() + os.Remove(path) + }() + + db := NewDB(bdb) + + var existingAddr *object.Address + + for i := 0; i < 10; i++ { + obj := generateObject(b, testPrm{}) + + existingAddr = obj.Address() + + require.NoError(b, db.Put(obj)) + } + + b.Run("existing address", func(b *testing.B) { + b.ReportAllocs() + b.ResetTimer() + + for i := 0; i < b.N; i++ { + _, err := db.Get(existingAddr) + + b.StopTimer() + require.NoError(b, err) + b.StartTimer() + } + }) + + b.Run("non-existing address", func(b *testing.B) { + b.ReportAllocs() + b.ResetTimer() + + for i := 0; i < b.N; i++ { + b.StopTimer() + addr := object.NewAddress() + addr.SetContainerID(testCID()) + addr.SetObjectID(testOID()) + b.StartTimer() + + _, err := db.Get(addr) + + b.StopTimer() + require.Error(b, err) + b.StartTimer() + } + }) +} diff --git a/pkg/local_object_storage/metabase/put_test.go b/pkg/local_object_storage/metabase/put_test.go new file mode 100644 index 00000000..db315fc5 --- /dev/null +++ b/pkg/local_object_storage/metabase/put_test.go @@ -0,0 +1,145 @@ +package meta + +import ( + "crypto/rand" + "crypto/sha256" + "fmt" + "os" + "testing" + + "github.com/nspcc-dev/neofs-api-go/pkg" + objectSDK "github.com/nspcc-dev/neofs-api-go/pkg/object" + "github.com/nspcc-dev/neofs-api-go/pkg/owner" + "github.com/nspcc-dev/neofs-node/pkg/core/object" + "github.com/nspcc-dev/neofs-node/pkg/util/test" + "github.com/stretchr/testify/require" + "go.etcd.io/bbolt" +) + +type testPrm struct { + withParent bool + + attrNum int +} + +func (p testPrm) String() string { + return fmt.Sprintf("[with_parent:%t, attributes:%d]", + p.withParent, + p.attrNum, + ) +} + +func generateChecksum() *pkg.Checksum { + cs := pkg.NewChecksum() + + sh := [sha256.Size]byte{} + rand.Read(sh[:]) + + cs.SetSHA256(sh) + + return cs +} + +func generateObject(t require.TestingT, prm testPrm) *object.Object { + obj := object.NewRaw() + obj.SetID(testOID()) + obj.SetVersion(pkg.SDKVersion()) + obj.SetContainerID(testCID()) + obj.SetChildren(testOID()) + obj.SetPreviousID(testOID()) + obj.SetParentID(testOID()) + obj.SetPayloadChecksum(generateChecksum()) + obj.SetPayloadHomomorphicHash(generateChecksum()) + obj.SetType(objectSDK.TypeRegular) + + as := make([]*objectSDK.Attribute, 0, prm.attrNum) + + for i := 0; i < prm.attrNum; i++ { + a := objectSDK.NewAttribute() + + k := make([]byte, 32) + rand.Read(k) + a.SetKey(string(k)) + + v := make([]byte, 32) + rand.Read(v) + a.SetValue(string(v)) + + as = append(as, a) + } + + obj.SetAttributes(as...) + + wallet, err := owner.NEO3WalletFromPublicKey(&test.DecodeKey(-1).PublicKey) + require.NoError(t, err) + + ownerID := owner.NewID() + ownerID.SetNeo3Wallet(wallet) + + obj.SetOwnerID(ownerID) + + if prm.withParent { + prm.withParent = false + obj.SetParent(generateObject(t, prm).SDK()) + } + + return obj.Object() +} + +func BenchmarkDB_Put(b *testing.B) { + path := "put_test.db" + + bdb, err := bbolt.Open(path, 0600, nil) + require.NoError(b, err) + + defer func() { + bdb.Close() + os.Remove(path) + }() + + db := NewDB(bdb) + + for _, prm := range []testPrm{ + { + withParent: false, + attrNum: 0, + }, + { + withParent: true, + attrNum: 0, + }, + { + withParent: false, + attrNum: 100, + }, + { + withParent: true, + attrNum: 100, + }, + { + withParent: false, + attrNum: 1000, + }, + { + withParent: true, + attrNum: 1000, + }, + } { + b.Run(prm.String(), func(b *testing.B) { + b.ReportAllocs() + b.ResetTimer() + + for i := 0; i < b.N; i++ { + b.StopTimer() + obj := generateObject(b, prm) + b.StartTimer() + + err := db.Put(obj) + + b.StopTimer() + require.NoError(b, err) + b.StartTimer() + } + }) + } +} diff --git a/pkg/local_object_storage/metabase/select_test.go b/pkg/local_object_storage/metabase/select_test.go new file mode 100644 index 00000000..94b93907 --- /dev/null +++ b/pkg/local_object_storage/metabase/select_test.go @@ -0,0 +1,100 @@ +package meta + +import ( + "crypto/rand" + "os" + "testing" + + objectSDK "github.com/nspcc-dev/neofs-api-go/pkg/object" + "github.com/stretchr/testify/require" + "go.etcd.io/bbolt" +) + +func addNFilters(fs *objectSDK.SearchFilters, n int) { + for i := 0; i < n; i++ { + key := make([]byte, 32) + rand.Read(key) + + val := make([]byte, 32) + rand.Read(val) + + fs.AddFilter(string(key), string(val), objectSDK.MatchStringEqual) + } +} + +func BenchmarkDB_Select(b *testing.B) { + path := "select_test.db" + + bdb, err := bbolt.Open(path, 0600, nil) + require.NoError(b, err) + + defer func() { + bdb.Close() + os.Remove(path) + }() + + db := NewDB(bdb) + + for i := 0; i < 100; i++ { + obj := generateObject(b, testPrm{ + withParent: true, + attrNum: 100, + }) + + require.NoError(b, db.Put(obj)) + } + + for _, item := range []struct { + name string + filters func(*objectSDK.SearchFilters) + }{ + { + name: "empty", + filters: func(*objectSDK.SearchFilters) { + return + }, + }, + { + name: "1 filter", + filters: func(fs *objectSDK.SearchFilters) { + addNFilters(fs, 1) + }, + }, + { + name: "10 filters", + filters: func(fs *objectSDK.SearchFilters) { + addNFilters(fs, 10) + }, + }, + { + name: "100 filters", + filters: func(fs *objectSDK.SearchFilters) { + addNFilters(fs, 100) + }, + }, + { + name: "1000 filters", + filters: func(fs *objectSDK.SearchFilters) { + addNFilters(fs, 1000) + }, + }, + } { + b.Run(item.name, func(b *testing.B) { + b.ReportAllocs() + b.ResetTimer() + + for i := 0; i < b.N; i++ { + b.StopTimer() + fs := new(objectSDK.SearchFilters) + item.filters(fs) + b.StartTimer() + + _, err := db.Select(*fs) + + b.StopTimer() + require.NoError(b, err) + b.StartTimer() + } + }) + } +}