feat(mt): move frame checksum finalization to Rust
The MT flush path already delegated checksum serialization to Rust but still computed XXH64_digest in C. Pass the live C-owned XXH64 state through the checked projection and let Rust finalize the digest before the existing little-endian write. C retains serial state storage and job/flush mutation. Test Plan: - ulimit -v 41943040; CARGO_BUILD_JOBS=1 cargo check --tests (rust) - ulimit -v 41943040; CARGO_BUILD_JOBS=1 cargo clippy --tests -- -A clippy::manual-bits -D warnings (rust) - ulimit -v 41943040; make -j1 - ulimit -v 41943040; make -j1 -C tests test - Focused cargo test compiles but remains link-blocked by existing C-owned decompression-view symbols.
This commit is contained in:
@@ -466,7 +466,7 @@ typedef struct {
|
|||||||
void* dst;
|
void* dst;
|
||||||
size_t dstCapacity;
|
size_t dstCapacity;
|
||||||
size_t cSize;
|
size_t cSize;
|
||||||
U32 checksum;
|
const XXH64_state_t* checksumState;
|
||||||
} ZSTDMT_RustFrameChecksumProjection;
|
} ZSTDMT_RustFrameChecksumProjection;
|
||||||
typedef char ZSTDMT_frame_checksum_projection_layout[
|
typedef char ZSTDMT_frame_checksum_projection_layout[
|
||||||
(offsetof(ZSTDMT_RustFrameChecksumProjection, dst) == 0
|
(offsetof(ZSTDMT_RustFrameChecksumProjection, dst) == 0
|
||||||
@@ -474,9 +474,8 @@ typedef char ZSTDMT_frame_checksum_projection_layout[
|
|||||||
== sizeof(void*)
|
== sizeof(void*)
|
||||||
&& offsetof(ZSTDMT_RustFrameChecksumProjection, cSize)
|
&& offsetof(ZSTDMT_RustFrameChecksumProjection, cSize)
|
||||||
== 2 * sizeof(void*)
|
== 2 * sizeof(void*)
|
||||||
&& offsetof(ZSTDMT_RustFrameChecksumProjection, checksum)
|
&& offsetof(ZSTDMT_RustFrameChecksumProjection, checksumState)
|
||||||
== 3 * sizeof(void*)
|
== 3 * sizeof(void*)
|
||||||
&& sizeof(U32) == 4
|
|
||||||
&& sizeof(ZSTDMT_RustFrameChecksumProjection)
|
&& sizeof(ZSTDMT_RustFrameChecksumProjection)
|
||||||
== 4 * sizeof(void*))
|
== 4 * sizeof(void*))
|
||||||
? 1 : -1];
|
? 1 : -1];
|
||||||
@@ -3440,12 +3439,11 @@ static void ZSTDMT_addFrameChecksum(void* opaque, unsigned jobID,
|
|||||||
{
|
{
|
||||||
ZSTDMT_CCtx* const mtctx = (ZSTDMT_CCtx*)opaque;
|
ZSTDMT_CCtx* const mtctx = (ZSTDMT_CCtx*)opaque;
|
||||||
ZSTDMT_jobDescription* const job = &mtctx->jobs[jobID];
|
ZSTDMT_jobDescription* const job = &mtctx->jobs[jobID];
|
||||||
U32 const checksum = (U32)XXH64_digest(&mtctx->serial.xxhState);
|
|
||||||
ZSTDMT_RustFrameChecksumProjection const checksumProjection = {
|
ZSTDMT_RustFrameChecksumProjection const checksumProjection = {
|
||||||
job->dstBuff.start,
|
job->dstBuff.start,
|
||||||
job->dstBuff.capacity,
|
job->dstBuff.capacity,
|
||||||
job->cSize,
|
job->cSize,
|
||||||
checksum
|
&mtctx->serial.xxhState
|
||||||
};
|
};
|
||||||
size_t const cSize = ZSTDMT_rust_writeFrameChecksum(&checksumProjection);
|
size_t const cSize = ZSTDMT_rust_writeFrameChecksum(&checksumProjection);
|
||||||
|
|
||||||
|
|||||||
+44
-14
@@ -23,7 +23,7 @@ use std::sync::Mutex;
|
|||||||
use crate::bits::ZSTD_highbit32;
|
use crate::bits::ZSTD_highbit32;
|
||||||
use crate::errors::{ERR_isError, ZstdErrorCode, ERROR};
|
use crate::errors::{ERR_isError, ZstdErrorCode, ERROR};
|
||||||
use crate::mem::MEM_writeLE32;
|
use crate::mem::MEM_writeLE32;
|
||||||
use crate::xxhash::{XXH64_state_t, XXH64_update};
|
use crate::xxhash::{XXH64_digest, XXH64_state_t, XXH64_update};
|
||||||
use crate::zstd_compress::{ZSTD_frameProgression, ZSTD_rust_invalidateRepCodes};
|
use crate::zstd_compress::{ZSTD_frameProgression, ZSTD_rust_invalidateRepCodes};
|
||||||
use crate::zstd_compress_frame::ZSTD_rust_writeFrameHeader;
|
use crate::zstd_compress_frame::ZSTD_rust_writeFrameHeader;
|
||||||
use crate::zstd_compress_params::{
|
use crate::zstd_compress_params::{
|
||||||
@@ -1893,23 +1893,22 @@ pub struct ZSTDMT_flushJobProjection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Narrow projection for serializing the C-owned frame checksum. C retains
|
/// Narrow projection for serializing the C-owned frame checksum. C retains
|
||||||
/// the serial XXH64 state and computes the checksum; Rust owns only the
|
/// the serial XXH64 state; Rust owns digest finalization, the deterministic
|
||||||
/// deterministic little-endian write and destination policy.
|
/// little-endian write, and destination policy.
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
||||||
pub struct ZSTDMT_frameChecksumProjection {
|
pub struct ZSTDMT_frameChecksumProjection {
|
||||||
pub dst: *mut c_void,
|
pub dst: *mut c_void,
|
||||||
pub dstCapacity: usize,
|
pub dstCapacity: usize,
|
||||||
pub cSize: usize,
|
pub cSize: usize,
|
||||||
pub checksum: c_uint,
|
pub checksumState: *const XXH64_state_t,
|
||||||
}
|
}
|
||||||
|
|
||||||
const _: () = {
|
const _: () = {
|
||||||
assert!(offset_of!(ZSTDMT_frameChecksumProjection, dst) == 0);
|
assert!(offset_of!(ZSTDMT_frameChecksumProjection, dst) == 0);
|
||||||
assert!(offset_of!(ZSTDMT_frameChecksumProjection, dstCapacity) == size_of::<usize>());
|
assert!(offset_of!(ZSTDMT_frameChecksumProjection, dstCapacity) == size_of::<usize>());
|
||||||
assert!(offset_of!(ZSTDMT_frameChecksumProjection, cSize) == 2 * size_of::<usize>());
|
assert!(offset_of!(ZSTDMT_frameChecksumProjection, cSize) == 2 * size_of::<usize>());
|
||||||
assert!(offset_of!(ZSTDMT_frameChecksumProjection, checksum) == 3 * size_of::<usize>());
|
assert!(offset_of!(ZSTDMT_frameChecksumProjection, checksumState) == 3 * size_of::<usize>());
|
||||||
assert!(size_of::<c_uint>() == 4);
|
|
||||||
assert!(size_of::<ZSTDMT_frameChecksumProjection>() == 4 * size_of::<usize>());
|
assert!(size_of::<ZSTDMT_frameChecksumProjection>() == 4 * size_of::<usize>());
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1921,11 +1920,15 @@ fn write_frame_checksum(projection: &ZSTDMT_frameChecksumProjection) -> usize {
|
|||||||
{
|
{
|
||||||
return ERROR(ZstdErrorCode::DstSizeTooSmall);
|
return ERROR(ZstdErrorCode::DstSizeTooSmall);
|
||||||
}
|
}
|
||||||
|
if projection.checksumState.is_null() {
|
||||||
|
return ERROR(ZstdErrorCode::Generic);
|
||||||
|
}
|
||||||
|
let checksum = unsafe { XXH64_digest(projection.checksumState) as c_uint };
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
MEM_writeLE32(
|
MEM_writeLE32(
|
||||||
projection.dst.cast::<u8>().add(projection.cSize).cast(),
|
projection.dst.cast::<u8>().add(projection.cSize).cast(),
|
||||||
projection.checksum,
|
checksum,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
projection.cSize + 4
|
projection.cSize + 4
|
||||||
@@ -5966,7 +5969,7 @@ pub unsafe extern "C" fn ZSTDMT_rust_cctx_pool_release(pool: *mut RustCCtxPool,
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::xxhash::{XXH64, XXH64_digest, XXH64_reset};
|
use crate::xxhash::{XXH64_digest, XXH64_reset, XXH64_update, XXH64};
|
||||||
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
|
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
|
||||||
use std::{cell::RefCell, rc::Rc};
|
use std::{cell::RefCell, rc::Rc};
|
||||||
|
|
||||||
@@ -9321,46 +9324,73 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn frame_checksum_is_serialized_little_endian() {
|
fn frame_checksum_is_serialized_little_endian() {
|
||||||
let mut dst = [0xa5u8; 8];
|
let mut dst = [0xa5u8; 8];
|
||||||
|
let input = b"mt frame checksum";
|
||||||
|
let mut checksum_state = unsafe { MaybeUninit::<XXH64_state_t>::zeroed().assume_init() };
|
||||||
|
unsafe {
|
||||||
|
assert_eq!(XXH64_reset(&mut checksum_state, 0), 0);
|
||||||
|
assert_eq!(
|
||||||
|
XXH64_update(&mut checksum_state, input.as_ptr().cast(), input.len()),
|
||||||
|
0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let checksum = unsafe { XXH64(input.as_ptr().cast(), input.len(), 0) as u32 };
|
||||||
let projection = ZSTDMT_frameChecksumProjection {
|
let projection = ZSTDMT_frameChecksumProjection {
|
||||||
dst: dst.as_mut_ptr().cast(),
|
dst: dst.as_mut_ptr().cast(),
|
||||||
dstCapacity: dst.len(),
|
dstCapacity: dst.len(),
|
||||||
cSize: 4,
|
cSize: 4,
|
||||||
checksum: 0x7856_3412,
|
checksumState: &checksum_state,
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(write_frame_checksum(&projection), 8);
|
assert_eq!(write_frame_checksum(&projection), 8);
|
||||||
assert_eq!(&dst[..4], &[0xa5; 4]);
|
assert_eq!(&dst[..4], &[0xa5; 4]);
|
||||||
assert_eq!(&dst[4..], &[0x12, 0x34, 0x56, 0x78]);
|
assert_eq!(&dst[4..], &checksum.to_le_bytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn frame_checksum_accepts_exact_destination_capacity() {
|
fn frame_checksum_accepts_exact_destination_capacity() {
|
||||||
let mut dst = [0xa5u8; 6];
|
let mut dst = [0xa5u8; 6];
|
||||||
|
let input = b"exact capacity";
|
||||||
|
let mut checksum_state = unsafe { MaybeUninit::<XXH64_state_t>::zeroed().assume_init() };
|
||||||
|
unsafe {
|
||||||
|
assert_eq!(XXH64_reset(&mut checksum_state, 0), 0);
|
||||||
|
assert_eq!(
|
||||||
|
XXH64_update(&mut checksum_state, input.as_ptr().cast(), input.len()),
|
||||||
|
0
|
||||||
|
);
|
||||||
|
}
|
||||||
let projection = ZSTDMT_frameChecksumProjection {
|
let projection = ZSTDMT_frameChecksumProjection {
|
||||||
dst: dst.as_mut_ptr().cast(),
|
dst: dst.as_mut_ptr().cast(),
|
||||||
dstCapacity: dst.len(),
|
dstCapacity: dst.len(),
|
||||||
cSize: 2,
|
cSize: 2,
|
||||||
checksum: 0x1122_3344,
|
checksumState: &checksum_state,
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(write_frame_checksum(&projection), dst.len());
|
assert_eq!(write_frame_checksum(&projection), dst.len());
|
||||||
assert_eq!(&dst, &[0xa5, 0xa5, 0x44, 0x33, 0x22, 0x11]);
|
assert_eq!(&dst[..2], &[0xa5, 0xa5]);
|
||||||
|
assert_eq!(
|
||||||
|
&dst[2..],
|
||||||
|
&(unsafe { XXH64(input.as_ptr().cast(), input.len(), 0) as u32 }).to_le_bytes()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn frame_checksum_rejects_too_small_or_null_destination() {
|
fn frame_checksum_rejects_too_small_or_null_destination() {
|
||||||
let mut dst = [0xa5u8; 8];
|
let mut dst = [0xa5u8; 8];
|
||||||
|
let mut checksum_state = unsafe { MaybeUninit::<XXH64_state_t>::zeroed().assume_init() };
|
||||||
|
unsafe {
|
||||||
|
assert_eq!(XXH64_reset(&mut checksum_state, 0), 0);
|
||||||
|
}
|
||||||
let too_small = ZSTDMT_frameChecksumProjection {
|
let too_small = ZSTDMT_frameChecksumProjection {
|
||||||
dst: dst.as_mut_ptr().cast(),
|
dst: dst.as_mut_ptr().cast(),
|
||||||
dstCapacity: 7,
|
dstCapacity: 7,
|
||||||
cSize: 4,
|
cSize: 4,
|
||||||
checksum: 0x0102_0304,
|
checksumState: &checksum_state,
|
||||||
};
|
};
|
||||||
let null_destination = ZSTDMT_frameChecksumProjection {
|
let null_destination = ZSTDMT_frameChecksumProjection {
|
||||||
dst: ptr::null_mut(),
|
dst: ptr::null_mut(),
|
||||||
dstCapacity: 4,
|
dstCapacity: 4,
|
||||||
cSize: 0,
|
cSize: 0,
|
||||||
checksum: 0x0102_0304,
|
checksumState: &checksum_state,
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|||||||
Reference in New Issue
Block a user