From e6fd7f4c073132d9f7447caaefe336b8a0582e3a Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Mon, 22 May 2023 11:01:53 -0400 Subject: [PATCH] gopls/internal/lsp/cache: limit module scan to 100K files When no go.work or go.mod file is found, gopls searches to see if there is exactly one module in a nested directory, in which case it narrows the workspace to this one module. This is a legacy workaround for polyglot repositories, and will be made obsolete by golang/go#57979. However, in the meantime this feature is still necessary, and is the last remaining place where we walk the workspace looking for modules. As reported in golang/go#56496, this search can be expensive in very large directories. Reduce the search limit 10x, from 1M->100K, and use the more efficient filepath.WalkDir. Fixes golang/go#56496 Change-Id: Ia46dd90ac2220b09debc68742dd882885c38eb42 Reviewed-on: https://go-review.googlesource.com/c/tools/+/496880 Reviewed-by: Alan Donovan TryBot-Result: Gopher Robot Run-TryBot: Robert Findley --- gopls/internal/lsp/cache/workspace.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/gopls/internal/lsp/cache/workspace.go b/gopls/internal/lsp/cache/workspace.go index de36da69b91..28179f5a0b9 100644 --- a/gopls/internal/lsp/cache/workspace.go +++ b/gopls/internal/lsp/cache/workspace.go @@ -8,6 +8,7 @@ import ( "context" "errors" "fmt" + "io/fs" "os" "path/filepath" "sort" @@ -127,7 +128,10 @@ var errExhausted = errors.New("exhausted") // Limit go.mod search to 1 million files. As a point of reference, // Kubernetes has 22K files (as of 2020-11-24). -const fileLimit = 1000000 +// +// Note: per golang/go#56496, the previous limit of 1M files was too slow, at +// which point this limit was decreased to 100K. +const fileLimit = 100_000 // findModules recursively walks the root directory looking for go.mod files, // returning the set of modules it discovers. If modLimit is non-zero, @@ -139,7 +143,7 @@ func findModules(root span.URI, excludePath func(string) bool, modLimit int) (ma modFiles := make(map[span.URI]struct{}) searched := 0 errDone := errors.New("done") - err := filepath.Walk(root.Filename(), func(path string, info os.FileInfo, err error) error { + err := filepath.WalkDir(root.Filename(), func(path string, info fs.DirEntry, err error) error { if err != nil { // Probably a permission error. Keep looking. return filepath.SkipDir