feat(compress): move external producer success path into Rust
Move block-level external sequence producer invocation, result post-processing, source-length validation, and transfer ordering into a Rust-owned ABI leaf. Retain the private CCtx transfer callback and C-side fallback/block-compressor selection, preserving producer-error fallback eligibility and direct invalid-sequence/transfer failures. Test Plan: - cargo test --manifest-path rust/Cargo.toml --lib - cargo clippy --manifest-path rust/Cargo.toml --all-targets -- -D warnings - make -B -C programs -j1 zstd - make -C tests -j1 test-zstream ZSTREAM_TESTTIME=-T1s - focused external_sequence_producer unit tests
This commit is contained in:
@@ -1163,14 +1163,9 @@ void ZSTD_rust_confirmRepcodesAndEntropyTables(
|
||||
void ZSTD_rust_storeLastLiterals(SeqStore_t* seqStorePtr,
|
||||
const BYTE* anchor, size_t lastLLSize);
|
||||
void ZSTD_rust_resetSeqStore(SeqStore_t* ssPtr);
|
||||
size_t ZSTD_rust_fastSequenceLengthSum(const ZSTD_Sequence* seqBuf,
|
||||
size_t seqBufSize);
|
||||
void ZSTD_rust_validateSeqStore(const SeqStore_t* seqStore, U32 minMatch);
|
||||
BlockSummary ZSTD_rust_get1BlockSummary(const ZSTD_Sequence* seqs,
|
||||
size_t nbSeqs);
|
||||
size_t ZSTD_rust_postProcessSequenceProducerResult(
|
||||
ZSTD_Sequence* outSeqs, size_t nbExternalSeqs,
|
||||
size_t outSeqsCapacity, size_t srcSize);
|
||||
size_t ZSTD_rust_deriveBlockSplits(
|
||||
U32* partitions, U32 nbSeq,
|
||||
const SeqStore_t* originalSeqStore,
|
||||
@@ -1344,6 +1339,57 @@ typedef char ZSTD_rust_build_seq_store_state_layout[
|
||||
== 7 * sizeof(void*) + sizeof(U32) + sizeof(int))
|
||||
? 1 : -1];
|
||||
|
||||
typedef size_t (*ZSTD_rust_externalSequenceTransfer_f)(
|
||||
void* context, ZSTD_SequencePosition* seqPos,
|
||||
const ZSTD_Sequence* inSeqs, size_t inSeqsSize,
|
||||
const void* src, size_t blockSize);
|
||||
typedef struct {
|
||||
void* callbackContext;
|
||||
void* producerState;
|
||||
ZSTD_sequenceProducer_F producer;
|
||||
ZSTD_Sequence* extSeqBuf;
|
||||
const size_t* extSeqBufCapacity;
|
||||
const void* src;
|
||||
const size_t* srcSize;
|
||||
const int* compressionLevel;
|
||||
const size_t* windowSize;
|
||||
ZSTD_rust_externalSequenceTransfer_f transfer;
|
||||
size_t* externalSeqCount;
|
||||
int* seqStoreComplete;
|
||||
int* allowFallback;
|
||||
} ZSTD_rust_externalSequenceProducerState;
|
||||
size_t ZSTD_rust_tryExternalSequenceProducer(
|
||||
const ZSTD_rust_externalSequenceProducerState* state);
|
||||
typedef char ZSTD_rust_external_sequence_producer_state_layout[
|
||||
(offsetof(ZSTD_rust_externalSequenceProducerState, callbackContext) == 0
|
||||
&& offsetof(ZSTD_rust_externalSequenceProducerState, producerState)
|
||||
== sizeof(void*)
|
||||
&& offsetof(ZSTD_rust_externalSequenceProducerState, producer)
|
||||
== 2 * sizeof(void*)
|
||||
&& offsetof(ZSTD_rust_externalSequenceProducerState, extSeqBuf)
|
||||
== 3 * sizeof(void*)
|
||||
&& offsetof(ZSTD_rust_externalSequenceProducerState, extSeqBufCapacity)
|
||||
== 4 * sizeof(void*)
|
||||
&& offsetof(ZSTD_rust_externalSequenceProducerState, src)
|
||||
== 5 * sizeof(void*)
|
||||
&& offsetof(ZSTD_rust_externalSequenceProducerState, srcSize)
|
||||
== 6 * sizeof(void*)
|
||||
&& offsetof(ZSTD_rust_externalSequenceProducerState, compressionLevel)
|
||||
== 7 * sizeof(void*)
|
||||
&& offsetof(ZSTD_rust_externalSequenceProducerState, windowSize)
|
||||
== 8 * sizeof(void*)
|
||||
&& offsetof(ZSTD_rust_externalSequenceProducerState, transfer)
|
||||
== 9 * sizeof(void*)
|
||||
&& offsetof(ZSTD_rust_externalSequenceProducerState, externalSeqCount)
|
||||
== 10 * sizeof(void*)
|
||||
&& offsetof(ZSTD_rust_externalSequenceProducerState, seqStoreComplete)
|
||||
== 11 * sizeof(void*)
|
||||
&& offsetof(ZSTD_rust_externalSequenceProducerState, allowFallback)
|
||||
== 12 * sizeof(void*)
|
||||
&& sizeof(ZSTD_rust_externalSequenceProducerState)
|
||||
== 13 * sizeof(void*))
|
||||
? 1 : -1];
|
||||
|
||||
/* The sequence-compression loop receives only the state it actually reads or
|
||||
* updates. In particular, neither ZSTD_CCtx nor a C function pointer crosses
|
||||
* the Rust ABI. */
|
||||
@@ -3419,29 +3465,6 @@ void ZSTD_resetSeqStore(SeqStore_t* ssPtr)
|
||||
ZSTD_rust_resetSeqStore(ssPtr);
|
||||
}
|
||||
|
||||
/* ZSTD_postProcessSequenceProducerResult() :
|
||||
* Validates and post-processes sequences obtained through the external matchfinder API:
|
||||
* - Checks whether nbExternalSeqs represents an error condition.
|
||||
* - Appends a block delimiter to outSeqs if one is not already present.
|
||||
* See zstd.h for context regarding block delimiters.
|
||||
* Returns the number of sequences after post-processing, or an error code. */
|
||||
static size_t ZSTD_postProcessSequenceProducerResult(
|
||||
ZSTD_Sequence* outSeqs, size_t nbExternalSeqs, size_t outSeqsCapacity, size_t srcSize
|
||||
) {
|
||||
return ZSTD_rust_postProcessSequenceProducerResult(
|
||||
outSeqs, nbExternalSeqs, outSeqsCapacity, srcSize);
|
||||
}
|
||||
|
||||
/* ZSTD_fastSequenceLengthSum() :
|
||||
* Returns sum(litLen) + sum(matchLen) + lastLits for *seqBuf*.
|
||||
* Similar to another function in zstd_compress.c (determine_blockSize),
|
||||
* except it doesn't check for a block delimiter to end summation.
|
||||
* Removing the early exit allows the compiler to auto-vectorize (https://godbolt.org/z/cY1cajz9P).
|
||||
* This function can be deleted and replaced by determine_blockSize after we resolve issue #3456. */
|
||||
static size_t ZSTD_fastSequenceLengthSum(ZSTD_Sequence const* seqBuf, size_t seqBufSize) {
|
||||
return ZSTD_rust_fastSequenceLengthSum(seqBuf, seqBufSize);
|
||||
}
|
||||
|
||||
static size_t
|
||||
ZSTD_transferSequences_wBlockDelim(ZSTD_CCtx* cctx,
|
||||
ZSTD_SequencePosition* seqPos,
|
||||
@@ -3449,6 +3472,17 @@ ZSTD_transferSequences_wBlockDelim(ZSTD_CCtx* cctx,
|
||||
const void* src, size_t blockSize,
|
||||
ZSTD_ParamSwitch_e externalRepSearch);
|
||||
|
||||
static size_t ZSTD_rust_externalSequenceProducer_transfer(
|
||||
void* context, ZSTD_SequencePosition* seqPos,
|
||||
const ZSTD_Sequence* inSeqs, size_t inSeqsSize,
|
||||
const void* src, size_t blockSize)
|
||||
{
|
||||
ZSTD_CCtx* const zc = (ZSTD_CCtx*)context;
|
||||
return ZSTD_transferSequences_wBlockDelim(
|
||||
zc, seqPos, inSeqs, inSeqsSize, src, blockSize,
|
||||
zc->appliedParams.searchForExternalRepcodes);
|
||||
}
|
||||
|
||||
typedef enum { ZSTDbss_compress, ZSTDbss_noCompress } ZSTD_BuildSeqStore_e;
|
||||
|
||||
static void ZSTD_rust_buildSeqStore_skipSmallBlock(void* context, size_t srcSize)
|
||||
@@ -3537,41 +3571,38 @@ static size_t ZSTD_rust_buildSeqStore_selectSequences(
|
||||
zc->appliedParams.useRowMatchFinder, src, srcSize);
|
||||
assert(ldmSeqStore.pos == ldmSeqStore.size);
|
||||
} else if (ZSTD_hasExtSeqProd(&zc->appliedParams)) {
|
||||
size_t nbExternalSeqs = 0;
|
||||
int allowFallback = 0;
|
||||
ZSTD_rust_externalSequenceProducerState state;
|
||||
size_t const windowSize = (size_t)1 << zc->appliedParams.cParams.windowLog;
|
||||
assert(zc->extSeqBufCapacity >= ZSTD_sequenceBound(srcSize));
|
||||
assert(zc->appliedParams.extSeqProdFunc != NULL);
|
||||
|
||||
{ U32 const windowSize = (U32)1 << zc->appliedParams.cParams.windowLog;
|
||||
size_t const nbExternalSeqs = (zc->appliedParams.extSeqProdFunc)(
|
||||
zc->appliedParams.extSeqProdState,
|
||||
zc->extSeqBuf, zc->extSeqBufCapacity,
|
||||
src, srcSize, NULL, 0,
|
||||
zc->appliedParams.compressionLevel, windowSize);
|
||||
size_t const nbPostProcessedSeqs = ZSTD_postProcessSequenceProducerResult(
|
||||
zc->extSeqBuf, nbExternalSeqs,
|
||||
zc->extSeqBufCapacity, srcSize);
|
||||
state.callbackContext = zc;
|
||||
state.producerState = zc->appliedParams.extSeqProdState;
|
||||
state.producer = zc->appliedParams.extSeqProdFunc;
|
||||
state.extSeqBuf = zc->extSeqBuf;
|
||||
state.extSeqBufCapacity = &zc->extSeqBufCapacity;
|
||||
state.src = src;
|
||||
state.srcSize = &srcSize;
|
||||
state.compressionLevel = &zc->appliedParams.compressionLevel;
|
||||
state.windowSize = &windowSize;
|
||||
state.transfer = ZSTD_rust_externalSequenceProducer_transfer;
|
||||
state.externalSeqCount = &nbExternalSeqs;
|
||||
state.seqStoreComplete = seqStoreComplete;
|
||||
state.allowFallback = &allowFallback;
|
||||
|
||||
/* Return early if there is no error, since the delimiter already
|
||||
* carries the block's final literals. */
|
||||
if (!ZSTD_isError(nbPostProcessedSeqs)) {
|
||||
ZSTD_SequencePosition seqPos = {0,0,0};
|
||||
size_t const seqLenSum = ZSTD_fastSequenceLengthSum(
|
||||
zc->extSeqBuf, nbPostProcessedSeqs);
|
||||
RETURN_ERROR_IF(seqLenSum > srcSize, externalSequences_invalid,
|
||||
"External sequences imply too large a block!");
|
||||
FORWARD_IF_ERROR(ZSTD_transferSequences_wBlockDelim(
|
||||
zc, &seqPos, zc->extSeqBuf, nbPostProcessedSeqs,
|
||||
src, srcSize,
|
||||
zc->appliedParams.searchForExternalRepcodes),
|
||||
"Failed to copy external sequences to seqStore!");
|
||||
{ size_t const producerResult =
|
||||
ZSTD_rust_tryExternalSequenceProducer(&state);
|
||||
if (*seqStoreComplete) {
|
||||
ms->ldmSeqStore = NULL;
|
||||
*seqStoreComplete = 1;
|
||||
DEBUGLOG(5, "Copied %lu sequences from external sequence producer to internal seqStore.",
|
||||
(unsigned long)nbExternalSeqs);
|
||||
return 0;
|
||||
return producerResult;
|
||||
}
|
||||
|
||||
if (!zc->appliedParams.enableMatchFinderFallback)
|
||||
return nbPostProcessedSeqs;
|
||||
if (!allowFallback || !zc->appliedParams.enableMatchFinderFallback)
|
||||
return producerResult;
|
||||
|
||||
{ ZSTD_BlockCompressor_f const blockCompressor =
|
||||
ZSTD_selectBlockCompressor(
|
||||
|
||||
Reference in New Issue
Block a user