You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
apply_configure_options (crates/pet/src/jsonrpc.rs#L661-L719, introduced by #416) holds configuration.write() for the entire for locator in locators.iter() { locator.configure(...) } loop. Previously the lock was released before configuring locators.
Refresh threads take configuration.read() in three places, all of which now block on the configure writer:
GenerationGuardedReporter::report_if_current — read lock per report_environment call (jsonrpc.rs around L416)
sync_refresh_locator_state_if_current — read lock at end of refresh (jsonrpc.rs around L376)
Result: when configure and refresh overlap, every per-environment report can block on locator I/O happening inside a different RPC handler. The Python Environments extension team attributes this regression to a pet.refreshp90 +91% on darwin and +44% on win32 in the v1.33 insiders cohort vs v1.30 stable (May 25, 2026 telemetry).
Repro
In a workspace with ≥ 3 workspace folders and ≥ 50 discovered Python envs, issue configure and refresh RPCs concurrently from the client and measure per-event durations. Pre-#416, the two are independent. Post-#416, refresh duration tracks the slowest locator's configure() runtime.
Proposed fix
Add a configure_in_progress: Mutex<()> to Context. Acquire it at the top of apply_configure_options.
Briefly take configuration.write() only to compute next_config and next_generation (without publishing).
Drop the write lock; call locator.configure(&next_config) for each locator with no lock held.
Re-take configuration.write() for a fast publish (state.config = next_config; state.generation = next_generation).
This preserves the invariant introduced in #416 (the new generation is only observable after every locator has finished configuring) while restoring concurrency between configure and refresh.
Acceptance criteria
Existing test test_configure_publishes_state_after_shared_locators_are_configured still passes (the new generation is only observable after every locator's configure() returns).
New test: while one configure is mid-locator.configure() (use a test locator that blocks on a barrier), a concurrent refresh's report_environment calls complete without blocking on the configure thread.
New test: two concurrent configure calls serialize (no interleaved locator.configure() invocations).
Filed in response to the Python Environments extension team's May 25, 2026 regression report (PET v1.33 insiders vs v1.30 stable). Combined with the Hatch I/O amplifier tracked separately, this is the leading hypothesis for the observed cross-platform p90 doubling. Related PRs: #416 (root cause), #460 (Hatch amplifier).
Summary
apply_configure_options(crates/pet/src/jsonrpc.rs#L661-L719, introduced by #416) holdsconfiguration.write()for the entirefor locator in locators.iter() { locator.configure(...) }loop. Previously the lock was released before configuring locators.Refresh threads take
configuration.read()in three places, all of which now block on the configure writer:GenerationGuardedReporter::report_if_current— read lock perreport_environmentcall (jsonrpc.rs around L416)sync_refresh_locator_state_if_current— read lock at end of refresh (jsonrpc.rs around L376)execute_refresh— snapshot read at refresh start (jsonrpc.rs around L1046)Result: when
configureandrefreshoverlap, every per-environment report can block on locator I/O happening inside a different RPC handler. The Python Environments extension team attributes this regression to apet.refreshp90 +91% on darwin and +44% on win32 in the v1.33 insiders cohort vs v1.30 stable (May 25, 2026 telemetry).Repro
In a workspace with ≥ 3 workspace folders and ≥ 50 discovered Python envs, issue
configureandrefreshRPCs concurrently from the client and measure per-event durations. Pre-#416, the two are independent. Post-#416, refresh duration tracks the slowest locator'sconfigure()runtime.Proposed fix
configure_in_progress: Mutex<()>toContext. Acquire it at the top ofapply_configure_options.configuration.write()only to computenext_configandnext_generation(without publishing).locator.configure(&next_config)for each locator with no lock held.configuration.write()for a fast publish (state.config = next_config; state.generation = next_generation).panic::catch_unwind+ rollback semantics from fix: serialize configure locator updates #416 unchanged.This preserves the invariant introduced in #416 (the new
generationis only observable after every locator has finished configuring) while restoring concurrency betweenconfigureandrefresh.Acceptance criteria
test_configure_publishes_state_after_shared_locators_are_configuredstill passes (the newgenerationis only observable after every locator'sconfigure()returns).locator.configure()(use a test locator that blocks on a barrier), a concurrent refresh'sreport_environmentcalls complete without blocking on the configure thread.configurecalls serialize (no interleavedlocator.configure()invocations).cargo fmt --all+cargo clippy --all -- -D warningsclean.Context
Filed in response to the Python Environments extension team's May 25, 2026 regression report (PET v1.33 insiders vs v1.30 stable). Combined with the Hatch I/O amplifier tracked separately, this is the leading hypothesis for the observed cross-platform p90 doubling. Related PRs: #416 (root cause), #460 (Hatch amplifier).