diff --git a/internal/lsp/cache/external.go b/internal/lsp/cache/external.go index b52899ba7f..7a938a2f4c 100644 --- a/internal/lsp/cache/external.go +++ b/internal/lsp/cache/external.go @@ -15,6 +15,9 @@ import ( "golang.org/x/tools/internal/span" ) +// ioLimit limits the number of parallel file reads per process. +var ioLimit = make(chan struct{}, 128) + // nativeFileSystem implements FileSystem reading from the normal os file system. type nativeFileSystem struct{} @@ -54,6 +57,8 @@ func (h *nativeFileHandle) Kind() source.FileKind { func (h *nativeFileHandle) Read(ctx context.Context) ([]byte, string, error) { ctx, done := trace.StartSpan(ctx, "cache.nativeFileHandle.Read", telemetry.File.Of(h.identity.URI.Filename())) defer done() + ioLimit <- struct{}{} + defer func() { <-ioLimit }() //TODO: this should fail if the version is not the same as the handle data, err := ioutil.ReadFile(h.identity.URI.Filename()) if err != nil { diff --git a/internal/lsp/cache/parse.go b/internal/lsp/cache/parse.go index 3da4a6f238..8e9def8740 100644 --- a/internal/lsp/cache/parse.go +++ b/internal/lsp/cache/parse.go @@ -20,8 +20,8 @@ import ( errors "golang.org/x/xerrors" ) -// Limits the number of parallel file reads per process. -var ioLimit = make(chan struct{}, 20) +// Limits the number of parallel parser calls per process. +var parseLimit = make(chan struct{}, 20) // parseKey uniquely identifies a parsed Go file. type parseKey struct { @@ -104,13 +104,12 @@ func parseGo(ctx context.Context, c *cache, fh source.FileHandle, mode source.Pa ctx, done := trace.StartSpan(ctx, "cache.parseGo", telemetry.File.Of(fh.Identity().URI.Filename())) defer done() - ioLimit <- struct{}{} buf, _, err := fh.Read(ctx) - <-ioLimit if err != nil { return nil, err } - + parseLimit <- struct{}{} + defer func() { <-parseLimit }() parserMode := parser.AllErrors | parser.ParseComments if mode == source.ParseHeader { parserMode = parser.ImportsOnly | parser.ParseComments