Skip to content

Commit f394d45

Browse files
committed
gopls/internal/lsp/cache: compute xrefs and methodsets asynchronously
No need to wait on xrefs or methodsets while performing latency-sensitive operations on packages. For golang/go#53992 Change-Id: I9ea65269a8c1e604fb99ed8b25e14db79f179576 Reviewed-on: https://go-review.googlesource.com/c/tools/+/503015 gopls-CI: kokoro <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Run-TryBot: Robert Findley <[email protected]> Reviewed-by: Alan Donovan <[email protected]>
1 parent 27dbf85 commit f394d45

File tree

3 files changed

+37
-23
lines changed

3 files changed

+37
-23
lines changed

gopls/internal/lsp/cache/check.go

+14-16
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,7 @@ import (
2626
"golang.org/x/tools/gopls/internal/lsp/filecache"
2727
"golang.org/x/tools/gopls/internal/lsp/protocol"
2828
"golang.org/x/tools/gopls/internal/lsp/source"
29-
"golang.org/x/tools/gopls/internal/lsp/source/methodsets"
3029
"golang.org/x/tools/gopls/internal/lsp/source/typerefs"
31-
"golang.org/x/tools/gopls/internal/lsp/source/xrefs"
3230
"golang.org/x/tools/gopls/internal/span"
3331
"golang.org/x/tools/internal/event"
3432
"golang.org/x/tools/internal/event/tag"
@@ -44,6 +42,8 @@ const (
4442
preserveImportGraph = true // hold on to the import graph for open packages
4543
)
4644

45+
type unit = struct{}
46+
4747
// A typeCheckBatch holds data for a logical type-checking operation, which may
4848
// type-check many unrelated packages.
4949
//
@@ -56,7 +56,7 @@ type typeCheckBatch struct {
5656
handles map[PackageID]*packageHandle
5757
parseCache *parseCache
5858
fset *token.FileSet // describes all parsed or imported files
59-
cpulimit chan struct{} // concurrency limiter for CPU-bound operations
59+
cpulimit chan unit // concurrency limiter for CPU-bound operations
6060

6161
mu sync.Mutex
6262
syntaxPackages map[PackageID]*futurePackage // results of processing a requested package; may hold (nil, nil)
@@ -69,7 +69,7 @@ type typeCheckBatch struct {
6969
// The goroutine that creates the futurePackage is responsible for evaluating
7070
// its value, and closing the done channel.
7171
type futurePackage struct {
72-
done chan struct{}
72+
done chan unit
7373
v pkgOrErr
7474
}
7575

@@ -154,7 +154,7 @@ func (s *snapshot) getImportGraph(ctx context.Context) *importGraph {
154154
// for the work to be done.
155155
done := s.importGraphDone
156156
if done == nil {
157-
done = make(chan struct{})
157+
done = make(chan unit)
158158
s.importGraphDone = done
159159
release := s.Acquire() // must acquire to use the snapshot asynchronously
160160
go func() {
@@ -360,7 +360,7 @@ func (s *snapshot) forEachPackageInternal(ctx context.Context, importGraph *impo
360360
handles: handles,
361361
fset: fileSetWithBase(reservedForParsing),
362362
syntaxIndex: make(map[PackageID]int),
363-
cpulimit: make(chan struct{}, runtime.GOMAXPROCS(0)),
363+
cpulimit: make(chan unit, runtime.GOMAXPROCS(0)),
364364
syntaxPackages: make(map[PackageID]*futurePackage),
365365
importPackages: make(map[PackageID]*futurePackage),
366366
}
@@ -369,7 +369,7 @@ func (s *snapshot) forEachPackageInternal(ctx context.Context, importGraph *impo
369369
// Clone the file set every time, to ensure we do not leak files.
370370
b.fset = tokeninternal.CloneFileSet(importGraph.fset)
371371
// Pre-populate future cache with 'done' futures.
372-
done := make(chan struct{})
372+
done := make(chan unit)
373373
close(done)
374374
for id, res := range importGraph.imports {
375375
b.importPackages[id] = &futurePackage{done, res}
@@ -427,7 +427,7 @@ func (b *typeCheckBatch) getImportPackage(ctx context.Context, id PackageID) (pk
427427
}
428428
}
429429

430-
f = &futurePackage{done: make(chan struct{})}
430+
f = &futurePackage{done: make(chan unit)}
431431
b.importPackages[id] = f
432432
b.mu.Unlock()
433433

@@ -479,7 +479,7 @@ func (b *typeCheckBatch) handleSyntaxPackage(ctx context.Context, i int, id Pack
479479
return f.v.pkg, f.v.err
480480
}
481481

482-
f = &futurePackage{done: make(chan struct{})}
482+
f = &futurePackage{done: make(chan unit)}
483483
b.syntaxPackages[id] = f
484484
b.mu.Unlock()
485485
defer func() {
@@ -508,7 +508,7 @@ func (b *typeCheckBatch) handleSyntaxPackage(ctx context.Context, i int, id Pack
508508
select {
509509
case <-ctx.Done():
510510
return nil, ctx.Err()
511-
case b.cpulimit <- struct{}{}:
511+
case b.cpulimit <- unit{}:
512512
defer func() {
513513
<-b.cpulimit // release CPU token
514514
}()
@@ -637,8 +637,8 @@ func (b *typeCheckBatch) checkPackage(ctx context.Context, ph *packageHandle) (*
637637
// Write package data to disk asynchronously.
638638
go func() {
639639
toCache := map[string][]byte{
640-
xrefsKind: pkg.xrefs,
641-
methodSetsKind: pkg.methodsets.Encode(),
640+
xrefsKind: pkg.xrefs(),
641+
methodSetsKind: pkg.methodsets().Encode(),
642642
diagnosticsKind: encodeDiagnostics(pkg.diagnostics),
643643
}
644644

@@ -763,13 +763,13 @@ func (s *snapshot) getPackageHandles(ctx context.Context, ids []PackageID) (map[
763763
// Collect all reachable IDs, and create done channels.
764764
// TODO: opt: modify SortPostOrder to make this pre-traversal unnecessary.
765765
var allIDs []PackageID
766-
dones := make(map[PackageID]chan struct{})
766+
dones := make(map[PackageID]chan unit)
767767
var walk func(PackageID)
768768
walk = func(id PackageID) {
769769
if _, ok := dones[id]; ok {
770770
return
771771
}
772-
dones[id] = make(chan struct{})
772+
dones[id] = make(chan unit)
773773
allIDs = append(allIDs, id)
774774
m := meta.metadata[id]
775775
for _, depID := range m.DepsByPkgPath {
@@ -1262,8 +1262,6 @@ func typeCheckImpl(ctx context.Context, b *typeCheckBatch, inputs typeCheckInput
12621262
if err != nil {
12631263
return nil, err
12641264
}
1265-
pkg.methodsets = methodsets.NewIndex(pkg.fset, pkg.types)
1266-
pkg.xrefs = xrefs.Index(pkg.compiledGoFiles, pkg.types, pkg.typesInfo)
12671265

12681266
// Our heuristic for whether to show type checking errors is:
12691267
// + If any file was 'fixed', don't show type checking errors as we

gopls/internal/lsp/cache/pkg.go

+21-5
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,11 @@ import (
1111
"go/scanner"
1212
"go/token"
1313
"go/types"
14+
"sync"
1415

1516
"golang.org/x/tools/gopls/internal/lsp/source"
1617
"golang.org/x/tools/gopls/internal/lsp/source/methodsets"
18+
"golang.org/x/tools/gopls/internal/lsp/source/xrefs"
1719
"golang.org/x/tools/gopls/internal/span"
1820
)
1921

@@ -53,11 +55,25 @@ type syntaxPackage struct {
5355
importMap map[PackagePath]*types.Package
5456
hasFixedFiles bool // if true, AST was sufficiently mangled that we should hide type errors
5557

56-
// TODO(rfindley): opt: xrefs and methodsets do not need to be pinned to the
57-
// package, and perhaps should be computed asynchronously to package
58-
// diagnostics.
59-
xrefs []byte
60-
methodsets *methodsets.Index
58+
xrefsOnce sync.Once
59+
_xrefs []byte // only used by the xrefs method
60+
61+
methodsetsOnce sync.Once
62+
_methodsets *methodsets.Index // only used by the methodsets method
63+
}
64+
65+
func (p *syntaxPackage) xrefs() []byte {
66+
p.xrefsOnce.Do(func() {
67+
p._xrefs = xrefs.Index(p.compiledGoFiles, p.types, p.typesInfo)
68+
})
69+
return p._xrefs
70+
}
71+
72+
func (p *syntaxPackage) methodsets() *methodsets.Index {
73+
p.methodsetsOnce.Do(func() {
74+
p._methodsets = methodsets.NewIndex(p.fset, p.types)
75+
})
76+
return p._methodsets
6177
}
6278

6379
func (p *Package) String() string { return string(p.ph.m.ID) }

gopls/internal/lsp/cache/snapshot.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -688,7 +688,7 @@ func (s *snapshot) References(ctx context.Context, ids ...PackageID) ([]source.X
688688
return true
689689
}
690690
post := func(i int, pkg *Package) {
691-
indexes[i] = XrefIndex{m: pkg.ph.m, data: pkg.pkg.xrefs}
691+
indexes[i] = XrefIndex{m: pkg.ph.m, data: pkg.pkg.xrefs()}
692692
}
693693
return indexes, s.forEachPackage(ctx, ids, pre, post)
694694
}
@@ -719,7 +719,7 @@ func (s *snapshot) MethodSets(ctx context.Context, ids ...PackageID) ([]*methods
719719
return true
720720
}
721721
post := func(i int, pkg *Package) {
722-
indexes[i] = pkg.pkg.methodsets
722+
indexes[i] = pkg.pkg.methodsets()
723723
}
724724
return indexes, s.forEachPackage(ctx, ids, pre, post)
725725
}

0 commit comments

Comments
 (0)