feat(compress): move dictionary match-state publication to Rust
Replace the dictionary loader's C match-state publication callback with a live field projection. Rust now publishes nextToUpdate, loadedDictEnd, and forceNonContiguous at the existing orchestration point while C retains the private match-state layout. Keep the window base indirect so a preceding window update cannot leave Rust with a stale offset origin. Test Plan: - git diff --cached --check - capped cargo check --tests - capped cargo clippy --tests -- -A clippy::manual-bits -D warnings - capped make -j1 - capped make -j1 -C tests test
This commit is contained in:
@@ -2769,13 +2769,31 @@ typedef void (*ZSTD_rust_loadDictionaryContent_windowUpdate_f)(
|
|||||||
void* context, int ldm, const void* src, size_t srcSize);
|
void* context, int ldm, const void* src, size_t srcSize);
|
||||||
typedef void (*ZSTD_rust_loadDictionaryContent_setLdmLoadedDictEnd_f)(
|
typedef void (*ZSTD_rust_loadDictionaryContent_setLdmLoadedDictEnd_f)(
|
||||||
void* context, const void* iend, int forceWindow);
|
void* context, const void* iend, int forceWindow);
|
||||||
typedef void (*ZSTD_rust_loadDictionaryContent_publishMatchState_f)(
|
|
||||||
void* context, const void* ip, const void* iend,
|
|
||||||
int forceWindow, int deterministicRefPrefix);
|
|
||||||
typedef void (*ZSTD_rust_loadDictionaryContent_fillLdm_f)(
|
typedef void (*ZSTD_rust_loadDictionaryContent_fillLdm_f)(
|
||||||
void* context, const void* ip, const void* iend);
|
void* context, const void* ip, const void* iend);
|
||||||
typedef void (*ZSTD_rust_loadDictionaryContent_overflowCorrect_f)(
|
typedef void (*ZSTD_rust_loadDictionaryContent_overflowCorrect_f)(
|
||||||
void* context, const void* ip, const void* iend);
|
void* context, const void* ip, const void* iend);
|
||||||
|
typedef struct {
|
||||||
|
const BYTE** base;
|
||||||
|
U32* nextToUpdate;
|
||||||
|
U32* loadedDictEnd;
|
||||||
|
int* forceNonContiguous;
|
||||||
|
} ZSTD_rust_loadDictionaryContentMatchStatePublicationState;
|
||||||
|
typedef char ZSTD_rust_load_dictionary_match_state_publication_layout[
|
||||||
|
(offsetof(ZSTD_rust_loadDictionaryContentMatchStatePublicationState, base)
|
||||||
|
== 0
|
||||||
|
&& offsetof(ZSTD_rust_loadDictionaryContentMatchStatePublicationState,
|
||||||
|
nextToUpdate)
|
||||||
|
== sizeof(void*)
|
||||||
|
&& offsetof(ZSTD_rust_loadDictionaryContentMatchStatePublicationState,
|
||||||
|
loadedDictEnd)
|
||||||
|
== 2 * sizeof(void*)
|
||||||
|
&& offsetof(ZSTD_rust_loadDictionaryContentMatchStatePublicationState,
|
||||||
|
forceNonContiguous)
|
||||||
|
== 3 * sizeof(void*)
|
||||||
|
&& sizeof(ZSTD_rust_loadDictionaryContentMatchStatePublicationState)
|
||||||
|
== 4 * sizeof(void*))
|
||||||
|
? 1 : -1];
|
||||||
/* The Fast dictionary-table leaf is implemented in Rust. Keep only the
|
/* The Fast dictionary-table leaf is implemented in Rust. Keep only the
|
||||||
* fields needed by that leaf in the ABI projection; the complete
|
* fields needed by that leaf in the ABI projection; the complete
|
||||||
* ZSTD_MatchState_t layout remains private to C. */
|
* ZSTD_MatchState_t layout remains private to C. */
|
||||||
@@ -2874,7 +2892,7 @@ typedef struct {
|
|||||||
ZSTD_rust_loadDictionaryContent_assertWindowEmpty_f assertWindowEmpty;
|
ZSTD_rust_loadDictionaryContent_assertWindowEmpty_f assertWindowEmpty;
|
||||||
ZSTD_rust_loadDictionaryContent_windowUpdate_f windowUpdate;
|
ZSTD_rust_loadDictionaryContent_windowUpdate_f windowUpdate;
|
||||||
ZSTD_rust_loadDictionaryContent_setLdmLoadedDictEnd_f setLdmLoadedDictEnd;
|
ZSTD_rust_loadDictionaryContent_setLdmLoadedDictEnd_f setLdmLoadedDictEnd;
|
||||||
ZSTD_rust_loadDictionaryContent_publishMatchState_f publishMatchState;
|
const ZSTD_rust_loadDictionaryContentMatchStatePublicationState* publishMatchState;
|
||||||
ZSTD_rust_loadDictionaryContent_fillLdm_f fillLdm;
|
ZSTD_rust_loadDictionaryContent_fillLdm_f fillLdm;
|
||||||
ZSTD_rust_loadDictionaryContent_overflowCorrect_f overflowCorrect;
|
ZSTD_rust_loadDictionaryContent_overflowCorrect_f overflowCorrect;
|
||||||
const ZSTD_rust_loadDictionaryContentFastTableState* fastTable;
|
const ZSTD_rust_loadDictionaryContentFastTableState* fastTable;
|
||||||
@@ -6897,20 +6915,6 @@ static void ZSTD_loadDictionaryContent_setLdmLoadedDictEnd(
|
|||||||
: (U32)((const BYTE*)iend - context->ldmState->window.base);
|
: (U32)((const BYTE*)iend - context->ldmState->window.base);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ZSTD_loadDictionaryContent_publishMatchState(
|
|
||||||
void* opaque, const void* ip, const void* iend,
|
|
||||||
int forceWindow, int deterministicRefPrefix)
|
|
||||||
{
|
|
||||||
ZSTD_loadDictionaryContent_context const* const context =
|
|
||||||
(const ZSTD_loadDictionaryContent_context*)opaque;
|
|
||||||
context->matchState->nextToUpdate =
|
|
||||||
(U32)((const BYTE*)ip - context->matchState->window.base);
|
|
||||||
context->matchState->loadedDictEnd = forceWindow
|
|
||||||
? 0
|
|
||||||
: (U32)((const BYTE*)iend - context->matchState->window.base);
|
|
||||||
context->matchState->forceNonContiguous = deterministicRefPrefix;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ZSTD_loadDictionaryContent_fillLdm(
|
static void ZSTD_loadDictionaryContent_fillLdm(
|
||||||
void* opaque, const void* ip, const void* iend)
|
void* opaque, const void* ip, const void* iend)
|
||||||
{
|
{
|
||||||
@@ -7026,6 +7030,7 @@ static size_t ZSTD_loadDictionaryContent_callback(
|
|||||||
int dtlm, int tfp)
|
int dtlm, int tfp)
|
||||||
{
|
{
|
||||||
ZSTD_loadDictionaryContent_context context;
|
ZSTD_loadDictionaryContent_context context;
|
||||||
|
ZSTD_rust_loadDictionaryContentMatchStatePublicationState matchStatePublication;
|
||||||
ZSTD_rust_loadDictionaryContentFastTableState fastTable;
|
ZSTD_rust_loadDictionaryContentFastTableState fastTable;
|
||||||
ZSTD_rust_loadDictionaryContentDoubleFastTableState doubleFastTable;
|
ZSTD_rust_loadDictionaryContentDoubleFastTableState doubleFastTable;
|
||||||
ZSTD_rust_loadDictionaryContentState state;
|
ZSTD_rust_loadDictionaryContentState state;
|
||||||
@@ -7039,6 +7044,11 @@ static size_t ZSTD_loadDictionaryContent_callback(
|
|||||||
context.workspace = ws;
|
context.workspace = ws;
|
||||||
context.params = cctxParams;
|
context.params = cctxParams;
|
||||||
|
|
||||||
|
matchStatePublication.base = &ms->window.base;
|
||||||
|
matchStatePublication.nextToUpdate = &ms->nextToUpdate;
|
||||||
|
matchStatePublication.loadedDictEnd = &ms->loadedDictEnd;
|
||||||
|
matchStatePublication.forceNonContiguous = &ms->forceNonContiguous;
|
||||||
|
|
||||||
assert((tfp == ZSTD_tfp_forCDict && dtlm == ZSTD_dtlm_full)
|
assert((tfp == ZSTD_tfp_forCDict && dtlm == ZSTD_dtlm_full)
|
||||||
|| (tfp != ZSTD_tfp_forCDict && dtlm == ZSTD_dtlm_fast));
|
|| (tfp != ZSTD_tfp_forCDict && dtlm == ZSTD_dtlm_fast));
|
||||||
/* These fields are mutated by the window/publish callbacks before the
|
/* These fields are mutated by the window/publish callbacks before the
|
||||||
@@ -7088,7 +7098,7 @@ static size_t ZSTD_loadDictionaryContent_callback(
|
|||||||
state.assertWindowEmpty = ZSTD_loadDictionaryContent_assertWindowEmpty;
|
state.assertWindowEmpty = ZSTD_loadDictionaryContent_assertWindowEmpty;
|
||||||
state.windowUpdate = ZSTD_loadDictionaryContent_windowUpdate;
|
state.windowUpdate = ZSTD_loadDictionaryContent_windowUpdate;
|
||||||
state.setLdmLoadedDictEnd = ZSTD_loadDictionaryContent_setLdmLoadedDictEnd;
|
state.setLdmLoadedDictEnd = ZSTD_loadDictionaryContent_setLdmLoadedDictEnd;
|
||||||
state.publishMatchState = ZSTD_loadDictionaryContent_publishMatchState;
|
state.publishMatchState = &matchStatePublication;
|
||||||
state.fillLdm = ZSTD_loadDictionaryContent_fillLdm;
|
state.fillLdm = ZSTD_loadDictionaryContent_fillLdm;
|
||||||
state.overflowCorrect = ZSTD_loadDictionaryContent_overflowCorrect;
|
state.overflowCorrect = ZSTD_loadDictionaryContent_overflowCorrect;
|
||||||
state.fastTable = &fastTable;
|
state.fastTable = &fastTable;
|
||||||
|
|||||||
@@ -129,17 +129,50 @@ type LoadDictionaryContentWindowUpdateFn =
|
|||||||
unsafe extern "C" fn(context: *mut c_void, ldm: c_int, src: *const c_void, src_size: usize);
|
unsafe extern "C" fn(context: *mut c_void, ldm: c_int, src: *const c_void, src_size: usize);
|
||||||
type LoadDictionaryContentSetLdmLoadedDictEndFn =
|
type LoadDictionaryContentSetLdmLoadedDictEndFn =
|
||||||
unsafe extern "C" fn(context: *mut c_void, iend: *const c_void, force_window: c_int);
|
unsafe extern "C" fn(context: *mut c_void, iend: *const c_void, force_window: c_int);
|
||||||
type LoadDictionaryContentPublishMatchStateFn = unsafe extern "C" fn(
|
|
||||||
context: *mut c_void,
|
|
||||||
ip: *const c_void,
|
|
||||||
iend: *const c_void,
|
|
||||||
force_window: c_int,
|
|
||||||
deterministic_ref_prefix: c_int,
|
|
||||||
);
|
|
||||||
type LoadDictionaryContentFillLdmFn =
|
type LoadDictionaryContentFillLdmFn =
|
||||||
unsafe extern "C" fn(context: *mut c_void, ip: *const c_void, iend: *const c_void);
|
unsafe extern "C" fn(context: *mut c_void, ip: *const c_void, iend: *const c_void);
|
||||||
type LoadDictionaryContentOverflowCorrectFn =
|
type LoadDictionaryContentOverflowCorrectFn =
|
||||||
unsafe extern "C" fn(context: *mut c_void, ip: *const c_void, iend: *const c_void);
|
unsafe extern "C" fn(context: *mut c_void, ip: *const c_void, iend: *const c_void);
|
||||||
|
|
||||||
|
/// Live match-state fields used when the dictionary loader publishes the
|
||||||
|
/// current prefix. The base is indirect because window updates may replace it
|
||||||
|
/// before this publication point.
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
|
struct ZSTD_rust_loadDictionaryContentMatchStatePublicationState {
|
||||||
|
base: *const *const u8,
|
||||||
|
next_to_update: *mut c_uint,
|
||||||
|
loaded_dict_end: *mut c_uint,
|
||||||
|
force_non_contiguous: *mut c_int,
|
||||||
|
}
|
||||||
|
|
||||||
|
const _: () = {
|
||||||
|
assert!(
|
||||||
|
offset_of!(ZSTD_rust_loadDictionaryContentMatchStatePublicationState, base) == 0
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
offset_of!(
|
||||||
|
ZSTD_rust_loadDictionaryContentMatchStatePublicationState,
|
||||||
|
next_to_update
|
||||||
|
) == size_of::<usize>()
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
offset_of!(
|
||||||
|
ZSTD_rust_loadDictionaryContentMatchStatePublicationState,
|
||||||
|
loaded_dict_end
|
||||||
|
) == 2 * size_of::<usize>()
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
offset_of!(
|
||||||
|
ZSTD_rust_loadDictionaryContentMatchStatePublicationState,
|
||||||
|
force_non_contiguous
|
||||||
|
) == 3 * size_of::<usize>()
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
size_of::<ZSTD_rust_loadDictionaryContentMatchStatePublicationState>()
|
||||||
|
== 4 * size_of::<usize>()
|
||||||
|
);
|
||||||
|
};
|
||||||
/// Direct projection for the Fast dictionary-table leaf.
|
/// Direct projection for the Fast dictionary-table leaf.
|
||||||
///
|
///
|
||||||
/// C exposes pointers to the live scalar fields needed by the Fast leaf.
|
/// C exposes pointers to the live scalar fields needed by the Fast leaf.
|
||||||
@@ -210,7 +243,7 @@ pub struct ZSTD_rust_loadDictionaryContentState {
|
|||||||
assert_window_empty: LoadDictionaryContentAssertWindowEmptyFn,
|
assert_window_empty: LoadDictionaryContentAssertWindowEmptyFn,
|
||||||
window_update: LoadDictionaryContentWindowUpdateFn,
|
window_update: LoadDictionaryContentWindowUpdateFn,
|
||||||
set_ldm_loaded_dict_end: LoadDictionaryContentSetLdmLoadedDictEndFn,
|
set_ldm_loaded_dict_end: LoadDictionaryContentSetLdmLoadedDictEndFn,
|
||||||
publish_match_state: LoadDictionaryContentPublishMatchStateFn,
|
publish_match_state: *const ZSTD_rust_loadDictionaryContentMatchStatePublicationState,
|
||||||
fill_ldm: LoadDictionaryContentFillLdmFn,
|
fill_ldm: LoadDictionaryContentFillLdmFn,
|
||||||
overflow_correct: LoadDictionaryContentOverflowCorrectFn,
|
overflow_correct: LoadDictionaryContentOverflowCorrectFn,
|
||||||
fast_table: *const ZSTD_rust_loadDictionaryContentFastTableState,
|
fast_table: *const ZSTD_rust_loadDictionaryContentFastTableState,
|
||||||
@@ -229,7 +262,6 @@ const _: () = {
|
|||||||
assert!(size_of::<LoadDictionaryContentAssertWindowEmptyFn>() == size_of::<usize>());
|
assert!(size_of::<LoadDictionaryContentAssertWindowEmptyFn>() == size_of::<usize>());
|
||||||
assert!(size_of::<LoadDictionaryContentWindowUpdateFn>() == size_of::<usize>());
|
assert!(size_of::<LoadDictionaryContentWindowUpdateFn>() == size_of::<usize>());
|
||||||
assert!(size_of::<LoadDictionaryContentSetLdmLoadedDictEndFn>() == size_of::<usize>());
|
assert!(size_of::<LoadDictionaryContentSetLdmLoadedDictEndFn>() == size_of::<usize>());
|
||||||
assert!(size_of::<LoadDictionaryContentPublishMatchStateFn>() == size_of::<usize>());
|
|
||||||
assert!(size_of::<LoadDictionaryContentFillLdmFn>() == size_of::<usize>());
|
assert!(size_of::<LoadDictionaryContentFillLdmFn>() == size_of::<usize>());
|
||||||
assert!(size_of::<LoadDictionaryContentOverflowCorrectFn>() == size_of::<usize>());
|
assert!(size_of::<LoadDictionaryContentOverflowCorrectFn>() == size_of::<usize>());
|
||||||
assert!(offset_of!(ZSTD_rust_loadDictionaryContentFastTableState, hash_table) == 0);
|
assert!(offset_of!(ZSTD_rust_loadDictionaryContentFastTableState, hash_table) == 0);
|
||||||
@@ -314,6 +346,10 @@ const _: () = {
|
|||||||
offset_of!(ZSTD_rust_loadDictionaryContentState, assert_c_params)
|
offset_of!(ZSTD_rust_loadDictionaryContentState, assert_c_params)
|
||||||
== 18 * size_of::<usize>()
|
== 18 * size_of::<usize>()
|
||||||
);
|
);
|
||||||
|
assert!(
|
||||||
|
offset_of!(ZSTD_rust_loadDictionaryContentState, publish_match_state)
|
||||||
|
== 22 * size_of::<usize>()
|
||||||
|
);
|
||||||
assert!(
|
assert!(
|
||||||
offset_of!(ZSTD_rust_loadDictionaryContentState, fast_table) == 25 * size_of::<usize>()
|
offset_of!(ZSTD_rust_loadDictionaryContentState, fast_table) == 25 * size_of::<usize>()
|
||||||
);
|
);
|
||||||
@@ -470,11 +506,35 @@ unsafe fn fill_double_fast_dictionary_table(
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn publish_dictionary_match_state(
|
||||||
|
publication: &ZSTD_rust_loadDictionaryContentMatchStatePublicationState,
|
||||||
|
ip: *const u8,
|
||||||
|
iend: *const u8,
|
||||||
|
force_window: usize,
|
||||||
|
deterministic_ref_prefix: usize,
|
||||||
|
) {
|
||||||
|
let base = unsafe { *publication.base };
|
||||||
|
unsafe {
|
||||||
|
*publication.next_to_update = ip.offset_from(base) as c_uint;
|
||||||
|
*publication.loaded_dict_end = if force_window != 0 {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
iend.offset_from(base) as c_uint
|
||||||
|
};
|
||||||
|
*publication.force_non_contiguous = deterministic_ref_prefix as c_int;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
unsafe fn load_dictionary_content(
|
unsafe fn load_dictionary_content(
|
||||||
state: &ZSTD_rust_loadDictionaryContentState,
|
state: &ZSTD_rust_loadDictionaryContentState,
|
||||||
src: *const c_void,
|
src: *const c_void,
|
||||||
src_size: usize,
|
src_size: usize,
|
||||||
) -> usize {
|
) -> usize {
|
||||||
|
if state.publish_match_state.is_null() {
|
||||||
|
return ERROR(ZstdErrorCode::Generic);
|
||||||
|
}
|
||||||
|
let match_state_publication = unsafe { &*state.publish_match_state };
|
||||||
unsafe { (state.assert_c_params)(state.callback_context) };
|
unsafe { (state.assert_c_params)(state.callback_context) };
|
||||||
|
|
||||||
let load_ldm_dict = state.ldm_enabled != 0 && state.has_ldm_state != 0;
|
let load_ldm_dict = state.ldm_enabled != 0 && state.has_ldm_state != 0;
|
||||||
@@ -524,12 +584,12 @@ unsafe fn load_dictionary_content(
|
|||||||
}
|
}
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
(state.publish_match_state)(
|
publish_dictionary_match_state(
|
||||||
state.callback_context,
|
match_state_publication,
|
||||||
ip.cast(),
|
ip,
|
||||||
iend.cast(),
|
iend,
|
||||||
(state.force_window != 0) as c_int,
|
state.force_window,
|
||||||
(state.deterministic_ref_prefix != 0) as c_int,
|
state.deterministic_ref_prefix,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -6805,6 +6865,51 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn dictionary_match_state_projection_publishes_live_offsets() {
|
||||||
|
let input = [0u8; 64];
|
||||||
|
let mut base_ptr = input.as_ptr();
|
||||||
|
let mut next_to_update = 0u32;
|
||||||
|
let mut loaded_dict_end = 0u32;
|
||||||
|
let mut force_non_contiguous = 0i32;
|
||||||
|
let projection = ZSTD_rust_loadDictionaryContentMatchStatePublicationState {
|
||||||
|
base: &base_ptr,
|
||||||
|
next_to_update: &mut next_to_update,
|
||||||
|
loaded_dict_end: &mut loaded_dict_end,
|
||||||
|
force_non_contiguous: &mut force_non_contiguous,
|
||||||
|
};
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
publish_dictionary_match_state(
|
||||||
|
&projection,
|
||||||
|
input.as_ptr().add(7),
|
||||||
|
input.as_ptr().add(42),
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
assert_eq!(next_to_update, 7);
|
||||||
|
assert_eq!(loaded_dict_end, 42);
|
||||||
|
assert_eq!(force_non_contiguous, 1);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
ptr::write(&mut base_ptr, input.as_ptr().add(3));
|
||||||
|
assert_eq!(*projection.base, input.as_ptr().add(3));
|
||||||
|
}
|
||||||
|
unsafe {
|
||||||
|
publish_dictionary_match_state(
|
||||||
|
&projection,
|
||||||
|
input.as_ptr().add(10),
|
||||||
|
input.as_ptr().add(30),
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
assert_eq!(next_to_update, 7);
|
||||||
|
assert_eq!(loaded_dict_end, 0);
|
||||||
|
assert_eq!(force_non_contiguous, 0);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn fast_dictionary_table_projection_dispatches_to_rust_leaf() {
|
fn fast_dictionary_table_projection_dispatches_to_rust_leaf() {
|
||||||
let hash_log = 4u32;
|
let hash_log = 4u32;
|
||||||
|
|||||||
Reference in New Issue
Block a user