From a9b11394ce9752a6c925693518012c89bbcefed1 Mon Sep 17 00:00:00 2001 From: ddidderr Date: Sat, 18 Jul 2026 15:18:26 +0200 Subject: [PATCH] feat(cli): move patch-from window policy to Rust Keep patch-from orchestration in C while extracting only the bounded window selection and automatic-LDM decision into the Rust CLI leaf. The C caller still computes the raw file window with FIO_highbit64, obtains cParams, updates the memory limit, emits warnings and optimal-parser notes, and writes comprParams->windowLog and prefs->ldmFlag. Rust receives only scalar policy inputs and two output pointers, clamps the selected window to the target's 10..30/31 bounds, and compares the unclamped value strictly against cycleLog. This preserves equality as no-LDM and keeps values above the maximum eligible to trigger LDM. Focused unit tests cover both clamps and each comparison edge. Test Plan: - `cargo clippy --manifest-path rust/Cargo.toml --no-default-features --features compression` with library, `--benches`, and `--tests`, before and after formatting -- passed - `cargo +nightly fmt --manifest-path rust/Cargo.toml -- --config skip_children=true` and nightly rustfmt on the owned file -- passed - `cargo test --manifest-path rust/cli/Cargo.toml --no-default-features --features cli,compression,decompression,benchmark fileio_prefs` -- 36 passed - `make -C programs -j2 zstd` -- passed - `make -C tests -j2 test-cli-tests` -- 41 passed - Focused patch-from round trip and automatic long-mode trigger -- passed --- programs/fileio.c | 14 +++++++-- rust/src/fileio_prefs.rs | 63 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 2 deletions(-) diff --git a/programs/fileio.c b/programs/fileio.c index 4af2c0942..6ce4c32ab 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -329,6 +329,10 @@ int FIO_rust_checkFilenameCollisions(const char** filenameTable, unsigned nbFile unsigned FIO_rust_highbit64(unsigned long long v); unsigned long long FIO_rust_getLargestFileSize(const char** inFileNames, unsigned nbFiles); unsigned FIO_rust_cycleLog(unsigned hashLog, int strategy); +void FIO_rust_patchFromWindowPolicy(unsigned fileWindowLog, + unsigned cycleLog, + unsigned* windowLog, + int* enableLdm); void FIO_rust_setInBuffer(ZSTD_inBuffer* output, const void* buf, size_t s, size_t pos); void FIO_rust_setOutBuffer(ZSTD_outBuffer* output, void* buf, size_t s, size_t pos); const char* FIO_rust_determineCompressedName(const char* srcFileName, const char* outDirName, const char* suffix); @@ -877,11 +881,17 @@ static void FIO_adjustParamsForPatchFromMode(FIO_prefs_t* const prefs, { unsigned const fileWindowLog = FIO_highbit64(maxSrcFileSize) + 1; ZSTD_compressionParameters const cParams = ZSTD_getCParams(cLevel, (size_t)maxSrcFileSize, (size_t)dictSize); + unsigned windowLog; + int enableLdm; FIO_adjustMemLimitForPatchFromMode(prefs, dictSize, maxSrcFileSize); + FIO_rust_patchFromWindowPolicy(fileWindowLog, + ZSTD_cycleLog(cParams.chainLog, cParams.strategy), + &windowLog, + &enableLdm); if (fileWindowLog > ZSTD_WINDOWLOG_MAX) DISPLAYLEVEL(1, "Max window log exceeded by file (compression ratio will suffer)\n"); - comprParams->windowLog = MAX(ZSTD_WINDOWLOG_MIN, MIN(ZSTD_WINDOWLOG_MAX, fileWindowLog)); - if (fileWindowLog > ZSTD_cycleLog(cParams.chainLog, cParams.strategy)) { + comprParams->windowLog = windowLog; + if (enableLdm) { if (!prefs->ldmFlag) DISPLAYLEVEL(2, "long mode automatically triggered\n"); FIO_setLdmFlag(prefs, 1); diff --git a/rust/src/fileio_prefs.rs b/rust/src/fileio_prefs.rs index 101db5fba..42ca020e3 100644 --- a/rust/src/fileio_prefs.rs +++ b/rust/src/fileio_prefs.rs @@ -29,6 +29,7 @@ const FIO_MULTI_FILES_ACTION_DISABLE_REMOVE: c_int = 3; const FIO_MULTI_FILES_ACTION_QUIET_ABORT: c_int = 4; const FIO_MULTI_FILES_ACTION_CONFIRM: c_int = 5; const UTIL_FILESIZE_UNKNOWN: u64 = u64::MAX; +const ZSTD_WINDOWLOG_MIN: u32 = 10; const ZSTD_WINDOWLOG_MAX: u32 = if size_of::() == 4 { 30 } else { 31 }; const ZSTD_BTLAZY2: c_int = 6; static STDOUT_MARK: &[u8] = b"/*stdout*\\\0"; @@ -609,6 +610,20 @@ pub extern "C" fn FIO_rust_cycleLog(hash_log: c_uint, strategy: c_int) -> c_uint cycle_log(hash_log, strategy) } +/// Rust scalar ABI for patch-from window and automatic-LDM policy. +#[no_mangle] +pub unsafe extern "C" fn FIO_rust_patchFromWindowPolicy( + file_window_log: c_uint, + cycle_log: c_uint, + window_log: *mut c_uint, + enable_ldm: *mut c_int, +) { + unsafe { + window_log.write(file_window_log.clamp(ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX)); + enable_ldm.write(c_int::from(file_window_log > cycle_log)); + } +} + #[allow(clippy::too_many_arguments)] #[inline] fn multi_files_concat_action( @@ -1179,6 +1194,54 @@ mod tests { assert_eq!(FIO_rust_cycleLog(20, ZSTD_BTLAZY2 + 3), 19); } + fn patch_from_window_policy(file_window_log: c_uint, cycle_log: c_uint) -> (c_uint, c_int) { + let mut window_log = c_uint::MAX; + let mut enable_ldm = -1; + unsafe { + FIO_rust_patchFromWindowPolicy( + file_window_log, + cycle_log, + &mut window_log, + &mut enable_ldm, + ); + } + (window_log, enable_ldm) + } + + #[test] + fn patch_from_window_policy_clamps_to_lower_bound() { + assert_eq!( + patch_from_window_policy(ZSTD_WINDOWLOG_MIN - 1, ZSTD_WINDOWLOG_MIN), + (ZSTD_WINDOWLOG_MIN, 0) + ); + } + + #[test] + fn patch_from_window_policy_clamps_to_upper_bound() { + assert_eq!( + patch_from_window_policy(ZSTD_WINDOWLOG_MAX + 1, ZSTD_WINDOWLOG_MAX + 1), + (ZSTD_WINDOWLOG_MAX, 0) + ); + } + + #[test] + fn patch_from_window_policy_keeps_equal_cycle_log_out_of_ldm() { + assert_eq!(patch_from_window_policy(20, 20), (20, 0)); + } + + #[test] + fn patch_from_window_policy_enables_ldm_one_above_cycle_log() { + assert_eq!(patch_from_window_policy(20, 19), (20, 1)); + } + + #[test] + fn patch_from_window_policy_uses_raw_value_above_upper_bound_for_ldm() { + assert_eq!( + patch_from_window_policy(ZSTD_WINDOWLOG_MAX + 1, ZSTD_WINDOWLOG_MAX), + (ZSTD_WINDOWLOG_MAX, 1) + ); + } + #[test] fn multi_files_concat_policy_protects_stdout_and_test_mode_removal() { assert_eq!(