From c7844fb1fbe1c0ae34760ca6a9260e446883316b Mon Sep 17 00:00:00 2001 From: Klaus Post Date: Fri, 29 Nov 2019 02:57:14 -0800 Subject: [PATCH] posix: cache disk ID for a short while (#8564) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `*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. --- cmd/posix.go | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/cmd/posix.go b/cmd/posix.go index bafebde07..9d8f1b029 100644 --- a/cmd/posix.go +++ b/cmd/posix.go @@ -89,7 +89,8 @@ type posix struct { diskID string - formatFileInfo os.FileInfo + formatFileInfo os.FileInfo + formatLastCheck time.Time // Disk usage metrics stopUsageCh chan struct{} @@ -391,8 +392,23 @@ func (s *posix) getVolDir(volume string) (string, error) { func (s *posix) getDiskID() (string, error) { s.RLock() diskID := s.diskID + fileInfo := s.formatFileInfo + lastCheck := s.formatLastCheck 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) fi, err := os.Stat(formatFile) if err != nil { @@ -400,13 +416,12 @@ func (s *posix) getDiskID() (string, error) { 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. + s.formatLastCheck = time.Now() return diskID, nil } - s.Lock() - defer s.Unlock() b, err := ioutil.ReadFile(formatFile) if err != nil { return "", err @@ -418,6 +433,7 @@ func (s *posix) getDiskID() (string, error) { } s.diskID = format.XL.This s.formatFileInfo = fi + s.formatLastCheck = time.Now() return s.diskID, nil }