internal/lsp: only cache type information for active packages

Currently, we cache source.CheckPackageHandles for each file and package
that we are aware of, as well as dependencies. This is not necessary,
since the active packages pin their imports in memory.

Change-Id: Ia0101f4d4a2d36d5baeb890af3d7c8baec297847
Reviewed-on: https://go-review.googlesource.com/c/tools/+/196982
Run-TryBot: Rebecca Stambler <rstambler@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
This commit is contained in:
Rebecca Stambler 2019-09-23 18:18:01 -04:00
parent 6816ec868d
commit 0f9bb8f614
3 changed files with 36 additions and 48 deletions

View File

@ -220,11 +220,6 @@ func (imp *importer) Import(pkgPath string) (*types.Package, error) {
return nil, err
}
imp.parentPkg.imports[packagePath(pkgPath)] = pkg
// Add every file in this package to our cache.
if err := imp.cachePackage(ctx, cph); err != nil {
return nil, err
}
return pkg.GetTypes(), nil
}
@ -335,45 +330,6 @@ func (imp *importer) child(ctx context.Context, pkg *pkg, cph *checkPackageHandl
}
}
func (imp *importer) cachePackage(ctx context.Context, cph *checkPackageHandle) error {
for _, ph := range cph.files {
uri := ph.File().Identity().URI
f, err := imp.view.GetFile(ctx, uri)
if err != nil {
return errors.Errorf("no such file %s: %v", uri, err)
}
gof, ok := f.(*goFile)
if !ok {
return errors.Errorf("%s is not a Go file", uri)
}
if err := imp.cachePerFile(ctx, gof, ph, cph); err != nil {
return errors.Errorf("failed to cache file %s: %v", gof.URI(), err)
}
}
return nil
}
func (imp *importer) cachePerFile(ctx context.Context, gof *goFile, ph source.ParseGoHandle, cph *checkPackageHandle) error {
gof.mu.Lock()
defer gof.mu.Unlock()
// Set the package even if we failed to parse the file.
if gof.cphs == nil {
gof.cphs = make(map[packageKey]*checkPackageHandle)
}
gof.cphs[packageKey{
id: cph.m.id,
mode: ph.Mode(),
}] = cph
file, _, _, err := ph.Parse(ctx)
if err != nil {
return err
}
gof.imports = file.Imports
return nil
}
func (c *cache) appendPkgError(pkg *pkg, err error) {
if err == nil {
return

View File

@ -53,6 +53,7 @@ func (h *nativeFileHandle) Identity() source.FileIdentity {
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

View File

@ -7,6 +7,7 @@ package cache
import (
"context"
"fmt"
"go/ast"
"golang.org/x/tools/go/packages"
"golang.org/x/tools/internal/lsp/source"
@ -38,15 +39,45 @@ func (view *view) loadParseTypecheck(ctx context.Context, f *goFile, fh source.F
log.Error(ctx, "loadParseTypeCheck: failed to get CheckPackageHandle", err, telemetry.Package.Of(m.id))
continue
}
// Cache this package on the file object, since all dependencies are cached in the Import function.
if err := imp.cachePackage(ctx, cph); err != nil {
log.Error(ctx, "loadParseTypeCheck: failed to cache package", err, telemetry.Package.Of(m.id))
continue
// Cache the package type information for the top-level package.
for _, ph := range cph.files {
file, _, _, err := ph.Parse(ctx)
if err != nil {
return err
}
f, err := imp.view.GetFile(ctx, ph.File().Identity().URI)
if err != nil {
return errors.Errorf("no such file %s: %v", ph.File().Identity().URI, err)
}
gof, ok := f.(*goFile)
if !ok {
return errors.Errorf("%s is not a Go file", ph.File().Identity().URI)
}
if err := cachePerFile(ctx, gof, ph.Mode(), file.Imports, cph); err != nil {
return err
}
}
}
return nil
}
func cachePerFile(ctx context.Context, f *goFile, mode source.ParseMode, imports []*ast.ImportSpec, cph *checkPackageHandle) error {
f.mu.Lock()
defer f.mu.Unlock()
f.imports = imports
if f.cphs == nil {
f.cphs = make(map[packageKey]*checkPackageHandle)
}
f.cphs[packageKey{
id: cph.m.id,
mode: mode,
}] = cph
return nil
}
func (view *view) load(ctx context.Context, f *goFile, fh source.FileHandle) ([]*metadata, error) {
ctx, done := trace.StartSpan(ctx, "cache.view.load", telemetry.URI.Of(f.URI()))
defer done()