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_resolveExternalSequenceValidation(int mode);
|
||||||
int ZSTD_rust_params_rowMatchFinderSupported(int strategy);
|
int ZSTD_rust_params_rowMatchFinderSupported(int strategy);
|
||||||
int ZSTD_rust_params_rowMatchFinderUsed(int strategy, int mode);
|
int ZSTD_rust_params_rowMatchFinderUsed(int strategy, int mode);
|
||||||
int ZSTD_rust_params_selectBlockCompressor(int strategy, int mode);
|
|
||||||
int ZSTD_rust_params_resolveRowMatchFinderMode(
|
int ZSTD_rust_params_resolveRowMatchFinderMode(
|
||||||
int mode, ZSTD_compressionParameters cParams);
|
int mode, ZSTD_compressionParameters cParams);
|
||||||
int ZSTD_rust_params_resolveBlockSplitterMode(
|
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_attachDictPref,
|
||||||
int params_forceWindow);
|
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.
|
/* CCtx parameter state is mirrored by rust/src/zstd_compress_params_api.rs.
|
||||||
* Rust owns parameter bounds and clamping; C exposes only the
|
* Rust owns parameter bounds and clamping; C exposes only the
|
||||||
* build-configuration values required by that narrow ABI. */
|
* build-configuration values required by that narrow ABI. */
|
||||||
@@ -5123,15 +5139,6 @@ ZSTD_BlockCompressor_f ZSTD_selectBlockCompressor(ZSTD_strategy strat, ZSTD_Para
|
|||||||
NULL,
|
NULL,
|
||||||
NULL }
|
NULL }
|
||||||
};
|
};
|
||||||
ZSTD_BlockCompressor_f selectedCompressor;
|
|
||||||
int selectedCompressorIndex;
|
|
||||||
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] = {
|
static const ZSTD_BlockCompressor_f rowBasedBlockCompressors[4][3] = {
|
||||||
{
|
{
|
||||||
ZSTD_COMPRESSBLOCK_GREEDY_ROW,
|
ZSTD_COMPRESSBLOCK_GREEDY_ROW,
|
||||||
@@ -5154,12 +5161,19 @@ ZSTD_BlockCompressor_f ZSTD_selectBlockCompressor(ZSTD_strategy strat, ZSTD_Para
|
|||||||
ZSTD_COMPRESSBLOCK_LAZY2_DEDICATEDDICTSEARCH_ROW
|
ZSTD_COMPRESSBLOCK_LAZY2_DEDICATEDDICTSEARCH_ROW
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
DEBUGLOG(5, "Selecting a row-based matchfinder");
|
ZSTD_rust_selectBlockCompressorState state;
|
||||||
assert(useRowMatchFinder != ZSTD_ps_auto);
|
ZSTD_BlockCompressor_f selectedCompressor = NULL;
|
||||||
selectedCompressor = rowBasedBlockCompressors[(int)dictMode][selectedCompressorIndex];
|
size_t selectionResult;
|
||||||
} else {
|
ZSTD_STATIC_ASSERT((unsigned)ZSTD_fast == 1);
|
||||||
selectedCompressor = blockCompressor[(int)dictMode][selectedCompressorIndex - 3];
|
|
||||||
}
|
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);
|
||||||
|
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);
|
assert(selectedCompressor != NULL);
|
||||||
return selectedCompressor;
|
return selectedCompressor;
|
||||||
}
|
}
|
||||||
|
|||||||
+201
-2
@@ -34,8 +34,9 @@ use crate::zstd_compress_params::{
|
|||||||
ZSTD_rust_params_checkCParams, ZSTD_rust_params_defaultCLevel,
|
ZSTD_rust_params_checkCParams, ZSTD_rust_params_defaultCLevel,
|
||||||
ZSTD_rust_params_estimateMatchStateSize, ZSTD_rust_params_getParamsInternal,
|
ZSTD_rust_params_estimateMatchStateSize, ZSTD_rust_params_getParamsInternal,
|
||||||
ZSTD_rust_params_maxNbSeq, ZSTD_rust_params_resolveMaxBlockSize,
|
ZSTD_rust_params_maxNbSeq, ZSTD_rust_params_resolveMaxBlockSize,
|
||||||
ZSTD_rust_params_rowMatchFinderUsed, ZSTD_rust_params_selectCParams,
|
ZSTD_rust_params_rowMatchFinderUsed, ZSTD_rust_params_selectBlockCompressor,
|
||||||
ZSTD_RUST_CPM_NO_ATTACH_DICT, ZSTD_RUST_PS_AUTO, ZSTD_RUST_PS_DISABLE, ZSTD_RUST_PS_ENABLE,
|
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::{
|
use crate::zstd_compress_params_api::{
|
||||||
ZSTD_CCtxParams_setParameter, ZSTD_CCtx_params, ZSTD_customMem, ZSTD_rust_isUpdateAuthorized,
|
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;
|
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 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.
|
/// Explicit projection for the sequence-store builder.
|
||||||
///
|
///
|
||||||
/// Rust owns the threshold/reset/repcode/literal-store orchestration. The
|
/// Rust owns the threshold/reset/repcode/literal-store orchestration. The
|
||||||
@@ -9430,6 +9514,121 @@ mod tests {
|
|||||||
const ZSTD_BTOPT: c_int = 7;
|
const ZSTD_BTOPT: c_int = 7;
|
||||||
const ZSTD_BTULTRA2: c_int = 9;
|
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)]
|
#[derive(Default)]
|
||||||
struct BuildSeqStoreSelectProbe {
|
struct BuildSeqStoreSelectProbe {
|
||||||
events: Vec<&'static str>,
|
events: Vec<&'static str>,
|
||||||
|
|||||||
Reference in New Issue
Block a user