Skip to content

fix: share the per-repo SCIP LMDB env; clear frozen C# index error state - #214

Merged
flupkede merged 2 commits into
developfrom
fix/scip-lmdb-double-open
Aug 21, 2026
Merged

fix: share the per-repo SCIP LMDB env; clear frozen C# index error state#214
flupkede merged 2 commits into
developfrom
fix/scip-lmdb-double-open

Conversation

@flupkede

Copy link
Copy Markdown
Owner

Problem

Every SCIP symbol-index operation (C#/TS query, watcher rebuild, lazy find-refs, ref-cache prewarm) opened its own short-lived LMDB env on db_path/scip. LMDB allows only one open env per directory per process, so any overlap between a long-lived query (a lazy find-refs can hold its env for minutes on a large solution) and a watcher-triggered rebuild failed the loser with "LMDB double-open prevented". Observed live: HUSQ.Aprimo-231210's C# rebuild failed mid-session, and HUSQ.Aprimo-209169's failure froze as a permanent red C#! in the TUI status view (repo_statuses_lightweight prefers the cached error over its on-disk probe, and a closed repo has no watcher left to retry or clear it).

Fix

  1. Shared SCIP LMDB env (src/lmdb_registry.rs, src/symbols/mod.rs, src/symbols/csharp.rs, src/symbols/typescript.rs, src/constants.rs): all SCIP opens now route through a Weak-ref-cached get_or_open_shared_env. Concurrent callers (C# and TS both) share one Arc; writers serialize on LMDB's single-writer mutex instead of failing each other. The cache never keeps an env alive - last Arc drop still closes and frees the slot, so remove_repo's holder-drain is unaffected.
  2. Error-state lifecycle (src/serve/mod.rs): evict_idle_repos and close_repo now clear the cached csharp_index_status/csharp_index_error entries for the alias, letting the on-disk probe (helper available + index exists -> Ready) restore the truth instead of freezing a stale Error forever.

Verification

  • New unit tests: lmdb_registry shared-env concurrency/reopen/init-failure tests, symbols::mod wiring test, serve::tests::evicting_idle_repo_clears_frozen_csharp_error_state.
  • Full suite green on this branch: 618 passed / 0 failed, clippy clean, fmt clean (QC gate on push).
  • Reviewed in 2 stages + 1 final full-range review, all PASS.

CHANGELOG entry added under the [1.3.4] pending heading.

…rebuilds and adapters

Every SCIP operation (C#/TS query, watcher rebuild, lazy find-refs,
ref-cache prewarm) opened its own short-lived TrackedEnv on db_path/scip.
LMDB allows one open env per directory per process, so any overlap — a
rebuild starting while a lazy find-refs held its env for minutes —
failed the loser with `LMDB double-open prevented` (observed live on
HUSQ.Aprimo-231210: rebuild failed at the exact moment a 35s-old
find-refs env was alive; the resulting red `C#!` froze on the TUI).

All opens now route through get_or_open_shared_env (Weak-ref cache in
lmdb_registry): concurrent users get the same Arc<TrackedEnv>, writers
serialise on LMDB's single-writer mutex, readers never block, C# and TS
share one env (5 named DBs pre-created once per session). The cache
never keeps an env alive: last Arc drop still closes + frees the slot,
so remove_repo's holder-drain is unaffected. scip_meta hoisted to
constants (was a duplicated literal in both adapters).

Review-fixes:
- [Design] get_or_open_shared_env doc: closures run under the cache shard lock and must not re-enter (self-deadlock on same shard)
- [Debt] csharp.rs comments still asserted the old per-caller-env invariant ("opens its own env", "must drop before ... opens its own env") — rewritten for the shared env
repo_statuses_lightweight() prefers the cached csharp_index_status over
its on-disk probe, so an Error entry outlives the repo itself: a closed
repo has no watcher left to retry a rebuild or emit Succeeded, and the
red `C#!` renders forever (observed: HUSQ.Aprimo-209169 stuck red for
days after losing one double-open race before 2026-08-18).

evict_idle_repos and close_repo now clear the status+error entries; the
fallback probe (helper available + index exists -> Ready) restores the
on-disk truth. Regression test with EnvRestore + serial pins eviction
clearing both maps.

CHANGELOG: entry for both stages under the pending [1.3.4] section
(assumption: extend the existing undated top section, matching where
PR #213 added its entry after the 1.3.5 auto-bump).

Review-fixes:
- [Debt] clear_csharp_index_state doc overclaimed "called whenever a repo's stores close" — remove_repo deliberately skips it (unregistered alias = display-unreachable entry); doc now states the asymmetry
@flupkede
flupkede merged commit 235ab76 into develop Aug 21, 2026
4 of 5 checks passed
@flupkede
flupkede deleted the fix/scip-lmdb-double-open branch August 21, 2026 08:37
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