feat(mt): move serial reset orchestration into Rust

Move the MT serial-state reset ordering into Rust. C retains parameter adjustment, private LDM table allocation and clearing, dictionary loading, window/checksum state, and allocator behavior behind callbacks; Rust now owns the reset sequencing and allocation-failure stop point.

Test Plan:
- ulimit -v 41943040; CARGO_BUILD_JOBS=1; cargo test --manifest-path rust/Cargo.toml
- ulimit -v 41943040; CARGO_BUILD_JOBS=1; cargo clippy --manifest-path rust/Cargo.toml --all-targets -- -D warnings
- ulimit -v 41943040; make -B -C programs -j1 zstd
- ulimit -v 41943040; make -C tests -j1 test-zstream ZSTREAM_TESTTIME=-T1s
This commit is contained in:
2026-07-19 20:11:35 +02:00
parent 2557319583
commit e3fe5b5a24
2 changed files with 371 additions and 44 deletions
+141 -44
View File
@@ -451,6 +451,19 @@ typedef void (*ZSTDMT_initSetBufferSizeFn)(void* opaque, size_t size);
typedef size_t (*ZSTDMT_initResizeRoundBufferFn)(void* opaque, size_t capacity);
typedef void (*ZSTDMT_initResetStreamFn)(void* opaque);
typedef size_t (*ZSTDMT_initSerialResetFn)(void* opaque, size_t targetSectionSize);
typedef void (*ZSTDMT_serialResetVoidFn)(void* opaque);
typedef void (*ZSTDMT_serialResetSetNbSeqFn)(void* opaque, size_t nbSeq);
typedef int (*ZSTDMT_serialResetResizeFn)(void* opaque);
int ZSTDMT_rust_serialStateReset(
int enableLdm, int checksumEnabled, size_t maxNbSeq, void* opaque,
ZSTDMT_serialResetVoidFn resetNextJob,
ZSTDMT_serialResetVoidFn resetChecksum,
ZSTDMT_serialResetSetNbSeqFn setNbSeq,
ZSTDMT_serialResetVoidFn resetWindow,
ZSTDMT_serialResetResizeFn resizeTables,
ZSTDMT_serialResetVoidFn zeroTables,
ZSTDMT_serialResetVoidFn loadDictionary,
ZSTDMT_serialResetVoidFn copyWindow);
size_t ZSTDMT_rust_initCStream(
const ZSTDMT_RustInitCStreamProjection* projection, void* opaque,
ZSTDMT_initResizeFn resize, ZSTDMT_initDrainFn drain,
@@ -824,6 +837,99 @@ typedef struct {
ZSTD_window_t ldmWindow; /* A thread-safe copy of ldmState.window */
} SerialState;
typedef struct {
SerialState* serialState;
ZSTDMT_seqPool* seqPool;
ZSTD_CCtx_params* params;
const void* dict;
size_t dictSize;
ZSTD_dictContentType_e dictContentType;
size_t hashSize;
size_t numBuckets;
unsigned bucketLog;
unsigned prevBucketLog;
ZSTD_customMem cMem;
} ZSTDMT_serialResetContext;
static void ZSTDMT_serialResetNextJob(void* opaque)
{
ZSTDMT_serialResetContext* const context = (ZSTDMT_serialResetContext*)opaque;
context->serialState->nextJobID = 0;
}
static void ZSTDMT_serialResetChecksum(void* opaque)
{
ZSTDMT_serialResetContext* const context = (ZSTDMT_serialResetContext*)opaque;
XXH64_reset(&context->serialState->xxhState, 0);
}
static void ZSTDMT_serialResetSetNbSeq(void* opaque, size_t nbSeq)
{
ZSTDMT_serialResetContext* const context = (ZSTDMT_serialResetContext*)opaque;
ZSTDMT_setNbSeq(context->seqPool, nbSeq);
}
static void ZSTDMT_serialResetWindow(void* opaque)
{
ZSTDMT_serialResetContext* const context = (ZSTDMT_serialResetContext*)opaque;
ZSTD_window_init(&context->serialState->ldmState.window);
}
static int ZSTDMT_serialResetResizeTables(void* opaque)
{
ZSTDMT_serialResetContext* const context = (ZSTDMT_serialResetContext*)opaque;
SerialState* const serialState = context->serialState;
ldmParams_t const* const ldmParams = &context->params->ldmParams;
if (serialState->ldmState.hashTable == NULL ||
serialState->params.ldmParams.hashLog < ldmParams->hashLog) {
ZSTD_customFree(serialState->ldmState.hashTable, context->cMem);
serialState->ldmState.hashTable = (ldmEntry_t*)ZSTD_customMalloc(
context->hashSize, context->cMem);
}
if (serialState->ldmState.bucketOffsets == NULL ||
context->prevBucketLog < context->bucketLog) {
ZSTD_customFree(serialState->ldmState.bucketOffsets, context->cMem);
serialState->ldmState.bucketOffsets = (BYTE*)ZSTD_customMalloc(
context->numBuckets, context->cMem);
}
return !serialState->ldmState.hashTable || !serialState->ldmState.bucketOffsets;
}
static void ZSTDMT_serialResetZeroTables(void* opaque)
{
ZSTDMT_serialResetContext* const context = (ZSTDMT_serialResetContext*)opaque;
SerialState* const serialState = context->serialState;
ZSTD_memset(serialState->ldmState.hashTable, 0, context->hashSize);
ZSTD_memset(serialState->ldmState.bucketOffsets, 0, context->numBuckets);
}
static void ZSTDMT_serialResetLoadDictionary(void* opaque)
{
ZSTDMT_serialResetContext* const context = (ZSTDMT_serialResetContext*)opaque;
SerialState* const serialState = context->serialState;
serialState->ldmState.loadedDictEnd = 0;
if (context->dictSize > 0 &&
context->dictContentType == ZSTD_dct_rawContent) {
BYTE const* const dictEnd = (const BYTE*)context->dict + context->dictSize;
ZSTD_window_update(&serialState->ldmState.window,
context->dict, context->dictSize,
/* forceNonContiguous */ 0);
ZSTD_ldm_fillHashTable(&serialState->ldmState,
(const BYTE*)context->dict, dictEnd,
&context->params->ldmParams);
serialState->ldmState.loadedDictEnd = context->params->forceWindow
? 0 : (U32)(dictEnd - serialState->ldmState.window.base);
}
}
static void ZSTDMT_serialResetCopyWindow(void* opaque)
{
ZSTDMT_serialResetContext* const context = (ZSTDMT_serialResetContext*)opaque;
context->serialState->ldmWindow = context->serialState->ldmState.window;
}
static int
ZSTDMT_serialState_reset(SerialState* serialState,
ZSTDMT_seqPool* seqPool,
@@ -832,6 +938,8 @@ ZSTDMT_serialState_reset(SerialState* serialState,
const void* dict, size_t const dictSize,
ZSTD_dictContentType_e dictContentType)
{
ZSTDMT_serialResetContext context;
/* Adjust parameters */
if (params.ldmParams.enableLdm == ZSTD_ps_enable) {
DEBUGLOG(4, "LDM window size = %u KB", (1U << params.cParams.windowLog) >> 10);
@@ -841,53 +949,42 @@ ZSTDMT_serialState_reset(SerialState* serialState,
} else {
ZSTD_memset(&params.ldmParams, 0, sizeof(params.ldmParams));
}
serialState->nextJobID = 0;
if (params.fParams.checksumFlag)
XXH64_reset(&serialState->xxhState, 0);
context.serialState = serialState;
context.seqPool = seqPool;
context.params = &params;
context.dict = dict;
context.dictSize = dictSize;
context.dictContentType = dictContentType;
context.cMem = params.customMem;
context.hashSize = 0;
context.numBuckets = 0;
context.bucketLog = 0;
context.prevBucketLog = 0;
if (params.ldmParams.enableLdm == ZSTD_ps_enable) {
ZSTD_customMem cMem = params.customMem;
unsigned const hashLog = params.ldmParams.hashLog;
size_t const hashSize = ((size_t)1 << hashLog) * sizeof(ldmEntry_t);
unsigned const bucketLog =
params.ldmParams.hashLog - params.ldmParams.bucketSizeLog;
unsigned const prevBucketLog =
serialState->params.ldmParams.hashLog -
serialState->params.ldmParams.bucketSizeLog;
size_t const numBuckets = (size_t)1 << bucketLog;
/* Size the seq pool tables */
ZSTDMT_setNbSeq(seqPool, ZSTD_ldm_getMaxNbSeq(params.ldmParams, jobSize));
/* Reset the window */
ZSTD_window_init(&serialState->ldmState.window);
/* Resize tables and output space if necessary. */
if (serialState->ldmState.hashTable == NULL || serialState->params.ldmParams.hashLog < hashLog) {
ZSTD_customFree(serialState->ldmState.hashTable, cMem);
serialState->ldmState.hashTable = (ldmEntry_t*)ZSTD_customMalloc(hashSize, cMem);
}
if (serialState->ldmState.bucketOffsets == NULL || prevBucketLog < bucketLog) {
ZSTD_customFree(serialState->ldmState.bucketOffsets, cMem);
serialState->ldmState.bucketOffsets = (BYTE*)ZSTD_customMalloc(numBuckets, cMem);
}
if (!serialState->ldmState.hashTable || !serialState->ldmState.bucketOffsets)
return 1;
/* Zero the tables */
ZSTD_memset(serialState->ldmState.hashTable, 0, hashSize);
ZSTD_memset(serialState->ldmState.bucketOffsets, 0, numBuckets);
context.hashSize = ((size_t)1 << hashLog) * sizeof(ldmEntry_t);
context.bucketLog = params.ldmParams.hashLog - params.ldmParams.bucketSizeLog;
context.prevBucketLog =
serialState->params.ldmParams.hashLog -
serialState->params.ldmParams.bucketSizeLog;
context.numBuckets = (size_t)1 << context.bucketLog;
}
/* Update window state and fill hash table with dict */
serialState->ldmState.loadedDictEnd = 0;
if (dictSize > 0) {
if (dictContentType == ZSTD_dct_rawContent) {
BYTE const* const dictEnd = (const BYTE*)dict + dictSize;
ZSTD_window_update(&serialState->ldmState.window, dict, dictSize, /* forceNonContiguous */ 0);
ZSTD_ldm_fillHashTable(&serialState->ldmState, (const BYTE*)dict, dictEnd, &params.ldmParams);
serialState->ldmState.loadedDictEnd = params.forceWindow ? 0 : (U32)(dictEnd - serialState->ldmState.window.base);
} else {
/* don't even load anything */
}
}
/* Initialize serialState's copy of ldmWindow. */
serialState->ldmWindow = serialState->ldmState.window;
if (ZSTDMT_rust_serialStateReset(
params.ldmParams.enableLdm == ZSTD_ps_enable,
params.fParams.checksumFlag,
ZSTD_ldm_getMaxNbSeq(params.ldmParams, jobSize),
&context,
ZSTDMT_serialResetNextJob,
ZSTDMT_serialResetChecksum,
ZSTDMT_serialResetSetNbSeq,
ZSTDMT_serialResetWindow,
ZSTDMT_serialResetResizeTables,
ZSTDMT_serialResetZeroTables,
ZSTDMT_serialResetLoadDictionary,
ZSTDMT_serialResetCopyWindow)) {
return 1;
}
serialState->params = params;