Revert "internal/lsp: move initialization entirely into the snapshot"
This reverts commit deb1282f0497b70cd2a6848d21a9442892ee664e.
Reason for revert: Merge conflicts for Rob's CL stack
Change-Id: I166b3bd60ec2b727a79a090049f0764864656d47
Reviewed-on: https://go-review.googlesource.com/c/tools/+/266699
Reviewed-by: Robert Findley <rfindley@google.com>
Reviewed-by: Heschi Kreinick <heschi@google.com>
diff --git a/internal/lsp/cache/load.go b/internal/lsp/cache/load.go
index dd8930c..0d07070 100644
--- a/internal/lsp/cache/load.go
+++ b/internal/lsp/cache/load.go
@@ -91,6 +91,8 @@
ctx, done := event.Start(ctx, "cache.view.load", tag.Query.Of(query))
defer done()
+ cleanup := func() {}
+
_, inv, cleanup, err := s.goCommandInvocation(ctx, source.ForTypeChecking, &gocommand.Invocation{
WorkingDir: s.view.rootURI.Filename(),
})
diff --git a/internal/lsp/cache/session.go b/internal/lsp/cache/session.go
index 6e34538..733c937 100644
--- a/internal/lsp/cache/session.go
+++ b/internal/lsp/cache/session.go
@@ -186,6 +186,9 @@
v := &View{
session: s,
+ initialized: make(chan struct{}),
+ initializationSema: make(chan struct{}, 1),
+ initializeOnce: &sync.Once{},
id: strconv.FormatInt(index, 10),
options: options,
baseCtx: baseCtx,
@@ -206,26 +209,23 @@
},
}
v.snapshot = &snapshot{
- id: snapshotID,
- view: v,
- initialized: make(chan struct{}),
- initializationSema: make(chan struct{}, 1),
- initializeOnce: &sync.Once{},
- generation: s.cache.store.Generation(generationName(v, 0)),
- packages: make(map[packageKey]*packageHandle),
- ids: make(map[span.URI][]packageID),
- metadata: make(map[packageID]*metadata),
- files: make(map[span.URI]source.VersionedFileHandle),
- goFiles: make(map[parseKey]*parseGoHandle),
- importedBy: make(map[packageID][]packageID),
- actions: make(map[actionKey]*actionHandle),
- workspacePackages: make(map[packageID]packagePath),
- unloadableFiles: make(map[span.URI]struct{}),
- parseModHandles: make(map[span.URI]*parseModHandle),
- modTidyHandles: make(map[span.URI]*modTidyHandle),
- modUpgradeHandles: make(map[span.URI]*modUpgradeHandle),
- modWhyHandles: make(map[span.URI]*modWhyHandle),
- modules: modules,
+ id: snapshotID,
+ view: v,
+ generation: s.cache.store.Generation(generationName(v, 0)),
+ packages: make(map[packageKey]*packageHandle),
+ ids: make(map[span.URI][]packageID),
+ metadata: make(map[packageID]*metadata),
+ files: make(map[span.URI]source.VersionedFileHandle),
+ goFiles: make(map[parseKey]*parseGoHandle),
+ importedBy: make(map[packageID][]packageID),
+ actions: make(map[actionKey]*actionHandle),
+ workspacePackages: make(map[packageID]packagePath),
+ unloadableFiles: make(map[span.URI]struct{}),
+ parseModHandles: make(map[span.URI]*parseModHandle),
+ modTidyHandles: make(map[span.URI]*modTidyHandle),
+ modUpgradeHandles: make(map[span.URI]*modUpgradeHandle),
+ modWhyHandles: make(map[span.URI]*modWhyHandle),
+ modules: modules,
}
v.snapshot.workspaceDirectories = v.snapshot.findWorkspaceDirectories(ctx)
diff --git a/internal/lsp/cache/snapshot.go b/internal/lsp/cache/snapshot.go
index ecd0219..f26772e 100644
--- a/internal/lsp/cache/snapshot.go
+++ b/internal/lsp/cache/snapshot.go
@@ -46,33 +46,6 @@
// builtin pins the AST and package for builtin.go in memory.
builtin *builtinPackageHandle
- // The snapshot's initialization state is controlled by the fields below.
- // These fields are propagated across snapshots to avoid multiple
- // concurrent initializations. They may be invalidated during cloning.
- //
- // initialized is closed when the snapshot has been fully initialized. On
- // initialization, the snapshot's workspace packages are loaded. All of the
- // fields below are set as part of initialization. If we failed to load, we
- // only retry if the go.mod file changes, to avoid too many go/packages
- // calls.
- //
- // When the view is created, its snapshot's initializeOnce is non-nil,
- // initialized is open. Once initialization completes, initializedErr may
- // be set and initializeOnce becomes nil. If initializedErr is non-nil,
- // initialization may be retried (depending on how files are changed). To
- // indicate that initialization should be retried, initializeOnce will be
- // set. The next time a caller requests workspace packages, the
- // initialization will retry.
- initialized chan struct{}
-
- // initializationSema is used as a mutex to guard initializeOnce and
- // initializedErr, which will be updated after each attempt to initialize
- // the snapshot. We use a channel instead of a mutex to avoid blocking when
- // a context is canceled.
- initializationSema chan struct{}
- initializeOnce *sync.Once
- initializedErr error
-
// mu guards all of the maps in the snapshot.
mu sync.Mutex
@@ -893,7 +866,7 @@
s.mu.Lock()
defer s.mu.Unlock()
if len(s.metadata) == 0 {
- return s.initializedErr
+ return s.view.initializedErr
}
return nil
}
@@ -902,7 +875,7 @@
select {
case <-ctx.Done():
return
- case <-s.initialized:
+ case <-s.view.initialized:
}
// We typically prefer to run something as intensive as the IWL without
// blocking. I'm not sure if there is a way to do that here.
@@ -1019,7 +992,7 @@
return fmt.Sprintf("v%v/%v", v.id, snapshotID)
}
-func (s *snapshot) clone(ctx context.Context, withoutURIs map[span.URI]source.VersionedFileHandle, forceReloadMetadata bool) *snapshot {
+func (s *snapshot) clone(ctx context.Context, withoutURIs map[span.URI]source.VersionedFileHandle, forceReloadMetadata bool) (*snapshot, reinitializeView) {
s.mu.Lock()
defer s.mu.Unlock()
@@ -1029,10 +1002,6 @@
generation: newGen,
view: s.view,
builtin: s.builtin,
- initialized: s.initialized,
- initializationSema: s.initializationSema,
- initializeOnce: s.initializeOnce,
- initializedErr: s.initializedErr,
ids: make(map[span.URI][]packageID),
importedBy: make(map[packageID][]packageID),
metadata: make(map[packageID]*metadata),
@@ -1329,17 +1298,20 @@
// Don't bother copying the importedBy graph,
// as it changes each time we update metadata.
+ var reinitialize reinitializeView
+ if modulesChanged {
+ reinitialize = maybeReinit
+ }
+ if shouldReinitializeView {
+ reinitialize = definitelyReinit
+ }
+
// If the snapshot's workspace mode has changed, the packages loaded using
// the previous mode are no longer relevant, so clear them out.
if s.workspaceMode() != result.workspaceMode() {
result.workspacePackages = map[packageID]packagePath{}
}
-
- // The snapshot may need to be reinitialized.
- if modulesChanged || shouldReinitializeView {
- result.reinitialize(shouldReinitializeView)
- }
- return result
+ return result, reinitialize
}
// guessPackagesForURI returns all packages related to uri. If we haven't seen this
@@ -1392,6 +1364,14 @@
return found
}
+type reinitializeView int
+
+const (
+ doNotReinit = reinitializeView(iota)
+ maybeReinit
+ definitelyReinit
+)
+
// fileWasSaved reports whether the FileHandle passed in has been saved. It
// accomplishes this by checking to see if the original and current FileHandles
// are both overlays, and if the current FileHandle is saved while the original
diff --git a/internal/lsp/cache/view.go b/internal/lsp/cache/view.go
index 008acef..42017a8 100644
--- a/internal/lsp/cache/view.go
+++ b/internal/lsp/cache/view.go
@@ -68,13 +68,34 @@
filesByURI map[span.URI]*fileBase
filesByBase map[string][]*fileBase
- // initCancelFirstAttempt can be used to terminate the view's first
- // attempt at initialization.
- initCancelFirstAttempt context.CancelFunc
-
snapshotMu sync.Mutex
snapshot *snapshot
+ // initialized is closed when the view has been fully initialized. On
+ // initialization, the view's workspace packages are loaded. All of the
+ // fields below are set as part of initialization. If we failed to load, we
+ // only retry if the go.mod file changes, to avoid too many go/packages
+ // calls.
+ //
+ // When the view is created, initializeOnce is non-nil, initialized is
+ // open, and initCancelFirstAttempt can be used to terminate
+ // initialization. Once initialization completes, initializedErr may be set
+ // and initializeOnce becomes nil. If initializedErr is non-nil,
+ // initialization may be retried (depending on how files are changed). To
+ // indicate that initialization should be retried, initializeOnce will be
+ // set. The next time a caller requests workspace packages, the
+ // initialization will retry.
+ initialized chan struct{}
+ initCancelFirstAttempt context.CancelFunc
+
+ // initializationSema is used as a mutex to guard initializeOnce and
+ // initializedErr, which will be updated after each attempt to initialize
+ // the view. We use a channel instead of a mutex to avoid blocking when a
+ // context is canceled.
+ initializationSema chan struct{}
+ initializeOnce *sync.Once
+ initializedErr error
+
// workspaceInformation tracks various details about this view's
// environment variables, go version, and use of modules.
workspaceInformation
@@ -474,21 +495,21 @@
select {
case <-ctx.Done():
return
- case s.initializationSema <- struct{}{}:
+ case s.view.initializationSema <- struct{}{}:
}
defer func() {
- <-s.initializationSema
+ <-s.view.initializationSema
}()
- if s.initializeOnce == nil {
+ if s.view.initializeOnce == nil {
return
}
- s.initializeOnce.Do(func() {
+ s.view.initializeOnce.Do(func() {
defer func() {
- s.initializeOnce = nil
+ s.view.initializeOnce = nil
if firstAttempt {
- close(s.initialized)
+ close(s.view.initialized)
}
}()
@@ -536,9 +557,9 @@
if err != nil {
event.Error(ctx, "initial workspace load failed", err)
if modErrors != nil {
- s.initializedErr = errors.Errorf("errors loading modules: %v: %w", err, modErrors)
+ s.view.initializedErr = errors.Errorf("errors loading modules: %v: %w", err, modErrors)
} else {
- s.initializedErr = err
+ s.view.initializedErr = err
}
}
})
@@ -563,9 +584,14 @@
defer v.snapshotMu.Unlock()
oldSnapshot := v.snapshot
- v.snapshot = oldSnapshot.clone(ctx, uris, forceReloadMetadata)
+ var reinitialize reinitializeView
+ v.snapshot, reinitialize = oldSnapshot.clone(ctx, uris, forceReloadMetadata)
go oldSnapshot.generation.Destroy()
+ if reinitialize == maybeReinit || reinitialize == definitelyReinit {
+ v.reinitialize(reinitialize == definitelyReinit)
+ }
+
return v.snapshot, v.snapshot.generation.Acquire(ctx)
}
@@ -580,17 +606,17 @@
v.backgroundCtx, v.cancel = context.WithCancel(v.baseCtx)
}
-func (s *snapshot) reinitialize(force bool) {
- s.initializationSema <- struct{}{}
+func (v *View) reinitialize(force bool) {
+ v.initializationSema <- struct{}{}
defer func() {
- <-s.initializationSema
+ <-v.initializationSema
}()
- if !force && s.initializedErr == nil {
+ if !force && v.initializedErr == nil {
return
}
var once sync.Once
- s.initializeOnce = &once
+ v.initializeOnce = &once
}
func (s *Session) getWorkspaceInformation(ctx context.Context, folder span.URI, options *source.Options) (*workspaceInformation, error) {