feat(mt): move worker trace policy to Rust

Move the first-job versus continuation-job trace policy out of the C worker
callback. Rust now decides when the external-dictionary assertion is required
and orders it before the trace, while C retains the private window assertion
and trace-recording leaves.

Test Plan:
- ulimit -v 41943040; CARGO_BUILD_JOBS=1 cargo check --tests
- ulimit -v 41943040; CARGO_BUILD_JOBS=1 cargo clippy --tests -- -A clippy::manual-bits -D warnings
- ulimit -v 41943040; make -j1
- ulimit -v 41943040; make -j1 -C tests test
This commit is contained in:
2026-07-21 23:17:26 +02:00
parent cf6a316693
commit 9589c5e327
2 changed files with 128 additions and 8 deletions
+84
View File
@@ -840,6 +840,67 @@ const _: () = {
+ size_of::<ZSTDMT_compressionJobFinishPublicationProjection>());
};
/// C retains the private window assertion and trace-recording leaves for an
/// MT worker. Rust owns the first-job policy that determines whether the
/// external-dictionary assertion is required before tracing.
#[repr(C)]
#[derive(Clone, Copy)]
pub struct ZSTDMT_compressionJobTraceProjection {
pub callbackContext: *mut c_void,
pub firstJob: c_uint,
pub assertNoExtDict: Option<ZSTDMT_compressionJobVoidFn>,
pub trace: Option<ZSTDMT_compressionJobVoidFn>,
}
const _: () = {
assert!(offset_of!(ZSTDMT_compressionJobTraceProjection, callbackContext) == 0);
assert!(offset_of!(ZSTDMT_compressionJobTraceProjection, firstJob) == size_of::<usize>());
assert!(
offset_of!(ZSTDMT_compressionJobTraceProjection, assertNoExtDict)
== 2 * size_of::<usize>()
);
assert!(offset_of!(ZSTDMT_compressionJobTraceProjection, trace) == 3 * size_of::<usize>());
assert!(size_of::<ZSTDMT_compressionJobTraceProjection>() == 4 * size_of::<usize>());
};
#[inline]
fn compression_job_trace_with<A, T>(first_job: c_uint, mut assert_no_ext_dict: A, mut trace: T)
where
A: FnMut(),
T: FnMut(),
{
if first_job == 0 {
assert_no_ext_dict();
}
trace();
}
/// Apply the worker trace policy while C retains the opaque trace leaves.
#[no_mangle]
pub unsafe extern "C" fn ZSTDMT_rust_compressionJobTrace(
projection: *const ZSTDMT_compressionJobTraceProjection,
) {
let Some(projection) = (unsafe { projection.as_ref() }) else {
return;
};
let Some(trace) = projection.trace else {
return;
};
if projection.firstJob == 0 && projection.assertNoExtDict.is_none() {
return;
}
let assert_no_ext_dict = projection.assertNoExtDict;
compression_job_trace_with(
projection.firstJob,
|| {
if let Some(assert_no_ext_dict) = assert_no_ext_dict {
unsafe { assert_no_ext_dict(projection.callbackContext) };
}
},
|| unsafe { trace(projection.callbackContext) },
);
}
pub type ZSTDMT_serialWaitForTurnFn = unsafe extern "C" fn(*mut c_void, c_uint) -> c_int;
pub type ZSTDMT_serialLdmWindowUpdateFn =
unsafe extern "C" fn(*mut c_void, *mut ZstdMtRawSeqStore, *const c_void, usize);
@@ -7041,6 +7102,29 @@ mod tests {
);
}
#[test]
fn compression_job_trace_guards_only_continuation_jobs() {
let first_job_events = Rc::new(RefCell::new(Vec::<&'static str>::new()));
let first_job_assert_events = Rc::clone(&first_job_events);
let first_job_trace_events = Rc::clone(&first_job_events);
compression_job_trace_with(
1,
move || first_job_assert_events.borrow_mut().push("assert"),
move || first_job_trace_events.borrow_mut().push("trace"),
);
assert_eq!(&*first_job_events.borrow(), &["trace"]);
let continuation_events = Rc::new(RefCell::new(Vec::<&'static str>::new()));
let continuation_assert_events = Rc::clone(&continuation_events);
let continuation_trace_events = Rc::clone(&continuation_events);
compression_job_trace_with(
0,
move || continuation_assert_events.borrow_mut().push("assert"),
move || continuation_trace_events.borrow_mut().push("trace"),
);
assert_eq!(&*continuation_events.borrow(), &["assert", "trace"]);
}
#[test]
fn compression_job_runs_first_job_stages_and_reports_final_block() {
let state = Rc::new(RefCell::new(MockCompressionJob::default()));