diff options
| author | qmuntal <quimmuntal@gmail.com> | 2022-11-22 18:46:35 +0100 |
|---|---|---|
| committer | Quim Muntal <quimmuntal@gmail.com> | 2023-01-24 13:26:00 +0000 |
| commit | 1951857ec07c1d491e1836770a647d3902934a67 (patch) | |
| tree | c6d132e27692470402908a581ae3b3c893ff7366 /src/os/file_windows.go | |
| parent | 7b5a34418cd32ec4d2c0f7d6e4c7e6fe7585a17f (diff) | |
| download | go-1951857ec07c1d491e1836770a647d3902934a67.tar.xz | |
os: use handle based APIs to read directories on windows
This CL updates File.readdir() on windows so it uses
GetFileInformationByHandleEx with FILE_ID_BOTH_DIR_INFO
instead of Find* APIs. The former is more performant because
it allows us to buffer IO calls and reduces the number of system calls,
passing from 1 per file to 1 every ~100 files
(depending on the size of the file name and the size of the buffer).
This change improve performance of File.ReadDir by 20-30%.
name old time/op new time/op delta
ReadDir-12 562µs ±14% 385µs ± 9% -31.60% (p=0.000 n=9+9)
name old alloc/op new alloc/op delta
ReadDir-12 29.7kB ± 0% 29.5kB ± 0% -0.88% (p=0.000 n=8+10)
name old allocs/op new allocs/op delta
ReadDir-12 399 ± 0% 397 ± 0% -0.50% (p=0.000 n=10+10)
This change also speeds up calls to os.SameFile when using FileStats
returned from File.readdir(), as their file ID can be inferred while
reading the directory.
Change-Id: Id56a338ee66c39656b564105cac131099218fb5d
Reviewed-on: https://go-review.googlesource.com/c/go/+/452995
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Damien Neil <dneil@google.com>
Reviewed-by: Alex Brainman <alex.brainman@gmail.com>
Run-TryBot: Quim Muntal <quimmuntal@gmail.com>
Reviewed-by: Bryan Mills <bcmills@google.com>
Diffstat (limited to 'src/os/file_windows.go')
| -rw-r--r-- | src/os/file_windows.go | 69 |
1 files changed, 0 insertions, 69 deletions
diff --git a/src/os/file_windows.go b/src/os/file_windows.go index d94b78f524..a48feca855 100644 --- a/src/os/file_windows.go +++ b/src/os/file_windows.go @@ -84,18 +84,6 @@ func NewFile(fd uintptr, name string) *File { return newFile(h, name, "file") } -// Auxiliary information if the File describes a directory -type dirInfo struct { - h syscall.Handle // search handle created with FindFirstFile - data syscall.Win32finddata - path string - isempty bool // set if FindFirstFile returns ERROR_FILE_NOT_FOUND -} - -func (d *dirInfo) close() error { - return syscall.FindClose(d.h) -} - func epipecheck(file *File, e error) { } @@ -103,63 +91,6 @@ func epipecheck(file *File, e error) { // On Unix-like systems, it is "/dev/null"; on Windows, "NUL". const DevNull = "NUL" -func openDir(name string) (d *dirInfo, e error) { - var mask string - - path := fixLongPath(name) - - if len(path) == 2 && path[1] == ':' { // it is a drive letter, like C: - mask = path + `*` - } else if len(path) > 0 { - lc := path[len(path)-1] - if lc == '/' || lc == '\\' { - mask = path + `*` - } else { - mask = path + `\*` - } - } else { - mask = `\*` - } - maskp, e := syscall.UTF16PtrFromString(mask) - if e != nil { - return nil, e - } - d = new(dirInfo) - d.h, e = syscall.FindFirstFile(maskp, &d.data) - if e != nil { - // FindFirstFile returns ERROR_FILE_NOT_FOUND when - // no matching files can be found. Then, if directory - // exists, we should proceed. - // If FindFirstFile failed because name does not point - // to a directory, we should return ENOTDIR. - var fa syscall.Win32FileAttributeData - pathp, e1 := syscall.UTF16PtrFromString(path) - if e1 != nil { - return nil, e - } - e1 = syscall.GetFileAttributesEx(pathp, syscall.GetFileExInfoStandard, (*byte)(unsafe.Pointer(&fa))) - if e1 != nil { - return nil, e - } - if fa.FileAttributes&syscall.FILE_ATTRIBUTE_DIRECTORY == 0 { - return nil, syscall.ENOTDIR - } - if e != syscall.ERROR_FILE_NOT_FOUND { - return nil, e - } - d.isempty = true - } - d.path = path - if !isAbs(d.path) { - d.path, e = syscall.FullPath(d.path) - if e != nil { - d.close() - return nil, e - } - } - return d, nil -} - // openFileNolog is the Windows implementation of OpenFile. func openFileNolog(name string, flag int, perm FileMode) (*File, error) { if name == "" { |
