diff --git a/programs/fileio.c b/programs/fileio.c index 81b9991d7..8c8e854c2 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -387,6 +387,7 @@ void FIO_rust_freeDict(int dictBufferType, void** dictHandle); int FIO_rust_removeFile(const char* path); int FIO_rust_passThrough(ReadPoolCtx_t* readCtx, WritePoolCtx_t* writeCtx); +void FIO_rust_displayCompressionParameters(const FIO_prefs_t* prefs); #ifdef ZSTD_LZ4COMPRESS int FIO_rust_LZ4_GetBlockSize_FromBlockId(int id); #endif @@ -1944,52 +1945,12 @@ FIO_compressFilename_srcFile(FIO_ctx_t* const fCtx, return result; } -static const char* -checked_index(const char* options[], size_t length, size_t index) { - assert(index < length); - /* Necessary to avoid warnings since -O3 will omit the above `assert` */ - (void) length; - return options[index]; -} - -#define INDEX(options, index) checked_index((options), sizeof(options) / sizeof(char*), (size_t)(index)) - void FIO_displayCompressionParameters(const FIO_prefs_t* prefs) { - static const char* formatOptions[5] = {ZSTD_EXTENSION, GZ_EXTENSION, XZ_EXTENSION, - LZMA_EXTENSION, LZ4_EXTENSION}; - static const char* sparseOptions[3] = {" --no-sparse", "", " --sparse"}; - static const char* checkSumOptions[3] = {" --no-check", "", " --check"}; - static const char* rowMatchFinderOptions[3] = {"", " --no-row-match-finder", " --row-match-finder"}; - static const char* compressLiteralsOptions[3] = {"", " --compress-literals", " --no-compress-literals"}; - assert(g_display_prefs.displayLevel >= 4); - - DISPLAY("--format=%s", formatOptions[prefs->compressionType]); - DISPLAY("%s", INDEX(sparseOptions, prefs->sparseFileSupport)); - DISPLAY("%s", prefs->dictIDFlag ? "" : " --no-dictID"); - DISPLAY("%s", INDEX(checkSumOptions, prefs->checksumFlag)); - DISPLAY(" --block-size=%d", prefs->blockSize); - if (prefs->adaptiveMode) - DISPLAY(" --adapt=min=%d,max=%d", prefs->minAdaptLevel, prefs->maxAdaptLevel); - DISPLAY("%s", INDEX(rowMatchFinderOptions, prefs->useRowMatchFinder)); - DISPLAY("%s", prefs->rsyncable ? " --rsyncable" : ""); - if (prefs->streamSrcSize) - DISPLAY(" --stream-size=%u", (unsigned) prefs->streamSrcSize); - if (prefs->srcSizeHint) - DISPLAY(" --size-hint=%d", prefs->srcSizeHint); - if (prefs->targetCBlockSize) - DISPLAY(" --target-compressed-block-size=%u", (unsigned) prefs->targetCBlockSize); - DISPLAY("%s", INDEX(compressLiteralsOptions, prefs->literalCompressionMode)); - DISPLAY(" --memory=%u", prefs->memLimit ? prefs->memLimit : 128 MB); - DISPLAY(" --threads=%d", prefs->nbWorkers); - DISPLAY("%s", prefs->excludeCompressedFiles ? " --exclude-compressed" : ""); - DISPLAY(" --%scontent-size", prefs->contentSize ? "" : "no-"); - DISPLAY("\n"); + FIO_rust_displayCompressionParameters(prefs); } -#undef INDEX - int FIO_compressFilename(FIO_ctx_t* const fCtx, FIO_prefs_t* const prefs, const char* dstFileName, const char* srcFileName, const char* dictFileName, int compressionLevel, ZSTD_compressionParameters comprParams) diff --git a/rust/src/fileio_prefs.rs b/rust/src/fileio_prefs.rs index f4fa7c732..8b360db44 100644 --- a/rust/src/fileio_prefs.rs +++ b/rust/src/fileio_prefs.rs @@ -712,6 +712,89 @@ fn display(level: c_int, message: &str) { } } +fn checked_option(options: &[&'static str], index: c_int) -> &'static str { + options + .get(index as usize) + .copied() + .unwrap_or_else(|| std::process::abort()) +} + +fn format_compression_parameters(prefs: &FIO_prefs_t) -> String { + let format = checked_option( + &[".zst", ".gz", ".xz", ".lzma", ".lz4"], + prefs.compressionType, + ); + let sparse = checked_option(&[" --no-sparse", "", " --sparse"], prefs.sparseFileSupport); + let checksum = checked_option(&[" --no-check", "", " --check"], prefs.checksumFlag); + let row_match_finder = checked_option( + &["", " --no-row-match-finder", " --row-match-finder"], + prefs.useRowMatchFinder, + ); + let compress_literals = checked_option( + &["", " --compress-literals", " --no-compress-literals"], + prefs.literalCompressionMode, + ); + + let mut result = format!("--format={format}{sparse}"); + if prefs.dictIDFlag == 0 { + result.push_str(" --no-dictID"); + } + result.push_str(checksum); + result.push_str(&format!(" --block-size={}", prefs.blockSize)); + if prefs.adaptiveMode != 0 { + result.push_str(&format!( + " --adapt=min={},max={}", + prefs.minAdaptLevel, prefs.maxAdaptLevel + )); + } + result.push_str(row_match_finder); + if prefs.rsyncable != 0 { + result.push_str(" --rsyncable"); + } + if prefs.streamSrcSize != 0 { + result.push_str(&format!(" --stream-size={}", prefs.streamSrcSize as c_uint)); + } + if prefs.srcSizeHint != 0 { + result.push_str(&format!(" --size-hint={}", prefs.srcSizeHint)); + } + if prefs.targetCBlockSize != 0 { + result.push_str(&format!( + " --target-compressed-block-size={}", + prefs.targetCBlockSize as c_uint + )); + } + result.push_str(compress_literals); + result.push_str(&format!( + " --memory={} --threads={}", + if prefs.memLimit != 0 { + prefs.memLimit + } else { + 128 * 1024 * 1024 + }, + prefs.nbWorkers + )); + if prefs.excludeCompressedFiles != 0 { + result.push_str(" --exclude-compressed"); + } + result.push_str(if prefs.contentSize != 0 { + " --content-size" + } else { + " --no-content-size" + }); + result.push('\n'); + result +} + +/// Rust implementation of the verbose preference summary used by CLI diagnostics. +#[no_mangle] +pub unsafe extern "C" fn FIO_rust_displayCompressionParameters(prefs: *const FIO_prefs_t) { + if prefs.is_null() { + return; + } + let output = format_compression_parameters(unsafe { &*prefs }); + eprint!("{output}"); +} + fn throw(error: c_int, message: &str) -> ! { let enabled = unsafe { (*display_prefs()).displayLevel >= 1 }; if enabled { @@ -2557,6 +2640,38 @@ mod tests { unsafe { FIO_freePreferences(prefs as *const FIO_prefs_t as *mut FIO_prefs_t) }; } + #[test] + fn compression_parameter_format_matches_fileio_c() { + let mut prefs = unsafe { std::mem::zeroed::() }; + prefs.compressionType = FIO_ZSTD_COMPRESSION; + prefs.sparseFileSupport = 2; + prefs.dictIDFlag = 0; + prefs.checksumFlag = 2; + prefs.blockSize = 131_072; + prefs.adaptiveMode = 1; + prefs.minAdaptLevel = 1; + prefs.maxAdaptLevel = 9; + prefs.useRowMatchFinder = 1; + prefs.rsyncable = 1; + prefs.streamSrcSize = 4096; + prefs.srcSizeHint = 8192; + prefs.targetCBlockSize = 16_384; + prefs.literalCompressionMode = 2; + prefs.memLimit = 64 * 1024 * 1024; + prefs.nbWorkers = 3; + prefs.excludeCompressedFiles = 1; + prefs.contentSize = 0; + + assert_eq!( + format_compression_parameters(&prefs), + "--format=.zst --sparse --no-dictID --check --block-size=131072 ".to_owned() + + "--adapt=min=1,max=9 --no-row-match-finder --rsyncable " + + "--stream-size=4096 --size-hint=8192 " + + "--target-compressed-block-size=16384 --no-compress-literals " + + "--memory=67108864 --threads=3 --exclude-compressed --no-content-size\n" + ); + } + #[test] fn context_defaults_and_setters_match_fileio_c() { let ctx = unsafe { FIO_createContext() };