Files
Charon/docs/database-maintenance.md
2026-03-04 18:34:49 +00:00

8.5 KiB

title, description
title description
Database Maintenance SQLite database maintenance guide for Charon. Covers backups, recovery, and troubleshooting database issues.

Database Maintenance

Charon uses SQLite as its embedded database. This guide explains how the database is configured, how to maintain it, and what to do if something goes wrong.


Overview

Why SQLite?

SQLite is perfect for Charon because:

  • Zero setup — No external database server needed
  • Portable — One file contains everything
  • Reliable — Used by billions of devices worldwide
  • Fast — Local file access beats network calls

Where Is My Data?

Environment Database Location
Docker /app/data/charon.db
Local dev backend/data/charon.db

You may also see these files next to the database:

  • charon.db-wal — Write-Ahead Log (temporary transactions)
  • charon.db-shm — Shared memory file (temporary)

Don't delete the WAL or SHM files while Charon is running! They contain pending transactions.


Database Configuration

Charon automatically configures SQLite with optimized settings:

Setting Value What It Does
journal_mode WAL Enables concurrent reads while writing
busy_timeout 5000ms Waits 5 seconds before failing on lock
synchronous NORMAL Balanced safety and speed
cache_size 64MB Memory cache for faster queries

What Is WAL Mode?

WAL (Write-Ahead Logging) is a more modern journaling mode for SQLite that:

  • Allows readers while writing (no blocking)
  • Faster for most workloads
  • Reduces disk I/O
  • Safer crash recovery

Charon enables WAL mode automatically — you don't need to do anything.


Backups

Automatic Backups

Charon creates automatic backups before destructive operations (like deleting hosts). These are stored in:

Environment Backup Location
Docker /app/data/backups/
Local dev backend/data/backups/

Manual Backups

To create a manual backup:

# Docker
docker exec charon cp /app/data/charon.db /app/data/backups/manual_backup.db

# Local development
cp backend/data/charon.db backend/data/backups/manual_backup.db

Important: If WAL mode is active, also copy the -wal and -shm files:

cp backend/data/charon.db-wal backend/data/backups/manual_backup.db-wal
cp backend/data/charon.db-shm backend/data/backups/manual_backup.db-shm

Or use the recovery script which handles this automatically (see below).


Database Recovery

If your database becomes corrupted (rare, but possible after power loss or disk failure), Charon includes a recovery script.

When to Use Recovery

Use the recovery script if you see errors like:

  • "database disk image is malformed"
  • "database is locked" (persists after restart)
  • "SQLITE_CORRUPT"
  • Application won't start due to database errors

Running the Recovery Script

In Docker:

# First, stop Charon to release database locks
docker stop charon

# Run recovery (from host)
docker run --rm -v charon_data:/app/data charon:latest /app/scripts/db-recovery.sh

# Restart Charon
docker start charon

Local Development:

# Make sure Charon is not running, then:
./scripts/db-recovery.sh

Force mode (skip confirmations):

./scripts/db-recovery.sh --force

What the Recovery Script Does

  1. Creates a backup — Saves your current database before any changes
  2. Runs integrity check — Uses SQLite's PRAGMA integrity_check
  3. If healthy — Confirms database is OK, enables WAL mode
  4. If corrupted — Attempts automatic recovery:
    • Exports data using SQLite .dump command
    • Creates a new database from the dump
    • Verifies the new database integrity
    • Replaces the old database with the recovered one
  5. Cleans up — Removes old backups (keeps last 10)

Recovery Output Example

Healthy database:

==============================================
  Charon Database Recovery Tool
==============================================

[INFO] sqlite3 found: 3.40.1
[INFO] Running in Docker environment
[INFO] Database path: /app/data/charon.db
[INFO] Creating backup: /app/data/backups/charon_backup_20250101_120000.db
[SUCCESS] Backup created successfully

==============================================
  Integrity Check Results
==============================================
ok
[SUCCESS] Database integrity check passed!
[INFO] WAL mode already enabled

==============================================
  Summary
==============================================
[SUCCESS] Database is healthy
[INFO] Backup stored at: /app/data/backups/charon_backup_20250101_120000.db

Corrupted database (with successful recovery):

==============================================
  Integrity Check Results
==============================================
*** in database main ***
Page 42: btree page count invalid
[ERROR] Database integrity check FAILED

WARNING: Database corruption detected!
This script will attempt to recover the database.
A backup has already been created.

Continue with recovery? (y/N): y

==============================================
  Recovery Process
==============================================
[INFO] Attempting database recovery...
[INFO] Exporting database via .dump command...
[SUCCESS] Database dump created
[INFO] Creating new database from dump...
[SUCCESS] Recovered database created
[SUCCESS] Recovered database passed integrity check
[INFO] Replacing original database with recovered version...
[SUCCESS] Database replaced successfully

==============================================
  Summary
==============================================
[SUCCESS] Database recovery completed successfully!
[INFO] Please restart the Charon application

Preventive Measures

Do

  • Keep regular backups — Use the backup page in Charon or manual copies
  • Use proper shutdown — Stop Charon gracefully (docker stop charon)
  • Monitor disk space — SQLite needs space for temporary files
  • Use reliable storage — SSDs are more reliable than HDDs

Don't

  • Don't kill Charon — Avoid docker kill or kill -9 (use stop instead)
  • Don't edit the database manually — Unless you know SQLite well
  • Don't delete WAL files — While Charon is running
  • Don't run out of disk space — Can cause corruption

Troubleshooting

"Database is locked"

Cause: Another process has the database open.

Fix:

  1. Stop all Charon instances
  2. Check for zombie processes: ps aux | grep charon
  3. Kill any remaining processes
  4. Restart Charon

"Database disk image is malformed"

Cause: Database corruption (power loss, disk failure, etc.)

Fix:

  1. Stop Charon
  2. Run the recovery script: ./scripts/db-recovery.sh
  3. Restart Charon

"SQLITE_BUSY"

Cause: Long-running transaction blocking others.

Fix: Usually resolves itself (5-second timeout). If persistent:

  1. Restart Charon
  2. If still occurring, check for stuck processes

WAL File Is Very Large

Cause: Many writes without checkpointing.

Fix: This is usually handled automatically. To force a checkpoint:

sqlite3 /path/to/charon.db "PRAGMA wal_checkpoint(TRUNCATE);"

Lost Data After Recovery

What happened: The .dump command recovers readable data, but severely corrupted records may be lost.

What to do:

  1. Check your automatic backups in data/backups/
  2. Restore from the most recent pre-corruption backup
  3. Re-create any missing configuration manually

Advanced: Manual Recovery

If the automatic script fails, you can try manual recovery:

# 1. Create a SQL dump of whatever is readable
sqlite3 charon.db ".dump" > backup.sql

# 2. Check what was exported
head -100 backup.sql

# 3. Create a new database
sqlite3 charon_new.db < backup.sql

# 4. Verify the new database
sqlite3 charon_new.db "PRAGMA integrity_check;"

# 5. If OK, replace the old database
mv charon.db charon_corrupted.db
mv charon_new.db charon.db

# 6. Enable WAL mode on the new database
sqlite3 charon.db "PRAGMA journal_mode=WAL;"

Need Help?

If recovery fails or you're unsure what to do:

  1. Don't panic — Your backup was created before recovery attempts
  2. Check backups — Look in data/backups/ for recent copies
  3. Ask for help — Open an issue on GitHub with your error messages