feat(mt): move external sequence gate to Rust
The MT worker previously kept the external-sequence non-empty gate and LDM invariant assertion in C, bundled with the private CCtx operation. Project the CCtx pointer and raw-sequence store through a layout-checked seam so Rust owns the gate and the apply point while C retains only the opaque ZSTD_referenceExternalSequences() leaf. Preserve the callback ordering after worker CCtx initialization and keep empty stores as a no-op. Test Plan: - git diff --cached --check -- passed before commit. - Static rg inspection confirmed all projection initializers include the new sequence-state pointer and no old serialState_applySequences symbol remains. - Cargo, make, compiler checks, and full tests were not run per worker scope.
This commit is contained in:
+133
-3
@@ -365,6 +365,18 @@ pub struct ZSTDMT_compressionJobProjection {
|
||||
pub firstJob: c_uint,
|
||||
pub lastJob: c_uint,
|
||||
pub frameHeaderState: *const ZSTDMT_compressionJobFrameHeaderState,
|
||||
pub sequenceState: *const ZSTDMT_compressionJobSequenceState,
|
||||
}
|
||||
|
||||
/// Indirection into the worker-owned state used by the external-sequence
|
||||
/// gate. Rust sees only pointers to the opaque CCtx and the already-projected
|
||||
/// raw-sequence store; the private worker-state layout remains in C.
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
||||
pub struct ZSTDMT_compressionJobSequenceState {
|
||||
pub cctx: *mut *mut c_void,
|
||||
pub rawSeqStore: *const ZstdMtRawSeqStore,
|
||||
pub ldmEnabled: c_int,
|
||||
}
|
||||
|
||||
/// Scalar projection for the non-first MT job frame header. The destination,
|
||||
@@ -393,9 +405,24 @@ const _: () = {
|
||||
offset_of!(ZSTDMT_compressionJobProjection, frameHeaderState) == size_of::<[c_uint; 2]>()
|
||||
);
|
||||
assert!(
|
||||
size_of::<ZSTDMT_compressionJobProjection>()
|
||||
offset_of!(ZSTDMT_compressionJobProjection, sequenceState)
|
||||
== size_of::<[c_uint; 2]>() + size_of::<usize>()
|
||||
);
|
||||
assert!(
|
||||
size_of::<ZSTDMT_compressionJobProjection>()
|
||||
== size_of::<[c_uint; 2]>() + 2 * size_of::<usize>()
|
||||
);
|
||||
assert!(offset_of!(ZSTDMT_compressionJobSequenceState, cctx) == 0);
|
||||
assert!(
|
||||
offset_of!(ZSTDMT_compressionJobSequenceState, rawSeqStore) == size_of::<usize>()
|
||||
);
|
||||
assert!(
|
||||
offset_of!(ZSTDMT_compressionJobSequenceState, ldmEnabled) == 2 * size_of::<usize>()
|
||||
);
|
||||
assert!(
|
||||
size_of::<ZSTDMT_compressionJobSequenceState>()
|
||||
== if size_of::<usize>() == 8 { 24 } else { 12 }
|
||||
);
|
||||
assert!(offset_of!(ZSTDMT_compressionJobFrameHeaderState, dst) == 0);
|
||||
assert!(offset_of!(ZSTDMT_compressionJobFrameHeaderState, dst_capacity) == size_of::<usize>());
|
||||
assert!(offset_of!(ZSTDMT_compressionJobFrameHeaderState, stage) == 2 * size_of::<usize>());
|
||||
@@ -504,6 +531,57 @@ pub type ZSTDMT_compressionJobCompressFn =
|
||||
unsafe extern "C" fn(*mut c_void, c_uint) -> ZSTDMT_chunkProcessResult;
|
||||
pub type ZSTDMT_compressionJobSizeFn = unsafe extern "C" fn(*mut c_void, usize);
|
||||
pub type ZSTDMT_compressionJobSetParameterFn = unsafe extern "C" fn(*mut c_void, c_int) -> usize;
|
||||
pub type ZSTDMT_compressionJobApplySequencesFn =
|
||||
unsafe extern "C" fn(*mut c_void, *mut c_void, *mut c_void, usize);
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
||||
struct ZSTDMT_compressionJobSequenceProjection {
|
||||
cctx: *mut c_void,
|
||||
sequences: *mut c_void,
|
||||
nbSequences: usize,
|
||||
ldmEnabled: c_int,
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn compression_job_sequence_projection(
|
||||
state: *const ZSTDMT_compressionJobSequenceState,
|
||||
) -> Option<ZSTDMT_compressionJobSequenceProjection> {
|
||||
let state = unsafe { state.as_ref() }?;
|
||||
if state.cctx.is_null() || state.rawSeqStore.is_null() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let cctx = unsafe { *state.cctx };
|
||||
let raw_seq_store = unsafe { &*state.rawSeqStore };
|
||||
Some(ZSTDMT_compressionJobSequenceProjection {
|
||||
cctx,
|
||||
sequences: raw_seq_store.seq.cast(),
|
||||
nbSequences: raw_seq_store.size,
|
||||
ldmEnabled: state.ldmEnabled,
|
||||
})
|
||||
}
|
||||
|
||||
/// Apply the worker's external-sequence policy after CCtx initialization.
|
||||
/// Rust owns the non-empty gate and LDM invariant; C retains only the opaque
|
||||
/// `ZSTD_referenceExternalSequences()` leaf behind the callback.
|
||||
#[inline]
|
||||
fn apply_compression_job_sequences_with<R>(
|
||||
projection: Option<ZSTDMT_compressionJobSequenceProjection>,
|
||||
mut reference_sequences: R,
|
||||
) where
|
||||
R: FnMut(*mut c_void, *mut c_void, usize),
|
||||
{
|
||||
let Some(projection) = projection else {
|
||||
return;
|
||||
};
|
||||
if projection.nbSequences == 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
debug_assert_eq!(projection.ldmEnabled, ZSTD_PS_ENABLE);
|
||||
debug_assert!(!projection.cctx.is_null());
|
||||
reference_sequences(projection.cctx, projection.sequences, projection.nbSequences);
|
||||
}
|
||||
|
||||
/// Scalar view used to choose the private worker-context initialization path.
|
||||
/// C retains the cdict, parameter, and CCtx objects; Rust owns the branch and
|
||||
@@ -2779,7 +2857,7 @@ pub unsafe extern "C" fn ZSTDMT_rust_compressionJob(
|
||||
prepareParameters: Option<ZSTDMT_compressionJobVoidFn>,
|
||||
generateSequences: Option<ZSTDMT_compressionJobVoidFn>,
|
||||
beginJob: Option<ZSTDMT_compressionJobStepFn>,
|
||||
applySequences: Option<ZSTDMT_compressionJobVoidFn>,
|
||||
applySequences: Option<ZSTDMT_compressionJobApplySequencesFn>,
|
||||
compressJob: Option<ZSTDMT_compressionJobCompressFn>,
|
||||
traceJob: Option<ZSTDMT_compressionJobVoidFn>,
|
||||
) {
|
||||
@@ -2810,6 +2888,8 @@ pub unsafe extern "C" fn ZSTDMT_rust_compressionJob(
|
||||
return;
|
||||
};
|
||||
|
||||
let sequence_state = projection.sequenceState;
|
||||
|
||||
compression_job_with(
|
||||
projection,
|
||||
finish,
|
||||
@@ -2817,7 +2897,13 @@ pub unsafe extern "C" fn ZSTDMT_rust_compressionJob(
|
||||
|| unsafe { prepare_parameters(opaque) },
|
||||
|| unsafe { generate_sequences(opaque) },
|
||||
|| unsafe { begin_job(opaque) },
|
||||
|| unsafe { apply_sequences(opaque) },
|
||||
|| {
|
||||
let sequence_projection =
|
||||
unsafe { compression_job_sequence_projection(sequence_state) };
|
||||
apply_compression_job_sequences_with(sequence_projection, |cctx, sequences, count| {
|
||||
unsafe { apply_sequences(opaque, cctx, sequences, count) }
|
||||
});
|
||||
},
|
||||
|| unsafe { ZSTDMT_rust_writeFrameHeader(projection.frameHeaderState) },
|
||||
|last_job| unsafe { compress_job(opaque, last_job) },
|
||||
|| unsafe { trace_job(opaque) },
|
||||
@@ -6591,6 +6677,47 @@ mod tests {
|
||||
assert_eq!(&output[result..], &[0xa5; 12]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compression_job_sequence_gate_skips_empty_store_without_ldm_assertion() {
|
||||
let mut calls = Vec::new();
|
||||
let projection = ZSTDMT_compressionJobSequenceProjection {
|
||||
cctx: 0x10usize as *mut c_void,
|
||||
sequences: ptr::null_mut(),
|
||||
nbSequences: 0,
|
||||
ldmEnabled: 0,
|
||||
};
|
||||
|
||||
apply_compression_job_sequences_with(Some(projection), |cctx, sequences, count| {
|
||||
calls.push((cctx, sequences, count));
|
||||
});
|
||||
|
||||
assert!(calls.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compression_job_sequence_gate_forwards_nonempty_store_after_ldm_check() {
|
||||
let mut calls = Vec::new();
|
||||
let projection = ZSTDMT_compressionJobSequenceProjection {
|
||||
cctx: 0x10usize as *mut c_void,
|
||||
sequences: 0x20usize as *mut c_void,
|
||||
nbSequences: 3,
|
||||
ldmEnabled: ZSTD_PS_ENABLE,
|
||||
};
|
||||
|
||||
apply_compression_job_sequences_with(Some(projection), |cctx, sequences, count| {
|
||||
calls.push((cctx, sequences, count));
|
||||
});
|
||||
|
||||
assert_eq!(
|
||||
calls,
|
||||
vec![(
|
||||
0x10usize as *mut c_void,
|
||||
0x20usize as *mut c_void,
|
||||
3
|
||||
)]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compression_job_resources_order_pool_gets_destination_and_ldm_check() {
|
||||
let events = Rc::new(RefCell::new(Vec::<&'static str>::new()));
|
||||
@@ -6753,6 +6880,7 @@ mod tests {
|
||||
firstJob: 1,
|
||||
lastJob: 1,
|
||||
frameHeaderState: ptr::null(),
|
||||
sequenceState: ptr::null(),
|
||||
},
|
||||
finish,
|
||||
move || {
|
||||
@@ -6814,6 +6942,7 @@ mod tests {
|
||||
firstJob: 1,
|
||||
lastJob: 0,
|
||||
frameHeaderState: ptr::null(),
|
||||
sequenceState: ptr::null(),
|
||||
},
|
||||
finish,
|
||||
move || {
|
||||
@@ -7077,6 +7206,7 @@ mod tests {
|
||||
firstJob: 0,
|
||||
lastJob: 1,
|
||||
frameHeaderState: ptr::null(),
|
||||
sequenceState: ptr::null(),
|
||||
},
|
||||
finish,
|
||||
move || {
|
||||
|
||||
Reference in New Issue
Block a user