Skip to content

Commit f4c8627

Browse files
committed
gopls: fix raciness related to TestOrphanedFiles
While investigating the high rate of flakiness in TestOrphanedFiles, I found two problems: - The change to use Await(...) rather than AfterChange(..), which was intended to *avoid* flakes due to asynchronous log messages, actually increased flakiness. After that change, the test can sometimes proceed to make additional edits before change processing completes, so that the load succeeds but the snapshot is cloned before the resulting state can be written (sigh...). - If the load succeeds, we should proceed to update state even if the context is cancelled. Writing the state is not expensive. Fixes golang/go#61521 Change-Id: I4e70526a0108013c66d378da966289a7c2f5dbe2 Reviewed-on: https://go-review.googlesource.com/c/tools/+/518975 TryBot-Result: Gopher Robot <[email protected]> Run-TryBot: Robert Findley <[email protected]> Reviewed-by: Alan Donovan <[email protected]> gopls-CI: kokoro <[email protected]>
1 parent 6290d8a commit f4c8627

File tree

2 files changed

+21
-11
lines changed

2 files changed

+21
-11
lines changed

gopls/internal/lsp/cache/snapshot.go

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -755,12 +755,22 @@ func (s *snapshot) MetadataForFile(ctx context.Context, uri span.URI) ([]*source
755755
scope := fileLoadScope(uri)
756756
err := s.load(ctx, false, scope)
757757

758-
// Guard against failed loads due to context cancellation.
759758
//
760759
// Return the context error here as the current operation is no longer
761760
// valid.
762-
if ctxErr := ctx.Err(); ctxErr != nil {
763-
return nil, ctxErr
761+
if err != nil {
762+
// Guard against failed loads due to context cancellation. We don't want
763+
// to mark loads as completed if they failed due to context cancellation.
764+
if ctx.Err() != nil {
765+
return nil, ctx.Err()
766+
}
767+
768+
// Don't return an error here, as we may still return stale IDs.
769+
// Furthermore, the result of MetadataForFile should be consistent upon
770+
// subsequent calls, even if the file is marked as unloadable.
771+
if !errors.Is(err, errNoPackages) {
772+
event.Error(ctx, "MetadataForFile", err)
773+
}
764774
}
765775

766776
// We must clear scopes after loading.
@@ -769,13 +779,6 @@ func (s *snapshot) MetadataForFile(ctx context.Context, uri span.URI) ([]*source
769779
// packages as loaded. We could do this from snapshot.load and avoid
770780
// raciness.
771781
s.clearShouldLoad(scope)
772-
773-
// Don't return an error here, as we may still return stale IDs.
774-
// Furthermore, the result of MetadataForFile should be consistent upon
775-
// subsequent calls, even if the file is marked as unloadable.
776-
if err != nil && !errors.Is(err, errNoPackages) {
777-
event.Error(ctx, "MetadataForFile", err)
778-
}
779782
}
780783

781784
// Retrieve the metadata.

gopls/internal/regtest/diagnostics/diagnostics_test.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1307,7 +1307,14 @@ func _() {
13071307
env.OpenFile("a/a_exclude.go")
13081308

13091309
loadOnce := LogMatching(protocol.Info, "query=.*file=.*a_exclude.go", 1, false)
1310-
env.Await(loadOnce) // can't use OnceMet or AfterChange as logs are async
1310+
1311+
// can't use OnceMet or AfterChange as logs are async
1312+
env.Await(loadOnce)
1313+
// ...but ensure that the change has been fully processed before editing.
1314+
// Otherwise, there may be a race where the snapshot is cloned before all
1315+
// state changes resulting from the load have been processed
1316+
// (golang/go#61521).
1317+
env.AfterChange()
13111318

13121319
// Check that orphaned files are not reloaded, by making a change in
13131320
// a.go file and confirming that the workspace diagnosis did not reload

0 commit comments

Comments
 (0)