feat(mt): move worker finish publication to Rust

Replace the C worker finish callbacks that publish errors, final block sizes,
consumed bytes, and completion signals with a Rust-owned publication path. The
nested projection keeps the job counters and pthread operations private to C,
while Rust preserves the error/success ordering and size_t wrapping behavior.
The consumed-size assertion remains a C validation callback at the original
point before publication.

Test Plan:
- git diff --cached --check
- capped cargo check --tests
- capped cargo clippy --tests -- -A clippy::manual-bits -D warnings
- capped make -j1
- capped make -j1 -C tests test
- standalone hybrid cargo test remains unavailable because its link lacks the
  pre-existing ZSTD_rust_dctx_trace_view, ZSTD_rust_dctx_view, and
  ZSTD_rust_block_context_init symbols
This commit is contained in:
2026-07-21 22:27:57 +02:00
parent 0b18e73d4b
commit 6b8051b98a
2 changed files with 262 additions and 150 deletions
+59 -59
View File
@@ -300,16 +300,48 @@ typedef char ZSTDMT_compression_job_progress_projection_layout[
void ZSTDMT_rust_compressionJobProgress( void ZSTDMT_rust_compressionJobProgress(
void* opaque, size_t cSize, size_t consumed); void* opaque, size_t cSize, size_t consumed);
typedef struct {
void* callbackContext;
size_t* cSize;
size_t* consumed;
size_t srcSize;
ZSTDMT_compressionJobVoidFn lock;
ZSTDMT_compressionJobVoidFn signal;
ZSTDMT_compressionJobVoidFn unlock;
ZSTDMT_compressionJobSizeFn validateConsumed;
} ZSTDMT_RustCompressionJobFinishPublicationProjection;
typedef char ZSTDMT_compression_job_finish_publication_projection_layout[
(offsetof(ZSTDMT_RustCompressionJobFinishPublicationProjection,
callbackContext) == 0
&& offsetof(ZSTDMT_RustCompressionJobFinishPublicationProjection, cSize)
== sizeof(void*)
&& offsetof(ZSTDMT_RustCompressionJobFinishPublicationProjection,
consumed)
== sizeof(void*) + sizeof(size_t)
&& offsetof(ZSTDMT_RustCompressionJobFinishPublicationProjection,
srcSize)
== sizeof(void*) + 2 * sizeof(size_t)
&& offsetof(ZSTDMT_RustCompressionJobFinishPublicationProjection, lock)
== sizeof(void*) + 3 * sizeof(size_t)
&& offsetof(ZSTDMT_RustCompressionJobFinishPublicationProjection, signal)
== sizeof(void*) + 3 * sizeof(size_t) + sizeof(void*)
&& offsetof(ZSTDMT_RustCompressionJobFinishPublicationProjection,
unlock)
== sizeof(void*) + 3 * sizeof(size_t) + 2 * sizeof(void*)
&& offsetof(ZSTDMT_RustCompressionJobFinishPublicationProjection,
validateConsumed)
== sizeof(void*) + 3 * sizeof(size_t) + 3 * sizeof(void*)
&& sizeof(ZSTDMT_RustCompressionJobFinishPublicationProjection)
== sizeof(void*) + 3 * sizeof(size_t) + 4 * sizeof(void*))
? 1 : -1];
typedef struct { typedef struct {
void* callbackContext; void* callbackContext;
size_t srcSize; size_t srcSize;
ZSTDMT_compressionJobVoidFn ensureFinished; ZSTDMT_compressionJobVoidFn ensureFinished;
ZSTDMT_compressionJobSizeFn publishError; ZSTDMT_RustCompressionJobFinishPublicationProjection publication;
ZSTDMT_compressionJobSizeFn publishLastBlockSize;
ZSTDMT_compressionJobVoidFn releaseSeq; ZSTDMT_compressionJobVoidFn releaseSeq;
ZSTDMT_compressionJobVoidFn releaseCCtx; ZSTDMT_compressionJobVoidFn releaseCCtx;
ZSTDMT_compressionJobSizeFn publishConsumed;
ZSTDMT_compressionJobVoidFn signal;
} ZSTDMT_RustCompressionJobFinishProjection; } ZSTDMT_RustCompressionJobFinishProjection;
typedef char ZSTDMT_compression_job_finish_projection_layout[ typedef char ZSTDMT_compression_job_finish_projection_layout[
(offsetof(ZSTDMT_RustCompressionJobFinishProjection, callbackContext) == 0 (offsetof(ZSTDMT_RustCompressionJobFinishProjection, callbackContext) == 0
@@ -317,19 +349,17 @@ typedef char ZSTDMT_compression_job_finish_projection_layout[
== sizeof(void*) == sizeof(void*)
&& offsetof(ZSTDMT_RustCompressionJobFinishProjection, ensureFinished) && offsetof(ZSTDMT_RustCompressionJobFinishProjection, ensureFinished)
== 2 * sizeof(void*) == 2 * sizeof(void*)
&& offsetof(ZSTDMT_RustCompressionJobFinishProjection, publishError) && offsetof(ZSTDMT_RustCompressionJobFinishProjection, publication)
== 3 * sizeof(void*) == 3 * sizeof(void*)
&& offsetof(ZSTDMT_RustCompressionJobFinishProjection, publishLastBlockSize)
== 4 * sizeof(void*)
&& offsetof(ZSTDMT_RustCompressionJobFinishProjection, releaseSeq) && offsetof(ZSTDMT_RustCompressionJobFinishProjection, releaseSeq)
== 5 * sizeof(void*) == 3 * sizeof(void*)
+ sizeof(ZSTDMT_RustCompressionJobFinishPublicationProjection)
&& offsetof(ZSTDMT_RustCompressionJobFinishProjection, releaseCCtx) && offsetof(ZSTDMT_RustCompressionJobFinishProjection, releaseCCtx)
== 6 * sizeof(void*) == 4 * sizeof(void*)
&& offsetof(ZSTDMT_RustCompressionJobFinishProjection, publishConsumed) + sizeof(ZSTDMT_RustCompressionJobFinishPublicationProjection)
== 7 * sizeof(void*) && sizeof(ZSTDMT_RustCompressionJobFinishProjection)
&& offsetof(ZSTDMT_RustCompressionJobFinishProjection, signal) == 5 * sizeof(void*)
== 8 * sizeof(void*) + sizeof(ZSTDMT_RustCompressionJobFinishPublicationProjection))
&& sizeof(ZSTDMT_RustCompressionJobFinishProjection) == 9 * sizeof(void*))
? 1 : -1]; ? 1 : -1];
typedef struct { typedef struct {
@@ -2243,28 +2273,6 @@ static void ZSTDMT_compressionJobEnsureFinished(void* opaque)
DEBUGLOG(5, "Finished with source: %zx", (size_t)job->src.start); DEBUGLOG(5, "Finished with source: %zx", (size_t)job->src.start);
} }
static void ZSTDMT_compressionJobPublishError(void* opaque, size_t error)
{
ZSTDMT_compressionJobState* const state =
(ZSTDMT_compressionJobState*)opaque;
ZSTDMT_jobDescription* const job = state->job;
ZSTD_PTHREAD_MUTEX_LOCK(&job->job_mutex);
job->cSize = error;
ZSTD_pthread_mutex_unlock(&job->job_mutex);
}
static void ZSTDMT_compressionJobPublishLastBlockSize(void* opaque, size_t lastCBlockSize)
{
ZSTDMT_compressionJobState* const state =
(ZSTDMT_compressionJobState*)opaque;
ZSTDMT_jobDescription* const job = state->job;
ZSTD_PTHREAD_MUTEX_LOCK(&job->job_mutex);
job->cSize += lastCBlockSize;
ZSTD_pthread_mutex_unlock(&job->job_mutex);
}
static void ZSTDMT_compressionJobReleaseSeq(void* opaque) static void ZSTDMT_compressionJobReleaseSeq(void* opaque)
{ {
ZSTDMT_compressionJobState* const state = ZSTDMT_compressionJobState* const state =
@@ -2283,27 +2291,11 @@ static void ZSTDMT_compressionJobReleaseCCtx(void* opaque)
ZSTDMT_releaseCCtx(job->cctxPool, state->cctx); ZSTDMT_releaseCCtx(job->cctxPool, state->cctx);
} }
static void ZSTDMT_compressionJobPublishConsumed(void* opaque, size_t srcSize) static void ZSTDMT_compressionJobValidateConsumed(void* opaque, size_t srcSize)
{ {
ZSTDMT_compressionJobState* const state = ZSTDMT_jobDescription* const job = (ZSTDMT_jobDescription*)opaque;
(ZSTDMT_compressionJobState*)opaque;
ZSTDMT_jobDescription* const job = state->job;
assert(srcSize == job->src.size); assert(srcSize == job->src.size);
ZSTD_PTHREAD_MUTEX_LOCK(&job->job_mutex);
job->consumed = srcSize; /* when job->consumed == job->src.size , compression job is presumed completed */
ZSTD_pthread_mutex_unlock(&job->job_mutex);
}
static void ZSTDMT_compressionJobSignal(void* opaque)
{
ZSTDMT_compressionJobState* const state =
(ZSTDMT_compressionJobState*)opaque;
ZSTDMT_jobDescription* const job = state->job;
ZSTD_PTHREAD_MUTEX_LOCK(&job->job_mutex);
ZSTD_pthread_cond_signal(&job->job_cond);
ZSTD_pthread_mutex_unlock(&job->job_mutex);
} }
/* ZSTDMT_compressionJob() is a POOL_function type. Rust owns the stage /* ZSTDMT_compressionJob() is a POOL_function type. Rust owns the stage
@@ -2313,6 +2305,7 @@ static void ZSTDMT_compressionJob(void* jobDescription)
ZSTDMT_jobDescription* const job = (ZSTDMT_jobDescription*)jobDescription; ZSTDMT_jobDescription* const job = (ZSTDMT_jobDescription*)jobDescription;
ZSTDMT_compressionJobState state; ZSTDMT_compressionJobState state;
ZSTDMT_RustCompressionJobSequenceState sequenceState; ZSTDMT_RustCompressionJobSequenceState sequenceState;
ZSTDMT_RustCompressionJobFinishPublicationProjection publication;
ZSTDMT_RustCompressionJobFinishProjection finishProjection; ZSTDMT_RustCompressionJobFinishProjection finishProjection;
ZSTDMT_RustCompressionJobProjection projection; ZSTDMT_RustCompressionJobProjection projection;
@@ -2331,16 +2324,23 @@ static void ZSTDMT_compressionJob(void* jobDescription)
&state.frameHeaderState, &state.frameHeaderState,
&sequenceState &sequenceState
}; };
publication = (ZSTDMT_RustCompressionJobFinishPublicationProjection){
job,
&job->cSize,
&job->consumed,
job->src.size,
ZSTDMT_compressionJobProgressLock,
ZSTDMT_compressionJobProgressSignal,
ZSTDMT_compressionJobProgressUnlock,
ZSTDMT_compressionJobValidateConsumed
};
finishProjection = (ZSTDMT_RustCompressionJobFinishProjection){ finishProjection = (ZSTDMT_RustCompressionJobFinishProjection){
&state, &state,
job->src.size, job->src.size,
ZSTDMT_compressionJobEnsureFinished, ZSTDMT_compressionJobEnsureFinished,
ZSTDMT_compressionJobPublishError, publication,
ZSTDMT_compressionJobPublishLastBlockSize,
ZSTDMT_compressionJobReleaseSeq, ZSTDMT_compressionJobReleaseSeq,
ZSTDMT_compressionJobReleaseCCtx, ZSTDMT_compressionJobReleaseCCtx
ZSTDMT_compressionJobPublishConsumed,
ZSTDMT_compressionJobSignal
}; };
ZSTDMT_rust_compressionJob( ZSTDMT_rust_compressionJob(
+203 -91
View File
@@ -755,24 +755,66 @@ pub unsafe extern "C" fn ZSTDMT_rust_compressionJobBegin(
) )
} }
/// Live fields and synchronization callbacks for worker-job finish
/// publication. The private job descriptor and pthread objects remain in C;
/// Rust owns the counter updates and completion signal order.
#[repr(C)]
#[derive(Clone, Copy)]
pub struct ZSTDMT_compressionJobFinishPublicationProjection {
pub callbackContext: *mut c_void,
pub cSize: *mut usize,
pub consumed: *mut usize,
pub srcSize: usize,
pub lock: Option<ZSTDMT_compressionJobVoidFn>,
pub signal: Option<ZSTDMT_compressionJobVoidFn>,
pub unlock: Option<ZSTDMT_compressionJobVoidFn>,
pub validateConsumed: Option<ZSTDMT_compressionJobSizeFn>,
}
const _: () = {
assert!(
offset_of!(ZSTDMT_compressionJobFinishPublicationProjection, callbackContext) == 0
);
assert!(
offset_of!(ZSTDMT_compressionJobFinishPublicationProjection, cSize)
== size_of::<*mut c_void>()
);
assert!(
offset_of!(ZSTDMT_compressionJobFinishPublicationProjection, consumed)
== size_of::<*mut c_void>() + size_of::<usize>()
);
assert!(
offset_of!(ZSTDMT_compressionJobFinishPublicationProjection, srcSize)
== size_of::<*mut c_void>() + 2 * size_of::<usize>()
);
assert!(offset_of!(ZSTDMT_compressionJobFinishPublicationProjection, lock)
== size_of::<*mut c_void>() + 3 * size_of::<usize>());
assert!(offset_of!(ZSTDMT_compressionJobFinishPublicationProjection, signal)
== size_of::<*mut c_void>() + 3 * size_of::<usize>() + size_of::<usize>());
assert!(offset_of!(ZSTDMT_compressionJobFinishPublicationProjection, unlock)
== size_of::<*mut c_void>() + 3 * size_of::<usize>() + 2 * size_of::<usize>());
assert!(
offset_of!(ZSTDMT_compressionJobFinishPublicationProjection, validateConsumed)
== size_of::<*mut c_void>() + 3 * size_of::<usize>() + 3 * size_of::<usize>()
);
assert!(size_of::<ZSTDMT_compressionJobFinishPublicationProjection>()
== size_of::<*mut c_void>() + 3 * size_of::<usize>() + 4 * size_of::<usize>());
};
/// C-owned leaves for the worker-job finish path. /// C-owned leaves for the worker-job finish path.
/// ///
/// Rust owns the error/success branch and callback order. C keeps the job /// Rust owns the error/success branch and callback order. C keeps the job
/// descriptor, pthread objects, private pools, and serial state behind these /// descriptor, pthread objects, private pools, and serial state behind the
/// callbacks; the source size is the only scalar needed for consumed-size /// remaining callbacks; publication state crosses through one live projection.
/// publication.
#[repr(C)] #[repr(C)]
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub struct ZSTDMT_compressionJobFinishProjection { pub struct ZSTDMT_compressionJobFinishProjection {
pub callbackContext: *mut c_void, pub callbackContext: *mut c_void,
pub srcSize: usize, pub srcSize: usize,
pub ensureFinished: Option<ZSTDMT_compressionJobVoidFn>, pub ensureFinished: Option<ZSTDMT_compressionJobVoidFn>,
pub publishError: Option<ZSTDMT_compressionJobSizeFn>, pub publication: ZSTDMT_compressionJobFinishPublicationProjection,
pub publishLastBlockSize: Option<ZSTDMT_compressionJobSizeFn>,
pub releaseSeq: Option<ZSTDMT_compressionJobVoidFn>, pub releaseSeq: Option<ZSTDMT_compressionJobVoidFn>,
pub releaseCCtx: Option<ZSTDMT_compressionJobVoidFn>, pub releaseCCtx: Option<ZSTDMT_compressionJobVoidFn>,
pub publishConsumed: Option<ZSTDMT_compressionJobSizeFn>,
pub signal: Option<ZSTDMT_compressionJobVoidFn>,
} }
const _: () = { const _: () = {
@@ -781,25 +823,21 @@ const _: () = {
assert!( assert!(
offset_of!(ZSTDMT_compressionJobFinishProjection, ensureFinished) == 2 * size_of::<usize>() offset_of!(ZSTDMT_compressionJobFinishProjection, ensureFinished) == 2 * size_of::<usize>()
); );
assert!(offset_of!(ZSTDMT_compressionJobFinishProjection, publication)
== 3 * size_of::<usize>());
assert!( assert!(
offset_of!(ZSTDMT_compressionJobFinishProjection, publishError) == 3 * size_of::<usize>() offset_of!(ZSTDMT_compressionJobFinishProjection, releaseSeq)
== 3 * size_of::<usize>()
+ size_of::<ZSTDMT_compressionJobFinishPublicationProjection>()
); );
assert!( assert!(
offset_of!(ZSTDMT_compressionJobFinishProjection, publishLastBlockSize) offset_of!(ZSTDMT_compressionJobFinishProjection, releaseCCtx)
== 4 * size_of::<usize>() == 4 * size_of::<usize>()
+ size_of::<ZSTDMT_compressionJobFinishPublicationProjection>()
); );
assert!( assert!(size_of::<ZSTDMT_compressionJobFinishProjection>()
offset_of!(ZSTDMT_compressionJobFinishProjection, releaseSeq) == 5 * size_of::<usize>() == 5 * size_of::<usize>()
); + size_of::<ZSTDMT_compressionJobFinishPublicationProjection>());
assert!(
offset_of!(ZSTDMT_compressionJobFinishProjection, releaseCCtx) == 6 * size_of::<usize>()
);
assert!(
offset_of!(ZSTDMT_compressionJobFinishProjection, publishConsumed)
== 7 * size_of::<usize>()
);
assert!(offset_of!(ZSTDMT_compressionJobFinishProjection, signal) == usize::BITS as usize);
assert!(size_of::<ZSTDMT_compressionJobFinishProjection>() == 9 * size_of::<usize>());
}; };
pub type ZSTDMT_serialWaitForTurnFn = unsafe extern "C" fn(*mut c_void, c_uint) -> c_int; pub type ZSTDMT_serialWaitForTurnFn = unsafe extern "C" fn(*mut c_void, c_uint) -> c_int;
@@ -2570,6 +2608,78 @@ pub unsafe extern "C" fn ZSTDMT_rust_createCompressionJob(
) )
} }
#[inline]
unsafe fn publish_finish_error(
publication: ZSTDMT_compressionJobFinishPublicationProjection,
error: usize,
) {
let (Some(lock), Some(unlock)) = (publication.lock, publication.unlock) else {
return;
};
if publication.cSize.is_null() {
return;
}
unsafe {
lock(publication.callbackContext);
*publication.cSize = error;
unlock(publication.callbackContext);
}
}
#[inline]
unsafe fn publish_finish_last_block_size(
publication: ZSTDMT_compressionJobFinishPublicationProjection,
last_block_size: usize,
) {
let (Some(lock), Some(unlock)) = (publication.lock, publication.unlock) else {
return;
};
if publication.cSize.is_null() {
return;
}
unsafe {
lock(publication.callbackContext);
*publication.cSize = (*publication.cSize).wrapping_add(last_block_size);
unlock(publication.callbackContext);
}
}
#[inline]
unsafe fn publish_finish_consumed(
publication: ZSTDMT_compressionJobFinishPublicationProjection,
src_size: usize,
) {
debug_assert_eq!(publication.srcSize, src_size);
if let Some(validate_consumed) = publication.validateConsumed {
unsafe { validate_consumed(publication.callbackContext, src_size) };
}
let (Some(lock), Some(unlock)) = (publication.lock, publication.unlock) else {
return;
};
if publication.consumed.is_null() {
return;
}
unsafe {
lock(publication.callbackContext);
*publication.consumed = src_size;
unlock(publication.callbackContext);
}
}
#[inline]
unsafe fn signal_finish(publication: ZSTDMT_compressionJobFinishPublicationProjection) {
let (Some(lock), Some(signal), Some(unlock)) =
(publication.lock, publication.signal, publication.unlock)
else {
return;
};
unsafe {
lock(publication.callbackContext);
signal(publication.callbackContext);
unlock(publication.callbackContext);
}
}
/// Finish a worker job with Rust-owned branch and callback ordering. /// Finish a worker job with Rust-owned branch and callback ordering.
/// ///
/// Error publication happens before serial completion and resource release, /// Error publication happens before serial completion and resource release,
@@ -2640,22 +2750,10 @@ fn compression_job_with<A, P, S, B, Q, H, C, T>(
C: FnMut(c_uint) -> ZSTDMT_chunkProcessResult, C: FnMut(c_uint) -> ZSTDMT_chunkProcessResult,
T: FnMut(), T: FnMut(),
{ {
let ( let (Some(ensure_finished), Some(release_seq), Some(release_cctx)) = (
Some(ensure_finished),
Some(publish_error),
Some(publish_last_block_size),
Some(release_seq),
Some(release_cctx),
Some(publish_consumed),
Some(signal),
) = (
finish.ensureFinished, finish.ensureFinished,
finish.publishError,
finish.publishLastBlockSize,
finish.releaseSeq, finish.releaseSeq,
finish.releaseCCtx, finish.releaseCCtx,
finish.publishConsumed,
finish.signal,
) )
else { else {
return; return;
@@ -2690,19 +2788,18 @@ fn compression_job_with<A, P, S, B, Q, H, C, T>(
if ERR_isError(error) { if ERR_isError(error) {
last_block_size = 0; last_block_size = 0;
} }
let publication = finish.publication;
finish_compression_job_with( finish_compression_job_with(
error, error,
last_block_size, last_block_size,
finish.srcSize, finish.srcSize,
|error| unsafe { publish_error(finish.callbackContext, error) }, |error| unsafe { publish_finish_error(publication, error) },
|| unsafe { ensure_finished(finish.callbackContext) }, || unsafe { ensure_finished(finish.callbackContext) },
|| unsafe { release_seq(finish.callbackContext) }, || unsafe { release_seq(finish.callbackContext) },
|| unsafe { release_cctx(finish.callbackContext) }, || unsafe { release_cctx(finish.callbackContext) },
|last_block_size| unsafe { |last_block_size| unsafe { publish_finish_last_block_size(publication, last_block_size) },
publish_last_block_size(finish.callbackContext, last_block_size) |src_size| unsafe { publish_finish_consumed(publication, src_size) },
}, || unsafe { signal_finish(publication) },
|src_size| unsafe { publish_consumed(finish.callbackContext, src_size) },
|| unsafe { signal(finish.callbackContext) },
); );
} }
@@ -6287,9 +6384,9 @@ mod tests {
#[derive(Default)] #[derive(Default)]
struct MockCompressionJob { struct MockCompressionJob {
events: Vec<&'static str>, events: Vec<&'static str>,
errors: Vec<usize>, c_size: usize,
finished: Vec<usize>, consumed_size: usize,
consumed: Vec<usize>, expected_src_size: usize,
} }
struct WaitForLdmTestContext { struct WaitForLdmTestContext {
@@ -6659,25 +6756,6 @@ mod tests {
record_compression_job_finish_event(context, "ensure"); record_compression_job_finish_event(context, "ensure");
} }
unsafe extern "C" fn compression_job_finish_test_error(context: *mut c_void, error: usize) {
unsafe {
let state = &*context.cast::<RefCell<MockCompressionJob>>();
state.borrow_mut().errors.push(error);
}
record_compression_job_finish_event(context, "error");
}
unsafe extern "C" fn compression_job_finish_test_last_block(
context: *mut c_void,
last_block_size: usize,
) {
unsafe {
let state = &*context.cast::<RefCell<MockCompressionJob>>();
state.borrow_mut().finished.push(last_block_size);
}
record_compression_job_finish_event(context, "last-block");
}
unsafe extern "C" fn compression_job_finish_test_release_seq(context: *mut c_void) { unsafe extern "C" fn compression_job_finish_test_release_seq(context: *mut c_void) {
record_compression_job_finish_event(context, "release-seq"); record_compression_job_finish_event(context, "release-seq");
} }
@@ -6686,35 +6764,57 @@ mod tests {
record_compression_job_finish_event(context, "release-cctx"); record_compression_job_finish_event(context, "release-cctx");
} }
unsafe extern "C" fn compression_job_finish_test_consumed( unsafe extern "C" fn compression_job_finish_test_lock(context: *mut c_void) {
context: *mut c_void, record_compression_job_finish_event(context, "lock");
src_size: usize,
) {
unsafe {
let state = &*context.cast::<RefCell<MockCompressionJob>>();
state.borrow_mut().consumed.push(src_size);
}
record_compression_job_finish_event(context, "consumed");
} }
unsafe extern "C" fn compression_job_finish_test_signal(context: *mut c_void) { unsafe extern "C" fn compression_job_finish_test_signal(context: *mut c_void) {
record_compression_job_finish_event(context, "signal"); record_compression_job_finish_event(context, "signal");
} }
unsafe extern "C" fn compression_job_finish_test_unlock(context: *mut c_void) {
record_compression_job_finish_event(context, "unlock");
}
unsafe extern "C" fn compression_job_finish_test_validate(
context: *mut c_void,
src_size: usize,
) {
let state = unsafe { &*context.cast::<RefCell<MockCompressionJob>>() };
assert_eq!(state.borrow().expected_src_size, src_size);
record_compression_job_finish_event(context, "validate");
}
fn compression_job_finish_test_projection( fn compression_job_finish_test_projection(
state: &Rc<RefCell<MockCompressionJob>>, state: &Rc<RefCell<MockCompressionJob>>,
src_size: usize, src_size: usize,
) -> ZSTDMT_compressionJobFinishProjection { ) -> ZSTDMT_compressionJobFinishProjection {
let state_cell = Rc::as_ptr(state);
let state_value = unsafe { (*state_cell).as_ptr() };
let (c_size, consumed) = unsafe {
(*state_value).expected_src_size = src_size;
(
&mut (*state_value).c_size as *mut usize,
&mut (*state_value).consumed_size as *mut usize,
)
};
let callback_context = state_cell.cast_mut().cast();
ZSTDMT_compressionJobFinishProjection { ZSTDMT_compressionJobFinishProjection {
callbackContext: Rc::as_ptr(state).cast_mut().cast(), callbackContext: callback_context,
srcSize: src_size, srcSize: src_size,
ensureFinished: Some(compression_job_finish_test_ensure), ensureFinished: Some(compression_job_finish_test_ensure),
publishError: Some(compression_job_finish_test_error), publication: ZSTDMT_compressionJobFinishPublicationProjection {
publishLastBlockSize: Some(compression_job_finish_test_last_block), callbackContext: callback_context,
cSize: c_size,
consumed,
srcSize: src_size,
lock: Some(compression_job_finish_test_lock),
signal: Some(compression_job_finish_test_signal),
unlock: Some(compression_job_finish_test_unlock),
validateConsumed: Some(compression_job_finish_test_validate),
},
releaseSeq: Some(compression_job_finish_test_release_seq), releaseSeq: Some(compression_job_finish_test_release_seq),
releaseCCtx: Some(compression_job_finish_test_release_cctx), releaseCCtx: Some(compression_job_finish_test_release_cctx),
publishConsumed: Some(compression_job_finish_test_consumed),
signal: Some(compression_job_finish_test_signal),
} }
} }
@@ -6998,14 +7098,18 @@ mod tests {
"ensure", "ensure",
"release-seq", "release-seq",
"release-cctx", "release-cctx",
"last-block", "lock",
"consumed", "unlock",
"validate",
"lock",
"unlock",
"lock",
"signal", "signal",
"unlock",
] ]
); );
assert!(state.errors.is_empty()); assert_eq!(state.c_size, 7);
assert_eq!(state.finished, vec![7]); assert_eq!(state.consumed_size, 19);
assert_eq!(state.consumed, vec![19]);
} }
#[test] #[test]
@@ -7041,17 +7145,21 @@ mod tests {
state.events, state.events,
vec![ vec![
"acquire", "acquire",
"error", "lock",
"unlock",
"ensure", "ensure",
"release-seq", "release-seq",
"release-cctx", "release-cctx",
"consumed", "validate",
"lock",
"unlock",
"lock",
"signal", "signal",
"unlock",
] ]
); );
assert_eq!(state.errors, vec![expected_error]); assert_eq!(state.c_size, expected_error);
assert!(state.finished.is_empty()); assert_eq!(state.consumed_size, 11);
assert_eq!(state.consumed, vec![11]);
} }
#[test] #[test]
@@ -7324,17 +7432,21 @@ mod tests {
"apply", "apply",
"header", "header",
"compress", "compress",
"error", "lock",
"unlock",
"ensure", "ensure",
"release-seq", "release-seq",
"release-cctx", "release-cctx",
"consumed", "validate",
"lock",
"unlock",
"lock",
"signal", "signal",
"unlock",
] ]
); );
assert_eq!(state.errors, vec![expected_error]); assert_eq!(state.c_size, expected_error);
assert!(state.finished.is_empty()); assert_eq!(state.consumed_size, 23);
assert_eq!(state.consumed, vec![23]);
} }
fn init_projection() -> ZSTDMT_initCStreamProjection { fn init_projection() -> ZSTDMT_initCStreamProjection {