internal/lsp/cache: fix mod file change check
The modfiles function only works with Go 1.14. When it is enabled,
it reenters the view, causing a deadlock. Stop using it, and move the
process env under a separate lock so to break the deadlock.
Change-Id: I34c528c2be1f32c06b423ead44e90155f60c2214
Reviewed-on: https://go-review.googlesource.com/c/tools/+/215679
Run-TryBot: Heschi Kreinick <heschi@google.com>
Reviewed-by: Rebecca Stambler <rstambler@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
diff --git a/internal/lsp/cache/view.go b/internal/lsp/cache/view.go
index 16fe0ae..c43d986 100644
--- a/internal/lsp/cache/view.go
+++ b/internal/lsp/cache/view.go
@@ -60,6 +60,8 @@
// mod is the module information for this view.
mod *moduleInformation
+ // importsMu guards imports-related state, particularly the ProcessEnv.
+ importsMu sync.Mutex
// process is the process env for this view.
// Note: this contains cached module and filesystem state.
//
@@ -274,8 +276,9 @@
}
func (v *view) RunProcessEnvFunc(ctx context.Context, fn func(*imports.Options) error) error {
- v.mu.Lock()
- defer v.mu.Unlock()
+ v.importsMu.Lock()
+ defer v.importsMu.Unlock()
+
if v.processEnv == nil {
var err error
if v.processEnv, err = v.buildProcessEnv(ctx); err != nil {
@@ -284,11 +287,12 @@
}
// In module mode, check if the mod file has changed.
- if mod, _, err := v.Snapshot().ModFiles(ctx); err == nil && mod != nil {
- if mod.Identity() != v.cachedModFileVersion {
+ if v.gomod != "" && v.gomod != os.DevNull {
+ mod, err := v.Snapshot().GetFile(span.FileURI(v.gomod))
+ if err == nil && mod.Identity() != v.cachedModFileVersion {
v.processEnv.GetResolver().(*imports.ModuleResolver).ClearForNewMod()
+ v.cachedModFileVersion = mod.Identity()
}
- v.cachedModFileVersion = mod.Identity()
}
// Run the user function.
@@ -323,20 +327,20 @@
func (v *view) refreshProcessEnv() {
start := time.Now()
- v.mu.Lock()
+ v.importsMu.Lock()
env := v.processEnv
env.GetResolver().ClearForNewScan()
- v.mu.Unlock()
+ v.importsMu.Unlock()
// We don't have a context handy to use for logging, so use the stdlib for now.
stdlog.Printf("background imports cache refresh starting")
err := imports.PrimeCache(context.Background(), env)
stdlog.Printf("background refresh finished after %v with err: %v", time.Since(start), err)
- v.mu.Lock()
+ v.importsMu.Lock()
v.cacheRefreshDuration = time.Since(start)
v.cacheRefreshTimer = nil
- v.mu.Unlock()
+ v.importsMu.Unlock()
}
func (v *view) buildProcessEnv(ctx context.Context) (*imports.ProcessEnv, error) {