130 lines
4.5 KiB
Markdown
130 lines
4.5 KiB
Markdown
# DB Repair Playbook
|
|
|
|
## Symptome einer korrupten DB
|
|
|
|
- `POST /api/sync/push` → 500, Server-Log zeigt `SqliteError: database disk image is malformed`
|
|
- `GET /api/admin/integrity` → `{ ok: false, result: "..." }`
|
|
- Startup-Log: `[db] integrity_check failed:`
|
|
|
|
## Ursachen
|
|
|
|
- Azure App Service hat Container während eines laufenden SQLite-Writes neugestartet
|
|
- WAL-Datei (`ka-note.db-wal`) war nicht committed beim Neustart
|
|
- **Hinweis:** WAL-Mode ist aktiv (`journal_mode = WAL`) — schützt vor vielen, aber nicht allen Szenarien
|
|
|
|
## Schritt 1: Integrität prüfen
|
|
|
|
```
|
|
GET /api/admin/integrity
|
|
→ { ok: true/false, result: "ok" | "<Fehlermeldung>" }
|
|
```
|
|
|
|
Oder lokal nach DB-Download:
|
|
```cmd
|
|
.\sqlite3.exe ka-note.db "PRAGMA integrity_check;"
|
|
```
|
|
|
|
## Schritt 2: DB herunterladen (Kudu REST API)
|
|
|
|
Deployment-Credentials aus Portal: **App Service → Deployment Center → FTPS credentials**
|
|
|
|
```powershell
|
|
$user = 'ka-note\$ka-note' # anpassen
|
|
$pass = 'deinPassword'
|
|
$creds = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes("${user}:${pass}"))
|
|
|
|
Invoke-WebRequest `
|
|
-Uri "https://ka-note.scm.azurewebsites.net/api/vfs/data/ka-note.db" `
|
|
-Headers @{ Authorization = "Basic $creds" } `
|
|
-OutFile "ka-note.db"
|
|
|
|
(Get-Item "ka-note.db").Length # muss > 0 sein
|
|
```
|
|
|
|
sqlite3.exe herunterladen von https://www.sqlite.org/download.html (sqlite-tools-win-x64-*.zip)
|
|
|
|
## Schritt 3: DB reparieren
|
|
|
|
```powershell
|
|
# 1. Dump erzeugen
|
|
.\sqlite3.exe ka-note.db ".dump" > dump.sql
|
|
|
|
# 2. Doppelte INSERT-Konflikte entschärfen + ROLLBACK→COMMIT
|
|
(Get-Content dump.sql) -replace '^INSERT INTO', 'INSERT OR IGNORE INTO' | Set-Content dump-fixed.sql
|
|
|
|
# 3. unistr()-Calls dekodieren (nötig wenn Server neueres SQLite als lokal)
|
|
node fix-unistr.js # siehe unten
|
|
|
|
# 4. Importieren (cmd.exe wegen Piping-Problemen in PowerShell)
|
|
cmd /c ".\sqlite3.exe ka-note-repaired.db < dump-fixed2.sql"
|
|
|
|
# 5. Integrität prüfen
|
|
.\sqlite3.exe ka-note-repaired.db "PRAGMA integrity_check;"
|
|
.\sqlite3.exe ka-note-repaired.db ".tables"
|
|
.\sqlite3.exe ka-note-repaired.db "SELECT COUNT(*) FROM contexts; SELECT COUNT(*) FROM topics; SELECT COUNT(*) FROM history_entries;"
|
|
```
|
|
|
|
### fix-unistr.js (im sqlite-Arbeitsverzeichnis ablegen)
|
|
|
|
```js
|
|
import { readFileSync, writeFileSync } from 'fs';
|
|
let sql = readFileSync('dump-fixed.sql', 'utf8');
|
|
// unistr('\uXXXX') → plain UTF-8 string
|
|
sql = sql.replace(/unistr\('((?:[^'\\]|\\.)*)'\)/g, (_, inner) => {
|
|
const decoded = inner.replace(/\\u([0-9a-fA-F]{4})/g, (_, hex) =>
|
|
String.fromCharCode(parseInt(hex, 16))
|
|
);
|
|
return `'${decoded}'`;
|
|
});
|
|
// ROLLBACK at end of corrupt dump → COMMIT so import doesn't discard everything
|
|
sql = sql.replace(/^ROLLBACK;.*$/m, 'COMMIT;');
|
|
writeFileSync('dump-fixed2.sql', sql, 'utf8');
|
|
console.log('done');
|
|
```
|
|
|
|
**Kritisch:** Ein korrupter Dump endet mit `ROLLBACK; -- due to errors` statt `COMMIT;`.
|
|
SQLite verwirft dann die gesamte Transaktion → 0-Byte-Zieldatei.
|
|
Das Script ersetzt `ROLLBACK` durch `COMMIT`.
|
|
|
|
## Schritt 4: Reparierte DB hochladen
|
|
|
|
```powershell
|
|
# App stoppen (DB darf nicht aktiv sein)
|
|
az webapp stop --name ka-note --resource-group <RG>
|
|
|
|
# Hochladen
|
|
Invoke-RestMethod `
|
|
-Uri "https://ka-note.scm.azurewebsites.net/api/vfs/data/ka-note.db" `
|
|
-Method PUT `
|
|
-Headers @{ Authorization = "Basic $creds"; "Content-Type" = "application/octet-stream" } `
|
|
-InFile "ka-note-repaired.db"
|
|
|
|
# App starten
|
|
az webapp start --name ka-note --resource-group <RG>
|
|
```
|
|
|
|
## Schritt 5: Verifizieren
|
|
|
|
```
|
|
GET /api/admin/integrity → { ok: true }
|
|
GET /api/sync/status → Anzahl contexts/topics/history_entries prüfen
|
|
```
|
|
|
|
## Präventionsmaßnahmen (umgesetzt)
|
|
|
|
- **WAL-Mode** (`journal_mode = WAL`) — aktiv seit Beginn, schützt vor den meisten Write-Crashes
|
|
- **Integrity-Check beim Start** — `[db] integrity_check ok` im Startup-Log sichtbar
|
|
- **Integrity-Check vor Backup** — korrupte DB wird nicht als Backup gespeichert, Fehler im Log
|
|
- **`GET /api/admin/integrity`** — on-demand prüfbar ohne Server-Zugriff
|
|
- **Structured Error Logging** — alle Route-Handler loggen Fehler mit Label, Method, Path, Stack
|
|
|
|
## Bekannte Fallstricke
|
|
|
|
| Problem | Ursache | Lösung |
|
|
|---|---|---|
|
|
| Download → 0 Byte | Falscher Pfad oder Auth | Pfad mit `/api/vfs/data/` prüfen |
|
|
| Import → 0 Byte | PowerShell-Piping kaputt | `cmd /c sqlite3 < file` verwenden |
|
|
| `unistr()` Fehler | Versionsunterschied sqlite3 | fix-unistr.js ausführen |
|
|
| UNIQUE constraint | Doppelte Rows aus Korruption | `INSERT OR IGNORE` in dump-fixed.sql |
|
|
| Alles verworfen | Dump endet mit ROLLBACK | ROLLBACK → COMMIT ersetzen (fix-unistr.js macht das) |
|