posix: cache disk ID for a short while (#8564)

`*posix.getDiskID()` takes up to 30% of all CPU due to the `os.Stat` call on `GET` calls.

Before:
```
Operation: GET - Concurrency: 12
* Average: 1333.97 MB/s, 1365.99 obj/s, 1365.98 ops ended/s (4m59.975s)
* First Byte: Average: 7.801487ms, Median: 7.9974ms, Best: 1.9822ms, Worst: 110.0021ms

Aggregated, split into 299 x 1s time segments:
* Fastest: 1453.50 MB/s, 1488.38 obj/s, 1492.00 ops ended/s (1s)
* 50% Median: 1360.47 MB/s, 1393.12 obj/s, 1393.00 ops ended/s (1s)
* Slowest: 978.68 MB/s, 1002.17 obj/s, 1004.00 ops ended/s (1s)
```

After:
```
Operation: GET - Concurrency: 12
* Average: 1706.07 MB/s, 1747.02 obj/s, 1747.01 ops ended/s (4m59.985s)
* First Byte: Average: 5.797886ms, Median: 5.9959ms, Best: 996.3µs, Worst: 84.0007ms

Aggregated, split into 299 x 1s time segments:
* Fastest: 1830.03 MB/s, 1873.96 obj/s, 1872.00 ops ended/s (1s)
* 50% Median: 1735.04 MB/s, 1776.68 obj/s, 1776.00 ops ended/s (1s)
* Slowest: 994.94 MB/s, 1018.82 obj/s, 1018.00 ops ended/s (1s)
```

TLDR; `os.Stat` is not free.
master
Klaus Post 5 years ago committed by Harshavardhana
parent 2ff8132e2d
commit c7844fb1fb
  1. 24
      cmd/posix.go

@ -89,7 +89,8 @@ type posix struct {
diskID string diskID string
formatFileInfo os.FileInfo formatFileInfo os.FileInfo
formatLastCheck time.Time
// Disk usage metrics // Disk usage metrics
stopUsageCh chan struct{} stopUsageCh chan struct{}
@ -391,8 +392,23 @@ func (s *posix) getVolDir(volume string) (string, error) {
func (s *posix) getDiskID() (string, error) { func (s *posix) getDiskID() (string, error) {
s.RLock() s.RLock()
diskID := s.diskID diskID := s.diskID
fileInfo := s.formatFileInfo
lastCheck := s.formatLastCheck
s.RUnlock() s.RUnlock()
// check if we have a valid disk ID that is less than 1 second old.
if fileInfo != nil && diskID != "" && time.Now().Before(lastCheck.Add(time.Second)) {
return diskID, nil
}
s.Lock()
defer s.Unlock()
// If somebody else updated the disk ID and changed the time, return what they got.
if !s.formatLastCheck.Equal(lastCheck) {
// Somebody else got the lock first.
return diskID, nil
}
formatFile := pathJoin(s.diskPath, minioMetaBucket, formatConfigFile) formatFile := pathJoin(s.diskPath, minioMetaBucket, formatConfigFile)
fi, err := os.Stat(formatFile) fi, err := os.Stat(formatFile)
if err != nil { if err != nil {
@ -400,13 +416,12 @@ func (s *posix) getDiskID() (string, error) {
return "", err return "", err
} }
if xioutil.SameFile(fi, s.formatFileInfo) { if xioutil.SameFile(fi, fileInfo) {
// If the file has not changed, just return the cached diskID information. // If the file has not changed, just return the cached diskID information.
s.formatLastCheck = time.Now()
return diskID, nil return diskID, nil
} }
s.Lock()
defer s.Unlock()
b, err := ioutil.ReadFile(formatFile) b, err := ioutil.ReadFile(formatFile)
if err != nil { if err != nil {
return "", err return "", err
@ -418,6 +433,7 @@ func (s *posix) getDiskID() (string, error) {
} }
s.diskID = format.XL.This s.diskID = format.XL.This
s.formatFileInfo = fi s.formatFileInfo = fi
s.formatLastCheck = time.Now()
return s.diskID, nil return s.diskID, nil
} }

Loading…
Cancel
Save