use singleflight when bucket metadata is reloaded() (#20216)

this allows for de-duplicating the callers when called
concurrently, allowing for bucketmetadata reads to be
single call. All concurrent callers will get the same data
as the first one.
This commit is contained in:
Harshavardhana 2024-08-05 09:50:11 -07:00 committed by GitHub
parent e3eb5c1328
commit dea9abed29
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 18 additions and 8 deletions

View File

@ -39,6 +39,7 @@ import (
"github.com/minio/minio/internal/logger" "github.com/minio/minio/internal/logger"
"github.com/minio/pkg/v3/policy" "github.com/minio/pkg/v3/policy"
"github.com/minio/pkg/v3/sync/errgroup" "github.com/minio/pkg/v3/sync/errgroup"
"golang.org/x/sync/singleflight"
) )
// BucketMetadataSys captures all bucket metadata for a given cluster. // BucketMetadataSys captures all bucket metadata for a given cluster.
@ -47,6 +48,7 @@ type BucketMetadataSys struct {
sync.RWMutex sync.RWMutex
initialized bool initialized bool
group *singleflight.Group
metadataMap map[string]BucketMetadata metadataMap map[string]BucketMetadata
} }
@ -62,6 +64,7 @@ func (sys *BucketMetadataSys) Count() int {
func (sys *BucketMetadataSys) Remove(buckets ...string) { func (sys *BucketMetadataSys) Remove(buckets ...string) {
sys.Lock() sys.Lock()
for _, bucket := range buckets { for _, bucket := range buckets {
sys.group.Forget(bucket)
delete(sys.metadataMap, bucket) delete(sys.metadataMap, bucket)
globalBucketMonitor.DeleteBucket(bucket) globalBucketMonitor.DeleteBucket(bucket)
} }
@ -154,8 +157,7 @@ func (sys *BucketMetadataSys) updateAndParse(ctx context.Context, bucket string,
return updatedAt, fmt.Errorf("Unknown bucket %s metadata update requested %s", bucket, configFile) return updatedAt, fmt.Errorf("Unknown bucket %s metadata update requested %s", bucket, configFile)
} }
err = sys.save(ctx, meta) return updatedAt, sys.save(ctx, meta)
return updatedAt, err
} }
func (sys *BucketMetadataSys) save(ctx context.Context, meta BucketMetadata) error { func (sys *BucketMetadataSys) save(ctx context.Context, meta BucketMetadata) error {
@ -451,13 +453,20 @@ func (sys *BucketMetadataSys) GetConfig(ctx context.Context, bucket string) (met
if ok { if ok {
return meta, reloaded, nil return meta, reloaded, nil
} }
val, err, _ := sys.group.Do(bucket, func() (val interface{}, err error) {
meta, err = loadBucketMetadata(ctx, objAPI, bucket) meta, err = loadBucketMetadata(ctx, objAPI, bucket)
if err != nil { if err != nil {
if !sys.Initialized() { if !sys.Initialized() {
// bucket metadata not yet initialized // bucket metadata not yet initialized
return newBucketMetadata(bucket), reloaded, errBucketMetadataNotInitialized return newBucketMetadata(bucket), errBucketMetadataNotInitialized
} }
return meta, reloaded, err }
return meta, err
})
meta, _ = val.(BucketMetadata)
if err != nil {
return meta, false, err
} }
sys.Lock() sys.Lock()
sys.metadataMap[bucket] = meta sys.metadataMap[bucket] = meta
@ -630,5 +639,6 @@ func (sys *BucketMetadataSys) Reset() {
func NewBucketMetadataSys() *BucketMetadataSys { func NewBucketMetadataSys() *BucketMetadataSys {
return &BucketMetadataSys{ return &BucketMetadataSys{
metadataMap: make(map[string]BucketMetadata), metadataMap: make(map[string]BucketMetadata),
group: &singleflight.Group{},
} }
} }