feat(compress): move block compressor dispatch policy to Rust
`ZSTD_selectBlockCompressor` already delegated scalar strategy/index calculation to the Rust parameter module, but C still owned table selection and dictionary-mode offsets. Keep the configuration-dependent C function- pointer tables and NULL entries for excluded compressors as private leaves, and pass those tables through a narrow ABI state so Rust owns row versus ordinary selection, dictionary-mode indexing, and selected callback publication. The legacy C selector signature remains intact for the LDM caller. Test Plan: - `rustfmt --edition 2021 --check rust/src/zstd_compress.rs` -- passed. - `git diff --check` and `git diff --cached --check` -- passed. - Heavy cargo/make/test/fuzzer verification not run per the enforced 40 GiB serial verification limit.
This commit is contained in:
@@ -1793,7 +1793,6 @@ size_t ZSTD_rust_params_getBlockSize(size_t maxBlockSize, U32 windowLog);
|
||||
int ZSTD_rust_params_resolveExternalSequenceValidation(int mode);
|
||||
int ZSTD_rust_params_rowMatchFinderSupported(int strategy);
|
||||
int ZSTD_rust_params_rowMatchFinderUsed(int strategy, int mode);
|
||||
int ZSTD_rust_params_selectBlockCompressor(int strategy, int mode);
|
||||
int ZSTD_rust_params_resolveRowMatchFinderMode(
|
||||
int mode, ZSTD_compressionParameters cParams);
|
||||
int ZSTD_rust_params_resolveBlockSplitterMode(
|
||||
@@ -1811,6 +1810,23 @@ int ZSTD_rust_params_getCParamMode(int cdict_present, int cdict_strategy,
|
||||
int params_attachDictPref,
|
||||
int params_forceWindow);
|
||||
|
||||
typedef struct {
|
||||
const ZSTD_BlockCompressor_f* blockCompressors;
|
||||
const ZSTD_BlockCompressor_f* rowBlockCompressors;
|
||||
ZSTD_BlockCompressor_f* selectedCompressor;
|
||||
} ZSTD_rust_selectBlockCompressorState;
|
||||
size_t ZSTD_rust_selectBlockCompressor(
|
||||
const ZSTD_rust_selectBlockCompressorState* state,
|
||||
int strategy, int useRowMatchFinder, int dictMode);
|
||||
typedef char ZSTD_rust_select_block_compressor_state_layout[
|
||||
(offsetof(ZSTD_rust_selectBlockCompressorState, blockCompressors) == 0
|
||||
&& offsetof(ZSTD_rust_selectBlockCompressorState, rowBlockCompressors)
|
||||
== sizeof(void*)
|
||||
&& offsetof(ZSTD_rust_selectBlockCompressorState, selectedCompressor)
|
||||
== 2 * sizeof(void*)
|
||||
&& sizeof(ZSTD_rust_selectBlockCompressorState) == 3 * sizeof(void*))
|
||||
? 1 : -1];
|
||||
|
||||
/* CCtx parameter state is mirrored by rust/src/zstd_compress_params_api.rs.
|
||||
* Rust owns parameter bounds and clamping; C exposes only the
|
||||
* build-configuration values required by that narrow ABI. */
|
||||
@@ -5123,43 +5139,41 @@ ZSTD_BlockCompressor_f ZSTD_selectBlockCompressor(ZSTD_strategy strat, ZSTD_Para
|
||||
NULL,
|
||||
NULL }
|
||||
};
|
||||
ZSTD_BlockCompressor_f selectedCompressor;
|
||||
int selectedCompressorIndex;
|
||||
static const ZSTD_BlockCompressor_f rowBasedBlockCompressors[4][3] = {
|
||||
{
|
||||
ZSTD_COMPRESSBLOCK_GREEDY_ROW,
|
||||
ZSTD_COMPRESSBLOCK_LAZY_ROW,
|
||||
ZSTD_COMPRESSBLOCK_LAZY2_ROW
|
||||
},
|
||||
{
|
||||
ZSTD_COMPRESSBLOCK_GREEDY_EXTDICT_ROW,
|
||||
ZSTD_COMPRESSBLOCK_LAZY_EXTDICT_ROW,
|
||||
ZSTD_COMPRESSBLOCK_LAZY2_EXTDICT_ROW
|
||||
},
|
||||
{
|
||||
ZSTD_COMPRESSBLOCK_GREEDY_DICTMATCHSTATE_ROW,
|
||||
ZSTD_COMPRESSBLOCK_LAZY_DICTMATCHSTATE_ROW,
|
||||
ZSTD_COMPRESSBLOCK_LAZY2_DICTMATCHSTATE_ROW
|
||||
},
|
||||
{
|
||||
ZSTD_COMPRESSBLOCK_GREEDY_DEDICATEDDICTSEARCH_ROW,
|
||||
ZSTD_COMPRESSBLOCK_LAZY_DEDICATEDDICTSEARCH_ROW,
|
||||
ZSTD_COMPRESSBLOCK_LAZY2_DEDICATEDDICTSEARCH_ROW
|
||||
}
|
||||
};
|
||||
ZSTD_rust_selectBlockCompressorState state;
|
||||
ZSTD_BlockCompressor_f selectedCompressor = NULL;
|
||||
size_t selectionResult;
|
||||
ZSTD_STATIC_ASSERT((unsigned)ZSTD_fast == 1);
|
||||
|
||||
assert(ZSTD_cParam_withinBounds(ZSTD_c_strategy, (int)strat));
|
||||
DEBUGLOG(5, "Selected block compressor: dictMode=%d strat=%d rowMatchfinder=%d", (int)dictMode, (int)strat, (int)useRowMatchFinder);
|
||||
selectedCompressorIndex = ZSTD_rust_params_selectBlockCompressor(
|
||||
(int)strat, (int)useRowMatchFinder);
|
||||
if (selectedCompressorIndex < 3) {
|
||||
static const ZSTD_BlockCompressor_f rowBasedBlockCompressors[4][3] = {
|
||||
{
|
||||
ZSTD_COMPRESSBLOCK_GREEDY_ROW,
|
||||
ZSTD_COMPRESSBLOCK_LAZY_ROW,
|
||||
ZSTD_COMPRESSBLOCK_LAZY2_ROW
|
||||
},
|
||||
{
|
||||
ZSTD_COMPRESSBLOCK_GREEDY_EXTDICT_ROW,
|
||||
ZSTD_COMPRESSBLOCK_LAZY_EXTDICT_ROW,
|
||||
ZSTD_COMPRESSBLOCK_LAZY2_EXTDICT_ROW
|
||||
},
|
||||
{
|
||||
ZSTD_COMPRESSBLOCK_GREEDY_DICTMATCHSTATE_ROW,
|
||||
ZSTD_COMPRESSBLOCK_LAZY_DICTMATCHSTATE_ROW,
|
||||
ZSTD_COMPRESSBLOCK_LAZY2_DICTMATCHSTATE_ROW
|
||||
},
|
||||
{
|
||||
ZSTD_COMPRESSBLOCK_GREEDY_DEDICATEDDICTSEARCH_ROW,
|
||||
ZSTD_COMPRESSBLOCK_LAZY_DEDICATEDDICTSEARCH_ROW,
|
||||
ZSTD_COMPRESSBLOCK_LAZY2_DEDICATEDDICTSEARCH_ROW
|
||||
}
|
||||
};
|
||||
DEBUGLOG(5, "Selecting a row-based matchfinder");
|
||||
assert(useRowMatchFinder != ZSTD_ps_auto);
|
||||
selectedCompressor = rowBasedBlockCompressors[(int)dictMode][selectedCompressorIndex];
|
||||
} else {
|
||||
selectedCompressor = blockCompressor[(int)dictMode][selectedCompressorIndex - 3];
|
||||
}
|
||||
state.blockCompressors = &blockCompressor[0][0];
|
||||
state.rowBlockCompressors = &rowBasedBlockCompressors[0][0];
|
||||
state.selectedCompressor = &selectedCompressor;
|
||||
selectionResult = ZSTD_rust_selectBlockCompressor(
|
||||
&state, (int)strat, (int)useRowMatchFinder, (int)dictMode);
|
||||
assert(!ERR_isError(selectionResult));
|
||||
assert(selectedCompressor != NULL);
|
||||
return selectedCompressor;
|
||||
}
|
||||
|
||||
+201
-2
@@ -34,8 +34,9 @@ use crate::zstd_compress_params::{
|
||||
ZSTD_rust_params_checkCParams, ZSTD_rust_params_defaultCLevel,
|
||||
ZSTD_rust_params_estimateMatchStateSize, ZSTD_rust_params_getParamsInternal,
|
||||
ZSTD_rust_params_maxNbSeq, ZSTD_rust_params_resolveMaxBlockSize,
|
||||
ZSTD_rust_params_rowMatchFinderUsed, ZSTD_rust_params_selectCParams,
|
||||
ZSTD_RUST_CPM_NO_ATTACH_DICT, ZSTD_RUST_PS_AUTO, ZSTD_RUST_PS_DISABLE, ZSTD_RUST_PS_ENABLE,
|
||||
ZSTD_rust_params_rowMatchFinderUsed, ZSTD_rust_params_selectBlockCompressor,
|
||||
ZSTD_rust_params_selectCParams, ZSTD_RUST_CPM_NO_ATTACH_DICT, ZSTD_RUST_PS_AUTO,
|
||||
ZSTD_RUST_PS_DISABLE, ZSTD_RUST_PS_ENABLE,
|
||||
};
|
||||
use crate::zstd_compress_params_api::{
|
||||
ZSTD_CCtxParams_setParameter, ZSTD_CCtx_params, ZSTD_customMem, ZSTD_rust_isUpdateAuthorized,
|
||||
@@ -191,6 +192,89 @@ type BuildSeqStoreTryExternalProducerFn =
|
||||
unsafe extern "C" fn(*mut c_void, *const c_void, usize, *mut c_int, *mut c_int) -> usize;
|
||||
type BuildSeqStoreClearLdmFn = unsafe extern "C" fn(*mut c_void);
|
||||
|
||||
type BlockCompressorFn =
|
||||
unsafe extern "C" fn(*mut c_void, *mut SeqStore_t, *mut u32, *const c_void, usize) -> usize;
|
||||
|
||||
const ZSTD_RUST_BLOCK_COMPRESSOR_TABLE_WIDTH: usize = 10;
|
||||
const ZSTD_RUST_ROW_BLOCK_COMPRESSOR_TABLE_WIDTH: usize = 3;
|
||||
const ZSTD_RUST_DICT_MODE_COUNT: c_int = 4;
|
||||
const ZSTD_RUST_BLOCK_COMPRESSOR_MAX_STRATEGY: c_int =
|
||||
ZSTD_RUST_BLOCK_COMPRESSOR_TABLE_WIDTH as c_int - 1;
|
||||
|
||||
/// C supplies the configuration-dependent compressor tables and their private
|
||||
/// match-state leaves. Rust owns the strategy/row-mode index and dictionary
|
||||
/// mode dispatch into those tables.
|
||||
#[repr(C)]
|
||||
pub struct ZSTD_rust_selectBlockCompressorState {
|
||||
block_compressors: *const Option<BlockCompressorFn>,
|
||||
row_block_compressors: *const Option<BlockCompressorFn>,
|
||||
selected_compressor: *mut Option<BlockCompressorFn>,
|
||||
}
|
||||
|
||||
const _: () = {
|
||||
assert!(size_of::<BlockCompressorFn>() == size_of::<usize>());
|
||||
assert!(size_of::<Option<BlockCompressorFn>>() == size_of::<usize>());
|
||||
assert!(offset_of!(ZSTD_rust_selectBlockCompressorState, block_compressors) == 0);
|
||||
assert!(
|
||||
offset_of!(ZSTD_rust_selectBlockCompressorState, row_block_compressors)
|
||||
== size_of::<usize>()
|
||||
);
|
||||
assert!(
|
||||
offset_of!(ZSTD_rust_selectBlockCompressorState, selected_compressor)
|
||||
== 2 * size_of::<usize>()
|
||||
);
|
||||
assert!(size_of::<ZSTD_rust_selectBlockCompressorState>() == 3 * size_of::<usize>());
|
||||
};
|
||||
|
||||
/// Select one C-owned match-state compressor while keeping the table policy
|
||||
/// and dispatch-index arithmetic in Rust.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn ZSTD_rust_selectBlockCompressor(
|
||||
state: *const ZSTD_rust_selectBlockCompressorState,
|
||||
strategy: c_int,
|
||||
use_row_match_finder: c_int,
|
||||
dict_mode: c_int,
|
||||
) -> usize {
|
||||
if state.is_null() {
|
||||
return ERROR(ZstdErrorCode::Generic);
|
||||
}
|
||||
let state = unsafe { &*state };
|
||||
if state.block_compressors.is_null()
|
||||
|| state.row_block_compressors.is_null()
|
||||
|| state.selected_compressor.is_null()
|
||||
|| !(ZSTD_FAST..=ZSTD_RUST_BLOCK_COMPRESSOR_MAX_STRATEGY).contains(&strategy)
|
||||
|| !(0..ZSTD_RUST_DICT_MODE_COUNT).contains(&dict_mode)
|
||||
{
|
||||
return ERROR(ZstdErrorCode::Generic);
|
||||
}
|
||||
|
||||
unsafe { *state.selected_compressor = None };
|
||||
let selected_index = ZSTD_rust_params_selectBlockCompressor(strategy, use_row_match_finder);
|
||||
let (table, table_width, table_index) = if selected_index < 3 {
|
||||
(
|
||||
state.row_block_compressors,
|
||||
ZSTD_RUST_ROW_BLOCK_COMPRESSOR_TABLE_WIDTH,
|
||||
selected_index,
|
||||
)
|
||||
} else {
|
||||
(
|
||||
state.block_compressors,
|
||||
ZSTD_RUST_BLOCK_COMPRESSOR_TABLE_WIDTH,
|
||||
selected_index - 3,
|
||||
)
|
||||
};
|
||||
if table_index < 0 {
|
||||
return ERROR(ZstdErrorCode::Generic);
|
||||
}
|
||||
|
||||
let callback = unsafe { *table.add(dict_mode as usize * table_width + table_index as usize) };
|
||||
let Some(callback) = callback else {
|
||||
return ERROR(ZstdErrorCode::Generic);
|
||||
};
|
||||
unsafe { *state.selected_compressor = Some(callback) };
|
||||
0
|
||||
}
|
||||
|
||||
/// Explicit projection for the sequence-store builder.
|
||||
///
|
||||
/// Rust owns the threshold/reset/repcode/literal-store orchestration. The
|
||||
@@ -9430,6 +9514,121 @@ mod tests {
|
||||
const ZSTD_BTOPT: c_int = 7;
|
||||
const ZSTD_BTULTRA2: c_int = 9;
|
||||
|
||||
unsafe extern "C" fn select_block_compressor_test_default(
|
||||
_match_state: *mut c_void,
|
||||
_seq_store: *mut SeqStore_t,
|
||||
_rep: *mut u32,
|
||||
_src: *const c_void,
|
||||
_src_size: usize,
|
||||
) -> usize {
|
||||
7
|
||||
}
|
||||
|
||||
unsafe extern "C" fn select_block_compressor_test_ordinary(
|
||||
_match_state: *mut c_void,
|
||||
_seq_store: *mut SeqStore_t,
|
||||
_rep: *mut u32,
|
||||
_src: *const c_void,
|
||||
_src_size: usize,
|
||||
) -> usize {
|
||||
41
|
||||
}
|
||||
|
||||
unsafe extern "C" fn select_block_compressor_test_row(
|
||||
_match_state: *mut c_void,
|
||||
_seq_store: *mut SeqStore_t,
|
||||
_rep: *mut u32,
|
||||
_src: *const c_void,
|
||||
_src_size: usize,
|
||||
) -> usize {
|
||||
43
|
||||
}
|
||||
|
||||
fn select_block_compressor_test_state(
|
||||
block_compressors: &[Option<BlockCompressorFn>],
|
||||
row_block_compressors: &[Option<BlockCompressorFn>],
|
||||
selected_compressor: &mut Option<BlockCompressorFn>,
|
||||
) -> ZSTD_rust_selectBlockCompressorState {
|
||||
ZSTD_rust_selectBlockCompressorState {
|
||||
block_compressors: block_compressors.as_ptr(),
|
||||
row_block_compressors: row_block_compressors.as_ptr(),
|
||||
selected_compressor,
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn select_block_compressor_dispatches_ordinary_and_row_tables() {
|
||||
let default = Some(select_block_compressor_test_default as BlockCompressorFn);
|
||||
let mut block_compressors = [default; 4 * ZSTD_RUST_BLOCK_COMPRESSOR_TABLE_WIDTH];
|
||||
let mut row_block_compressors = [default; 4 * ZSTD_RUST_ROW_BLOCK_COMPRESSOR_TABLE_WIDTH];
|
||||
block_compressors[ZSTD_RUST_BLOCK_COMPRESSOR_TABLE_WIDTH + 2] =
|
||||
Some(select_block_compressor_test_ordinary as BlockCompressorFn);
|
||||
row_block_compressors[3 * ZSTD_RUST_ROW_BLOCK_COMPRESSOR_TABLE_WIDTH] =
|
||||
Some(select_block_compressor_test_row as BlockCompressorFn);
|
||||
let mut selected_compressor = None;
|
||||
let state = select_block_compressor_test_state(
|
||||
&block_compressors,
|
||||
&row_block_compressors,
|
||||
&mut selected_compressor,
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
unsafe { ZSTD_rust_selectBlockCompressor(&state, ZSTD_DFAST, ZSTD_RUST_PS_DISABLE, 1) },
|
||||
0
|
||||
);
|
||||
let ordinary = selected_compressor.expect("ordinary compressor should be selected");
|
||||
assert_eq!(
|
||||
unsafe {
|
||||
ordinary(
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
ptr::null(),
|
||||
0,
|
||||
)
|
||||
},
|
||||
41
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
unsafe { ZSTD_rust_selectBlockCompressor(&state, ZSTD_GREEDY, ZSTD_RUST_PS_ENABLE, 3) },
|
||||
0
|
||||
);
|
||||
let row = selected_compressor.expect("row compressor should be selected");
|
||||
assert_eq!(
|
||||
unsafe {
|
||||
row(
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
ptr::null(),
|
||||
0,
|
||||
)
|
||||
},
|
||||
43
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn select_block_compressor_rejects_an_excluded_dispatch_leaf() {
|
||||
let default = Some(select_block_compressor_test_default as BlockCompressorFn);
|
||||
let mut block_compressors = [default; 4 * ZSTD_RUST_BLOCK_COMPRESSOR_TABLE_WIDTH];
|
||||
let row_block_compressors = [default; 4 * ZSTD_RUST_ROW_BLOCK_COMPRESSOR_TABLE_WIDTH];
|
||||
block_compressors[1] = None;
|
||||
let mut selected_compressor = None;
|
||||
let state = select_block_compressor_test_state(
|
||||
&block_compressors,
|
||||
&row_block_compressors,
|
||||
&mut selected_compressor,
|
||||
);
|
||||
|
||||
let result =
|
||||
unsafe { ZSTD_rust_selectBlockCompressor(&state, ZSTD_FAST, ZSTD_RUST_PS_DISABLE, 0) };
|
||||
|
||||
assert!(ERR_isError(result));
|
||||
assert!(selected_compressor.is_none());
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct BuildSeqStoreSelectProbe {
|
||||
events: Vec<&'static str>,
|
||||
|
||||
Reference in New Issue
Block a user