Skip to content

Commit f663a2c

Browse files
committed
*: replace os.FileInfo with os.DirEntry where possible
Previously, in a few places, we converted os.DirEntry to os.FileInfo by calling entry.Info(), which triggers a stat syscall for each entry. Most callers only needed the entry name, which is directly available from os.DirEntry via Name(). This patch switches to os.DirEntry throughout the codebase, avoiding unnecessary stat syscalls. In the few places where file size or mode is needed, we now call Info() only when required. Epic: none Release note: None Fixes: none
1 parent d90b48f commit f663a2c

File tree

10 files changed

+39
-88
lines changed

10 files changed

+39
-88
lines changed

pkg/security/securityassets/security_assets.go

Lines changed: 2 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,21 @@
66
package securityassets
77

88
import (
9-
"io/fs"
109
"os"
1110

1211
"github.com/cockroachdb/errors/oserror"
1312
)
1413

1514
// Loader describes the functions necessary to read certificate and key files.
1615
type Loader struct {
17-
ReadDir func(dirname string) ([]os.FileInfo, error)
16+
ReadDir func(dirname string) ([]os.DirEntry, error)
1817
ReadFile func(filename string) ([]byte, error)
1918
Stat func(name string) (os.FileInfo, error)
2019
}
2120

2221
// defaultLoader uses real filesystem calls.
2322
var defaultLoader = Loader{
24-
ReadDir: readDir,
23+
ReadDir: os.ReadDir,
2524
ReadFile: os.ReadFile,
2625
Stat: os.Stat,
2726
}
@@ -55,29 +54,3 @@ func (al Loader) FileExists(filename string) (bool, error) {
5554
}
5655
return true, nil
5756
}
58-
59-
// readDir reads the directory named by dirname and returns a list of
60-
// fs.FileInfo for the directory's contents, sorted by filename. If an error
61-
// occurs reading the directory, ReadDir returns no directory entries along with
62-
// the error.
63-
func readDir(dirname string) ([]os.FileInfo, error) {
64-
entries, err := os.ReadDir(dirname)
65-
if err != nil {
66-
return nil, err
67-
}
68-
infos := make([]fs.FileInfo, 0, len(entries))
69-
for _, entry := range entries {
70-
info, err := entry.Info()
71-
if err != nil {
72-
// Skip files that disappeared between ReadDir and Info().
73-
// This can happen when the directory contains transient files
74-
// like Unix socket lock files that are created/deleted rapidly.
75-
if oserror.IsNotExist(err) {
76-
continue
77-
}
78-
return nil, err
79-
}
80-
infos = append(infos, info)
81-
}
82-
return infos, nil
83-
}

pkg/security/securitytest/securitytest.go

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -96,27 +96,23 @@ func AppendFile(assetPath, dstPath string) error {
9696
return errors.CombineErrors(err, f.Close())
9797
}
9898

99-
// AssetReadDir mimics ioutil.ReadDir, returning a list of []os.FileInfo for
100-
// the specified directory.
101-
func AssetReadDir(name string) ([]os.FileInfo, error) {
99+
// AssetReadDir mimics os.ReadDir, returning a list of []os.DirEntry for the
100+
// specified directory.
101+
func AssetReadDir(name string) ([]os.DirEntry, error) {
102102
entries, err := testCerts.ReadDir(name)
103103
if err != nil {
104104
return nil, err
105105
}
106-
infos := make([]os.FileInfo, 0, len(entries))
106+
filtered_entries := make([]os.DirEntry, 0, len(entries))
107107
for _, e := range entries {
108-
info, err := e.Info()
109-
if err != nil {
110-
return nil, err
111-
}
112108
if strings.HasSuffix(e.Name(), ".md") ||
113109
strings.HasSuffix(e.Name(), ".sh") ||
114110
strings.HasSuffix(e.Name(), ".cnf") {
115111
continue
116112
}
117-
infos = append(infos, &fileInfo{inner: info})
113+
filtered_entries = append(filtered_entries, e)
118114
}
119-
return infos, nil
115+
return filtered_entries, nil
120116
}
121117

122118
// AssetStat wraps Stat().

pkg/server/dumpstore/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ go_library(
99
"//pkg/settings",
1010
"//pkg/settings/cluster",
1111
"//pkg/util/log",
12+
"@com_github_cockroachdb_errors//oserror",
1213
],
1314
)
1415

pkg/server/dumpstore/dumpstore.go

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@ package dumpstore
77

88
import (
99
"context"
10-
"io/fs"
1110
"os"
1211
"path/filepath"
1312
"time"
1413

1514
"github.com/cockroachdb/cockroach/pkg/settings"
1615
"github.com/cockroachdb/cockroach/pkg/settings/cluster"
1716
"github.com/cockroachdb/cockroach/pkg/util/log"
17+
"github.com/cockroachdb/errors/oserror"
1818
)
1919

2020
// DumpStore represents a store for dump files.
@@ -59,10 +59,10 @@ type Dumper interface {
5959
//
6060
// There may be files not owned by this dumper in the files array;
6161
// these should be ignored.
62-
PreFilter(ctx context.Context, files []os.FileInfo, cleanupFn func(fileName string) error) (preserved map[int]bool, err error)
62+
PreFilter(ctx context.Context, files []os.DirEntry, cleanupFn func(fileName string) error) (preserved map[int]bool, err error)
6363

6464
// CheckOwnsFile returns true iff the dumper owns the given file.
65-
CheckOwnsFile(ctx context.Context, fi os.FileInfo) bool
65+
CheckOwnsFile(ctx context.Context, fi os.DirEntry) bool
6666
}
6767

6868
// NewStore creates a new DumpStore.
@@ -83,22 +83,13 @@ func (s *DumpStore) GetFullPath(fileName string) string {
8383

8484
// GC runs the GC policy on this store.
8585
func (s *DumpStore) GC(ctx context.Context, now time.Time, dumper Dumper) {
86-
// NB: ioutil.ReadDir sorts the file names in ascending order.
86+
// NB: os.ReadDir sorts the file names in ascending order.
8787
// This brings the oldest files first.
88-
entries, err := os.ReadDir(s.dir)
88+
files, err := os.ReadDir(s.dir)
8989
if err != nil {
9090
log.Dev.Warningf(ctx, "%v", err)
9191
return
9292
}
93-
files := make([]fs.FileInfo, 0, len(entries))
94-
for _, entry := range entries {
95-
info, err := entry.Info()
96-
if err != nil {
97-
log.Dev.Warningf(ctx, "%v", err)
98-
return
99-
}
100-
files = append(files, info)
101-
}
10293

10394
maxS := s.maxCombinedFileSizeSetting.Get(&s.st.SV)
10495

@@ -129,7 +120,7 @@ func (s *DumpStore) GC(ctx context.Context, now time.Time, dumper Dumper) {
129120
func removeOldAndTooBigExcept(
130121
ctx context.Context,
131122
dumper Dumper,
132-
files []os.FileInfo,
123+
files []os.DirEntry,
133124
now time.Time,
134125
maxS int64,
135126
preserved map[int]bool,
@@ -144,8 +135,16 @@ func removeOldAndTooBigExcept(
144135
continue
145136
}
146137

138+
info, err := fi.Info()
139+
if err != nil {
140+
if !oserror.IsNotExist(err) {
141+
log.Dev.Warningf(ctx, "%v", err)
142+
}
143+
continue
144+
}
145+
147146
// Note: we are counting preserved files against the maximum.
148-
actualSize += fi.Size()
147+
actualSize += info.Size()
149148

150149
// Ignore all the preserved entries, even if they are "too old".
151150
if preserved[i] {

pkg/server/dumpstore/dumpstore_test.go

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ package dumpstore
88
import (
99
"context"
1010
"fmt"
11-
"io/fs"
1211
"os"
1312
"path/filepath"
1413
"strings"
@@ -156,16 +155,16 @@ func TestRemoveOldAndTooBig(t *testing.T) {
156155
type myDumper struct{}
157156

158157
func (myDumper) PreFilter(
159-
_ context.Context, files []os.FileInfo, cleanupFn func(fileName string) error,
158+
_ context.Context, files []os.DirEntry, cleanupFn func(fileName string) error,
160159
) (preserved map[int]bool, err error) {
161160
panic("unimplemented")
162161
}
163162

164-
func (myDumper) CheckOwnsFile(_ context.Context, fi os.FileInfo) bool {
163+
func (myDumper) CheckOwnsFile(_ context.Context, fi os.DirEntry) bool {
165164
return strings.HasPrefix(fi.Name(), "memprof")
166165
}
167166

168-
func populate(t *testing.T, dirName string, fileNames []string, sizes []int64) []os.FileInfo {
167+
func populate(t *testing.T, dirName string, fileNames []string, sizes []int64) []os.DirEntry {
169168
if len(sizes) > 0 {
170169
require.Equal(t, len(fileNames), len(sizes))
171170
}
@@ -187,17 +186,9 @@ func populate(t *testing.T, dirName string, fileNames []string, sizes []int64) [
187186
}
188187

189188
// Retrieve the file list for the remainder of the test.
190-
entries, err := os.ReadDir(dirName)
189+
files, err := os.ReadDir(dirName)
191190
if err != nil {
192191
t.Fatal(err)
193192
}
194-
files := make([]fs.FileInfo, 0, len(entries))
195-
for _, entry := range entries {
196-
info, err := entry.Info()
197-
if err != nil {
198-
t.Fatal(err)
199-
}
200-
files = append(files, info)
201-
}
202193
return files
203194
}

pkg/server/goroutinedumper/goroutinedumper.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ func (gd *GoroutineDumper) gcDumps(ctx context.Context, now time.Time) {
136136

137137
// PreFilter is part of the dumpstore.Dumper interface.
138138
func (gd *GoroutineDumper) PreFilter(
139-
ctx context.Context, files []os.FileInfo, cleanupFn func(fileName string) error,
139+
ctx context.Context, files []os.DirEntry, cleanupFn func(fileName string) error,
140140
) (preserved map[int]bool, _ error) {
141141
preserved = make(map[int]bool)
142142
for i := len(files) - 1; i >= 0; i-- {
@@ -150,7 +150,7 @@ func (gd *GoroutineDumper) PreFilter(
150150
}
151151

152152
// CheckOwnsFile is part of the dumpstore.Dumper interface.
153-
func (gd *GoroutineDumper) CheckOwnsFile(_ context.Context, fi os.FileInfo) bool {
153+
func (gd *GoroutineDumper) CheckOwnsFile(_ context.Context, fi os.DirEntry) bool {
154154
return strings.HasPrefix(fi.Name(), goroutineDumpPrefix)
155155
}
156156

pkg/server/profiler/profilestore.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,15 +67,15 @@ func (s *profileStore) makeNewFileName(timestamp time.Time, curHeap int64) strin
6767

6868
// PreFilter is part of the dumpstore.Dumper interface.
6969
func (s *profileStore) PreFilter(
70-
ctx context.Context, files []os.FileInfo, cleanupFn func(fileName string) error,
70+
ctx context.Context, files []os.DirEntry, cleanupFn func(fileName string) error,
7171
) (preserved map[int]bool, _ error) {
7272
maxP := maxProfiles.Get(&s.st.SV)
7373
preserved = s.cleanupLastRampup(ctx, files, maxP, cleanupFn)
7474
return
7575
}
7676

7777
// CheckOwnsFile is part of the dumpstore.Dumper interface.
78-
func (s *profileStore) CheckOwnsFile(ctx context.Context, fi os.FileInfo) bool {
78+
func (s *profileStore) CheckOwnsFile(ctx context.Context, fi os.DirEntry) bool {
7979
ok, _, _ := s.parseFileName(ctx, fi.Name())
8080
return ok
8181
}
@@ -91,7 +91,7 @@ func (s *profileStore) CheckOwnsFile(ctx context.Context, fi os.FileInfo) bool {
9191
// The preserved return value contains the indexes in files
9292
// corresponding to the last ramp-up that were not passed to fn.
9393
func (s *profileStore) cleanupLastRampup(
94-
ctx context.Context, files []os.FileInfo, maxP int64, fn func(string) error,
94+
ctx context.Context, files []os.DirEntry, maxP int64, fn func(string) error,
9595
) (preserved map[int]bool) {
9696
preserved = make(map[int]bool)
9797
curMaxHeap := uint64(math.MaxUint64)

pkg/server/profiler/profilestore_test.go

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ package profiler
88
import (
99
"context"
1010
"fmt"
11-
"io/fs"
1211
"os"
1312
"path/filepath"
1413
"testing"
@@ -208,7 +207,7 @@ func TestCleanupLastRampup(t *testing.T) {
208207
}
209208
}
210209

211-
func populate(t *testing.T, dirName string, fileNames []string) []os.FileInfo {
210+
func populate(t *testing.T, dirName string, fileNames []string) []os.DirEntry {
212211
for _, fn := range fileNames {
213212
f, err := os.Create(filepath.Join(dirName, fn))
214213
if err != nil {
@@ -221,17 +220,9 @@ func populate(t *testing.T, dirName string, fileNames []string) []os.FileInfo {
221220
}
222221

223222
// Retrieve the file list for the remainder of the test.
224-
entries, err := os.ReadDir(dirName)
223+
files, err := os.ReadDir(dirName)
225224
if err != nil {
226225
t.Fatal(err)
227226
}
228-
files := make([]fs.FileInfo, 0, len(entries))
229-
for _, entry := range entries {
230-
info, err := entry.Info()
231-
if err != nil {
232-
t.Fatal(err)
233-
}
234-
files = append(files, info)
235-
}
236227
return files
237228
}

pkg/server/tracedumper/tracedumper.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ type TraceDumper struct {
3333

3434
// PreFilter is part of the dumpstore.Dumper interface.
3535
func (t *TraceDumper) PreFilter(
36-
ctx context.Context, files []os.FileInfo, _ func(fileName string) error,
36+
ctx context.Context, files []os.DirEntry, _ func(fileName string) error,
3737
) (preserved map[int]bool, err error) {
3838
preserved = make(map[int]bool)
3939
for i := len(files) - 1; i >= 0; i-- {
@@ -47,7 +47,7 @@ func (t *TraceDumper) PreFilter(
4747
}
4848

4949
// CheckOwnsFile is part of the dumpstore.Dumper interface.
50-
func (t *TraceDumper) CheckOwnsFile(ctx context.Context, fi os.FileInfo) bool {
50+
func (t *TraceDumper) CheckOwnsFile(ctx context.Context, fi os.DirEntry) bool {
5151
return strings.HasPrefix(fi.Name(), jobTraceDumpPrefix)
5252
}
5353

pkg/util/tracing/goexectrace/simple_flight_recorder.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,14 +103,14 @@ func (sfr *SimpleFlightRecorder) TimestampedFilename() string {
103103
var fileMatchRegexp = regexp.MustCompile("^executiontrace.*out$")
104104

105105
// CheckOwnsFile is part of the `Dumper` interface.
106-
func (sfr *SimpleFlightRecorder) CheckOwnsFile(ctx context.Context, fi os.FileInfo) bool {
106+
func (sfr *SimpleFlightRecorder) CheckOwnsFile(ctx context.Context, fi os.DirEntry) bool {
107107
return fileMatchRegexp.MatchString(fi.Name())
108108
}
109109

110110
// PreFilter is part of the `Dumper` interface. In this case we do not mark any
111111
// files for preservation.
112112
func (sfr *SimpleFlightRecorder) PreFilter(
113-
ctx context.Context, files []os.FileInfo, cleanupFn func(fileName string) error,
113+
ctx context.Context, files []os.DirEntry, cleanupFn func(fileName string) error,
114114
) (preserved map[int]bool, err error) {
115115
return nil, nil
116116
}

0 commit comments

Comments
 (0)