feat(cdict): move workspace reservation sizing to Rust
CDict initialization already lets Rust choose by-reference versus by-copy content, but the C bridge still selected the pointer-rounded content allocation and the HUF entropy-workspace size. That kept advanced and static CDict dictionary loading dependent on C policy even though the allocator itself can remain private. Compute the content reservation with the C-equivalent wrapping pointer alignment in Rust and pass both that size and the HUF workspace size through the existing callbacks. C now only forwards the sizes to ZSTD_cwksp_reserve_object; private CDict/workspace layouts and allocator behavior remain behind the ABI bridge. Focused probes cover alignment boundaries, by-copy content, and both reservation sizes. Test Plan: - `ulimit -v 41943040; cargo +nightly fmt --manifest-path rust/Cargo.toml --all -- --check` -- passed - `ulimit -v 41943040; gcc -fsyntax-only -std=c99 -DXXH_NAMESPACE=ZSTD_ -DDEBUGLEVEL=0 -DZSTD_MULTITHREAD -DZSTD_LEGACY_SUPPORT=5 -Ilib -Ilib/common -Ilib/compress -Ilib/decompress -Ilib/dict -Ilib/deprecated lib/compress/zstd_compress.c` -- passed - `ulimit -v 41943040; clang -fsyntax-only -std=c99 -DXXH_NAMESPACE=ZSTD_ -DDEBUGLEVEL=0 -DZSTD_MULTITHREAD -DZSTD_LEGACY_SUPPORT=5 -DZSTD_NO_ASM=1 -Ilib -Ilib/common -Ilib/compress -Ilib/decompress -Ilib/dict -Ilib/deprecated lib/compress/zstd_compress.c` -- passed - `git diff --check` and `git diff --cached --check` -- passed - Cargo builds/tests, make, fuzzers, and large upstream tests were not run per task constraints - GPG signing was unavailable because the configured pinentry could not start; this commit was created explicitly unsigned with `--no-gpg-sign`
This commit is contained in:
@@ -2639,7 +2639,8 @@ typedef char ZSTD_rust_external_sequence_store_state_layout[
|
|||||||
|
|
||||||
typedef void* (*ZSTD_rust_initCDictReserveContent_f)(
|
typedef void* (*ZSTD_rust_initCDictReserveContent_f)(
|
||||||
void* context, size_t dictSize);
|
void* context, size_t dictSize);
|
||||||
typedef void* (*ZSTD_rust_initCDictReserveEntropy_f)(void* context);
|
typedef void* (*ZSTD_rust_initCDictReserveEntropy_f)(
|
||||||
|
void* context, size_t workspaceSize);
|
||||||
typedef size_t (*ZSTD_rust_initCDictResetMatchState_f)(
|
typedef size_t (*ZSTD_rust_initCDictResetMatchState_f)(
|
||||||
void* context, const ZSTD_compressionParameters* cParams,
|
void* context, const ZSTD_compressionParameters* cParams,
|
||||||
int useRowMatchFinder);
|
int useRowMatchFinder);
|
||||||
@@ -6420,17 +6421,18 @@ ZSTD_compress_insertDictionary(ZSTD_compressedBlockState_t* bs,
|
|||||||
ZSTD_loadDictionaryContent_callback);
|
ZSTD_loadDictionaryContent_callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void* ZSTD_rust_initCDict_reserveContent(void* context, size_t dictSize)
|
static void* ZSTD_rust_initCDict_reserveContent(
|
||||||
|
void* context, size_t reservedSize)
|
||||||
{
|
{
|
||||||
ZSTD_CDict* const cdict = (ZSTD_CDict*)context;
|
ZSTD_CDict* const cdict = (ZSTD_CDict*)context;
|
||||||
return ZSTD_cwksp_reserve_object(
|
return ZSTD_cwksp_reserve_object(&cdict->workspace, reservedSize);
|
||||||
&cdict->workspace, ZSTD_cwksp_align(dictSize, sizeof(void*)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void* ZSTD_rust_initCDict_reserveEntropy(void* context)
|
static void* ZSTD_rust_initCDict_reserveEntropy(
|
||||||
|
void* context, size_t workspaceSize)
|
||||||
{
|
{
|
||||||
ZSTD_CDict* const cdict = (ZSTD_CDict*)context;
|
ZSTD_CDict* const cdict = (ZSTD_CDict*)context;
|
||||||
return ZSTD_cwksp_reserve_object(&cdict->workspace, HUF_WORKSPACE_SIZE);
|
return ZSTD_cwksp_reserve_object(&cdict->workspace, workspaceSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t ZSTD_rust_initCDict_resetMatchState(
|
static size_t ZSTD_rust_initCDict_resetMatchState(
|
||||||
|
|||||||
@@ -47,6 +47,13 @@ const ZSTD_DCT_RAW_CONTENT: c_int = 1;
|
|||||||
const ZSTD_DCT_FULL_DICT: c_int = 2;
|
const ZSTD_DCT_FULL_DICT: c_int = 2;
|
||||||
const ZSTD_DTL_FULL: c_int = 1;
|
const ZSTD_DTL_FULL: c_int = 1;
|
||||||
const ZSTD_STATIC_WORKSPACE_ALIGNMENT: usize = 8;
|
const ZSTD_STATIC_WORKSPACE_ALIGNMENT: usize = 8;
|
||||||
|
const CDICT_CONTENT_ALIGNMENT: usize = size_of::<*const c_void>();
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
const fn dictionary_content_reservation_size(dict_size: usize) -> usize {
|
||||||
|
let mask = CDICT_CONTENT_ALIGNMENT - 1;
|
||||||
|
dict_size.wrapping_add(mask) & !mask
|
||||||
|
}
|
||||||
|
|
||||||
/// C keeps match-state/content insertion private because it depends on the
|
/// C keeps match-state/content insertion private because it depends on the
|
||||||
/// configuration-sensitive `ZSTD_MatchState_t`, `ldmState_t`, workspace, and
|
/// configuration-sensitive `ZSTD_MatchState_t`, `ldmState_t`, workspace, and
|
||||||
@@ -1241,7 +1248,7 @@ pub unsafe extern "C" fn ZSTD_rust_compressBeginUsingDict(
|
|||||||
}
|
}
|
||||||
|
|
||||||
type InitCDictReserveContentFn = unsafe extern "C" fn(*mut c_void, usize) -> *mut c_void;
|
type InitCDictReserveContentFn = unsafe extern "C" fn(*mut c_void, usize) -> *mut c_void;
|
||||||
type InitCDictReserveEntropyFn = unsafe extern "C" fn(*mut c_void) -> *mut c_void;
|
type InitCDictReserveEntropyFn = unsafe extern "C" fn(*mut c_void, usize) -> *mut c_void;
|
||||||
type InitCDictResetMatchStateFn = unsafe extern "C" fn(*mut c_void, *const c_void, c_int) -> usize;
|
type InitCDictResetMatchStateFn = unsafe extern "C" fn(*mut c_void, *const c_void, c_int) -> usize;
|
||||||
type InitCDictInsertDictionaryFn = unsafe extern "C" fn(
|
type InitCDictInsertDictionaryFn = unsafe extern "C" fn(
|
||||||
*mut c_void,
|
*mut c_void,
|
||||||
@@ -1361,7 +1368,12 @@ pub unsafe extern "C" fn ZSTD_rust_initCDict(
|
|||||||
if dict_load_method == ZSTD_DLM_BY_REF || dict.is_null() || dict_size == 0 {
|
if dict_load_method == ZSTD_DLM_BY_REF || dict.is_null() || dict_size == 0 {
|
||||||
unsafe { *state.dict_content = dict };
|
unsafe { *state.dict_content = dict };
|
||||||
} else {
|
} else {
|
||||||
let internal_buffer = unsafe { reserve_content(state.callback_context, dict_size) };
|
let internal_buffer = unsafe {
|
||||||
|
reserve_content(
|
||||||
|
state.callback_context,
|
||||||
|
dictionary_content_reservation_size(dict_size),
|
||||||
|
)
|
||||||
|
};
|
||||||
if internal_buffer.is_null() {
|
if internal_buffer.is_null() {
|
||||||
return ERROR(ZstdErrorCode::MemoryAllocation);
|
return ERROR(ZstdErrorCode::MemoryAllocation);
|
||||||
}
|
}
|
||||||
@@ -1378,7 +1390,7 @@ pub unsafe extern "C" fn ZSTD_rust_initCDict(
|
|||||||
*state.dict_content_type = dict_content_type;
|
*state.dict_content_type = dict_content_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
let entropy_workspace = unsafe { reserve_entropy(state.callback_context) };
|
let entropy_workspace = unsafe { reserve_entropy(state.callback_context, HUF_WORKSPACE_SIZE) };
|
||||||
if entropy_workspace.is_null() {
|
if entropy_workspace.is_null() {
|
||||||
return ERROR(ZstdErrorCode::MemoryAllocation);
|
return ERROR(ZstdErrorCode::MemoryAllocation);
|
||||||
}
|
}
|
||||||
@@ -2626,6 +2638,7 @@ mod tests {
|
|||||||
inserted_content_type: c_int,
|
inserted_content_type: c_int,
|
||||||
inserted_dtlm: c_int,
|
inserted_dtlm: c_int,
|
||||||
inserted_tfp: c_int,
|
inserted_tfp: c_int,
|
||||||
|
reserved_entropy_size: usize,
|
||||||
entropy_workspace: *mut c_void,
|
entropy_workspace: *mut c_void,
|
||||||
reset_match_result: usize,
|
reset_match_result: usize,
|
||||||
insert_result: usize,
|
insert_result: usize,
|
||||||
@@ -2646,6 +2659,7 @@ mod tests {
|
|||||||
inserted_content_type: 0,
|
inserted_content_type: 0,
|
||||||
inserted_dtlm: 0,
|
inserted_dtlm: 0,
|
||||||
inserted_tfp: 0,
|
inserted_tfp: 0,
|
||||||
|
reserved_entropy_size: 0,
|
||||||
entropy_workspace: ptr::null_mut(),
|
entropy_workspace: ptr::null_mut(),
|
||||||
reset_match_result: 0,
|
reset_match_result: 0,
|
||||||
insert_result: 0,
|
insert_result: 0,
|
||||||
@@ -2671,9 +2685,13 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe extern "C" fn init_cdict_reserve_entropy(context: *mut c_void) -> *mut c_void {
|
unsafe extern "C" fn init_cdict_reserve_entropy(
|
||||||
|
context: *mut c_void,
|
||||||
|
workspace_size: usize,
|
||||||
|
) -> *mut c_void {
|
||||||
let probe = unsafe { init_cdict_probe(context) };
|
let probe = unsafe { init_cdict_probe(context) };
|
||||||
probe.events.push("reserve");
|
probe.events.push("reserve");
|
||||||
|
probe.reserved_entropy_size = workspace_size;
|
||||||
probe.entropy_workspace
|
probe.entropy_workspace
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2784,6 +2802,7 @@ mod tests {
|
|||||||
assert_eq!(probe.inserted_content_type, ZSTD_DCT_RAW_CONTENT);
|
assert_eq!(probe.inserted_content_type, ZSTD_DCT_RAW_CONTENT);
|
||||||
assert_eq!(probe.inserted_dtlm, ZSTD_DTL_FULL);
|
assert_eq!(probe.inserted_dtlm, ZSTD_DTL_FULL);
|
||||||
assert_eq!(probe.inserted_tfp, ZSTD_TFP_FOR_CDICT as c_int);
|
assert_eq!(probe.inserted_tfp, ZSTD_TFP_FOR_CDICT as c_int);
|
||||||
|
assert_eq!(probe.reserved_entropy_size, HUF_WORKSPACE_SIZE);
|
||||||
assert_eq!(match_state_c_params, c_params);
|
assert_eq!(match_state_c_params, c_params);
|
||||||
assert_eq!(dedicated_dict_search, enable_dedicated_dict_search);
|
assert_eq!(dedicated_dict_search, enable_dedicated_dict_search);
|
||||||
assert_eq!(dict_content_size, dictionary.len());
|
assert_eq!(dict_content_size, dictionary.len());
|
||||||
@@ -2865,13 +2884,17 @@ mod tests {
|
|||||||
probe.events,
|
probe.events,
|
||||||
["reserve-content", "reserve", "reset-match", "insert"]
|
["reserve-content", "reserve", "reset-match", "insert"]
|
||||||
);
|
);
|
||||||
assert_eq!(probe.reserved_content_size, dictionary.len());
|
assert_eq!(
|
||||||
|
probe.reserved_content_size,
|
||||||
|
dictionary_content_reservation_size(dictionary.len())
|
||||||
|
);
|
||||||
assert_eq!(&probe.content_storage[..dictionary.len()], &dictionary);
|
assert_eq!(&probe.content_storage[..dictionary.len()], &dictionary);
|
||||||
assert_eq!(dict_content, probe.content_storage.as_ptr().cast());
|
assert_eq!(dict_content, probe.content_storage.as_ptr().cast());
|
||||||
assert_eq!(probe.inserted_dict, dict_content);
|
assert_eq!(probe.inserted_dict, dict_content);
|
||||||
assert_eq!(dict_content_size, dictionary.len());
|
assert_eq!(dict_content_size, dictionary.len());
|
||||||
assert_eq!(probe.inserted_dtlm, ZSTD_DTL_FULL);
|
assert_eq!(probe.inserted_dtlm, ZSTD_DTL_FULL);
|
||||||
assert_eq!(probe.inserted_tfp, ZSTD_TFP_FOR_CDICT as c_int);
|
assert_eq!(probe.inserted_tfp, ZSTD_TFP_FOR_CDICT as c_int);
|
||||||
|
assert_eq!(probe.reserved_entropy_size, HUF_WORKSPACE_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CompressBeginProbe {
|
struct CompressBeginProbe {
|
||||||
@@ -5907,6 +5930,27 @@ mod tests {
|
|||||||
assert_eq!(dict_n_count_repeat(&normalized, 2, 2), FSE_REPEAT_CHECK);
|
assert_eq!(dict_n_count_repeat(&normalized, 2, 2), FSE_REPEAT_CHECK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn dictionary_content_reservation_matches_pointer_alignment() {
|
||||||
|
let alignment = CDICT_CONTENT_ALIGNMENT;
|
||||||
|
assert!(alignment.is_power_of_two());
|
||||||
|
assert_eq!(dictionary_content_reservation_size(0), 0);
|
||||||
|
assert_eq!(dictionary_content_reservation_size(1), alignment);
|
||||||
|
assert_eq!(
|
||||||
|
dictionary_content_reservation_size(alignment - 1),
|
||||||
|
alignment
|
||||||
|
);
|
||||||
|
assert_eq!(dictionary_content_reservation_size(alignment), alignment);
|
||||||
|
assert_eq!(
|
||||||
|
dictionary_content_reservation_size(alignment + 1),
|
||||||
|
alignment * 2
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
dictionary_content_reservation_size(usize::MAX),
|
||||||
|
usize::MAX.wrapping_add(alignment - 1) & !(alignment - 1)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn dictionary_content_policy_preserves_both_suffix_limits() {
|
fn dictionary_content_policy_preserves_both_suffix_limits() {
|
||||||
assert_eq!(dictionary_suffix(100, 20), (80, 20));
|
assert_eq!(dictionary_suffix(100, 20), (80, 20));
|
||||||
|
|||||||
Reference in New Issue
Block a user