All checks were successful
DCO action / DCO (pull_request) Successful in 2m13s
Build / Build Components (1.20) (pull_request) Successful in 2m36s
Vulncheck / Vulncheck (pull_request) Successful in 3m1s
Build / Build Components (1.21) (pull_request) Successful in 4m7s
Tests and linters / Staticcheck (pull_request) Successful in 4m1s
Tests and linters / Tests (1.20) (pull_request) Successful in 6m13s
Tests and linters / Lint (pull_request) Successful in 7m12s
Tests and linters / Tests with -race (pull_request) Successful in 7m27s
Tests and linters / Tests (1.21) (pull_request) Successful in 2m30s
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
121 lines
3.2 KiB
Go
121 lines
3.2 KiB
Go
package tree
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/pilorama"
|
|
cidSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
|
cidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id/test"
|
|
"github.com/google/uuid"
|
|
"google.golang.org/grpc"
|
|
)
|
|
|
|
func BenchmarkGetSubTree(b *testing.B) {
|
|
const count = simpleHeapFallbackThreshold
|
|
|
|
d := pilorama.CIDDescriptor{CID: cidtest.ID(), Size: 1}
|
|
treeID := "sometree"
|
|
|
|
body := &GetSubTreeRequest_Body{
|
|
TreeId: treeID,
|
|
RootId: pilorama.RootID,
|
|
Depth: 2,
|
|
OrderBy: &GetSubTreeRequest_Body_Order{
|
|
Direction: GetSubTreeRequest_Body_Order_Asc,
|
|
},
|
|
}
|
|
p := newBenchPilorama(count)
|
|
|
|
b.Run("latency", func(b *testing.B) {
|
|
b.ReportAllocs()
|
|
for i := 0; i < b.N; i++ {
|
|
acc := benchServer{start: time.Now(), errIndex: count + 1}
|
|
err := getSubTree(context.Background(), &acc, d.CID, body, p)
|
|
if err != nil {
|
|
b.Fatalf("Error: %v, expected: %d, got %d", err, count, acc.seen)
|
|
}
|
|
b.ReportMetric(float64(uint64(acc.first)/uint64(b.N)), "ns/op")
|
|
}
|
|
})
|
|
b.Run("total time", func(b *testing.B) {
|
|
b.ReportAllocs()
|
|
for i := 0; i < b.N; i++ {
|
|
acc := benchServer{start: time.Now(), errIndex: count + 1}
|
|
err := getSubTree(context.Background(), &acc, d.CID, body, p)
|
|
if err != nil {
|
|
b.Fatalf("Error: %v, expected: %d, got %d", err, count, acc.seen)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
// benchPilorama represents flat pilorama, i.e. tree of height 2 with many child nodes.
|
|
type benchPilorama struct {
|
|
pilorama.Forest // Satisfy interface.
|
|
nodes []pilorama.NodeInfo
|
|
}
|
|
|
|
func newBenchPilorama(size int) *benchPilorama {
|
|
nodes := make([]pilorama.NodeInfo, 0, size)
|
|
|
|
for i := 1; i <= size; i++ { // Start with 1 to avoid intersecting with RootID = 0.
|
|
nodes = append(nodes, pilorama.NodeInfo{
|
|
ParentID: pilorama.RootID,
|
|
ID: pilorama.Node(i),
|
|
Meta: pilorama.Meta{
|
|
Items: []pilorama.KeyValue{{
|
|
Key: pilorama.AttributeFilename,
|
|
Value: []byte(uuid.New().String()),
|
|
}},
|
|
},
|
|
})
|
|
}
|
|
return &benchPilorama{nodes: nodes}
|
|
}
|
|
|
|
func (p *benchPilorama) TreeGetChildren(ctx context.Context, cid cidSDK.ID, treeID string, nodeID pilorama.Node) ([]pilorama.NodeInfo, error) {
|
|
switch nodeID {
|
|
case pilorama.RootID:
|
|
result := make([]pilorama.NodeInfo, len(p.nodes))
|
|
copy(result, p.nodes)
|
|
return result, nil
|
|
default:
|
|
panic("unexpected")
|
|
}
|
|
}
|
|
|
|
func (p *benchPilorama) TreeGetMeta(ctx context.Context, cid cidSDK.ID, treeID string, root pilorama.Node) (pilorama.Meta, pilorama.Node, error) {
|
|
if root == pilorama.RootID {
|
|
return pilorama.Meta{}, pilorama.RootID, nil
|
|
}
|
|
return p.nodes[root-1].Meta, p.nodes[root-1].ParentID, nil
|
|
}
|
|
|
|
type benchServer struct {
|
|
grpc.ServerStream // to satisfy the interface
|
|
start time.Time
|
|
first time.Duration
|
|
seen int
|
|
errIndex int
|
|
}
|
|
|
|
var _ TreeService_GetSubTreeServer = (*benchServer)(nil)
|
|
|
|
func (s *benchServer) Send(r *GetSubTreeResponse) error {
|
|
if s.seen == 1 {
|
|
s.first = time.Since(s.start)
|
|
}
|
|
s.seen++
|
|
|
|
if s.errIndex >= 0 {
|
|
if s.seen == s.errIndex+1 {
|
|
return errSubTreeSend
|
|
}
|
|
if s.errIndex >= 0 && s.seen > s.errIndex {
|
|
return errSubTreeSendAfterError
|
|
}
|
|
}
|
|
return nil
|
|
}
|