FCS: fix races that made the background builder repeat work - #20481
Open
auduchinok wants to merge 3 commits into
Open
FCS: fix races that made the background builder repeat work#20481auduchinok wants to merge 3 commits into
auduchinok wants to merge 3 commits into
Conversation
- IncrementalBuilder: read and replace the state under the semaphore, so concurrent requests after a file change no longer each build their own chain of bound models, and concurrent NotifyFileChanged calls no longer lose each other's notification. - BackgroundCompiler: replace the builder node only if nobody else already did, so invalidated references create one builder instead of one per concurrent caller. - BackgroundCompiler: memoize parse results as a node created under the cache lock, so concurrent parses of the same source share one parse. - Add a stress test: 50 concurrent project checks after a file change type-checked every file 10 times before, once now. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Contributor
❗ Release notes requiredYou can open this PR in browser to add release notes: open in github.dev
|
T-Gro
reviewed
Sep 9, 2026
| // STATIC ROOT: FSharpLanguageServiceTestable.FSharpChecker.parseFileInProjectCache. Most recently used cache for parsing files. | ||
| let parseFileCache = | ||
| MruCache<ParseCacheLockToken, _ * SourceTextHash * _, _>( | ||
| MruCache<ParseCacheLockToken, _ * SourceTextHash * _, GraphNode<FSharpParseFileResults>>( |
Member
There was a problem hiding this comment.
🤖 🕵️ [P2] Unchanged files reparse after GC even while their parse results are retained. With FCS_ParseFileCacheSize=2 set before launch, this prints 0; true on base and 1; false on head: the weak entry targets a GraphNode that the retained result does not keep alive. Preserve weak reuse of completed results alongside in-flight sharing.
open System
open System.IO
open FSharp.Compiler.CodeAnalysis
open FSharp.Compiler.Text
let repro () =
let checker = FSharpChecker.Create(useTransparentCompiler = false)
let files = Array.init 3 (fun i -> Path.GetFullPath $"CacheProbe{i}.fs")
let options = { FSharpParsingOptions.Default with SourceFiles = files }
let source = SourceText.ofString "module CacheProbe\nlet value = 1"
let parse i = checker.ParseFile(files[i], source, options, cache = true) |> Async.RunSynchronously
let retained = Array.init 3 parse
GC.Collect()
GC.WaitForPendingFinalizers()
GC.Collect()
let before = FSharpChecker.ActualParseFileCount
let again = parse 0
printfn "%d; %b" (FSharpChecker.ActualParseFileCount - before)
(Object.ReferenceEquals(retained[0], again))
GC.KeepAlive retained
repro ()
T-Gro
self-requested a review
September 9, 2026 09:18
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The parse cache holds its older entries through a weak reference to the cached value. With a node as the value, the entry died at the next collection even while the caller still held the result, so unchanged files were reparsed. Results go back into the cache; parses that have not finished are tracked in a separate list so concurrent requests for the same source still share one parse. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.