From 481a53baf81ebdc093ca67279a7ce10b748bebeb Mon Sep 17 00:00:00 2001 From: ddidderr Date: Sun, 19 Jul 2026 21:05:48 +0200 Subject: [PATCH] feat(compress): move reduce-index policy into Rust Move match-table selection and btlazy2 marker policy out of the C overflow correction wrapper. Rust now decides whether chain and hash3 tables participate using the strategy, row-matchfinder, dedicated-dictionary, and log inputs, then delegates cell updates to the existing Rust reducer. C retains only the private table pointers and scalar projection. Test Plan: - cargo fmt --manifest-path rust/Cargo.toml -- --check - ulimit -v 41943040 && CARGO_BUILD_JOBS=1 cargo clippy --manifest-path rust/Cargo.toml --all-targets -- -D warnings - ulimit -v 41943040 && CARGO_BUILD_JOBS=1 cargo test --manifest-path rust/Cargo.toml zstd_compress::tests::reduce_index_for_match_state -- --nocapture - ulimit -v 41943040 && make -j1 - ulimit -v 41943040 && make -j1 -C tests test-fuzzer FUZZERTEST=-T3s FUZZER_FLAGS=--no-big-tests --- lib/compress/zstd_compress.c | 33 ++++++---------- rust/src/zstd_compress.rs | 77 ++++++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+), 21 deletions(-) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index b9b3ce701..1bc06c481 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -656,6 +656,12 @@ void ZSTD_rust_reduceIndex(U32* hashTable, U32 hashSize, U32* chainTable, U32 chainSize, U32* hashTable3, U32 hashSize3, U32 reducerValue, int preserveChainMark); +void ZSTD_rust_reduceIndexForMatchState( + U32* hashTable, U32 hashLog, + U32* chainTable, U32 chainLog, + U32* hashTable3, U32 hashLog3, + int strategy, int useRowMatchFinder, int dedicatedDictSearch, + U32 reducerValue); typedef int (*ZSTD_rust_overflowNeedCorrection_f)( void* context, const void* src, const void* srcEnd); typedef U32 (*ZSTD_rust_overflowCorrect_f)( @@ -4803,27 +4809,12 @@ size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx, unsigned long * rescale all indexes to avoid future overflow (indexes are U32) */ static void ZSTD_reduceIndex (ZSTD_MatchState_t* ms, ZSTD_CCtx_params const* params, const U32 reducerValue) { - U32 const hSize = (U32)1 << params->cParams.hashLog; - U32* chainTable = NULL; - U32 chainSize = 0; - U32* hashTable3 = NULL; - U32 hashSize3 = 0; - - if (ZSTD_allocateChainTable(params->cParams.strategy, params->useRowMatchFinder, (U32)ms->dedicatedDictSearch)) { - chainTable = ms->chainTable; - chainSize = (U32)1 << params->cParams.chainLog; - } - - if (ms->hashLog3) { - hashTable3 = ms->hashTable3; - hashSize3 = (U32)1 << ms->hashLog3; - } - - ZSTD_rust_reduceIndex(ms->hashTable, hSize, - chainTable, chainSize, - hashTable3, hashSize3, - reducerValue, - params->cParams.strategy == ZSTD_btlazy2); + ZSTD_rust_reduceIndexForMatchState( + ms->hashTable, params->cParams.hashLog, + ms->chainTable, params->cParams.chainLog, + ms->hashTable3, ms->hashLog3, + params->cParams.strategy, params->useRowMatchFinder, + ms->dedicatedDictSearch, reducerValue); } diff --git a/rust/src/zstd_compress.rs b/rust/src/zstd_compress.rs index d1c060703..0461eb43e 100644 --- a/rust/src/zstd_compress.rs +++ b/rust/src/zstd_compress.rs @@ -95,6 +95,7 @@ unsafe extern "C" { const ZSTD_FAST: c_int = 1; const ZSTD_DFAST: c_int = 2; +const ZSTD_BTLAZY2: c_int = 6; const ZSTD_REP_NUM: usize = 3; const ZSTD_BM_BUFFERED: c_int = 0; const ZSTD_BM_STABLE: c_int = 1; @@ -6871,6 +6872,53 @@ pub unsafe extern "C" fn ZSTD_rust_reduceIndex( } } +/// Select the match tables participating in overflow correction and delegate +/// their cell updates to the Rust reducer. C supplies private table pointers; +/// Rust owns the strategy, row-matchfinder, dedicated-dictionary, and marker +/// policy that determines the participating table set. +#[no_mangle] +pub unsafe extern "C" fn ZSTD_rust_reduceIndexForMatchState( + hash_table: *mut u32, + hash_log: c_uint, + chain_table: *mut u32, + chain_log: c_uint, + hash_table3: *mut u32, + hash_log3: c_uint, + strategy: c_int, + use_row_match_finder: c_int, + dedicated_dict_search: c_int, + reducer_value: c_uint, +) { + let hash_size = 1u32.wrapping_shl(hash_log); + let (chain_table, chain_size) = if ZSTD_rust_params_allocateChainTable( + strategy, + use_row_match_finder, + dedicated_dict_search, + ) != 0 + { + (chain_table, 1u32.wrapping_shl(chain_log)) + } else { + (ptr::null_mut(), 0) + }; + let (hash_table3, hash_size3) = if hash_log3 != 0 { + (hash_table3, 1u32.wrapping_shl(hash_log3)) + } else { + (ptr::null_mut(), 0) + }; + unsafe { + ZSTD_rust_reduceIndex( + hash_table, + hash_size, + chain_table, + chain_size, + hash_table3, + hash_size3, + reducer_value, + c_int::from(strategy == ZSTD_BTLAZY2), + ); + } +} + /// Copies a CDict match table into a CCtx, removing short-cache tags when the /// C-owned compression parameters say the source table is tagged. #[no_mangle] @@ -11121,6 +11169,35 @@ mod tests { assert_eq!(hash_table3[0], 0); } + #[test] + fn reduce_index_for_match_state_selects_chain_and_hash3_tables() { + let mut hash_table = [0u32; ZSTD_ROWSIZE]; + let mut chain_table = [0u32; ZSTD_ROWSIZE]; + let mut hash_table3 = [0u32; ZSTD_ROWSIZE]; + hash_table[0] = ZSTD_DUBT_UNSORTED_MARK; + chain_table[0] = ZSTD_DUBT_UNSORTED_MARK; + hash_table3[0] = ZSTD_DUBT_UNSORTED_MARK; + + unsafe { + ZSTD_rust_reduceIndexForMatchState( + hash_table.as_mut_ptr(), + 4, + chain_table.as_mut_ptr(), + 4, + hash_table3.as_mut_ptr(), + 4, + ZSTD_BTLAZY2, + ZSTD_RUST_PS_DISABLE, + 0, + 3, + ); + } + + assert_eq!(hash_table[0], 0); + assert_eq!(chain_table[0], ZSTD_DUBT_UNSORTED_MARK); + assert_eq!(hash_table3[0], 0); + } + #[test] fn copy_cdict_table_removes_short_cache_tags() { let source = [0x1234_56ff, 0xdead_beef, 0x0000_0100, u32::MAX];