fix(tests): replace sleep-race concurrency proofs in RetailDatLoaderTests
Two tests proved "these two unrelated DAT reads ran concurrently" by racing a fixed Thread.Sleep(40) window against .NET thread-pool scheduling latency for a second Task.Run. Under the CPU contention of a full `dotnet test AcDream.slnx` run (all 9 test projects' VSTest hosts launch concurrently) plus a busy machine, thread-pool injection can occasionally miss the window, making MaxConcurrentReads read 1 instead of 2 and failing the assertion with no underlying code defect. RetailAnimationLoader and RetailPhysicsScriptLoader both coalesce same-key reads correctly via ConcurrentDictionary<K, Lazy<T>>.GetOrAdd, which is atomic and timing-independent (verified by reading, not just running) - only the test's method of proving cross-key overlap was timing-fragile. DecodedTextureCacheTests already uses the correct deterministic-gate pattern; this brings RetailDatLoaderTests in line with it via a Barrier-backed rendezvous instead of a sleep race. Filed as #248 (docs/ISSUES.md) with the full attempt matrix: could not catch the originally-reported AcDream.Content.Tests failure in the act despite ~72 Content.Tests executions across four contention strategies over ~30 full-suite-equivalent runs, though the general mechanism reproduced 3x in AcDream.App.Tests's already-known zero-allocation flake class (left untouched, out of scope here). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
3b5e099241
commit
dc0468cc2b
2 changed files with 50 additions and 7 deletions
|
|
@ -488,7 +488,23 @@ tree is recoverable from git history at `844cf092^`.
|
|||
|
||||
## #255 — Two RetailDatLoader concurrency tests measured the thread pool, not the loader
|
||||
|
||||
**Status:** REOPENED 2026-07-29 — the `LongRunning` fix is a hint, not a
|
||||
**Status:** DONE — 2026-07-30 (Campaign P adjacent; flake hunt). The
|
||||
sleep-race class was root-caused and fixed for good: the two
|
||||
`RetailDatLoaderTests` concurrency proofs raced a fixed
|
||||
`ReadDelayMilliseconds=40` window against thread-pool injection latency —
|
||||
under full-solution CPU contention (9 concurrent VSTest hosts) the second
|
||||
`Task.Run` can miss the window, observe `MaxConcurrentReads==1`, and fail
|
||||
(the Slice-P3 one-in-three full-suite failure). Production coalescing
|
||||
(`ConcurrentDictionary<K, Lazy<T>>.GetOrAdd`) verified NOT racy. Fix:
|
||||
deterministic `RawDatabase.ArmConcurrencyGate(n)` (a `Barrier` rendezvous
|
||||
inside `TryGetFileBytes`) replaces the sleep race — the same pattern
|
||||
`DecodedTextureCacheTests` already uses. Proof: 3x full solution suite
|
||||
clean + 20x isolated filtered runs clean. Hunt attempt matrix: ~72
|
||||
Content.Tests executions across four contention strategies never caught
|
||||
the original failure live; root cause established by static analysis of
|
||||
the only wall-clock-dependent file in the project. (An earlier
|
||||
worktree-based writeup of this fix was drafted against a stale base as a
|
||||
new issue; reconciled into this entry — no separate issue number.)
|
||||
guarantee; `AnimationCache_Coalesces…` still fails under full-suite load on
|
||||
Windows. Reopened independently by two sessions on the same day; both evidence
|
||||
sets are kept at the end of this issue.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue