use Access() instead of Lstat() for frequent use (#11911)

using Lstat() is causing tiny memory allocations,
that are usually wasted and never used, instead
we can simply uses Access() call that does 0
memory allocations.
This commit is contained in:
Harshavardhana
2021-03-29 08:07:23 -07:00
committed by GitHub
parent 7c5b35d20f
commit d93c6cb9c7
9 changed files with 101 additions and 67 deletions

View File

@@ -39,6 +39,7 @@ const (
osMetricLstat
osMetricRemove
osMetricStat
osMetricAccess
// .... add more
osMetricLast
@@ -94,6 +95,14 @@ func OpenFile(name string, flag int, perm os.FileMode) (*os.File, error) {
return os.OpenFile(name, flag, perm)
}
// Access captures time taken to call syscall.Access()
// on windows, plan9 and solaris syscall.Access uses
// os.Lstat()
func Access(name string) error {
defer updateOSMetrics(osMetricAccess, name)()
return access(name)
}
// Open captures time taken to call os.Open
func Open(name string) (*os.File, error) {
defer updateOSMetrics(osMetricOpen, name)()

View File

@@ -24,6 +24,11 @@ import (
"syscall"
)
func access(name string) error {
_, err := os.Lstat(name)
return err
}
// Return all the entries at the directory dirPath.
func readDir(dirPath string) (entries []string, err error) {
return readDirN(dirPath, -1)

View File

@@ -25,8 +25,17 @@ import (
"sync"
"syscall"
"unsafe"
"golang.org/x/sys/unix"
)
func access(name string) error {
if err := unix.Access(name, unix.R_OK|unix.W_OK); err != nil {
return &os.PathError{Op: "lstat", Path: name, Err: err}
}
return nil
}
// The buffer must be at least a block long.
// refer https://github.com/golang/go/issues/24015
const blockSize = 8 << 10 // 8192

View File

@@ -24,6 +24,11 @@ import (
"syscall"
)
func access(name string) error {
_, err := os.Lstat(name)
return err
}
// Return all the entries at the directory dirPath.
func readDir(dirPath string) (entries []string, err error) {
return readDirN(dirPath, -1)

View File

@@ -17,12 +17,13 @@ func _() {
_ = x[osMetricLstat-6]
_ = x[osMetricRemove-7]
_ = x[osMetricStat-8]
_ = x[osMetricLast-9]
_ = x[osMetricAccess-9]
_ = x[osMetricLast-10]
}
const _osMetric_name = "RemoveAllMkdirAllRenameOpenFileOpenOpenFileDirectIOLstatRemoveStatLast"
const _osMetric_name = "RemoveAllMkdirAllRenameOpenFileOpenOpenFileDirectIOLstatRemoveStatAccessLast"
var _osMetric_index = [...]uint8{0, 9, 17, 23, 31, 35, 51, 56, 62, 66, 70}
var _osMetric_index = [...]uint8{0, 9, 17, 23, 31, 35, 51, 56, 62, 66, 72, 76}
func (i osMetric) String() string {
if i >= osMetric(len(_osMetric_index)-1) {

View File

@@ -529,8 +529,7 @@ func (s *xlStorage) GetDiskID() (string, error) {
if err != nil {
// If the disk is still not initialized.
if osIsNotExist(err) {
_, err = Lstat(s.diskPath)
if err == nil {
if err = Access(s.diskPath); err == nil {
// Disk is present but missing `format.json`
return "", errUnformattedDisk
}
@@ -560,8 +559,7 @@ func (s *xlStorage) GetDiskID() (string, error) {
if err != nil {
// If the disk is still not initialized.
if osIsNotExist(err) {
_, err = Lstat(s.diskPath)
if err == nil {
if err = Access(s.diskPath); err == nil {
// Disk is present but missing `format.json`
return "", errUnformattedDisk
}
@@ -623,7 +621,7 @@ func (s *xlStorage) MakeVol(ctx context.Context, volume string) error {
return err
}
if _, err := Lstat(volumeDir); err != nil {
if err = Access(volumeDir); err != nil {
// Volume does not exist we proceed to create.
if osIsNotExist(err) {
// Make a volume entry, with mode 0777 mkdir honors system umask.
@@ -675,6 +673,7 @@ func (s *xlStorage) StatVol(ctx context.Context, volume string) (vol VolInfo, er
if err != nil {
return VolInfo{}, err
}
// Stat a volume entry.
var st os.FileInfo
st, err = Lstat(volumeDir)
@@ -736,8 +735,7 @@ func (s *xlStorage) isLeaf(volume string, leafPath string) bool {
return false
}
_, err = Lstat(pathJoin(volumeDir, leafPath, xlStorageFormatFile))
if err == nil {
if err = Access(pathJoin(volumeDir, leafPath, xlStorageFormatFile)); err == nil {
return true
}
if osIsNotExist(err) {
@@ -767,10 +765,10 @@ func (s *xlStorage) ListDir(ctx context.Context, volume, dirPath string, count i
}
if err != nil {
if err == errFileNotFound {
if _, verr := Lstat(volumeDir); verr != nil {
if osIsNotExist(verr) {
if ierr := Access(volumeDir); ierr != nil {
if osIsNotExist(ierr) {
return nil, errVolumeNotFound
} else if isSysErrIO(verr) {
} else if isSysErrIO(ierr) {
return nil, errFaultyDisk
}
}
@@ -1042,8 +1040,7 @@ func (s *xlStorage) readAllData(volumeDir string, filePath string, requireDirect
if osIsNotExist(err) {
// Check if the object doesn't exist because its bucket
// is missing in order to return the correct error.
_, err = Lstat(volumeDir)
if err != nil && osIsNotExist(err) {
if err = Access(volumeDir); err != nil && osIsNotExist(err) {
return nil, errVolumeNotFound
}
return nil, errFileNotFound
@@ -1129,12 +1126,13 @@ func (s *xlStorage) ReadFile(ctx context.Context, volume string, path string, of
var n int
// Stat a volume entry.
_, err = Lstat(volumeDir)
if err != nil {
if err = Access(volumeDir); err != nil {
if osIsNotExist(err) {
return 0, errVolumeNotFound
} else if isSysErrIO(err) {
return 0, errFaultyDisk
} else if osIsPermission(err) {
return 0, errFileAccessDenied
}
return 0, err
}
@@ -1329,8 +1327,7 @@ func (s *xlStorage) ReadFileStream(ctx context.Context, volume, path string, off
if err != nil {
switch {
case osIsNotExist(err):
_, err = Lstat(volumeDir)
if err != nil && osIsNotExist(err) {
if err = Access(volumeDir); err != nil && osIsNotExist(err) {
return nil, errVolumeNotFound
}
return nil, errFileNotFound
@@ -1530,9 +1527,13 @@ func (s *xlStorage) AppendFile(ctx context.Context, volume string, path string,
}
// Stat a volume entry.
if _, err = Lstat(volumeDir); err != nil {
if err = Access(volumeDir); err != nil {
if osIsNotExist(err) {
return errVolumeNotFound
} else if osIsPermission(err) {
return errVolumeAccessDenied
} else if isSysErrIO(err) {
return errFaultyDisk
}
return err
}
@@ -1571,7 +1572,7 @@ func (s *xlStorage) CheckParts(ctx context.Context, volume string, path string,
}
// Stat a volume entry.
if _, err = Lstat(volumeDir); err != nil {
if err = Access(volumeDir); err != nil {
if osIsNotExist(err) {
return errVolumeNotFound
}
@@ -1721,8 +1722,7 @@ func (s *xlStorage) Delete(ctx context.Context, volume string, path string, recu
}
// Stat a volume entry.
_, err = Lstat(volumeDir)
if err != nil {
if err = Access(volumeDir); err != nil {
if osIsNotExist(err) {
return errVolumeNotFound
} else if osIsPermission(err) {
@@ -1757,8 +1757,7 @@ func (s *xlStorage) RenameData(ctx context.Context, srcVolume, srcPath, dataDir,
}
// Stat a volume entry.
_, err = Lstat(srcVolumeDir)
if err != nil {
if err = Access(srcVolumeDir); err != nil {
if osIsNotExist(err) {
return errVolumeNotFound
} else if isSysErrIO(err) {
@@ -1767,7 +1766,7 @@ func (s *xlStorage) RenameData(ctx context.Context, srcVolume, srcPath, dataDir,
return err
}
if _, err = Lstat(dstVolumeDir); err != nil {
if err = Access(dstVolumeDir); err != nil {
if osIsNotExist(err) {
return errVolumeNotFound
} else if isSysErrIO(err) {
@@ -1998,8 +1997,7 @@ func (s *xlStorage) RenameFile(ctx context.Context, srcVolume, srcPath, dstVolum
return err
}
// Stat a volume entry.
_, err = Lstat(srcVolumeDir)
if err != nil {
if err = Access(srcVolumeDir); err != nil {
if osIsNotExist(err) {
return errVolumeNotFound
} else if isSysErrIO(err) {
@@ -2007,8 +2005,8 @@ func (s *xlStorage) RenameFile(ctx context.Context, srcVolume, srcPath, dstVolum
}
return err
}
_, err = Lstat(dstVolumeDir)
if err != nil {
if err = Access(dstVolumeDir); err != nil {
if osIsNotExist(err) {
return errVolumeNotFound
} else if isSysErrIO(err) {
@@ -2142,8 +2140,7 @@ func (s *xlStorage) VerifyFile(ctx context.Context, volume, path string, fi File
}
// Stat a volume entry.
_, err = Lstat(volumeDir)
if err != nil {
if err = Access(volumeDir); err != nil {
if osIsNotExist(err) {
return errVolumeNotFound
} else if isSysErrIO(err) {

View File

@@ -869,7 +869,7 @@ func TestXLStorageListDir(t *testing.T) {
var dirList []string
dirList, err = xlStorage.ListDir(context.Background(), testCase.srcVol, testCase.srcPath, -1)
if err != testCase.expectedErr {
t.Fatalf("TestXLStorage case %d: Expected: \"%s\", got: \"%s\"", i+1, testCase.expectedErr, err)
t.Errorf("TestXLStorage case %d: Expected: \"%s\", got: \"%s\"", i+1, testCase.expectedErr, err)
}
if err == nil {
for _, expected := range testCase.expectedListDir {
@@ -900,8 +900,8 @@ func TestXLStorageListDir(t *testing.T) {
t.Fatalf("Unable to initialize xlStorage, %s", err)
}
if err = xlStorageNew.Delete(context.Background(), "mybucket", "myobject", false); err != errFileAccessDenied {
t.Errorf("expected: %s, got: %s", errFileAccessDenied, err)
if err = xlStorageNew.Delete(context.Background(), "mybucket", "myobject", false); err != errVolumeAccessDenied {
t.Errorf("expected: %s, got: %s", errVolumeAccessDenied, err)
}
}
@@ -915,6 +915,10 @@ func TestXLStorageListDir(t *testing.T) {
// TestXLStorageDeleteFile - Series of test cases construct valid and invalid input data and validates the result and the error response.
func TestXLStorageDeleteFile(t *testing.T) {
if runtime.GOOS == globalWindowsOSName {
t.Skip()
}
// create xlStorage test setup
xlStorage, path, err := newXLStorageTestSetup()
if err != nil {
@@ -994,7 +998,7 @@ func TestXLStorageDeleteFile(t *testing.T) {
{
srcVol: "no-permissions",
srcPath: "dir/file",
expectedErr: nil,
expectedErr: errVolumeAccessDenied,
},
}
@@ -1024,8 +1028,8 @@ func TestXLStorageDeleteFile(t *testing.T) {
t.Fatalf("Unable to initialize xlStorage, %s", err)
}
if err = xlStorageNew.Delete(context.Background(), "mybucket", "myobject", false); err != errFileAccessDenied {
t.Errorf("expected: %s, got: %s", errFileAccessDenied, err)
if err = xlStorageNew.Delete(context.Background(), "mybucket", "myobject", false); err != errVolumeAccessDenied {
t.Errorf("expected: %s, got: %s", errVolumeAccessDenied, err)
}
}
@@ -1401,8 +1405,8 @@ func TestXLStorageAppendFile(t *testing.T) {
t.Fatalf("Unable to initialize xlStorage, %s", err)
}
if err = xlStoragePermStorage.AppendFile(context.Background(), "mybucket", "myobject", []byte("hello, world")); err != errFileAccessDenied {
t.Fatalf("expected: Permission error, got: %s", err)
if err = xlStoragePermStorage.AppendFile(context.Background(), "mybucket", "myobject", []byte("hello, world")); err != errVolumeAccessDenied {
t.Fatalf("expected: errVolumeAccessDenied error, got: %s", err)
}
}