mirror of
https://github.com/pgsty/minio.git
synced 2026-10-17 15:16:00 +03:00
4ed86dfe62
Signed-off-by: Feng Ruohang <rh@vonng.com>
86 lines
2.7 KiB
Go
86 lines
2.7 KiB
Go
// Copyright (c) 2026 Ruohang Feng
|
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
|
|
package cmd
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"sync/atomic"
|
|
"testing"
|
|
)
|
|
|
|
// Run explicitly with -benchtime=1x. Fixture creation is excluded from timing;
|
|
// each request still discovers real on-disk metadata. The 16-drive/10k case
|
|
// deliberately exceeds the existing aggregate directory-entry budget.
|
|
func BenchmarkMultipartListingCapacity(b *testing.B) {
|
|
for _, tc := range []struct {
|
|
drives, uploads int
|
|
mixed, limited bool
|
|
}{
|
|
{4, 1_000, false, false},
|
|
{4, 10_000, false, false},
|
|
{4, 10_000, true, false},
|
|
{16, 1_000, false, false},
|
|
{16, 10_000, false, true},
|
|
} {
|
|
b.Run(fmt.Sprintf("drives=%d/uploads=%d/mixed=%t", tc.drives, tc.uploads, tc.mixed), func(b *testing.B) {
|
|
obj, dirs, err := prepareErasure(b.Context(), tc.drives)
|
|
if err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
z := obj.(*erasureServerPools)
|
|
b.Cleanup(func() { z.Shutdown(context.Background()); removeRoots(dirs) })
|
|
const bucket, other = "multipart-capacity", "multipart-unrelated"
|
|
for _, name := range []string{bucket, other} {
|
|
if err := z.MakeBucket(b.Context(), name, MakeBucketOptions{}); err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
}
|
|
for n := range tc.uploads {
|
|
target := bucket
|
|
if tc.mixed && n%2 != 0 {
|
|
target = other
|
|
}
|
|
key := fmt.Sprintf("dir/%05d", n)
|
|
mp, err := z.NewMultipartUpload(b.Context(), target, key, ObjectOptions{})
|
|
if err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
if tc.mixed && n%10 == 0 {
|
|
rewriteMultipartIdentity(b, z.serverPools[0].getHashedSet(key), target, key, mp.UploadID, removeMultipartIdentity)
|
|
}
|
|
}
|
|
z.mpCache.Clear()
|
|
var directoryCalls, metadataCalls atomic.Int64
|
|
for _, set := range z.serverPools[0].sets {
|
|
original := set.getDisks
|
|
set.getDisks = func() []StorageAPI {
|
|
disks := append([]StorageAPI(nil), original()...)
|
|
for i, disk := range disks {
|
|
disks[i] = multipartListingCountingDisk{disk, &directoryCalls, &metadataCalls}
|
|
}
|
|
return disks
|
|
}
|
|
b.Cleanup(func() { set.getDisks = original })
|
|
}
|
|
b.ResetTimer()
|
|
for range b.N {
|
|
got, err := z.ListMultipartUploads(b.Context(), bucket, "dir/", "", "", "", 1000)
|
|
if tc.limited {
|
|
var limited SlowDown
|
|
if !errors.As(err, &limited) || len(got.Uploads) != 0 {
|
|
b.Fatalf("overflow must return SlowDown without a partial page: %+v %v", got, err)
|
|
}
|
|
} else if err != nil || len(got.Uploads) != 1000 {
|
|
b.Fatalf("capacity listing: count=%d err=%v", len(got.Uploads), err)
|
|
}
|
|
}
|
|
b.StopTimer()
|
|
b.ReportMetric(float64(directoryCalls.Load())/float64(b.N), "ListDir/op")
|
|
b.ReportMetric(float64(metadataCalls.Load())/float64(b.N), "ReadVersion/op")
|
|
})
|
|
}
|
|
}
|