Add compression support to backup workflow

BackupScheduler Enhancement:
- copy_file() now compresses files using ZSTD or LZ4
- min_size threshold: 1024 bytes (smaller files not compressed)
- compression level: 3 (balanced speed/compression)

BackupConfigResponse Updated:
- Added compress, encrypt, include_checksums fields
- compress: 'none' | 'lz4' | 'zstd'
- Default: 'zstd'

REST API Enhancement:
- GET /api/v2/backup/config returns full config
- POST /api/v2/backup/config accepts compression settings

Test Results:
- Set compress='lz4':  Config updated
- Set compress='zstd':  Config updated
- Compression applied via run_backup() (scheduled backup)

Note: Direct create_snapshot API doesn't use compression
(scheduler.run_backup() is the primary backup mechanism)

Build: 495 tests pass
This commit is contained in:
Warren
2026-06-24 04:14:24 +08:00
parent 55caeabd94
commit 2d8e9049b0
3 changed files with 34 additions and 4 deletions

View File

@@ -2750,6 +2750,9 @@ pub struct BackupConfigResponse {
pub interval_hours: u64,
pub max_snapshots: usize,
pub auto_cleanup: bool,
pub compress: String,
pub encrypt: bool,
pub include_checksums: bool,
}
#[derive(Debug, Serialize, Deserialize)]
@@ -2790,24 +2793,37 @@ async fn get_backup_stats_handler() -> Json<BackupStatsResponse> {
async fn get_backup_config_handler() -> Json<BackupConfigResponse> {
let scheduler = BACKUP_SCHEDULER.lock().unwrap();
let config = scheduler.get_config();
let compress_name = match config.compress {
crate::vfs::VfsCompression::None => "none",
crate::vfs::VfsCompression::Lz4 => "lz4",
crate::vfs::VfsCompression::Zstd => "zstd",
};
Json(BackupConfigResponse {
enabled: config.enabled,
interval_hours: config.interval_hours,
max_snapshots: config.max_snapshots,
auto_cleanup: config.auto_cleanup,
compress: compress_name.to_string(),
encrypt: config.encrypt,
include_checksums: config.include_checksums,
})
}
async fn set_backup_config_handler(Json(config): Json<BackupConfigResponse>) -> Json<serde_json::Value> {
let mut scheduler = BACKUP_SCHEDULER.lock().unwrap();
let compress = match config.compress.as_str() {
"lz4" => crate::vfs::VfsCompression::Lz4,
"zstd" => crate::vfs::VfsCompression::Zstd,
_ => crate::vfs::VfsCompression::None,
};
let new_config = BackupScheduleConfig {
enabled: config.enabled,
interval_hours: config.interval_hours,
max_snapshots: config.max_snapshots,
auto_cleanup: config.auto_cleanup,
compress: scheduler.get_config().compress.clone(),
encrypt: scheduler.get_config().encrypt,
include_checksums: scheduler.get_config().include_checksums,
compress,
encrypt: config.encrypt,
include_checksums: config.include_checksums,
};
scheduler.set_config(new_config);
Json(serde_json::json!({"success": true, "message": "Backup config updated"}))

View File

@@ -180,14 +180,28 @@ impl BackupScheduler {
}
fn copy_file(&self, src: &PathBuf, dst: &PathBuf) -> Result<(), VfsError> {
use super::compression::Compressor;
use super::VfsCompressionConfig;
let mut src_file = self.backend.open_file(src, &super::open_flags::OpenFlags::new().read())?;
let data = src_file.read_all()?;
let final_data = if self.config.compress != super::VfsCompression::None {
let compressor = Compressor::new(VfsCompressionConfig {
algorithm: self.config.compress.clone(),
min_size: 1024,
level: 3,
});
compressor.compress(&data)?
} else {
data
};
let mut dst_file = self.backend.open_file(
dst,
&super::open_flags::OpenFlags::new().write().create().truncate(),
)?;
dst_file.write_all(&data)?;
dst_file.write_all(&final_data)?;
dst_file.flush()?;
Ok(())