feat(compress): move trace record construction to Rust
Keep the compression context extraction and the weak trace hook adapter in C, where the private CCtx layout and platform-specific tracing declarations remain available. Project only the scalar trace inputs and callback through an explicit ABI-checked boundary so Rust owns the enabled check, stable record layout, version field, compression-only null fields, and end-of-trace policy. The C entry point still clears traceCtx after Rust returns, preserving the old single-use lifecycle and keeping trace-disabled builds free of weak-hook calls. Test Plan: - ulimit -v 41943040; CARGO_BUILD_JOBS=1 cargo check --manifest-path rust/Cargo.toml --tests - 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 make -j1 - ulimit -v 41943040; make -j1 -C tests test
This commit is contained in:
@@ -7284,23 +7284,72 @@ size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel)
|
||||
}
|
||||
|
||||
|
||||
typedef void (*ZSTD_rust_traceEnd_f)(
|
||||
void* context, unsigned long long traceCtx, const void* trace);
|
||||
typedef struct {
|
||||
void* callbackContext;
|
||||
unsigned long long traceCtx;
|
||||
int streaming;
|
||||
unsigned dictionaryID;
|
||||
size_t dictionarySize;
|
||||
size_t uncompressedSize;
|
||||
size_t compressedSize;
|
||||
const void* params;
|
||||
const void* cctx;
|
||||
ZSTD_rust_traceEnd_f traceEnd;
|
||||
} ZSTD_rust_traceEndState;
|
||||
typedef char ZSTD_rust_trace_end_state_layout[
|
||||
(offsetof(ZSTD_rust_traceEndState, callbackContext) == 0
|
||||
&& offsetof(ZSTD_rust_traceEndState, traceCtx) == sizeof(void*)
|
||||
&& offsetof(ZSTD_rust_traceEndState, streaming)
|
||||
== sizeof(void*) + sizeof(unsigned long long)
|
||||
&& offsetof(ZSTD_rust_traceEndState, dictionaryID)
|
||||
== sizeof(void*) + sizeof(unsigned long long) + sizeof(int)
|
||||
&& offsetof(ZSTD_rust_traceEndState, dictionarySize)
|
||||
== sizeof(void*) + sizeof(unsigned long long) + 2 * sizeof(int)
|
||||
&& offsetof(ZSTD_rust_traceEndState, uncompressedSize)
|
||||
== offsetof(ZSTD_rust_traceEndState, dictionarySize) + sizeof(size_t)
|
||||
&& offsetof(ZSTD_rust_traceEndState, compressedSize)
|
||||
== offsetof(ZSTD_rust_traceEndState, dictionarySize) + 2 * sizeof(size_t)
|
||||
&& offsetof(ZSTD_rust_traceEndState, params)
|
||||
== offsetof(ZSTD_rust_traceEndState, dictionarySize) + 3 * sizeof(size_t)
|
||||
&& offsetof(ZSTD_rust_traceEndState, cctx)
|
||||
== offsetof(ZSTD_rust_traceEndState, dictionarySize) + 4 * sizeof(size_t)
|
||||
&& offsetof(ZSTD_rust_traceEndState, traceEnd)
|
||||
== offsetof(ZSTD_rust_traceEndState, dictionarySize) + 5 * sizeof(size_t)
|
||||
&& sizeof(ZSTD_rust_traceEndState)
|
||||
== offsetof(ZSTD_rust_traceEndState, dictionarySize) + 6 * sizeof(size_t))
|
||||
? 1 : -1];
|
||||
void ZSTD_rust_traceEnd(const ZSTD_rust_traceEndState* state);
|
||||
|
||||
#if ZSTD_TRACE
|
||||
static void ZSTD_rust_traceEnd_callback(void* context,
|
||||
unsigned long long traceCtx, const void* trace)
|
||||
{
|
||||
(void)context;
|
||||
if (ZSTD_trace_compress_end != NULL) {
|
||||
ZSTD_trace_compress_end((ZSTD_TraceCtx)traceCtx,
|
||||
(ZSTD_Trace const*)trace);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void ZSTD_CCtx_trace(ZSTD_CCtx* cctx, size_t extraCSize)
|
||||
{
|
||||
#if ZSTD_TRACE
|
||||
if (cctx->traceCtx && ZSTD_trace_compress_end != NULL) {
|
||||
int const streaming = cctx->inBuffSize > 0 || cctx->outBuffSize > 0 || cctx->appliedParams.nbWorkers > 0;
|
||||
ZSTD_Trace trace;
|
||||
ZSTD_memset(&trace, 0, sizeof(trace));
|
||||
trace.version = ZSTD_VERSION_NUMBER;
|
||||
trace.streaming = streaming;
|
||||
trace.dictionaryID = cctx->dictID;
|
||||
trace.dictionarySize = cctx->dictContentSize;
|
||||
trace.uncompressedSize = cctx->consumedSrcSize;
|
||||
trace.compressedSize = cctx->producedCSize + extraCSize;
|
||||
trace.params = &cctx->appliedParams;
|
||||
trace.cctx = cctx;
|
||||
ZSTD_trace_compress_end(cctx->traceCtx, &trace);
|
||||
}
|
||||
ZSTD_rust_traceEndState state;
|
||||
state.callbackContext = cctx;
|
||||
state.traceCtx = cctx->traceCtx;
|
||||
state.streaming = cctx->inBuffSize > 0 || cctx->outBuffSize > 0
|
||||
|| cctx->appliedParams.nbWorkers > 0;
|
||||
state.dictionaryID = cctx->dictID;
|
||||
state.dictionarySize = cctx->dictContentSize;
|
||||
state.uncompressedSize = cctx->consumedSrcSize;
|
||||
state.compressedSize = cctx->producedCSize + extraCSize;
|
||||
state.params = &cctx->appliedParams;
|
||||
state.cctx = cctx;
|
||||
state.traceEnd = ZSTD_rust_traceEnd_callback;
|
||||
ZSTD_rust_traceEnd(&state);
|
||||
cctx->traceCtx = 0;
|
||||
#else
|
||||
(void)cctx;
|
||||
|
||||
@@ -57,6 +57,7 @@ use crate::zstd_compress_stats::{
|
||||
ZSTD_rust_validateSeqStore, ZSTD_LLT_LITERAL_LENGTH, ZSTD_LLT_MATCH_LENGTH,
|
||||
};
|
||||
use crate::zstd_compress_superblock::ZSTD_rust_compressSuperBlock;
|
||||
use crate::zstd_common::ZSTD_VERSION_NUMBER;
|
||||
use std::ffi::c_void;
|
||||
use std::mem::{offset_of, size_of, MaybeUninit};
|
||||
use std::os::raw::{c_int, c_longlong, c_uint};
|
||||
@@ -2796,6 +2797,105 @@ pub unsafe extern "C" fn ZSTD_rust_compressContinue(
|
||||
|
||||
type CompressEndTraceFn = unsafe extern "C" fn(*mut c_void, usize);
|
||||
|
||||
type CompressTraceEndFn = unsafe extern "C" fn(*mut c_void, u64, *const c_void);
|
||||
|
||||
/// ABI-compatible compression trace record. The weak trace hook remains a C
|
||||
/// callback, but Rust owns construction of the record and its enabled/reset
|
||||
/// policy.
|
||||
#[repr(C)]
|
||||
struct ZSTD_Trace {
|
||||
version: c_uint,
|
||||
streaming: c_int,
|
||||
dictionary_id: c_uint,
|
||||
dictionary_is_cold: c_int,
|
||||
dictionary_size: usize,
|
||||
uncompressed_size: usize,
|
||||
compressed_size: usize,
|
||||
params: *const c_void,
|
||||
cctx: *const c_void,
|
||||
dctx: *const c_void,
|
||||
}
|
||||
|
||||
const _: () = {
|
||||
assert!(offset_of!(ZSTD_Trace, version) == 0);
|
||||
assert!(offset_of!(ZSTD_Trace, streaming) == size_of::<c_uint>());
|
||||
assert!(offset_of!(ZSTD_Trace, dictionary_id) == size_of::<c_uint>() + size_of::<c_int>());
|
||||
assert!(
|
||||
offset_of!(ZSTD_Trace, dictionary_is_cold)
|
||||
== 2 * size_of::<c_uint>() + size_of::<c_int>()
|
||||
);
|
||||
assert!(
|
||||
offset_of!(ZSTD_Trace, dictionary_size)
|
||||
== 2 * size_of::<c_uint>() + 2 * size_of::<c_int>()
|
||||
);
|
||||
assert!(offset_of!(ZSTD_Trace, uncompressed_size) == offset_of!(ZSTD_Trace, dictionary_size) + size_of::<usize>());
|
||||
assert!(offset_of!(ZSTD_Trace, compressed_size) == offset_of!(ZSTD_Trace, dictionary_size) + 2 * size_of::<usize>());
|
||||
assert!(offset_of!(ZSTD_Trace, params) == offset_of!(ZSTD_Trace, dictionary_size) + 3 * size_of::<usize>());
|
||||
assert!(offset_of!(ZSTD_Trace, cctx) == offset_of!(ZSTD_Trace, dictionary_size) + 4 * size_of::<usize>());
|
||||
assert!(offset_of!(ZSTD_Trace, dctx) == offset_of!(ZSTD_Trace, dictionary_size) + 5 * size_of::<usize>());
|
||||
assert!(size_of::<ZSTD_Trace>() == offset_of!(ZSTD_Trace, dictionary_size) + 6 * size_of::<usize>());
|
||||
};
|
||||
|
||||
/// Inputs for Rust-owned compression trace construction.
|
||||
#[repr(C)]
|
||||
pub struct ZSTD_rust_traceEndState {
|
||||
callback_context: *mut c_void,
|
||||
trace_ctx: u64,
|
||||
streaming: c_int,
|
||||
dictionary_id: c_uint,
|
||||
dictionary_size: usize,
|
||||
uncompressed_size: usize,
|
||||
compressed_size: usize,
|
||||
params: *const c_void,
|
||||
cctx: *const c_void,
|
||||
trace_end: CompressTraceEndFn,
|
||||
}
|
||||
|
||||
const _: () = {
|
||||
assert!(size_of::<CompressTraceEndFn>() == size_of::<usize>());
|
||||
assert!(offset_of!(ZSTD_rust_traceEndState, callback_context) == 0);
|
||||
assert!(offset_of!(ZSTD_rust_traceEndState, trace_ctx) == size_of::<usize>());
|
||||
assert!(offset_of!(ZSTD_rust_traceEndState, streaming) == size_of::<usize>() + size_of::<u64>());
|
||||
assert!(offset_of!(ZSTD_rust_traceEndState, dictionary_id) == size_of::<usize>() + size_of::<u64>() + size_of::<c_int>());
|
||||
assert!(offset_of!(ZSTD_rust_traceEndState, dictionary_size) == size_of::<usize>() + size_of::<u64>() + 2 * size_of::<c_int>());
|
||||
assert!(offset_of!(ZSTD_rust_traceEndState, uncompressed_size) == offset_of!(ZSTD_rust_traceEndState, dictionary_size) + size_of::<usize>());
|
||||
assert!(offset_of!(ZSTD_rust_traceEndState, compressed_size) == offset_of!(ZSTD_rust_traceEndState, dictionary_size) + 2 * size_of::<usize>());
|
||||
assert!(offset_of!(ZSTD_rust_traceEndState, params) == offset_of!(ZSTD_rust_traceEndState, dictionary_size) + 3 * size_of::<usize>());
|
||||
assert!(offset_of!(ZSTD_rust_traceEndState, cctx) == offset_of!(ZSTD_rust_traceEndState, dictionary_size) + 4 * size_of::<usize>());
|
||||
assert!(offset_of!(ZSTD_rust_traceEndState, trace_end) == offset_of!(ZSTD_rust_traceEndState, dictionary_size) + 5 * size_of::<usize>());
|
||||
assert!(size_of::<ZSTD_rust_traceEndState>() == offset_of!(ZSTD_rust_traceEndState, dictionary_size) + 6 * size_of::<usize>());
|
||||
};
|
||||
|
||||
/// Construct and publish a compression trace record, if tracing is enabled.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn ZSTD_rust_traceEnd(state: *const ZSTD_rust_traceEndState) {
|
||||
let Some(state) = (unsafe { state.as_ref() }) else {
|
||||
return;
|
||||
};
|
||||
if state.trace_ctx == 0 {
|
||||
return;
|
||||
}
|
||||
let trace = ZSTD_Trace {
|
||||
version: ZSTD_VERSION_NUMBER as c_uint,
|
||||
streaming: state.streaming,
|
||||
dictionary_id: state.dictionary_id,
|
||||
dictionary_is_cold: 0,
|
||||
dictionary_size: state.dictionary_size,
|
||||
uncompressed_size: state.uncompressed_size,
|
||||
compressed_size: state.compressed_size,
|
||||
params: state.params,
|
||||
cctx: state.cctx,
|
||||
dctx: ptr::null(),
|
||||
};
|
||||
unsafe {
|
||||
(state.trace_end)(
|
||||
state.callback_context,
|
||||
state.trace_ctx,
|
||||
(&trace as *const ZSTD_Trace).cast(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Explicit projection for the public end-of-frame orchestration.
|
||||
///
|
||||
/// Rust owns callback ordering, output offset/capacity accounting, and
|
||||
|
||||
Reference in New Issue
Block a user