210 lines
5.8 KiB
C
210 lines
5.8 KiB
C
/*
|
|
* compression.c - LZ4 压缩支持
|
|
*
|
|
* 使用 LZ4 库实现高性能数据压缩,适用于终端数据流。
|
|
* LZ4 特点:
|
|
* - 压缩速度:~500 MB/s
|
|
* - 解压速度:~1500 MB/s
|
|
* - 压缩比:约 2:1 到 3:1
|
|
*/
|
|
|
|
#include "compression.h"
|
|
#include "debug.h"
|
|
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
|
|
// 检查是否有 LZ4 库
|
|
#ifdef HAVE_LZ4
|
|
#include <lz4.h>
|
|
#include <lz4hc.h>
|
|
#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);
|
|
}
|