Verify preview admission bounds under contention and worker unwind

This commit is contained in:
karl committed 2026-10-13 14:38:24 +02:00
1 parent ec75a52cf7
commit c8e611081f
2 files changed
+55 -2

No files matched your search

@@ -413,6 +413,51 @@ pub fn error_response(status: StatusCode) -> Response<Vec<u8>> {
mod tests { mod tests {
use super::*; use super::*;
#[test]
fn concurrent_admission_stays_bounded_and_unwind_releases_capacity() {
let registry = Arc::new(PreviewRegistry::default());
let active = Arc::new(AtomicUsize::new(0));
let barrier = Arc::new(std::sync::Barrier::new(8));
let workers: Vec<_> = (0..8)
.map(|_| {
let registry = registry.clone();
let active = active.clone();
let barrier = barrier.clone();
std::thread::spawn(move || {
barrier.wait();
for _ in 0..500 {
if let Some(admission) = registry.admit() {
let count = active.fetch_add(1, Ordering::SeqCst) + 1;
assert!(count <= MAX_REQUESTS);
std::thread::yield_now();
active.fetch_sub(1, Ordering::SeqCst);
drop(admission);
}
}
})
})
.collect();
for worker in workers {
worker.join().unwrap();
}
assert_eq!(active.load(Ordering::SeqCst), 0);
assert_eq!(registry.requests.load(Ordering::SeqCst), 0);
let first = registry.admit().unwrap();
let interrupted = registry.clone();
assert!(std::panic::catch_unwind(move || {
let _second = interrupted.admit().unwrap();
panic!("injected preview worker panic");
})
.is_err());
let second = registry
.admit()
.expect("Unwinding must release the second slot");
assert!(registry.admit().is_none());
drop(first);
drop(second);
assert_eq!(registry.requests.load(Ordering::SeqCst), 0);
}
struct Fixture { struct Fixture {
_directory: tempfile::TempDir, _directory: tempfile::TempDir,
database: PathBuf, database: PathBuf,
+10 -2
View File
@@ -21,7 +21,8 @@ Index-change notifications also advance the preview selection identity, so a
same-path image/recording reloads rather than retaining previously decoded media. same-path image/recording reloads rather than retaining previously decoded media.
Failed native preview preparation and image/audio/video loading now offer an explicit **Retry preview** Failed native preview preparation and image/audio/video loading now offer an explicit **Retry preview**
button. It invalidates the old request revision and cannot restart a selection button. It invalidates the old request revision and cannot restart a selection
that has since changed. There is no automatic retry loop. The added regression that has since changed. Busy preparation receives at most one delayed retry;
other failures require explicit user action, with no unbounded retry loop. The added regression
passed with all 60 frontend tests, formatting and the production frontend build. passed with all 60 frontend tests, formatting and the production frontend build.
This does not hash every recording on every request. A same-size/mtime in-place This does not hash every recording on every request. A same-size/mtime in-place
@@ -53,7 +54,7 @@ for these protocol regressions.
Ubuntu 24.04 WSL compiled the immutable `370db7e` Git snapshot with the locked Ubuntu 24.04 WSL compiled the immutable `370db7e` Git snapshot with the locked
dependencies and `SEARCHI_FORCE_CPU=1`. All nine preview tests passed in 0.73 s; dependencies and `SEARCHI_FORCE_CPU=1`. All nine preview tests passed in 0.73 s;
the complete native desktop suite then passed 45/45 in 2.78 s, with no skips. the complete native desktop suite then passed 45/45 in 2.78 s, with no skips.
The native source tree remains identical to that snapshot; subsequent commits At the time of validation the native source tree matched that snapshot; subsequent commits
changed frontend retry behavior only. Compilation took 8m 18s after missing changed frontend retry behavior only. Compilation took 8m 18s after missing
locked dependencies were fetched. An initial offline attempt could not resolve locked dependencies were fetched. An initial offline attempt could not resolve
the uncached Single-Instance plugin; it was not a product test failure. the uncached Single-Instance plugin; it was not a product test failure.
@@ -69,3 +70,10 @@ The existing vendored GLib code emitted 34 compiler warnings. This was a debug
Rust test build, not strict Linux Clippy, a packaged desktop launch, WebKit Rust test build, not strict Linux Clippy, a packaged desktop launch, WebKit
playback, GPU inference or macOS validation. No model inference was executed. playback, GPU inference or macOS validation. No model inference was executed.
Native custom-protocol playback and seeking remain open on all release systems. Native custom-protocol playback and seeking remain open on all release systems.
A subsequent Windows CPU concurrency regression ran eight threads with 500
admission attempts each and checked that no more than two admitted jobs overlap.
It also injected a worker unwind and verified that capacity is released rather
than remaining busy. All 46 native tests passed in 1.04 s and strict all-target
Clippy passed. This added test was not included in the earlier Linux 45-test
snapshot; no additional production protocol behavior changed.