From 04c97aa36473bc0070a2fe46e86dc645dc75ee85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felipe=20Leopoldo=20Sologuren=20Guti=C3=A9rrez?= Date: Mon, 16 Jan 2023 13:21:44 -0300 Subject: [PATCH] Change use of Walk to WalkDir to improve disk performance (#22462) As suggest by Go developers, use `filepath.WalkDir` instead of `filepath.Walk` because [*Walk is less efficient than WalkDir, introduced in Go 1.16, which avoids calling `os.Lstat` on every file or directory visited](https://pkg.go.dev/path/filepath#Walk). This proposition address that, in a similar way as https://github.com/go-gitea/gitea/pull/22392 did. Co-authored-by: zeripath Co-authored-by: Lunny Xiao --- build/generate-bindata.go | 8 ++++++-- modules/log/file.go | 14 ++++++++++++-- modules/repository/generate.go | 4 ++-- modules/storage/local.go | 4 ++-- routers/web/user/setting/profile.go | 8 ++++---- services/repository/adopt.go | 12 ++++++------ 6 files changed, 32 insertions(+), 18 deletions(-) diff --git a/build/generate-bindata.go b/build/generate-bindata.go index ecd5d5047c..2fcb7c2f2a 100644 --- a/build/generate-bindata.go +++ b/build/generate-bindata.go @@ -32,11 +32,15 @@ func needsUpdate(dir, filename string) (bool, []byte) { hasher := sha1.New() - err = filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { + err = filepath.WalkDir(dir, func(path string, d os.DirEntry, err error) error { if err != nil { return err } - _, _ = hasher.Write([]byte(info.Name())) + info, err := d.Info() + if err != nil { + return err + } + _, _ = hasher.Write([]byte(d.Name())) _, _ = hasher.Write([]byte(info.ModTime().String())) _, _ = hasher.Write([]byte(strconv.FormatInt(info.Size(), 16))) return nil diff --git a/modules/log/file.go b/modules/log/file.go index 13386a320f..16fe26f84d 100644 --- a/modules/log/file.go +++ b/modules/log/file.go @@ -225,14 +225,24 @@ func compressOldLogFile(fname string, compressionLevel int) error { func (log *FileLogger) deleteOldLog() { dir := filepath.Dir(log.Filename) - _ = filepath.Walk(dir, func(path string, info os.FileInfo, err error) (returnErr error) { + _ = filepath.WalkDir(dir, func(path string, d os.DirEntry, err error) (returnErr error) { defer func() { if r := recover(); r != nil { returnErr = fmt.Errorf("Unable to delete old log '%s', error: %+v", path, r) } }() - if !info.IsDir() && info.ModTime().Unix() < (time.Now().Unix()-60*60*24*log.Maxdays) { + if err != nil { + return err + } + if d.IsDir() { + return nil + } + info, err := d.Info() + if err != nil { + return err + } + if info.ModTime().Unix() < (time.Now().Unix() - 60*60*24*log.Maxdays) { if strings.HasPrefix(filepath.Base(path), filepath.Base(log.Filename)) { if err := util.Remove(path); err != nil { returnErr = fmt.Errorf("Failed to remove %s: %w", path, err) diff --git a/modules/repository/generate.go b/modules/repository/generate.go index d72934729c..b6a1d7b43e 100644 --- a/modules/repository/generate.go +++ b/modules/repository/generate.go @@ -173,12 +173,12 @@ func generateRepoCommit(ctx context.Context, repo, templateRepo, generateRepo *r // Avoid walking tree if there are no globs if len(gt.Globs()) > 0 { tmpDirSlash := strings.TrimSuffix(filepath.ToSlash(tmpDir), "/") + "/" - if err := filepath.Walk(tmpDirSlash, func(path string, info os.FileInfo, walkErr error) error { + if err := filepath.WalkDir(tmpDirSlash, func(path string, d os.DirEntry, walkErr error) error { if walkErr != nil { return walkErr } - if info.IsDir() { + if d.IsDir() { return nil } diff --git a/modules/storage/local.go b/modules/storage/local.go index ca51d26c9a..a6a9d54a8c 100644 --- a/modules/storage/local.go +++ b/modules/storage/local.go @@ -129,7 +129,7 @@ func (l *LocalStorage) URL(path, name string) (*url.URL, error) { // IterateObjects iterates across the objects in the local storage func (l *LocalStorage) IterateObjects(fn func(path string, obj Object) error) error { - return filepath.Walk(l.dir, func(path string, info os.FileInfo, err error) error { + return filepath.WalkDir(l.dir, func(path string, d os.DirEntry, err error) error { if err != nil { return err } @@ -141,7 +141,7 @@ func (l *LocalStorage) IterateObjects(fn func(path string, obj Object) error) er if path == l.dir { return nil } - if info.IsDir() { + if d.IsDir() { return nil } relPath, err := filepath.Rel(l.dir, path) diff --git a/routers/web/user/setting/profile.go b/routers/web/user/setting/profile.go index dac00850b1..af16195250 100644 --- a/routers/web/user/setting/profile.go +++ b/routers/web/user/setting/profile.go @@ -280,17 +280,17 @@ func Repos(ctx *context.Context) { repos := map[string]*repo_model.Repository{} // We're going to iterate by pagesize. root := user_model.UserPath(ctxUser.Name) - if err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error { + if err := filepath.WalkDir(root, func(path string, d os.DirEntry, err error) error { if err != nil { if os.IsNotExist(err) { return nil } return err } - if !info.IsDir() || path == root { + if !d.IsDir() || path == root { return nil } - name := info.Name() + name := d.Name() if !strings.HasSuffix(name, ".git") { return filepath.SkipDir } @@ -304,7 +304,7 @@ func Repos(ctx *context.Context) { count++ return filepath.SkipDir }); err != nil { - ctx.ServerError("filepath.Walk", err) + ctx.ServerError("filepath.WalkDir", err) return } diff --git a/services/repository/adopt.go b/services/repository/adopt.go index 93eeb56456..8ebf2b6a3e 100644 --- a/services/repository/adopt.go +++ b/services/repository/adopt.go @@ -303,14 +303,16 @@ func ListUnadoptedRepositories(query string, opts *db.ListOptions) ([]string, in // We're going to iterate by pagesize. root := filepath.Clean(setting.RepoRootPath) - if err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error { + if err := filepath.WalkDir(root, func(path string, d os.DirEntry, err error) error { if err != nil { return err } - if !info.IsDir() || path == root { + if !d.IsDir() || path == root { return nil } + name := d.Name() + if !strings.ContainsRune(path[len(root)+1:], filepath.Separator) { // Got a new user if err = checkUnadoptedRepositories(userName, repoNamesToCheck, unadopted); err != nil { @@ -318,16 +320,14 @@ func ListUnadoptedRepositories(query string, opts *db.ListOptions) ([]string, in } repoNamesToCheck = repoNamesToCheck[:0] - if !globUser.Match(info.Name()) { + if !globUser.Match(name) { return filepath.SkipDir } - userName = info.Name() + userName = name return nil } - name := info.Name() - if !strings.HasSuffix(name, ".git") { return filepath.SkipDir }