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)(
|
||||
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)(
|
||||
void* context, const ZSTD_compressionParameters* cParams,
|
||||
int useRowMatchFinder);
|
||||
@@ -6420,17 +6421,18 @@ ZSTD_compress_insertDictionary(ZSTD_compressedBlockState_t* bs,
|
||||
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;
|
||||
return ZSTD_cwksp_reserve_object(
|
||||
&cdict->workspace, ZSTD_cwksp_align(dictSize, sizeof(void*)));
|
||||
return ZSTD_cwksp_reserve_object(&cdict->workspace, reservedSize);
|
||||
}
|
||||
|
||||
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;
|
||||
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(
|
||||
|
||||
@@ -47,6 +47,13 @@ const ZSTD_DCT_RAW_CONTENT: c_int = 1;
|
||||
const ZSTD_DCT_FULL_DICT: c_int = 2;
|
||||
const ZSTD_DTL_FULL: c_int = 1;
|
||||
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
|
||||
/// 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 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 InitCDictInsertDictionaryFn = unsafe extern "C" fn(
|
||||
*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 {
|
||||
unsafe { *state.dict_content = dict };
|
||||
} 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() {
|
||||
return ERROR(ZstdErrorCode::MemoryAllocation);
|
||||
}
|
||||
@@ -1378,7 +1390,7 @@ pub unsafe extern "C" fn ZSTD_rust_initCDict(
|
||||
*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() {
|
||||
return ERROR(ZstdErrorCode::MemoryAllocation);
|
||||
}
|
||||
@@ -2626,6 +2638,7 @@ mod tests {
|
||||
inserted_content_type: c_int,
|
||||
inserted_dtlm: c_int,
|
||||
inserted_tfp: c_int,
|
||||
reserved_entropy_size: usize,
|
||||
entropy_workspace: *mut c_void,
|
||||
reset_match_result: usize,
|
||||
insert_result: usize,
|
||||
@@ -2646,6 +2659,7 @@ mod tests {
|
||||
inserted_content_type: 0,
|
||||
inserted_dtlm: 0,
|
||||
inserted_tfp: 0,
|
||||
reserved_entropy_size: 0,
|
||||
entropy_workspace: ptr::null_mut(),
|
||||
reset_match_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) };
|
||||
probe.events.push("reserve");
|
||||
probe.reserved_entropy_size = workspace_size;
|
||||
probe.entropy_workspace
|
||||
}
|
||||
|
||||
@@ -2784,6 +2802,7 @@ mod tests {
|
||||
assert_eq!(probe.inserted_content_type, ZSTD_DCT_RAW_CONTENT);
|
||||
assert_eq!(probe.inserted_dtlm, ZSTD_DTL_FULL);
|
||||
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!(dedicated_dict_search, enable_dedicated_dict_search);
|
||||
assert_eq!(dict_content_size, dictionary.len());
|
||||
@@ -2865,13 +2884,17 @@ mod tests {
|
||||
probe.events,
|
||||
["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!(dict_content, probe.content_storage.as_ptr().cast());
|
||||
assert_eq!(probe.inserted_dict, dict_content);
|
||||
assert_eq!(dict_content_size, dictionary.len());
|
||||
assert_eq!(probe.inserted_dtlm, ZSTD_DTL_FULL);
|
||||
assert_eq!(probe.inserted_tfp, ZSTD_TFP_FOR_CDICT as c_int);
|
||||
assert_eq!(probe.reserved_entropy_size, HUF_WORKSPACE_SIZE);
|
||||
}
|
||||
|
||||
struct CompressBeginProbe {
|
||||
@@ -5907,6 +5930,27 @@ mod tests {
|
||||
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]
|
||||
fn dictionary_content_policy_preserves_both_suffix_limits() {
|
||||
assert_eq!(dictionary_suffix(100, 20), (80, 20));
|
||||
|
||||
Reference in New Issue
Block a user