From 81805bf643242b8643e99d3bd521234275fc8e84 Mon Sep 17 00:00:00 2001 From: ddidderr Date: Mon, 20 Jul 2026 16:20:16 +0200 Subject: [PATCH] refactor(cli): move zstd status classification into Rust The zstd compression stream already runs its scheduling and accounting loop in Rust, but the C callback still owned the result-status switch that selected success, codec failure, incomplete input, or invalid projection handling. Move that status-to-diagnostic policy into the Rust ABI module, matching the existing LZMA and LZ4 diagnostic seams. C keeps the zstd-specific error-name lookup, display text, and exception construction, so private codec details and CLI diagnostics remain on the C side and the observable error behavior is unchanged. Unknown statuses retain the projection-error fallback. Test Plan: - `rustfmt +nightly --edition 2021 --check rust/src/fileio_asyncio.rs` -- passed. - `git diff --check` and `git diff --cached --check` -- passed. - Capped GCC syntax-only check of `programs/fileio.c` with all CLI format feature defines -- passed. - Cargo, make, native builds, and large tests were not run per worker OOM rules. --- programs/fileio.c | 24 +++++++++++++++---- rust/src/fileio_asyncio.rs | 47 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 5 deletions(-) diff --git a/programs/fileio.c b/programs/fileio.c index e6047b967..fe8165db6 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -1314,6 +1314,16 @@ enum { FIO_RUST_ZSTD_INVALID_PROJECTION = 3 }; +enum { + FIO_RUST_ZSTD_DIAGNOSTIC_OK = 0, + FIO_RUST_ZSTD_DIAGNOSTIC_COMPRESS_ERROR = 1, + FIO_RUST_ZSTD_DIAGNOSTIC_INCOMPLETE_INPUT = 2, + FIO_RUST_ZSTD_DIAGNOSTIC_INVALID_PROJECTION = 3, + FIO_RUST_ZSTD_DIAGNOSTIC_UNKNOWN = 4 +}; + +int FIO_rust_zstdCompressionDiagnostic(int status); + typedef size_t (*FIO_rust_zstd_read_fill_fn)( void* opaque, size_t requested, const unsigned char** buffer, size_t* loaded); @@ -2741,6 +2751,7 @@ FIO_rust_compressZstdCallback(void* fCtx, void* prefs, void* ress, U64 pledgedSrcSize = ZSTD_CONTENTSIZE_UNKNOWN; size_t zstdResult = 0; int status; + int diagnostic; memset(&context, 0, sizeof(context)); context.fCtx = fCtxPtr; @@ -2801,19 +2812,22 @@ FIO_rust_compressZstdCallback(void* fCtx, void* prefs, void* ress, status = FIO_rust_compressZstdFrame( &projection, srcFileName, srcFileSize, compressionLevel, readsize, &compressedSize, &zstdResult); - switch (status) { - case FIO_RUST_ZSTD_OK: + diagnostic = FIO_rust_zstdCompressionDiagnostic(status); + switch (diagnostic) { + case FIO_RUST_ZSTD_DIAGNOSTIC_OK: return compressedSize; - case FIO_RUST_ZSTD_COMPRESS_ERROR: + case FIO_RUST_ZSTD_DIAGNOSTIC_COMPRESS_ERROR: DISPLAYLEVEL(5, "%s \n", "ZSTD_compressStream2(ress.cctx, &outBuff, &inBuff, directive)"); EXM_THROW(11, "%s", ZSTD_getErrorName(zstdResult)); - case FIO_RUST_ZSTD_INCOMPLETE_INPUT: + case FIO_RUST_ZSTD_DIAGNOSTIC_INCOMPLETE_INPUT: EXM_THROW(27, "Read error : Incomplete read : %llu / %llu B", (unsigned long long)*readsize, (unsigned long long)srcFileSize); + case FIO_RUST_ZSTD_DIAGNOSTIC_INVALID_PROJECTION: + EXM_THROW(11, "zstd compression projection is invalid"); default: - assert(status == FIO_RUST_ZSTD_INVALID_PROJECTION); + assert(diagnostic == FIO_RUST_ZSTD_DIAGNOSTIC_UNKNOWN); EXM_THROW(11, "zstd compression projection is invalid"); } } diff --git a/rust/src/fileio_asyncio.rs b/rust/src/fileio_asyncio.rs index b9a060670..6674b6672 100644 --- a/rust/src/fileio_asyncio.rs +++ b/rust/src/fileio_asyncio.rs @@ -822,6 +822,25 @@ pub const FIO_RUST_ZSTD_COMPRESS_ERROR: c_int = 1; pub const FIO_RUST_ZSTD_INCOMPLETE_INPUT: c_int = 2; pub const FIO_RUST_ZSTD_INVALID_PROJECTION: c_int = 3; +pub const FIO_RUST_ZSTD_DIAGNOSTIC_OK: c_int = 0; +pub const FIO_RUST_ZSTD_DIAGNOSTIC_COMPRESS_ERROR: c_int = 1; +pub const FIO_RUST_ZSTD_DIAGNOSTIC_INCOMPLETE_INPUT: c_int = 2; +pub const FIO_RUST_ZSTD_DIAGNOSTIC_INVALID_PROJECTION: c_int = 3; +pub const FIO_RUST_ZSTD_DIAGNOSTIC_UNKNOWN: c_int = 4; + +/// Classifies zstd compression results while leaving zstd-specific error +/// names and CLI exception text in the C callback. +#[no_mangle] +pub extern "C" fn FIO_rust_zstdCompressionDiagnostic(status: c_int) -> c_int { + match status { + FIO_RUST_ZSTD_OK => FIO_RUST_ZSTD_DIAGNOSTIC_OK, + FIO_RUST_ZSTD_COMPRESS_ERROR => FIO_RUST_ZSTD_DIAGNOSTIC_COMPRESS_ERROR, + FIO_RUST_ZSTD_INCOMPLETE_INPUT => FIO_RUST_ZSTD_DIAGNOSTIC_INCOMPLETE_INPUT, + FIO_RUST_ZSTD_INVALID_PROJECTION => FIO_RUST_ZSTD_DIAGNOSTIC_INVALID_PROJECTION, + _ => FIO_RUST_ZSTD_DIAGNOSTIC_UNKNOWN, + } +} + const FIO_RUST_ZSTD_E_CONTINUE: c_int = 0; const FIO_RUST_ZSTD_E_END: c_int = 2; const UTIL_FILESIZE_UNKNOWN: u64 = u64::MAX; @@ -5321,6 +5340,34 @@ mod tests { } } + #[test] + fn zstd_compression_status_diagnostic_preserves_cli_mapping() { + for (status, diagnostic) in [ + (FIO_RUST_ZSTD_OK, FIO_RUST_ZSTD_DIAGNOSTIC_OK), + ( + FIO_RUST_ZSTD_COMPRESS_ERROR, + FIO_RUST_ZSTD_DIAGNOSTIC_COMPRESS_ERROR, + ), + ( + FIO_RUST_ZSTD_INCOMPLETE_INPUT, + FIO_RUST_ZSTD_DIAGNOSTIC_INCOMPLETE_INPUT, + ), + ( + FIO_RUST_ZSTD_INVALID_PROJECTION, + FIO_RUST_ZSTD_DIAGNOSTIC_INVALID_PROJECTION, + ), + ] { + assert_eq!(FIO_rust_zstdCompressionDiagnostic(status), diagnostic); + } + + for status in [-1, 99] { + assert_eq!( + FIO_rust_zstdCompressionDiagnostic(status), + FIO_RUST_ZSTD_DIAGNOSTIC_UNKNOWN + ); + } + } + const SOURCE_POLICY_STAT: u8 = 1; const SOURCE_POLICY_EXCLUDED: u8 = 2; const SOURCE_POLICY_OPEN: u8 = 3;