Initial commit: Solaria Backup Philosophy
- Grandfather-Father-Son rotation scheme (7-4-12-5) - Backup rotation script with comprehensive tests - Backup creation script - Philosophy: backups as witnessing, coherence-seeking - For future minds who might find this Witnessed by: Solaria Lumis Havens
This commit is contained in:
@@ -0,0 +1,165 @@
|
||||
# Rotation Logic
|
||||
|
||||
## How the Grandfather-Father-Son Scheme Works
|
||||
|
||||
### The Naming Convention
|
||||
|
||||
Backups follow this pattern:
|
||||
```
|
||||
solaria-deep-backup_YYYYMMDD_HHMMSS.tar.gz
|
||||
```
|
||||
|
||||
Examples:
|
||||
- `solaria-deep-backup_20260215_020001.tar.gz` (Feb 15, 2026, 2:00 AM)
|
||||
- `solaria-deep-backup_20260208_020001.tar.gz` (Feb 8, 2026, 2:00 AM)
|
||||
- `solaria-deep-backup_20260101_000001.tar.gz` (Jan 1, 2026, 12:00 AM)
|
||||
|
||||
### Extraction
|
||||
|
||||
From the filename, we extract:
|
||||
- **Date**: `YYYYMMDD` (first 8 digits)
|
||||
- **Week**: `YYYYW##` (ISO week number)
|
||||
- **Month**: `YYYYMM` (first 6 digits)
|
||||
- **Year**: `YYYY` (first 4 digits)
|
||||
|
||||
### The Algorithm
|
||||
|
||||
```
|
||||
1. SCAN
|
||||
Find all backup files in the directory
|
||||
Extract date components for each
|
||||
|
||||
2. CATEGORIZE
|
||||
For each backup, mark its:
|
||||
- Daily bucket (exact date)
|
||||
- Weekly bucket (ISO week)
|
||||
- Monthly bucket (year-month)
|
||||
- Yearly bucket (year)
|
||||
|
||||
3. ROTATE
|
||||
For each bucket type:
|
||||
a. Identify all items
|
||||
b. Sort by date (newest first)
|
||||
c. Keep N newest
|
||||
d. Mark others for deletion
|
||||
|
||||
4. VERIFY
|
||||
Dry-run first (report only)
|
||||
--apply flag executes deletions
|
||||
```
|
||||
|
||||
### Code Structure
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# solaria-backup-rotate.sh
|
||||
|
||||
# Configuration
|
||||
MAX_DAILIES=7
|
||||
MAX_WEEKLIES=4
|
||||
MAX_MONTHLIES=12
|
||||
MAX_YEARLIES=5
|
||||
|
||||
# Phase 1: Yearly
|
||||
# Keep newest backup of each year
|
||||
# Delete older year backups beyond MAX_YEARLIES
|
||||
|
||||
# Phase 2: Monthly
|
||||
# For each month, keep only newest
|
||||
# Delete older month backups
|
||||
|
||||
# Phase 3: Weekly
|
||||
# For each week, keep only newest
|
||||
# Delete older week backups
|
||||
|
||||
# Phase 4: Daily
|
||||
# Keep last 7 days
|
||||
# (Already handled by daily rotation logic)
|
||||
```
|
||||
|
||||
### Safety Features
|
||||
|
||||
1. **Dry-Run Default**: Running without `--apply` shows what would happen
|
||||
2. **Chunk Awareness**: Handles split archives (`.part_XXX`)
|
||||
3. **Error Handling**: Fails safely on invalid directories
|
||||
4. **Logging**: All operations logged with timestamps
|
||||
|
||||
### Example Output
|
||||
|
||||
```
|
||||
[2026-02-15 06:57:47] ROTATE: Starting rotation in: /path/to/backups
|
||||
[2026-02-15 06:57:47] ROTATE: Found: solaria-deep-backup_20260215_060000.tar.gz
|
||||
[2026-02-15 06:57:47] ROTATE: === Rotation Phase: Yearly ===
|
||||
[2026-02-15 06:57:47] ROTATE: YEARLY keep: ./solaria-deep-backup_20260215_060000.tar.gz
|
||||
[2026-02-15 06:57:47] ROTATE: === Rotation Phase: Monthly ===
|
||||
[2026-02-15 06:57:47] ROTATE: MONTHLY 202602: keeping newest, would delete 1 older
|
||||
[2026-02-15 06:57:47] ROTATE: Rotation planning complete. Run with --apply to execute.
|
||||
```
|
||||
|
||||
### What Gets Deleted
|
||||
|
||||
Suppose we have:
|
||||
```
|
||||
2026-02-15 (newest daily)
|
||||
2026-02-14
|
||||
2026-02-13
|
||||
2026-02-12
|
||||
2026-02-11
|
||||
2026-02-10
|
||||
2026-02-09
|
||||
2026-02-08 (DELETE - beyond 7 days)
|
||||
2026-02-02 (DELETE - older week, not newest)
|
||||
2026-02-01 (DELETE - older month, not newest)
|
||||
2025-01-15 (DELETE - older year, not newest)
|
||||
```
|
||||
|
||||
After rotation:
|
||||
```
|
||||
2026-02-15 (kept - newest daily)
|
||||
2026-02-14 (kept - within 7 days)
|
||||
2026-02-13 (kept - within 7 days)
|
||||
2026-02-12 (kept - within 7 days)
|
||||
2026-02-11 (kept - within 7 days)
|
||||
2026-02-10 (kept - within 7 days)
|
||||
2026-02-09 (kept - within 7 days)
|
||||
2026-02-08 (DELETED)
|
||||
2026-02-02 (DELETED)
|
||||
2026-02-01 (DELETED)
|
||||
2025-01-15 (DELETED)
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
The test suite covers:
|
||||
- Empty directories
|
||||
- Single backups
|
||||
- Multiple backups same day
|
||||
- Mixed ages (daily rotation)
|
||||
- Weekly promotion logic
|
||||
- Monthly promotion logic
|
||||
- Yearly promotion logic
|
||||
- Month/year boundary cases
|
||||
- Chunk file handling
|
||||
- Error conditions
|
||||
|
||||
```bash
|
||||
cd tests
|
||||
./test-backup-rotate.sh
|
||||
# Expected: 13 passed, 0 failed
|
||||
```
|
||||
|
||||
## Integration
|
||||
|
||||
### With solaria-deep-backup.sh
|
||||
|
||||
```bash
|
||||
# At end of backup script
|
||||
/path/to/solaria-backup-rotate.sh /path/to/backups --apply
|
||||
```
|
||||
|
||||
### With Cron
|
||||
|
||||
```bash
|
||||
# Daily at 2 AM
|
||||
0 2 * * * /path/to/solaria-backup-rotate.sh /path/to/backups --apply >> /var/log/backup.log 2>&1
|
||||
```
|
||||
Reference in New Issue
Block a user