refactor(compress): move MT checksum serialization to Rust
Keep XXH64 state ownership and checksum calculation in the C MT scheduler, but project the final four-byte frame write through Rust. Rust now owns the little-endian serialization and destination-capacity policy, with ABI layout assertions and flush-state error propagation preserving the existing cleanup path. Focused tests cover byte order, exact capacity, invalid destinations, and callback error handling. Test Plan: - `ulimit -v 41943040; cargo +nightly fmt --manifest-path rust/Cargo.toml --all -- --check` - `ulimit -v 41943040; CARGO_BUILD_JOBS=1 cargo clippy --manifest-path rust/Cargo.toml --all-targets -- -D warnings` - `ulimit -v 41943040; make -j1` - `ulimit -v 41943040; make -j1 -C tests test` - `ulimit -v 41943040; CARGO_BUILD_JOBS=1 cargo clippy --manifest-path rust/cli/Cargo.toml --all-targets -- -D warnings` - `ulimit -v 41943040; CARGO_BUILD_JOBS=1 cargo test --manifest-path rust/cli/Cargo.toml --all-targets` The integrated checks ran under a serial 40 GiB virtual-memory limit. The full upstream suite passed, including large-file, multithreaded, API, fuzzer, and zstream coverage. Standalone root Rust unit linking remains unavailable because the crate imports C-owned bridge symbols without a Cargo build/link setup.
This commit is contained in:
@@ -285,6 +285,24 @@ typedef struct {
|
||||
size_t dstFlushed;
|
||||
unsigned frameChecksumNeeded;
|
||||
} ZSTDMT_RustFlushJobProjection;
|
||||
typedef struct {
|
||||
void* dst;
|
||||
size_t dstCapacity;
|
||||
size_t cSize;
|
||||
U32 checksum;
|
||||
} ZSTDMT_RustFrameChecksumProjection;
|
||||
typedef char ZSTDMT_frame_checksum_projection_layout[
|
||||
(offsetof(ZSTDMT_RustFrameChecksumProjection, dst) == 0
|
||||
&& offsetof(ZSTDMT_RustFrameChecksumProjection, dstCapacity)
|
||||
== sizeof(void*)
|
||||
&& offsetof(ZSTDMT_RustFrameChecksumProjection, cSize)
|
||||
== 2 * sizeof(void*)
|
||||
&& offsetof(ZSTDMT_RustFrameChecksumProjection, checksum)
|
||||
== 3 * sizeof(void*)
|
||||
&& sizeof(U32) == 4
|
||||
&& sizeof(ZSTDMT_RustFrameChecksumProjection)
|
||||
== 4 * sizeof(void*))
|
||||
? 1 : -1];
|
||||
typedef struct {
|
||||
unsigned doneJobID;
|
||||
unsigned nextJobID;
|
||||
@@ -319,6 +337,8 @@ ZSTDMT_RustFlushProducedResult ZSTDMT_rust_flushProduced(
|
||||
ZSTDMT_flushUpdateJobFn updateJob,
|
||||
ZSTDMT_flushCompleteJobFn completeJob,
|
||||
ZSTDMT_flushErrorFn onError);
|
||||
size_t ZSTDMT_rust_writeFrameChecksum(
|
||||
const ZSTDMT_RustFrameChecksumProjection* projection);
|
||||
|
||||
/* The Rust outer scheduler sees only this scalar snapshot. The MT context,
|
||||
* reusable input buffer, worker pool, and all synchronization remain private
|
||||
@@ -2786,15 +2806,23 @@ static void ZSTDMT_addFrameChecksum(void* opaque, unsigned jobID,
|
||||
ZSTDMT_CCtx* const mtctx = (ZSTDMT_CCtx*)opaque;
|
||||
ZSTDMT_jobDescription* const job = &mtctx->jobs[jobID];
|
||||
U32 const checksum = (U32)XXH64_digest(&mtctx->serial.xxhState);
|
||||
ZSTDMT_RustFrameChecksumProjection const checksumProjection = {
|
||||
job->dstBuff.start,
|
||||
job->dstBuff.capacity,
|
||||
job->cSize,
|
||||
checksum
|
||||
};
|
||||
size_t const cSize = ZSTDMT_rust_writeFrameChecksum(&checksumProjection);
|
||||
|
||||
assert(projection->frameChecksumNeeded);
|
||||
assert(projection->consumed == projection->srcSize);
|
||||
assert(projection->cSize == job->cSize);
|
||||
MEM_writeLE32((char*)job->dstBuff.start + job->cSize, checksum);
|
||||
job->cSize += 4;
|
||||
job->frameChecksumNeeded = 0;
|
||||
projection->cSize = job->cSize;
|
||||
projection->frameChecksumNeeded = 0;
|
||||
job->cSize = cSize;
|
||||
projection->cSize = cSize;
|
||||
if (!ZSTD_isError(cSize)) {
|
||||
job->frameChecksumNeeded = 0;
|
||||
projection->frameChecksumNeeded = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void ZSTDMT_updateFlushJob(void* opaque, unsigned jobID, size_t dstFlushed)
|
||||
|
||||
Reference in New Issue
Block a user