feat(mt): move serial reset orchestration into Rust
Move the MT serial-state reset ordering into Rust. C retains parameter adjustment, private LDM table allocation and clearing, dictionary loading, window/checksum state, and allocator behavior behind callbacks; Rust now owns the reset sequencing and allocation-failure stop point. Test Plan: - ulimit -v 41943040; CARGO_BUILD_JOBS=1; cargo test --manifest-path rust/Cargo.toml - ulimit -v 41943040; CARGO_BUILD_JOBS=1; cargo clippy --manifest-path rust/Cargo.toml --all-targets -- -D warnings - ulimit -v 41943040; make -B -C programs -j1 zstd - ulimit -v 41943040; make -C tests -j1 test-zstream ZSTREAM_TESTTIME=-T1s
This commit is contained in:
@@ -199,6 +199,9 @@ pub type ZSTDMT_initSetBufferSizeFn = unsafe extern "C" fn(*mut c_void, usize);
|
||||
pub type ZSTDMT_initResizeRoundBufferFn = unsafe extern "C" fn(*mut c_void, usize) -> usize;
|
||||
pub type ZSTDMT_initResetStreamFn = unsafe extern "C" fn(*mut c_void);
|
||||
pub type ZSTDMT_initSerialResetFn = unsafe extern "C" fn(*mut c_void, usize) -> usize;
|
||||
pub type ZSTDMT_serialResetVoidFn = unsafe extern "C" fn(*mut c_void);
|
||||
pub type ZSTDMT_serialResetSetNbSeqFn = unsafe extern "C" fn(*mut c_void, usize);
|
||||
pub type ZSTDMT_serialResetResizeFn = unsafe extern "C" fn(*mut c_void) -> c_int;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
||||
@@ -1134,6 +1137,67 @@ where
|
||||
serial_reset(target_section_size)
|
||||
}
|
||||
|
||||
/// Run the MT serial-state reset policy while C retains its private LDM
|
||||
/// tables, dictionary/window state, checksum state, and allocator callbacks.
|
||||
/// The callback order mirrors the original reset path and stops immediately
|
||||
/// when table allocation reports failure.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn ZSTDMT_rust_serialStateReset(
|
||||
enable_ldm: c_int,
|
||||
checksum_enabled: c_int,
|
||||
max_nb_seq: usize,
|
||||
opaque: *mut c_void,
|
||||
reset_next_job: Option<ZSTDMT_serialResetVoidFn>,
|
||||
reset_checksum: Option<ZSTDMT_serialResetVoidFn>,
|
||||
set_nb_seq: Option<ZSTDMT_serialResetSetNbSeqFn>,
|
||||
reset_window: Option<ZSTDMT_serialResetVoidFn>,
|
||||
resize_tables: Option<ZSTDMT_serialResetResizeFn>,
|
||||
zero_tables: Option<ZSTDMT_serialResetVoidFn>,
|
||||
load_dictionary: Option<ZSTDMT_serialResetVoidFn>,
|
||||
copy_window: Option<ZSTDMT_serialResetVoidFn>,
|
||||
) -> c_int {
|
||||
let (
|
||||
Some(reset_next_job),
|
||||
Some(reset_checksum),
|
||||
Some(set_nb_seq),
|
||||
Some(reset_window),
|
||||
Some(resize_tables),
|
||||
Some(zero_tables),
|
||||
Some(load_dictionary),
|
||||
Some(copy_window),
|
||||
) = (
|
||||
reset_next_job,
|
||||
reset_checksum,
|
||||
set_nb_seq,
|
||||
reset_window,
|
||||
resize_tables,
|
||||
zero_tables,
|
||||
load_dictionary,
|
||||
copy_window,
|
||||
)
|
||||
else {
|
||||
return 1;
|
||||
};
|
||||
|
||||
unsafe {
|
||||
reset_next_job(opaque);
|
||||
if checksum_enabled != 0 {
|
||||
reset_checksum(opaque);
|
||||
}
|
||||
if enable_ldm == ZSTD_PS_ENABLE {
|
||||
set_nb_seq(opaque, max_nb_seq);
|
||||
reset_window(opaque);
|
||||
if resize_tables(opaque) != 0 {
|
||||
return 1;
|
||||
}
|
||||
zero_tables(opaque);
|
||||
load_dictionary(opaque);
|
||||
copy_window(opaque);
|
||||
}
|
||||
}
|
||||
0
|
||||
}
|
||||
|
||||
/// C ABI entry point for the MT streaming initializer. C owns every
|
||||
/// allocation, dictionary handle, synchronization object, and private context
|
||||
/// mutation; this wrapper only connects those operations to the Rust policy.
|
||||
@@ -3734,6 +3798,172 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct SerialResetTestContext {
|
||||
events: Vec<&'static str>,
|
||||
max_nb_seq: usize,
|
||||
resize_result: c_int,
|
||||
}
|
||||
|
||||
unsafe extern "C" fn serial_reset_test_next_job(context: *mut c_void) {
|
||||
unsafe {
|
||||
(*context.cast::<SerialResetTestContext>())
|
||||
.events
|
||||
.push("next-job");
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "C" fn serial_reset_test_checksum(context: *mut c_void) {
|
||||
unsafe {
|
||||
(*context.cast::<SerialResetTestContext>())
|
||||
.events
|
||||
.push("checksum");
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "C" fn serial_reset_test_set_nb_seq(context: *mut c_void, max_nb_seq: usize) {
|
||||
unsafe {
|
||||
let context = &mut *context.cast::<SerialResetTestContext>();
|
||||
context.events.push("seq-size");
|
||||
context.max_nb_seq = max_nb_seq;
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "C" fn serial_reset_test_window(context: *mut c_void) {
|
||||
unsafe {
|
||||
(*context.cast::<SerialResetTestContext>())
|
||||
.events
|
||||
.push("window");
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "C" fn serial_reset_test_resize(context: *mut c_void) -> c_int {
|
||||
unsafe {
|
||||
let context = &mut *context.cast::<SerialResetTestContext>();
|
||||
context.events.push("resize");
|
||||
context.resize_result
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "C" fn serial_reset_test_zero(context: *mut c_void) {
|
||||
unsafe {
|
||||
(*context.cast::<SerialResetTestContext>())
|
||||
.events
|
||||
.push("zero");
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "C" fn serial_reset_test_dictionary(context: *mut c_void) {
|
||||
unsafe {
|
||||
(*context.cast::<SerialResetTestContext>())
|
||||
.events
|
||||
.push("dictionary");
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "C" fn serial_reset_test_copy_window(context: *mut c_void) {
|
||||
unsafe {
|
||||
(*context.cast::<SerialResetTestContext>())
|
||||
.events
|
||||
.push("copy-window");
|
||||
}
|
||||
}
|
||||
|
||||
type SerialResetTestCallbacks = (
|
||||
Option<ZSTDMT_serialResetVoidFn>,
|
||||
Option<ZSTDMT_serialResetVoidFn>,
|
||||
Option<ZSTDMT_serialResetSetNbSeqFn>,
|
||||
Option<ZSTDMT_serialResetVoidFn>,
|
||||
Option<ZSTDMT_serialResetResizeFn>,
|
||||
Option<ZSTDMT_serialResetVoidFn>,
|
||||
Option<ZSTDMT_serialResetVoidFn>,
|
||||
Option<ZSTDMT_serialResetVoidFn>,
|
||||
);
|
||||
|
||||
fn serial_reset_test_callbacks() -> SerialResetTestCallbacks {
|
||||
(
|
||||
Some(serial_reset_test_next_job),
|
||||
Some(serial_reset_test_checksum),
|
||||
Some(serial_reset_test_set_nb_seq),
|
||||
Some(serial_reset_test_window),
|
||||
Some(serial_reset_test_resize),
|
||||
Some(serial_reset_test_zero),
|
||||
Some(serial_reset_test_dictionary),
|
||||
Some(serial_reset_test_copy_window),
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn serial_state_reset_runs_ldm_operations_in_c_order() {
|
||||
let mut context = SerialResetTestContext::default();
|
||||
let callbacks = serial_reset_test_callbacks();
|
||||
|
||||
let result = unsafe {
|
||||
ZSTDMT_rust_serialStateReset(
|
||||
ZSTD_PS_ENABLE,
|
||||
1,
|
||||
123,
|
||||
(&mut context as *mut SerialResetTestContext).cast(),
|
||||
callbacks.0,
|
||||
callbacks.1,
|
||||
callbacks.2,
|
||||
callbacks.3,
|
||||
callbacks.4,
|
||||
callbacks.5,
|
||||
callbacks.6,
|
||||
callbacks.7,
|
||||
)
|
||||
};
|
||||
|
||||
assert_eq!(result, 0);
|
||||
assert_eq!(context.max_nb_seq, 123);
|
||||
assert_eq!(
|
||||
context.events,
|
||||
vec![
|
||||
"next-job",
|
||||
"checksum",
|
||||
"seq-size",
|
||||
"window",
|
||||
"resize",
|
||||
"zero",
|
||||
"dictionary",
|
||||
"copy-window",
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn serial_state_reset_stops_before_zeroing_after_resize_failure() {
|
||||
let mut context = SerialResetTestContext {
|
||||
resize_result: 1,
|
||||
..Default::default()
|
||||
};
|
||||
let callbacks = serial_reset_test_callbacks();
|
||||
|
||||
let result = unsafe {
|
||||
ZSTDMT_rust_serialStateReset(
|
||||
ZSTD_PS_ENABLE,
|
||||
0,
|
||||
123,
|
||||
(&mut context as *mut SerialResetTestContext).cast(),
|
||||
callbacks.0,
|
||||
callbacks.1,
|
||||
callbacks.2,
|
||||
callbacks.3,
|
||||
callbacks.4,
|
||||
callbacks.5,
|
||||
callbacks.6,
|
||||
callbacks.7,
|
||||
)
|
||||
};
|
||||
|
||||
assert_eq!(result, 1);
|
||||
assert_eq!(
|
||||
context.events,
|
||||
vec!["next-job", "seq-size", "window", "resize"]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn init_c_stream_preserves_success_order_and_normalization() {
|
||||
let projection = init_projection();
|
||||
|
||||
Reference in New Issue
Block a user