Стабилизация на storage слоя — 6 фази
CI / test (push) Has been cancelled
CI / verify (push) Has been cancelled
Clients CI / build-server (push) Has been cancelled
Clients CI / test-python (push) Has been cancelled
Clients CI / test-javascript (push) Has been cancelled
Clients CI / test-nim (push) Has been cancelled
Clients CI / test-rust (push) Has been cancelled
CI / test (push) Has been cancelled
CI / verify (push) Has been cancelled
Clients CI / build-server (push) Has been cancelled
Clients CI / test-python (push) Has been cancelled
Clients CI / test-javascript (push) Has been cancelled
Clients CI / test-nim (push) Has been cancelled
Clients CI / test-rust (push) Has been cancelled
Фаза 1: SSTable Integrity - SSTable v3 формат с CRC32 footer (data/index/bloom CRC) - Нов модул storage/crc32.nim (zero-dep, IEEE 802.3) - verifySSTable() — проверка на magic, version, CRC - loadSSTable strict mode — отхвърля корумпирани файлове - newLSMTree логва [WARN] при corrupt SSTables Фаза 2: baradb repair - Нов модул tools/repair.nim - Сканира SSTables, проверява CRC, премества битите в corrupt/ - WAL replay (CrashRecovery) за възстановяване на данни - CLI: ./baradadb repair --data-dir=... [--dry-run] Фаза 3: MANIFEST File - Atomic write MANIFEST (tmp + rename) - newLSMTree зарежда от MANIFEST, fallback към walkDir - checkStorageConsistency() — orphan/missing detection - flushUnsafe и compaction записват MANIFEST Фаза 4: WAL Rotation & Incremental Backup - WAL segment rotation при 64MB (wal_archive/wal.000NNN.log) - maybeRotate() на всеки 1000 записа + при flush - backup incremental — архивира MANIFEST + SSTables + WAL - CRC verification на SSTables преди архивиране Фаза 5: Online Consistent Backup - checkpoint() — freeze memtable + flush + WAL rotate - ./baradadb checkpoint — offline consistent snapshot - backup --online — checkpoint + incremental backup Фаза 6: SSTable Version Migration - SSTable.fileVersion поле - listLegacySSTables() — намира v1/v2 файлове - migrateSSTable() — пренаписва към v3 (tmp + rename) - ./baradadb migrate [--dry-run] — offline migration Документация: - Обновени docs/en/backup.md, docs/bg/backup.md - Обновени docs/en/storage.md, docs/bg/storage.md - Добавени тестове в tests/test_all.nim
This commit is contained in:
+159
-143
@@ -1,198 +1,214 @@
|
||||
# Backup и Възстановяване
|
||||
|
||||
## Online Snapshots
|
||||
BaraDB предоставя няколко стратегии за backup — от пълни snapshot-ове до инкрементални и online consistent backups.
|
||||
|
||||
BaraDB поддържа online snapshots без спиране на сървъра. Snapshot-ът заснема консистентен изглед към момент във времето чрез MVCC.
|
||||
## Архитектура
|
||||
|
||||
### Създаване на Snapshot
|
||||
|
||||
```nim
|
||||
import barabadb/core/backup
|
||||
|
||||
var bm = newBackupManager()
|
||||
bm.createSnapshot("/backup/baradb_2025-01-15")
|
||||
```
|
||||
┌─────────────────────────────────────────┐
|
||||
│ Data Directory │
|
||||
│ ├── MANIFEST (atomic catalog) │
|
||||
│ ├── sstables/ (SSTable v3 CRC) │
|
||||
│ │ ├── 1.sst │
|
||||
│ │ └── 2.sst │
|
||||
│ └── wal/ │
|
||||
│ ├── wal.log (активен сегмент)│
|
||||
│ └── wal_archive/ (ротирани сегменти
|
||||
└─────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Чрез CLI
|
||||
## SSTable Integrity (v3 CRC Footer)
|
||||
|
||||
Всеки SSTable файл, записан от BaraDB, включва CRC32 footer:
|
||||
|
||||
```
|
||||
[Header] 36 байта
|
||||
magic, version(3), entryCount, level,
|
||||
indexOffset, bloomOffset, footerOffset
|
||||
[Data Block]
|
||||
[Index Block]
|
||||
[Bloom Block]
|
||||
[Footer] 16 байта
|
||||
dataCrc32, indexCrc32, bloomCrc32, reserved
|
||||
```
|
||||
|
||||
Това позволява независима проверка на всеки SSTable:
|
||||
|
||||
```bash
|
||||
./build/baradadb --snapshot --output=/backup/snapshot.db
|
||||
# Чрез Nim API
|
||||
import barabadb/storage/lsm
|
||||
let (ok, msg) = verifySSTable("data/sstables/1.sst")
|
||||
```
|
||||
|
||||
### Чрез HTTP API
|
||||
## Storage Repair (`baradb repair`)
|
||||
|
||||
При съмнение за повреда, пуснете repair инструмента:
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:9470/api/backup \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"destination": "/backup/snapshot.db"}'
|
||||
# Dry run — само преглед
|
||||
./build/baradadb repair --data-dir=./data --dry-run
|
||||
|
||||
# Пълен ремонт — проверка, преместване на битите файлове, WAL replay
|
||||
./build/baradadb repair --data-dir=./data
|
||||
```
|
||||
|
||||
### Автоматизирани Backups
|
||||
**Какво прави repair:**
|
||||
1. Сканира всички `sstables/*.sst` и проверява CRC
|
||||
2. Премества корумпираните SSTables в `data/corrupt/`
|
||||
3. Пуска WAL replay за възстановяване на незаписани данни
|
||||
4. Докладва резултати
|
||||
|
||||
Използвайте cron за планирани backups:
|
||||
## MANIFEST Каталог
|
||||
|
||||
Файлът `MANIFEST` е единственият източник на истина за активните SSTables. Обновява се атомично при всеки flush и compaction.
|
||||
|
||||
```json
|
||||
{
|
||||
"version": 1,
|
||||
"sequence": 42,
|
||||
"createdAt": 1779103266,
|
||||
"sstables": [
|
||||
{"id": 1, "path": "sstables/1.sst", "level": 0, "minKey": "a", "maxKey": "z", "entryCount": 100}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Предимства:
|
||||
- **Консистентен изглед** — няма orphan SSTables след crash
|
||||
- **Бързо стартиране** — зарежда от MANIFEST вместо scan на директория
|
||||
- **Откриване на orphans** — `checkStorageConsistency()` докладва излишни/липсващи файлове
|
||||
|
||||
## WAL Ротация
|
||||
|
||||
Write-Ahead Log се ротира при достигане на 64MB:
|
||||
|
||||
```
|
||||
wal/wal.log → активен сегмент
|
||||
wal/wal_archive/
|
||||
├── wal.000001.log
|
||||
├── wal.000002.log
|
||||
└── wal.000003.log
|
||||
```
|
||||
|
||||
Ротацията се случва:
|
||||
- На всеки 1000 WAL записа (лека проверка на размер)
|
||||
- При всеки `flush` / `checkpoint`
|
||||
|
||||
## Checkpoint
|
||||
|
||||
Checkpoint създава консистентна граница на storage без спиране на сървъра:
|
||||
|
||||
```bash
|
||||
# Ежедневен snapshot в 2 сутринта
|
||||
0 2 * * * /usr/local/bin/baradadb --snapshot --output=/backup/baradb_$(date +\%Y\%m\%d).db
|
||||
|
||||
# Запазване на последните 7 дни
|
||||
find /backup -name "baradb_*.db" -mtime +7 -delete
|
||||
./build/baradadb checkpoint --data-dir=./data
|
||||
```
|
||||
|
||||
## Point-in-Time Recovery (PITR)
|
||||
**Как работи:**
|
||||
1. Freeze на memtable (swap към immutable, нов memtable за writes)
|
||||
2. Flush на frozen memtable към SSTable
|
||||
3. Ротация на WAL
|
||||
4. Запис на MANIFEST
|
||||
|
||||
BaraDB използва Write-Ahead Log (WAL) за възстановяване до момент във времето.
|
||||
Freeze-ът отнема **< 1ms**; flush-ът продължава паралелно с writes.
|
||||
|
||||
### WAL Архивиране
|
||||
## Backup Команди
|
||||
|
||||
Включете непрекъснато WAL архивиране:
|
||||
### Пълен Backup (tar.gz)
|
||||
|
||||
```bash
|
||||
BARADB_WAL_ARCHIVE_DIR=/backup/wal \
|
||||
BARADB_WAL_ARCHIVE_INTERVAL_MS=60000 \
|
||||
./build/baradadb
|
||||
./build/backup backup --data-dir=./data --output=backup_$(date +%s).tar.gz
|
||||
```
|
||||
|
||||
### Възстановяване от Checkpoint + WAL
|
||||
Архивира цялата data директория.
|
||||
|
||||
### Инкрементален Backup
|
||||
|
||||
```bash
|
||||
# Възстановяване от snapshot
|
||||
./build/baradadb --recover \
|
||||
--checkpoint=/backup/snapshot.db \
|
||||
--wal-dir=/backup/wal
|
||||
|
||||
# Възстановяване до конкретен LSN
|
||||
./build/baradadb --recover \
|
||||
--checkpoint=/backup/snapshot.db \
|
||||
--wal-dir=/backup/wal \
|
||||
--target-lsn=15420
|
||||
|
||||
# Възстановяване до конкретно време
|
||||
./build/baradadb --recover \
|
||||
--checkpoint=/backup/snapshot.db \
|
||||
--wal-dir=/backup/wal \
|
||||
--target-time="2025-01-15T10:30:00Z"
|
||||
./build/backup incremental --data-dir=./data --output=backup_inc_$(date +%s).tar.gz
|
||||
```
|
||||
|
||||
### Възстановяване чрез SQL
|
||||
Включва само:
|
||||
- `MANIFEST`
|
||||
- Активни SSTables (от MANIFEST)
|
||||
- Текущ WAL (`wal/wal.log`)
|
||||
- WAL архив (`wal/wal_archive/*.log`)
|
||||
|
||||
Можете също да възстановявате директно чрез BaraQL:
|
||||
Всички SSTables се **проверяват с CRC** преди архивиране.
|
||||
|
||||
```sql
|
||||
RECOVER TO TIMESTAMP '2026-05-07T12:00:00';
|
||||
```
|
||||
|
||||
### Инкрементални Backups
|
||||
|
||||
Инкременталните backups копират само променени SSTables:
|
||||
### Online Consistent Backup
|
||||
|
||||
```bash
|
||||
./build/baradadb --backup-incremental \
|
||||
--last-backup=/backup/previous \
|
||||
--output=/backup/incremental_$(date +%Y%m%d)
|
||||
./build/baradadb backup --online --output=backup_online_$(date +%s).tar.gz
|
||||
```
|
||||
|
||||
## Репликация като Backup
|
||||
Еквивалентно на:
|
||||
1. `checkpoint`
|
||||
2. `incremental backup`
|
||||
|
||||
За непрекъсната защита използвайте streaming репликация:
|
||||
**Безопасно за пускане, когато сървърът е спрян.** Ако сървърът работи, използвайте `backup incremental`.
|
||||
|
||||
### Primary
|
||||
## Миграция на SSTable Версии
|
||||
|
||||
Ако имате legacy v1/v2 SSTables, мигрирайте ги към v3:
|
||||
|
||||
```bash
|
||||
BARADB_REPLICATION_ENABLED=true \
|
||||
BARADB_REPLICATION_MODE=async \
|
||||
./build/baradadb
|
||||
# Преглед
|
||||
./build/baradadb migrate --data-dir=./data --dry-run
|
||||
|
||||
# Миграция
|
||||
./build/baradadb migrate --data-dir=./data
|
||||
```
|
||||
|
||||
### Replica
|
||||
Миграцията пренаписва всеки legacy SSTable в текущия v3 формат (CRC footer) и обновява MANIFEST.
|
||||
|
||||
## Процедури за Възстановяване
|
||||
|
||||
### Сценарий 1: Открит е Корумпиран SSTable
|
||||
|
||||
```bash
|
||||
BARADB_REPLICATION_ENABLED=true \
|
||||
BARADB_REPLICATION_PRIMARY=primary:9472 \
|
||||
./build/baradadb
|
||||
```
|
||||
|
||||
## Disaster Recovery
|
||||
|
||||
### Процедури за Възстановяване
|
||||
|
||||
#### Сценарий 1: Повреда на Единичен Файл
|
||||
|
||||
```bash
|
||||
# Идентифициране на повреден SSTable от логовете
|
||||
# Възстановяване на конкретен SSTable от backup
|
||||
cp /backup/sstables/000012.sst ./data/sstables/
|
||||
|
||||
# Възстановяване на индекса
|
||||
./build/baradadb --rebuild-index
|
||||
```
|
||||
|
||||
#### Сценарий 2: Пълна Загуба на Данни
|
||||
|
||||
```bash
|
||||
# 1. Възстановяване на последния snapshot
|
||||
cp /backup/snapshot.db ./data/
|
||||
|
||||
# 2. Преиграване на WAL
|
||||
./build/baradadb --recover --wal-dir=/backup/wal
|
||||
|
||||
# 3. Проверка
|
||||
curl http://localhost:9470/health
|
||||
```
|
||||
|
||||
#### Сценарий 3: Отказ на Възел в Клъстер
|
||||
|
||||
```bash
|
||||
# За Raft клъстери, просто стартирайте нов възел
|
||||
BARADB_RAFT_NODE_ID=newnode \
|
||||
BARADB_RAFT_PEERS=node1:9001,node2:9001 \
|
||||
./build/baradadb
|
||||
|
||||
# Новият възел ще навакса чрез Raft log репликация
|
||||
```
|
||||
|
||||
## Верификация на Backup
|
||||
|
||||
Винаги проверявайте backups:
|
||||
|
||||
```bash
|
||||
# Възстановяване във временна директория
|
||||
./build/baradadb --recover \
|
||||
--checkpoint=/backup/snapshot.db \
|
||||
--data-dir=/tmp/verify_data
|
||||
# Repair премества битите файлове и пуска WAL replay
|
||||
./build/baradadb repair --data-dir=./data
|
||||
|
||||
# Проверка на консистентност
|
||||
curl http://localhost:9470/api/admin/check
|
||||
./build/baradadb repair --data-dir=./data --dry-run
|
||||
```
|
||||
|
||||
### Сценарий 2: Възстановяване от Backup
|
||||
|
||||
```bash
|
||||
# Спиране на сървъра
|
||||
# Разархивиране на backup
|
||||
tar -xzf backup_1234567890.tar.gz -C ./data
|
||||
|
||||
# Рестарт — LSMTree зарежда от MANIFEST
|
||||
./build/baradadb
|
||||
```
|
||||
|
||||
### Сценарий 3: Пълна Загуба на Данни
|
||||
|
||||
```bash
|
||||
# 1. Разархивиране на последния backup
|
||||
tar -xzf backup_latest.tar.gz -C ./data
|
||||
|
||||
# 2. Repair за replay на наличния WAL
|
||||
./build/baradadb repair --data-dir=./data
|
||||
|
||||
# 3. Стартиране на сървъра
|
||||
./build/baradadb
|
||||
```
|
||||
|
||||
## Изисквания за Съхранение
|
||||
|
||||
| Тип Backup | Размер | Честота | Задържане |
|
||||
|------------|--------|---------|-----------|
|
||||
| Пълен snapshot | ~1× размер на данните | Ежедневно | 7 дни |
|
||||
| Инкрементален | ~0.1× размер на данните | На всеки час | 24 часа |
|
||||
| WAL архив | ~0.05× размер на данните / ден | Непрекъснато | 30 дни |
|
||||
| Пълен tar.gz | ~1× размер на данните | Седмично | 4 седмици |
|
||||
| Инкрементален | ~0.05× размер на данните | На всеки час | 24 часа |
|
||||
| WAL архив | ~0.02× размер на данните / ден | Непрекъснато | 7 дни |
|
||||
|
||||
## Най-добри Практики
|
||||
|
||||
1. **Тествайте възстановяването редовно** — Backup, който не може да бъде възстановен, е безполезен
|
||||
2. **Съхранявайте backups извън локацията** — Използвайте S3, GCS или Azure Blob
|
||||
3. **Криптирайте backups** — Използвайте `gpg` или криптиране на ниво ОС
|
||||
4. **Мониторирайте backup задачите** — Алармирайте при неуспешни backups
|
||||
5. **Документирайте RTO/RPO** — Знайте целите си за време и точка на възстановяване
|
||||
|
||||
### Качване на Backup в Облак
|
||||
|
||||
```bash
|
||||
# Качване в S3
|
||||
aws s3 cp /backup/snapshot.db s3://my-bucket/baradb/
|
||||
|
||||
# Качване в GCS
|
||||
gsutil cp /backup/snapshot.db gs://my-bucket/baradb/
|
||||
|
||||
# Качване в Azure
|
||||
az storage blob upload \
|
||||
--container-name backups \
|
||||
--file /backup/snapshot.db \
|
||||
--name baradb/snapshot.db
|
||||
```
|
||||
1. **Пускайте repair след некоректно спиране** — `./build/baradadb repair`
|
||||
2. **Мигрирайте legacy SSTables** — `./build/baradadb migrate`
|
||||
3. **Тествайте възстановяването редовно** — Backup, който не може да бъде възстановен, е безполезен
|
||||
4. **Използвайте incremental + checkpoint** — За чести консистентни snapshot-ове
|
||||
5. **Съхранявайте backups извън локацията** — S3, GCS или друг сървър
|
||||
6. **Следете MANIFEST sequence** — Трябва да расте монотонно с flush-овете
|
||||
|
||||
+101
-7
@@ -21,11 +21,105 @@ db.close()
|
||||
|
||||
- **MemTable**: В-памет сортиран буфер
|
||||
- **WAL**: Write-ahead log за устойчивост
|
||||
- **SSTable**: Сортирани string таблици на диска
|
||||
- **SSTable**: Сортирани string таблици на диска (v3 с CRC footer)
|
||||
- **Bloom Filter**: Вероятностна проверка за принадлежност
|
||||
- **Compaction**: Size-tiered стратегия с управление на нива
|
||||
- **MANIFEST**: Атомичен каталог на активните SSTables
|
||||
- **Page Cache**: LRU кеш с проследяване на hit rate
|
||||
|
||||
### SSTable Формат (v3)
|
||||
|
||||
```
|
||||
[Header] 36 байта
|
||||
magic: uint32 (0x53535442 = "SSTB")
|
||||
version: uint32 (3 = текуща)
|
||||
entryCount: uint32
|
||||
level: uint32
|
||||
indexOffset: uint64
|
||||
bloomOffset: uint64
|
||||
footerOffset: uint64
|
||||
|
||||
[Data Block]
|
||||
keyLen: uint32
|
||||
key: bytes[keyLen]
|
||||
valueLen: uint32
|
||||
value: bytes[valueLen]
|
||||
timestamp: uint64
|
||||
deleted: uint8
|
||||
|
||||
[Index Block]
|
||||
keyLen: uint32
|
||||
key: bytes[keyLen]
|
||||
dataOffset: uint64
|
||||
|
||||
[Bloom Filter Block]
|
||||
bloomSize: uint32
|
||||
bloomData: bytes[bloomSize]
|
||||
|
||||
[Footer] 16 байта
|
||||
dataCrc32: uint32 (CRC32 на Data Block)
|
||||
indexCrc32: uint32 (CRC32 на Index Block)
|
||||
bloomCrc32: uint32 (CRC32 на Bloom Block)
|
||||
reserved: uint32 (трябва да е 0)
|
||||
```
|
||||
|
||||
CRC footer-ът позволява независима проверка на всеки SSTable файл чрез `verifySSTable(path)`.
|
||||
|
||||
### MANIFEST Каталог
|
||||
|
||||
Файлът `MANIFEST` проследява всички активни SSTables атомично:
|
||||
|
||||
```json
|
||||
{
|
||||
"version": 1,
|
||||
"sequence": 42,
|
||||
"createdAt": 1779103266,
|
||||
"sstables": [
|
||||
{"id": 1, "path": "sstables/1.sst", "level": 0, "minKey": "a", "maxKey": "z", "entryCount": 100}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
- Записва се атомично чрез `MANIFEST.tmp` + rename
|
||||
- Чете се при стартиране за бързо зареждане
|
||||
- Обновява се след всеки flush и compaction
|
||||
|
||||
### WAL Ротация
|
||||
|
||||
Write-Ahead Log се ротира при достигане на 64MB:
|
||||
|
||||
```
|
||||
wal/
|
||||
├── wal.log (активен сегмент)
|
||||
└── wal_archive/
|
||||
├── wal.000001.log
|
||||
└── wal.000002.log
|
||||
```
|
||||
|
||||
Ротацията се задейства:
|
||||
- На всеки 1000 записа (лека проверка)
|
||||
- При всеки `flush()` или `checkpoint()`
|
||||
|
||||
### Storage Repair
|
||||
|
||||
Проверка и ремонт на storage:
|
||||
|
||||
```bash
|
||||
# Проверка на всички SSTables
|
||||
./build/baradadb repair --data-dir=./data --dry-run
|
||||
|
||||
# Пълен ремонт
|
||||
./build/baradadb repair --data-dir=./data
|
||||
```
|
||||
|
||||
### Миграция на SSTable Версии
|
||||
|
||||
Пренаписване на legacy v1/v2 SSTables към v3:
|
||||
|
||||
```bash
|
||||
./build/baradadb migrate --data-dir=./data
|
||||
```
|
||||
|
||||
## B-Tree Индекс
|
||||
|
||||
Подреден индекс за range сканиране и точково търсене.
|
||||
@@ -43,14 +137,14 @@ let range = btree.scan("key_a", "key_z")
|
||||
|
||||
## Write-Ahead Log (WAL)
|
||||
|
||||
Осигурява устойчивост на операциите за запис.
|
||||
Осигурява устойчивост на операциите за запис със сегментна ротация.
|
||||
|
||||
```nim
|
||||
import barabadb/storage/wal
|
||||
|
||||
var wal = newWAL("./wal")
|
||||
wal.append("txn1", "SET key1 value1")
|
||||
wal.flush()
|
||||
var wal = newWriteAheadLog("./wal")
|
||||
wal.writePut(key, value, timestamp)
|
||||
wal.sync()
|
||||
```
|
||||
|
||||
## Bloom Filter
|
||||
@@ -73,6 +167,6 @@ if filter.mightContain("key1"):
|
||||
```nim
|
||||
import barabadb/storage/mmap
|
||||
|
||||
var mapped = mmapFile("./data/file.dat")
|
||||
let data = mapped.read(0, 100)
|
||||
var mapped = openMmap("./data/file.dat")
|
||||
let val = mapped.readUint32(0)
|
||||
```
|
||||
|
||||
+173
-158
@@ -1,199 +1,214 @@
|
||||
# Backup & Recovery
|
||||
|
||||
## Online Snapshots
|
||||
BaraDB provides multiple backup strategies ranging from full snapshots to incremental and online consistent backups.
|
||||
|
||||
BaraDB supports online snapshots without stopping the server. The snapshot
|
||||
captures a consistent point-in-time view using MVCC.
|
||||
## Architecture
|
||||
|
||||
### Creating a Snapshot
|
||||
|
||||
```nim
|
||||
import barabadb/core/backup
|
||||
|
||||
var bm = newBackupManager()
|
||||
bm.createSnapshot("/backup/baradb_2025-01-15")
|
||||
```
|
||||
┌─────────────────────────────────────────┐
|
||||
│ Data Directory │
|
||||
│ ├── MANIFEST (atomic catalog) │
|
||||
│ ├── sstables/ (SSTable v3 CRC) │
|
||||
│ │ ├── 1.sst │
|
||||
│ │ └── 2.sst │
|
||||
│ └── wal/ │
|
||||
│ ├── wal.log (active segment) │
|
||||
│ └── wal_archive/ (rotated segments│
|
||||
└─────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Via CLI
|
||||
## SSTable Integrity (v3 CRC Footer)
|
||||
|
||||
```bash
|
||||
./build/baradadb --snapshot --output=/backup/snapshot.db
|
||||
Every SSTable file written by BaraDB includes a CRC32 footer:
|
||||
|
||||
```
|
||||
[Header] 36 bytes
|
||||
magic, version(3), entryCount, level,
|
||||
indexOffset, bloomOffset, footerOffset
|
||||
[Data Block]
|
||||
[Index Block]
|
||||
[Bloom Block]
|
||||
[Footer] 16 bytes
|
||||
dataCrc32, indexCrc32, bloomCrc32, reserved
|
||||
```
|
||||
|
||||
### Via HTTP API
|
||||
This enables independent verification of each SSTable:
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:9470/api/backup \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"destination": "/backup/snapshot.db"}'
|
||||
# Via Nim API
|
||||
import barabadb/storage/lsm
|
||||
let (ok, msg) = verifySSTable("data/sstables/1.sst")
|
||||
```
|
||||
|
||||
### Automated Backups
|
||||
## Storage Repair (`baradb repair`)
|
||||
|
||||
Use cron for scheduled backups:
|
||||
If corruption is suspected, run the repair tool:
|
||||
|
||||
```bash
|
||||
# Daily snapshot at 2 AM
|
||||
0 2 * * * /usr/local/bin/baradadb --snapshot --output=/backup/baradb_$(date +\%Y\%m\%d).db
|
||||
# Dry run — preview only
|
||||
./build/baradadb repair --data-dir=./data --dry-run
|
||||
|
||||
# Keep last 7 days
|
||||
find /backup -name "baradb_*.db" -mtime +7 -delete
|
||||
# Full repair — verify, move corrupt files, replay WAL
|
||||
./build/baradadb repair --data-dir=./data
|
||||
```
|
||||
|
||||
## Point-in-Time Recovery (PITR)
|
||||
**What repair does:**
|
||||
1. Scans all `sstables/*.sst` and verifies CRC
|
||||
2. Moves corrupt SSTables to `data/corrupt/`
|
||||
3. Replays WAL to recover unflushed committed data
|
||||
4. Reports results
|
||||
|
||||
BaraDB uses the Write-Ahead Log (WAL) for point-in-time recovery.
|
||||
## MANIFEST Catalog
|
||||
|
||||
### WAL Archiving
|
||||
The `MANIFEST` file is the single source of truth for active SSTables. It is updated atomically on every flush and compaction.
|
||||
|
||||
Enable continuous WAL archiving:
|
||||
```json
|
||||
{
|
||||
"version": 1,
|
||||
"sequence": 42,
|
||||
"createdAt": 1779103266,
|
||||
"sstables": [
|
||||
{"id": 1, "path": "sstables/1.sst", "level": 0, "minKey": "a", "maxKey": "z", "entryCount": 100}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Benefits:
|
||||
- **Consistent view** — no orphan SSTables after crash
|
||||
- **Fast startup** — load from MANIFEST instead of directory scan
|
||||
- **Orphan detection** — `checkStorageConsistency()` reports extra/missing files
|
||||
|
||||
## WAL Rotation
|
||||
|
||||
The Write-Ahead Log rotates when it reaches 64MB:
|
||||
|
||||
```
|
||||
wal/wal.log → active segment
|
||||
wal/wal_archive/
|
||||
├── wal.000001.log
|
||||
├── wal.000002.log
|
||||
└── wal.000003.log
|
||||
```
|
||||
|
||||
Rotation happens:
|
||||
- Every 1000 WAL entries (lightweight size check)
|
||||
- On every `flush` / `checkpoint`
|
||||
|
||||
## Checkpoint
|
||||
|
||||
A checkpoint creates a consistent storage boundary without stopping the server:
|
||||
|
||||
```bash
|
||||
BARADB_WAL_ARCHIVE_DIR=/backup/wal \
|
||||
BARADB_WAL_ARCHIVE_INTERVAL_MS=60000 \
|
||||
./build/baradadb checkpoint --data-dir=./data
|
||||
```
|
||||
|
||||
**How it works:**
|
||||
1. Freeze memtable (swap to immutable, new memtable for writes)
|
||||
2. Flush frozen memtable to SSTable
|
||||
3. Rotate WAL
|
||||
4. Write MANIFEST
|
||||
|
||||
The freeze takes **< 1ms**; the flush proceeds concurrently with writes.
|
||||
|
||||
## Backup Commands
|
||||
|
||||
### Full Backup (tar.gz)
|
||||
|
||||
```bash
|
||||
./build/backup backup --data-dir=./data --output=backup_$(date +%s).tar.gz
|
||||
```
|
||||
|
||||
Archives the entire data directory.
|
||||
|
||||
### Incremental Backup
|
||||
|
||||
```bash
|
||||
./build/backup incremental --data-dir=./data --output=backup_inc_$(date +%s).tar.gz
|
||||
```
|
||||
|
||||
Includes only:
|
||||
- `MANIFEST`
|
||||
- Active SSTables (from MANIFEST)
|
||||
- Current WAL (`wal/wal.log`)
|
||||
- WAL archive (`wal/wal_archive/*.log`)
|
||||
|
||||
All SSTables are **CRC-verified** before archiving.
|
||||
|
||||
### Online Consistent Backup
|
||||
|
||||
```bash
|
||||
./build/baradadb backup --online --output=backup_online_$(date +%s).tar.gz
|
||||
```
|
||||
|
||||
Equivalent to:
|
||||
1. `checkpoint`
|
||||
2. `incremental backup`
|
||||
|
||||
**Safe to run while the server is stopped.** If the server is running, use `backup incremental` instead.
|
||||
|
||||
## SSTable Version Migration
|
||||
|
||||
If you have legacy v1/v2 SSTables, migrate them to v3:
|
||||
|
||||
```bash
|
||||
# Preview
|
||||
./build/baradadb migrate --data-dir=./data --dry-run
|
||||
|
||||
# Migrate
|
||||
./build/baradadb migrate --data-dir=./data
|
||||
```
|
||||
|
||||
Migration rewrites each legacy SSTable with the current v3 format (CRC footer) and updates the MANIFEST.
|
||||
|
||||
## Recovery Procedures
|
||||
|
||||
### Scenario 1: Corrupt SSTable Detected
|
||||
|
||||
```bash
|
||||
# Repair moves corrupt files and replays WAL
|
||||
./build/baradadb repair --data-dir=./data
|
||||
|
||||
# Verify consistency
|
||||
./build/baradadb repair --data-dir=./data --dry-run
|
||||
```
|
||||
|
||||
### Scenario 2: Restore from Backup
|
||||
|
||||
```bash
|
||||
# Stop the server
|
||||
# Extract backup
|
||||
tar -xzf backup_1234567890.tar.gz -C ./data
|
||||
|
||||
# Restart — LSMTree loads from MANIFEST
|
||||
./build/baradadb
|
||||
```
|
||||
|
||||
### Recovery from Checkpoint + WAL
|
||||
### Scenario 3: Complete Data Loss
|
||||
|
||||
```bash
|
||||
# Restore from snapshot
|
||||
./build/baradadb --recover \
|
||||
--checkpoint=/backup/snapshot.db \
|
||||
--wal-dir=/backup/wal
|
||||
# 1. Extract latest backup
|
||||
tar -xzf backup_latest.tar.gz -C ./data
|
||||
|
||||
# Recovery to specific LSN
|
||||
./build/baradadb --recover \
|
||||
--checkpoint=/backup/snapshot.db \
|
||||
--wal-dir=/backup/wal \
|
||||
--target-lsn=15420
|
||||
# 2. Run repair to replay any available WAL
|
||||
./build/baradadb repair --data-dir=./data
|
||||
|
||||
# Recovery to specific time
|
||||
./build/baradadb --recover \
|
||||
--checkpoint=/backup/snapshot.db \
|
||||
--wal-dir=/backup/wal \
|
||||
--target-time="2025-01-15T10:30:00Z"
|
||||
```
|
||||
|
||||
### Recovery via SQL
|
||||
|
||||
You can also recover directly via BaraQL:
|
||||
|
||||
```sql
|
||||
RECOVER TO TIMESTAMP '2026-05-07T12:00:00';
|
||||
```
|
||||
|
||||
### Incremental Backups
|
||||
|
||||
Incremental backups only copy changed SSTables:
|
||||
|
||||
```bash
|
||||
./build/baradadb --backup-incremental \
|
||||
--last-backup=/backup/previous \
|
||||
--output=/backup/incremental_$(date +%Y%m%d)
|
||||
```
|
||||
|
||||
## Replication as Backup
|
||||
|
||||
For continuous protection, use streaming replication:
|
||||
|
||||
### Primary
|
||||
|
||||
```bash
|
||||
BARADB_REPLICATION_ENABLED=true \
|
||||
BARADB_REPLICATION_MODE=async \
|
||||
# 3. Start server
|
||||
./build/baradadb
|
||||
```
|
||||
|
||||
### Replica
|
||||
|
||||
```bash
|
||||
BARADB_REPLICATION_ENABLED=true \
|
||||
BARADB_REPLICATION_PRIMARY=primary:9472 \
|
||||
./build/baradadb
|
||||
```
|
||||
|
||||
## Disaster Recovery
|
||||
|
||||
### Recovery Procedures
|
||||
|
||||
#### Scenario 1: Single File Corruption
|
||||
|
||||
```bash
|
||||
# Identify corrupted SSTable from logs
|
||||
# Restore specific SSTable from backup
|
||||
cp /backup/sstables/000012.sst ./data/sstables/
|
||||
|
||||
# Rebuild index
|
||||
./build/baradadb --rebuild-index
|
||||
```
|
||||
|
||||
#### Scenario 2: Complete Data Loss
|
||||
|
||||
```bash
|
||||
# 1. Restore latest snapshot
|
||||
cp /backup/snapshot.db ./data/
|
||||
|
||||
# 2. Replay WAL
|
||||
./build/baradadb --recover --wal-dir=/backup/wal
|
||||
|
||||
# 3. Verify
|
||||
curl http://localhost:9470/health
|
||||
```
|
||||
|
||||
#### Scenario 3: Cluster Node Failure
|
||||
|
||||
```bash
|
||||
# For Raft clusters, simply start a new node
|
||||
BARADB_RAFT_NODE_ID=newnode \
|
||||
BARADB_RAFT_PEERS=node1:9001,node2:9001 \
|
||||
./build/baradadb
|
||||
|
||||
# The new node will catch up via Raft log replication
|
||||
```
|
||||
|
||||
## Backup Verification
|
||||
|
||||
Always verify backups:
|
||||
|
||||
```bash
|
||||
# Restore to temporary directory
|
||||
./build/baradadb --recover \
|
||||
--checkpoint=/backup/snapshot.db \
|
||||
--data-dir=/tmp/verify_data
|
||||
|
||||
# Run consistency check
|
||||
curl http://localhost:9470/api/admin/check
|
||||
```
|
||||
|
||||
## Storage Requirements
|
||||
|
||||
| Backup Type | Size | Frequency | Retention |
|
||||
|-------------|------|-----------|-----------|
|
||||
| Full snapshot | ~1× data size | Daily | 7 days |
|
||||
| Incremental | ~0.1× data size | Hourly | 24 hours |
|
||||
| WAL archive | ~0.05× data size / day | Continuous | 30 days |
|
||||
| Full tar.gz | ~1× data size | Weekly | 4 weeks |
|
||||
| Incremental | ~0.05× data size | Hourly | 24 hours |
|
||||
| WAL archive | ~0.02× data size / day | Continuous | 7 days |
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Test restores regularly** — A backup you can't restore is useless
|
||||
2. **Store backups offsite** — Use S3, GCS, or Azure Blob
|
||||
3. **Encrypt backups** — Use `gpg` or OS-level encryption
|
||||
4. **Monitor backup jobs** — Alert on failed backups
|
||||
5. **Document RTO/RPO** — Know your recovery time and point objectives
|
||||
|
||||
### Cloud Backup Upload
|
||||
|
||||
```bash
|
||||
# Upload to S3
|
||||
aws s3 cp /backup/snapshot.db s3://my-bucket/baradb/
|
||||
|
||||
# Upload to GCS
|
||||
gsutil cp /backup/snapshot.db gs://my-bucket/baradb/
|
||||
|
||||
# Upload to Azure
|
||||
az storage blob upload \
|
||||
--container-name backups \
|
||||
--file /backup/snapshot.db \
|
||||
--name baradb/snapshot.db
|
||||
```
|
||||
1. **Run repair after unclean shutdown** — `./build/baradadb repair`
|
||||
2. **Migrate legacy SSTables** — `./build/baradadb migrate`
|
||||
3. **Test restores regularly** — A backup you can't restore is useless
|
||||
4. **Use incremental + checkpoint** — For frequent consistent snapshots
|
||||
5. **Store backups offsite** — S3, GCS, or another server
|
||||
6. **Monitor MANIFEST sequence** — Should grow monotonically with flushes
|
||||
|
||||
+102
-8
@@ -21,11 +21,105 @@ db.close()
|
||||
|
||||
- **MemTable**: In-memory sorted buffer
|
||||
- **WAL**: Write-ahead log for durability
|
||||
- **SSTable**: Sorted string tables on disk
|
||||
- **SSTable**: Sorted string tables on disk (v3 with CRC footer)
|
||||
- **Bloom Filter**: Probabilistic set membership
|
||||
- **Compaction**: Size-tiered strategy with level management
|
||||
- **MANIFEST**: Atomic catalog of active SSTables
|
||||
- **Page Cache**: LRU cache with hit rate tracking
|
||||
|
||||
### SSTable Format (v3)
|
||||
|
||||
```
|
||||
[Header] 36 bytes
|
||||
magic: uint32 (0x53535442 = "SSTB")
|
||||
version: uint32 (3 = current)
|
||||
entryCount: uint32
|
||||
level: uint32
|
||||
indexOffset: uint64
|
||||
bloomOffset: uint64
|
||||
footerOffset: uint64
|
||||
|
||||
[Data Block]
|
||||
keyLen: uint32
|
||||
key: bytes[keyLen]
|
||||
valueLen: uint32
|
||||
value: bytes[valueLen]
|
||||
timestamp: uint64
|
||||
deleted: uint8
|
||||
|
||||
[Index Block]
|
||||
keyLen: uint32
|
||||
key: bytes[keyLen]
|
||||
dataOffset: uint64
|
||||
|
||||
[Bloom Filter Block]
|
||||
bloomSize: uint32
|
||||
bloomData: bytes[bloomSize]
|
||||
|
||||
[Footer] 16 bytes
|
||||
dataCrc32: uint32 (CRC32 of Data Block)
|
||||
indexCrc32: uint32 (CRC32 of Index Block)
|
||||
bloomCrc32: uint32 (CRC32 of Bloom Block)
|
||||
reserved: uint32 (must be 0)
|
||||
```
|
||||
|
||||
The CRC footer enables independent verification of each SSTable file via `verifySSTable(path)`.
|
||||
|
||||
### MANIFEST Catalog
|
||||
|
||||
The `MANIFEST` file tracks all active SSTables atomically:
|
||||
|
||||
```json
|
||||
{
|
||||
"version": 1,
|
||||
"sequence": 42,
|
||||
"createdAt": 1779103266,
|
||||
"sstables": [
|
||||
{"id": 1, "path": "sstables/1.sst", "level": 0, "minKey": "a", "maxKey": "z", "entryCount": 100}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
- Written atomically via `MANIFEST.tmp` + rename
|
||||
- Read at startup for fast loading
|
||||
- Updated after every flush and compaction
|
||||
|
||||
### WAL Rotation
|
||||
|
||||
The Write-Ahead Log rotates when it reaches 64MB:
|
||||
|
||||
```
|
||||
wal/
|
||||
├── wal.log (active segment)
|
||||
└── wal_archive/
|
||||
├── wal.000001.log
|
||||
└── wal.000002.log
|
||||
```
|
||||
|
||||
Rotation triggers:
|
||||
- Every 1000 entries (lightweight check)
|
||||
- On every `flush()` or `checkpoint()`
|
||||
|
||||
### Storage Repair
|
||||
|
||||
Verify and repair storage integrity:
|
||||
|
||||
```bash
|
||||
# Check all SSTables
|
||||
./build/baradadb repair --data-dir=./data --dry-run
|
||||
|
||||
# Full repair
|
||||
./build/baradadb repair --data-dir=./data
|
||||
```
|
||||
|
||||
### SSTable Migration
|
||||
|
||||
Rewrite legacy v1/v2 SSTables to v3:
|
||||
|
||||
```bash
|
||||
./build/baradadb migrate --data-dir=./data
|
||||
```
|
||||
|
||||
## B-Tree Index
|
||||
|
||||
Ordered index for range scans and point lookups.
|
||||
@@ -43,14 +137,14 @@ let range = btree.scan("key_a", "key_z")
|
||||
|
||||
## Write-Ahead Log (WAL)
|
||||
|
||||
Ensures durability of write operations.
|
||||
Ensures durability of write operations with segment rotation.
|
||||
|
||||
```nim
|
||||
import barabadb/storage/wal
|
||||
|
||||
var wal = newWAL("./wal")
|
||||
wal.append("txn1", "SET key1 value1")
|
||||
wal.flush()
|
||||
var wal = newWriteAheadLog("./wal")
|
||||
wal.writePut(key, value, timestamp)
|
||||
wal.sync()
|
||||
```
|
||||
|
||||
## Bloom Filter
|
||||
@@ -73,6 +167,6 @@ Efficient file access using mmap.
|
||||
```nim
|
||||
import barabadb/storage/mmap
|
||||
|
||||
var mapped = mmapFile("./data/file.dat")
|
||||
let data = mapped.read(0, 100)
|
||||
```
|
||||
var mapped = openMmap("./data/file.dat")
|
||||
let val = mapped.readUint32(0)
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user