/* * compression.c - LZ4 压缩支持 * * 使用 LZ4 库实现高性能数据压缩,适用于终端数据流。 * LZ4 特点: * - 压缩速度:~500 MB/s * - 解压速度:~1500 MB/s * - 压缩比:约 2:1 到 3:1 */ #include "compression.h" #include "debug.h" #include #include // 检查是否有 LZ4 库 #ifdef HAVE_LZ4 #include #include #define LZ4_AVAILABLE 1 #else // 如果没有 LZ4 库,提供一个简单的回退实现 #define LZ4_AVAILABLE 0 #endif void compression_init(CompressionContext* ctx, CompressionType type, int level) { if (ctx == NULL) return; memset(ctx, 0, sizeof(CompressionContext)); ctx->type = type; ctx->level = level > 0 ? level : 9; // 默认级别 ctx->enabled = (type != COMPRESS_NONE); #if !LZ4_AVAILABLE if (ctx->enabled) { DEBUG_LOG("警告: LZ4 库未编译,压缩功能已禁用"); ctx->enabled = 0; ctx->type = COMPRESS_NONE; } #endif DEBUG_LOG("压缩初始化: type=%d, level=%d, enabled=%d", ctx->type, ctx->level, ctx->enabled); } size_t get_compress_bound(size_t src_size) { #if LZ4_AVAILABLE return LZ4_compressBound(src_size); #else // 无压缩时,输出大小等于输入大小 return src_size; #endif } int compress_data(CompressionContext* ctx, const void* src, size_t src_size, void* dst, size_t dst_capacity, uint32_t* flags) { if (ctx == NULL || src == NULL || dst == NULL || flags == NULL) { return -1; } *flags = 0; // 如果压缩未启用或数据太小,直接复制 if (!ctx->enabled || src_size < COMPRESSION_THRESHOLD || src_size > MAX_COMPRESS_INPUT_SIZE) { if (dst_capacity < src_size) { DEBUG_LOG("compress_data: 缓冲区不足 %zu < %zu", dst_capacity, src_size); return -1; } memcpy(dst, src, src_size); ctx->skip_count++; return (int)src_size; } #if LZ4_AVAILABLE int compressed_size = 0; switch (ctx->type) { case COMPRESS_LZ4: compressed_size = LZ4_compress_default( (const char*)src, (char*)dst, (int)src_size, (int)dst_capacity); break; case COMPRESS_LZ4_HC: compressed_size = LZ4_compress_HC( (const char*)src, (char*)dst, (int)src_size, (int)dst_capacity, ctx->level); break; default: // 不应该到达这里 memcpy(dst, src, src_size); return (int)src_size; } if (compressed_size <= 0) { // 压缩失败,复制原始数据 DEBUG_LOG("压缩失败,使用原始数据"); if (dst_capacity < src_size) { return -1; } memcpy(dst, src, src_size); ctx->skip_count++; return (int)src_size; } // 如果压缩后更大,使用原始数据 if ((size_t)compressed_size >= src_size) { DEBUG_LOG("压缩后更大 (%d >= %zu),使用原始数据", compressed_size, src_size); memcpy(dst, src, src_size); ctx->skip_count++; return (int)src_size; } // 压缩成功 *flags = MSG_FLAG_COMPRESSED | MSG_FLAG_COMPRESS_LZ4; if (ctx->type == COMPRESS_LZ4_HC) { *flags |= MSG_FLAG_COMPRESS_HC; } ctx->bytes_in += src_size; ctx->bytes_out += compressed_size; ctx->compress_count++; DEBUG_LOG("压缩成功: %zu -> %d (%.1f%%)", src_size, compressed_size, (float)compressed_size / src_size * 100); return compressed_size; #else // 无 LZ4 库,直接复制 if (dst_capacity < src_size) { return -1; } memcpy(dst, src, src_size); ctx->skip_count++; return (int)src_size; #endif } int decompress_data(uint32_t flags, const void* src, size_t src_size, void* dst, size_t dst_capacity) { if (src == NULL || dst == NULL) { return -1; } // 如果数据未压缩,直接复制 if (!(flags & MSG_FLAG_COMPRESSED)) { if (dst_capacity < src_size) { DEBUG_LOG("decompress_data: 缓冲区不足 %zu < %zu", dst_capacity, src_size); return -1; } memcpy(dst, src, src_size); return (int)src_size; } #if LZ4_AVAILABLE // 使用 LZ4 解压 if (flags & MSG_FLAG_COMPRESS_LZ4) { int decompressed_size = LZ4_decompress_safe( (const char*)src, (char*)dst, (int)src_size, (int)dst_capacity); if (decompressed_size < 0) { DEBUG_LOG("LZ4 解压失败"); return -1; } DEBUG_LOG("解压成功: %zu -> %d", src_size, decompressed_size); return decompressed_size; } #endif // 不支持的压缩格式或无 LZ4 库 DEBUG_LOG("不支持的压缩格式: flags=0x%x", flags); return -1; } void compression_get_stats(const CompressionContext* ctx, uint64_t* bytes_in, uint64_t* bytes_out, uint64_t* compress_count, uint64_t* skip_count) { if (ctx == NULL) return; if (bytes_in) *bytes_in = ctx->bytes_in; if (bytes_out) *bytes_out = ctx->bytes_out; if (compress_count) *compress_count = ctx->compress_count; if (skip_count) *skip_count = ctx->skip_count; } void compression_reset_stats(CompressionContext* ctx) { if (ctx == NULL) return; ctx->bytes_in = 0; ctx->bytes_out = 0; ctx->compress_count = 0; ctx->skip_count = 0; } int compression_get_ratio(const CompressionContext* ctx) { if (ctx == NULL || ctx->bytes_in == 0) { return 100; // 无压缩 } return (int)(ctx->bytes_out * 100 / ctx->bytes_in); }