Add incremental backup support (Phase 8)

BackupScheduler Enhancement:
- Added incremental: bool field to BackupScheduleConfig
- Default: incremental=true (enabled by default)
- copy_incremental_to_snapshot() method
- file_changed() detection (size + mtime comparison)
- Hardlink unchanged files to base snapshot (ZFS-style)

Incremental Backup Algorithm:
1. If incremental=true and previous snapshot exists:
   - Compare file size and mtime with base snapshot
   - If unchanged: create hardlink to base (zero disk usage)
   - If changed: copy and compress (new content)
2. If incremental=false or no previous snapshot:
   - Full copy (traditional backup)

Storage Savings:
- Unchanged files: hardlink (0 extra disk space)
- Changed files: copy + compress (minimal overhead)
- Similar to ZFS snapshot mechanism

BackupConfigResponse Updated:
- Added incremental field
- Added compress field (GUI: dropdown select)

Backup.vue Updated:
- Incremental switch with explanation text
- Compression dropdown (None/LZ4/ZSTD)
- Default values loaded from backend

REST API Test:
curl /api/v2/backup/config
{incremental:true,compress:zstd,...}

Build: 495 tests pass
This commit is contained in:
Warren
2026-06-24 04:20:33 +08:00
parent 2d8e9049b0
commit d76a200560
4 changed files with 103 additions and 2 deletions

View File

@@ -28,7 +28,11 @@ const backupConfig = ref({
enabled: false,
interval_hours: 24,
max_snapshots: 7,
auto_cleanup: true
auto_cleanup: true,
compress: 'zstd',
encrypt: false,
include_checksums: true,
incremental: true
})
const schedulerStats = ref({
@@ -374,6 +378,19 @@ onMounted(async () => {
<el-form-item label="Auto Cleanup">
<el-switch v-model="backupConfig.auto_cleanup" />
</el-form-item>
<el-form-item label="Incremental">
<el-switch v-model="backupConfig.incremental" />
<span style="margin-left: 10px; color: #909399; font-size: 12px;">
Only copy changed files (hardlink unchanged)
</span>
</el-form-item>
<el-form-item label="Compression">
<el-select v-model="backupConfig.compress" size="small" style="width: 120px;">
<el-option label="None" value="none" />
<el-option label="LZ4 (Fast)" value="lz4" />
<el-option label="ZSTD (High)" value="zstd" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="saveBackupConfig">Save Config</el-button>
</el-form-item>