Skip to content

fix(workspace): settle gathers on first read instead of inside the edit - #537

Merged
HuiJun merged 2 commits into
developfrom
fix/lazy-workspace-regather
Sep 23, 2026
Merged

HuiJun merged 2 commits into
developfrom
fix/lazy-workspace-regather

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented Sep 22, 2026

Copy link
Copy Markdown
Contributor

What and why

Since #316, Workspace.Update ran the gather cascade (Gathers.RegathermosaUnionmosaAudit.kindOf/FeatureTypeSet over every symbol of the edited document, on a just-invalidated resolver) eagerly under the write lock. BenchmarkWorkspaceEdit/vehicle went 44.7 ms → 99.6 ms between v0.8.1 and develop while vehicle/reindex+diagnostics stayed flat (137 → 135 ms): the work moved from the first diagnostics read into every edit, i.e. onto every keystroke in the LSP.

The regather is now queued instead of run:

invalidateLocked(name):
    dropped := resolver.Invalidate(ch); drop diagCache/refs
    regatherPending += ch.Docs + gatheredDoc(dropped...)      // no cascade here

settleGathersLocked():   // called at the top of diagnosticsLocked, semanticsLocked, referencesLocked
    take regatherPending; run the previous cascade loop unchanged until nothing moves

settling guards the re-entry through contextLocked → semanticsLocked; invalidateAllLocked clears the queue. Every reader of resolver/model/diagCache/refs goes through one of the three settle points, and none of the RLock paths reach them, so settled state is only mutated under the write lock and every read sees exactly what it saw before — computed on the first read after an edit rather than inside it. Multiple edits before a read coalesce into one settle.

How it was verified

  • New TestLazyRegatherCoalescesUpdates (two updates, no read between; diagnostics match a fresh workspace with the same content); existing TestWorkspaceUnionJudgmentFollowsAnotherDocument covers the single-edit case.
  • go test ./internal/workspace/... ./internal/check/... ./internal/frontend/lsp ./internal/frontend/repl, -race on internal/workspace/model and internal/frontend/lsp.
  • Benchmarks (count 4): WorkspaceEdit/vehicle 99.6 ms → 43.7–49.3 ms (v0.8.1: 44.7 ms); vehicle/reindex+diagnostics unchanged at ~135 ms; WorkspaceEditSmallDocBesideLarge, LSP References*/WorkspaceUpdate unchanged.

Checklist

  • make test and make lint pass locally
  • Tests added or updated for the change
  • Documentation extended where it already covers the surface (see CONTRIBUTING.md)
  • Changelog entry added as changes/unreleased/<slug>.<section>.md, not as an edit to CHANGELOG.md
  • baselines regenerated and make docs-counts run if a gate count moved (compliance rows need nothing: the census is counted at docs build)
  • No internal work-item labels (waves, slices, F4, K5) in the body, docs, or changelog

devin-ai-integration Bot and others added 2 commits September 22, 2026 21:05
Co-Authored-By: jason.han <hanhuijun@gmail.com>
@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

I'll fix CI failures and address comments from users with write access. I'll skip comments containing "(aside)".

  • Disable automatic comment, CI, and merge conflict monitoring

@devin-ai-integration
devin-ai-integration Bot marked this pull request as ready for review September 22, 2026 22:06

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no bugs or issues to report.

Devin Review

@HuiJun
HuiJun merged commit c453f27 into develop Sep 23, 2026
15 checks passed
@HuiJun
HuiJun deleted the fix/lazy-workspace-regather branch September 23, 2026 01:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant