Ka-Note/docs/feature-dbrepair.md

4.5 KiB

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:

.\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

$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

# 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)

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

# 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)