refactor(mt): move input publication policy to Rust
Keep the C-owned compression job callback responsible for private buffer and job-state mutation, but return the range-active decision alongside its result. Rust now owns the outer scheduler policy that publishes or suppresses the reusable input count after job creation, including the error path. The focused seam test covers the callback-clears-range case without exposing the MT context layout. Test Plan: Not run in this atomic commit; the capped serial Rust, native, smoke, and original test-suite verification follows.
This commit is contained in:
+114
-14
@@ -1588,6 +1588,24 @@ pub struct ZSTDMT_streamFlushResult {
|
||||
pub outputPos: usize,
|
||||
}
|
||||
|
||||
/// Result of the C-owned job callback. C reports only whether its private
|
||||
/// input range remains active; Rust owns the policy that publishes its local
|
||||
/// `inBuffFilled` value after the callback.
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
||||
pub struct ZSTDMT_streamCreateJobResult {
|
||||
pub result: usize,
|
||||
pub inBuffActive: c_uint,
|
||||
}
|
||||
|
||||
const _: () = {
|
||||
assert!(offset_of!(ZSTDMT_streamCreateJobResult, result) == 0);
|
||||
assert!(
|
||||
offset_of!(ZSTDMT_streamCreateJobResult, inBuffActive) == size_of::<usize>()
|
||||
);
|
||||
assert!(size_of::<ZSTDMT_streamCreateJobResult>() == 2 * size_of::<usize>());
|
||||
};
|
||||
|
||||
/// Result of one outer MT stream scheduling pass.
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
||||
@@ -1611,7 +1629,11 @@ pub type ZSTDMT_streamTryGetInputRangeFn = unsafe extern "C" fn(
|
||||
projection: *mut ZSTDMT_streamInputRangeProjection,
|
||||
) -> c_int;
|
||||
pub type ZSTDMT_streamCreateJobFn =
|
||||
unsafe extern "C" fn(opaque: *mut c_void, src_size: usize, end: c_uint) -> usize;
|
||||
unsafe extern "C" fn(
|
||||
opaque: *mut c_void,
|
||||
src_size: usize,
|
||||
end: c_uint,
|
||||
) -> ZSTDMT_streamCreateJobResult;
|
||||
pub type ZSTDMT_streamFlushProducedFn = unsafe extern "C" fn(
|
||||
opaque: *mut c_void,
|
||||
output_dst: *mut c_void,
|
||||
@@ -3433,6 +3455,15 @@ fn compress_stream_result(
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn publishable_in_buff_filled(buffer_start: *mut c_void, buffer_filled: usize) -> usize {
|
||||
if buffer_start.is_null() {
|
||||
0
|
||||
} else {
|
||||
buffer_filled
|
||||
}
|
||||
}
|
||||
|
||||
/// Run one outer MT streaming pass while C retains the context and worker
|
||||
/// implementation details.
|
||||
///
|
||||
@@ -3454,7 +3485,7 @@ unsafe fn compress_stream_generic_with<T, J, F, S>(
|
||||
) -> ZSTDMT_compressStreamResult
|
||||
where
|
||||
T: FnMut(&mut ZSTDMT_streamInputRangeProjection) -> c_int,
|
||||
J: FnMut(usize, c_uint) -> usize,
|
||||
J: FnMut(usize, c_uint) -> ZSTDMT_streamCreateJobResult,
|
||||
F: FnMut(*mut c_void, usize, usize, c_uint, c_uint) -> ZSTDMT_streamFlushResult,
|
||||
S: FnMut(
|
||||
&ZSTDMT_compressStreamContextProjection,
|
||||
@@ -3464,6 +3495,8 @@ where
|
||||
{
|
||||
let mut input_pos = input.pos;
|
||||
let output_pos = output.pos;
|
||||
let initial_in_buff_filled =
|
||||
publishable_in_buff_filled(context.inBuffStart, context.inBuffFilled);
|
||||
if input_pos > input.size
|
||||
|| output_pos > output.size
|
||||
|| context.targetSectionSize == 0
|
||||
@@ -3474,7 +3507,7 @@ where
|
||||
ERROR(ZstdErrorCode::Generic),
|
||||
input_pos,
|
||||
output_pos,
|
||||
context.inBuffFilled,
|
||||
initial_in_buff_filled,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3483,7 +3516,7 @@ where
|
||||
ERROR(ZstdErrorCode::StageWrong),
|
||||
input_pos,
|
||||
output_pos,
|
||||
context.inBuffFilled,
|
||||
initial_in_buff_filled,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3520,7 +3553,10 @@ where
|
||||
ERROR(ZstdErrorCode::Generic),
|
||||
input_pos,
|
||||
output_pos,
|
||||
input_range.bufferFilled,
|
||||
publishable_in_buff_filled(
|
||||
input_range.bufferStart,
|
||||
input_range.bufferFilled,
|
||||
),
|
||||
);
|
||||
};
|
||||
if sync_point.toLoad > available
|
||||
@@ -3531,7 +3567,10 @@ where
|
||||
ERROR(ZstdErrorCode::Generic),
|
||||
input_pos,
|
||||
output_pos,
|
||||
input_range.bufferFilled,
|
||||
publishable_in_buff_filled(
|
||||
input_range.bufferStart,
|
||||
input_range.bufferFilled,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3564,6 +3603,8 @@ where
|
||||
end_op = ZSTD_E_FLUSH;
|
||||
}
|
||||
|
||||
let mut returned_in_buff_filled =
|
||||
publishable_in_buff_filled(input_range.bufferStart, input_range.bufferFilled);
|
||||
if context.jobReady != 0
|
||||
|| input_range.bufferFilled >= context.targetSectionSize
|
||||
|| (end_op != ZSTD_E_CONTINUE && input_range.bufferFilled > 0)
|
||||
@@ -3571,12 +3612,17 @@ where
|
||||
{
|
||||
debug_assert!(input_range.bufferFilled <= context.targetSectionSize);
|
||||
let create_result = create_job(input_range.bufferFilled, end_op);
|
||||
if ERR_isError(create_result) {
|
||||
returned_in_buff_filled = if create_result.inBuffActive != 0 {
|
||||
input_range.bufferFilled
|
||||
} else {
|
||||
0
|
||||
};
|
||||
if ERR_isError(create_result.result) {
|
||||
return compress_stream_result(
|
||||
create_result,
|
||||
create_result.result,
|
||||
input_pos,
|
||||
output_pos,
|
||||
input_range.bufferFilled,
|
||||
returned_in_buff_filled,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -3598,7 +3644,7 @@ where
|
||||
result,
|
||||
input_pos,
|
||||
flush_result.outputPos,
|
||||
input_range.bufferFilled,
|
||||
returned_in_buff_filled,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -8273,7 +8319,10 @@ mod tests {
|
||||
},
|
||||
|src_size, end| {
|
||||
create_calls.push((src_size, end));
|
||||
0
|
||||
ZSTDMT_streamCreateJobResult {
|
||||
result: 0,
|
||||
inBuffActive: 1,
|
||||
}
|
||||
},
|
||||
|_dst, _size, output_pos, block_to_flush, end| {
|
||||
flush_calls.push((block_to_flush, end));
|
||||
@@ -8300,6 +8349,47 @@ mod tests {
|
||||
assert_eq!(output_buffer[0], 0xb6);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn outer_scheduler_suppresses_filled_after_job_clears_range() {
|
||||
let mut round_buffer = [0xa5u8; 4];
|
||||
let context = ZSTDMT_compressStreamContextProjection {
|
||||
inBuffStart: round_buffer.as_mut_ptr().cast(),
|
||||
inBuffCapacity: round_buffer.len(),
|
||||
inBuffFilled: 2,
|
||||
targetSectionSize: round_buffer.len(),
|
||||
..ZSTDMT_compressStreamContextProjection::default()
|
||||
};
|
||||
let mut create_call = None;
|
||||
|
||||
let result = unsafe {
|
||||
compress_stream_generic_with(
|
||||
context,
|
||||
ZSTDMT_streamInputProjection::default(),
|
||||
ZSTDMT_streamOutputProjection::default(),
|
||||
ZSTD_E_FLUSH,
|
||||
|_projection| panic!("the active range must not be reacquired"),
|
||||
|src_size, end| {
|
||||
create_call = Some((src_size, end));
|
||||
ZSTDMT_streamCreateJobResult {
|
||||
result: 0,
|
||||
inBuffActive: 0,
|
||||
}
|
||||
},
|
||||
|_dst, _size, output_pos, _block_to_flush, _end| {
|
||||
ZSTDMT_streamFlushResult {
|
||||
result: 0,
|
||||
outputPos: output_pos,
|
||||
}
|
||||
},
|
||||
|_context, _input, _projection| panic!("no synchronization scan expected"),
|
||||
)
|
||||
};
|
||||
|
||||
assert_eq!(create_call, Some((2, ZSTD_E_FLUSH)));
|
||||
assert_eq!(result.result, 0);
|
||||
assert_eq!(result.inBuffFilled, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn outer_scheduler_forces_flush_before_end_when_input_remains() {
|
||||
let input_bytes = [7u8, 8, 9, 10, 11];
|
||||
@@ -8330,7 +8420,10 @@ mod tests {
|
||||
|_projection| panic!("input range should already be available"),
|
||||
|src_size, end| {
|
||||
create_end = Some((src_size, end));
|
||||
0
|
||||
ZSTDMT_streamCreateJobResult {
|
||||
result: 0,
|
||||
inBuffActive: 0,
|
||||
}
|
||||
},
|
||||
|_dst, _size, output_pos, block_to_flush, end| {
|
||||
flush_block = Some(block_to_flush);
|
||||
@@ -8381,7 +8474,10 @@ mod tests {
|
||||
|_projection| panic!("a ready job must skip input acquisition"),
|
||||
|src_size, end| {
|
||||
create_call = Some((src_size, end));
|
||||
0
|
||||
ZSTDMT_streamCreateJobResult {
|
||||
result: 0,
|
||||
inBuffActive: 0,
|
||||
}
|
||||
},
|
||||
|_dst, _size, output_pos, block_to_flush, end| {
|
||||
flush_call = Some((block_to_flush, end));
|
||||
@@ -8425,7 +8521,10 @@ mod tests {
|
||||
output,
|
||||
ZSTD_E_CONTINUE,
|
||||
|_projection| panic!("input range should already be available"),
|
||||
|_src_size, _end| ERROR(ZstdErrorCode::DstSizeTooSmall),
|
||||
|_src_size, _end| ZSTDMT_streamCreateJobResult {
|
||||
result: ERROR(ZstdErrorCode::DstSizeTooSmall),
|
||||
inBuffActive: 1,
|
||||
},
|
||||
|_dst, _size, output_pos, _block_to_flush, _end| {
|
||||
flush_called = true;
|
||||
ZSTDMT_streamFlushResult {
|
||||
@@ -8444,6 +8543,7 @@ mod tests {
|
||||
assert_eq!(result.result, ERROR(ZstdErrorCode::DstSizeTooSmall));
|
||||
assert_eq!(result.inputPos, round_buffer.len());
|
||||
assert_eq!(result.outputPos, 0);
|
||||
assert_eq!(result.inBuffFilled, round_buffer.len());
|
||||
assert!(!flush_called);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user