Skip to content

Commit c7c8212

Browse files
Simplify mkCacheInt32/mkCacheGeneric to use ConcurrentDictionary (#486)
`mkCacheInt32` and `mkCacheGeneric` were using `Dictionary` + `lock syncObj`, serializing all cache access including expensive metadata decode work. ## Changes - **`mkCacheInt32` / `mkCacheGeneric`**: replaced `Dictionary` + `lock` with `ConcurrentDictionary` using `TryGetValue` / `TryAdd`. No locks, no `syncObj`. ```fsharp let mkCacheInt32 lowMem _infile _nm _sz = if lowMem then (fun f x -> f x) else let cache = ConcurrentDictionary<int32, _>() fun f (idx:int32) -> match cache.TryGetValue idx with | true, v -> v | false, _ -> let v = f idx cache.TryAdd(idx, v) |> ignore cache.[idx] ``` `GetOrAdd(key, factory)` was not usable here — F# type inference cannot disambiguate it from `GetOrAdd(key, value)` when the value type is an unconstrained generic. `TryAdd` has no overloads and sidesteps the issue. On a concurrent cache miss, `f idx` may be computed twice (both `GetOrAdd` with factory and this pattern share that behaviour per the .NET docs), which is acceptable since these factories are pure metadata reads. <!-- START COPILOT CODING AGENT TIPS --> --- ⌨️ Start Copilot coding agent tasks without leaving your editor — available in [VS Code](https://gh.io/cca-vs-code-docs), [Visual Studio](https://gh.io/cca-visual-studio-docs), [JetBrains IDEs](https://gh.io/cca-jetbrains-docs) and [Eclipse](https://gh.io/cca-eclipse-docs). --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: sergey-tihon <1197905+sergey-tihon@users.noreply.github.com>
1 parent c38ff71 commit c7c8212

1 file changed

Lines changed: 14 additions & 18 deletions

File tree

src/ProvidedTypes.fs

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4586,29 +4586,25 @@ module internal AssemblyReader =
45864586

45874587
let mkCacheInt32 lowMem _infile _nm _sz =
45884588
if lowMem then (fun f x -> f x) else
4589-
let cache = Dictionary<int32, _>()
4590-
let syncObj = obj()
4589+
let cache = ConcurrentDictionary<int32, _>()
45914590
fun f (idx:int32) ->
4592-
lock syncObj (fun () ->
4593-
let mutable res = Unchecked.defaultof<_>
4594-
if cache.TryGetValue(idx, &res) then res
4595-
else
4596-
let v = f idx
4597-
cache.[idx] <- v
4598-
v)
4591+
match cache.TryGetValue idx with
4592+
| true, v -> v
4593+
| false, _ ->
4594+
let v = f idx
4595+
cache.TryAdd(idx, v) |> ignore
4596+
cache.[idx]
45994597

46004598
let mkCacheGeneric lowMem _inbase _nm _sz =
46014599
if lowMem then (fun f x -> f x) else
4602-
let cache = Dictionary<'T, _>()
4603-
let syncObj = obj()
4600+
let cache = ConcurrentDictionary<'T, _>()
46044601
fun f (idx :'T) ->
4605-
lock syncObj (fun () ->
4606-
match cache.TryGetValue idx with
4607-
| true, cached -> cached
4608-
| false, _ ->
4609-
let v = f idx
4610-
cache.[idx] <- v
4611-
v)
4602+
match cache.TryGetValue idx with
4603+
| true, v -> v
4604+
| false, _ ->
4605+
let v = f idx
4606+
cache.TryAdd(idx, v) |> ignore
4607+
cache.[idx]
46124608

46134609
let seekFindRow numRows rowChooser =
46144610
let mutable i = 1

0 commit comments

Comments
 (0)