mirror of https://github.com/minio/minio.git
cache disk info to avoid repeated calls (#9682)
This value is requested on every upload when there are multiple zones. Since this will result in an RPC call to every remote disk this scales quite badly in a distributed setup. Load every 1second interval. 2 servers, localhost only. In large distributed setups much bigger gains can be expected. ``` Operations: 21743 -> 22454 * Average: +3.28% (+0.0 MiB/s) throughput, +3.28% (+11.9) obj/s * Fastest: +3.37% (+0.0 MiB/s) throughput, +3.37% (+13.0) obj/s * 50% Median: +3.03% (+0.0 MiB/s) throughput, +3.03% (+11.2) obj/s * Slowest: +8.03% (+0.0 MiB/s) throughput, +8.03% (+22.8) obj/s ``` For easy management of this a generic helper has been added.
This commit is contained in:
parent
de6c286258
commit
95814359bd
57
cmd/utils.go
57
cmd/utils.go
|
@ -631,3 +631,60 @@ func iamPolicyClaimNameOpenID() string {
|
|||
func iamPolicyClaimNameSA() string {
|
||||
return "sa-policy"
|
||||
}
|
||||
|
||||
// timedValue contains a synchronized value that is considered valid
|
||||
// for a specific amount of time.
|
||||
// An Update function must be set to provide an updated value when needed.
|
||||
type timedValue struct {
|
||||
// Update must return an updated value.
|
||||
// If an error is returned the cached value is not set.
|
||||
// Only one caller will call this function at any time, others will be blocking.
|
||||
// The returned value can no longer be modified once returned.
|
||||
// Should be set before calling Get().
|
||||
Update func() (interface{}, error)
|
||||
|
||||
// TTL for a cached value.
|
||||
// If not set 1 second TTL is assumed.
|
||||
// Should be set before calling Get().
|
||||
TTL time.Duration
|
||||
|
||||
// Once can be used to initialize values for lazy initialization.
|
||||
// Should be set before calling Get().
|
||||
Once sync.Once
|
||||
|
||||
// Managed values.
|
||||
value interface{}
|
||||
lastUpdate time.Time
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
// Get will return a cached value or fetch a new one.
|
||||
// If the Update function returns an error the value is forwarded as is and not cached.
|
||||
func (t *timedValue) Get() (interface{}, error) {
|
||||
t.mu.Lock()
|
||||
defer t.mu.Unlock()
|
||||
if t.TTL <= 0 {
|
||||
t.TTL = time.Second
|
||||
}
|
||||
if t.value != nil {
|
||||
if time.Since(t.lastUpdate) < t.TTL {
|
||||
v := t.value
|
||||
return v, nil
|
||||
}
|
||||
t.value = nil
|
||||
}
|
||||
v, err := t.Update()
|
||||
if err != nil {
|
||||
return v, err
|
||||
}
|
||||
t.value = v
|
||||
t.lastUpdate = time.Now()
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// Invalidate the value in the cache.
|
||||
func (t *timedValue) Invalidate() {
|
||||
t.mu.Lock()
|
||||
t.value = nil
|
||||
t.mu.Unlock()
|
||||
}
|
||||
|
|
|
@ -95,6 +95,8 @@ type xlSets struct {
|
|||
// Distribution algorithm of choice.
|
||||
distributionAlgo string
|
||||
|
||||
disksStorageInfoCache timedValue
|
||||
|
||||
// Merge tree walk
|
||||
pool *MergeWalkPool
|
||||
poolSplunk *MergeWalkPool
|
||||
|
@ -368,7 +370,21 @@ func (s *xlSets) NewNSLock(ctx context.Context, bucket string, objects ...string
|
|||
}
|
||||
|
||||
// StorageInfo - combines output of StorageInfo across all erasure coded object sets.
|
||||
// Caches values for 1 second.
|
||||
func (s *xlSets) StorageInfo(ctx context.Context, local bool) StorageInfo {
|
||||
s.disksStorageInfoCache.Once.Do(func() {
|
||||
s.disksStorageInfoCache.TTL = time.Second
|
||||
s.disksStorageInfoCache.Update = func() (interface{}, error) {
|
||||
return s.storageInfo(ctx, local), nil
|
||||
}
|
||||
})
|
||||
v, _ := s.disksStorageInfoCache.Get()
|
||||
return v.(StorageInfo)
|
||||
}
|
||||
|
||||
// storageInfo - combines output of StorageInfo across all erasure coded object sets.
|
||||
// Use StorageInfo for a cached version.
|
||||
func (s *xlSets) storageInfo(ctx context.Context, local bool) StorageInfo {
|
||||
var storageInfo StorageInfo
|
||||
|
||||
storageInfos := make([]StorageInfo, len(s.sets))
|
||||
|
|
Loading…
Reference in New Issue