Script zum reparieren einer Sqlite DB nach "database disk image is malformed"

Begonnen von Hadl, 14 April 2023, 15:47:05

Vorheriges Thema - Nächstes Thema

Hadl

Hallo zusammen,
ich hatte immer mal wieder das Problem, das auf meinem Raspi die Sqlite Datenbank vom logdb defekt wird.
Ich bin mir nicht sicher woran das genau liegt, evtl. geht die Lebensdauer meiner SD Karte zu Ende.
Mit ner neuen SD Karte wurde es aber eher schlimmer, daher nehme ich wieder die ältere. Aber nun genug zum Hintergrund.

Meine Datenbank hat schon einige Jahre Daten an Board, und ist auch schön ca. 50GB groß, mit 128GB SD Karte reicht der Platz aber nicht um sie lokal doppelt zu haben, daher kommt mein NAS hier als Backup und zwischenspeicher zum Einsatz.
Da das ganze für den Raspi und das Netzwerk bei der Datenmenge ca. 1 Tag braucht, aber ich keine Daten verlieren will, kommt eine zwischenspeicher DB währenddessen zum Einsatz.

Ein Verzeichnis im NAS hab ich hierhin gemounted: "/mnt/nas/Sicherung/"

Das Reparieren macht grob folgende Schritte
  • Beendet Fhem kurz, benennt die Datenbank um, erzeugt eine neue leere temporäte Datenbank und startet Fhem neu
  • Macht einen SQL Dump der alten Datenbank auf das NAS und verschiebt dann die Datenbank selbst auch dorhin (als Backup)
  • Erzeugt eine neue Sqlite Datenbank aus dem Dump (dann ohne Fehler)
  • Beendet Fhem wieder kurz, fügt die Einträge aus der temporären Datenbank in die neue ein, und benennt die Datenbanken so um, das fhem die neue nutzt. Fhem startet wieder mit der reparierten DB.

#!/bin/bash
TIMESTAMP=$(date -d "today" +"%Y%m%d_%H%M%S")
SOURCE_DB="fhem.db"
TARGET_DB="fhem_new.db"

NAS_PATH="/mnt/nas/Sicherung/"

BACKUP_SQL="$NAS_PATH/${TIMESTAMP}_fhem_backup.sql"
BACKUP_DB="$NAS_PATH/${TIMESTAMP}_fhem_backup.db"

echo $TIMESTAMP

if [ ! -f "$SOURCE_DB" ]; then
echo "$SOURCE_DB does not exist"
exit
fi

/etc/init.d/fhem stop

# Create an empty Database with just the schema, to allow fhem to log data into while running the backup and repair.
rm -f empty.db
sqlite3 $SOURCE_DB .schema | sqlite3 empty.db

# Loop through all files (*.db, *.db-shm, *.db-wal) that are existing with the db name in the folder, and rename them.
for i in $( ls ${SOURCE_DB}* ); do
mv $i ${TIMESTAMP}_${i};
exitStat=$?
test $exitStat -eq 0 && echo "No error! Worked fine" || { echo "There was some error with Code $exitStat"; exit $exitStat; }
done

# Copy empty Database onto the source place, as temporary storage while the database bakup and repair is running.
mv empty.db $SOURCE_DB
chmod 777 $SOURCE_DB

# Start fhem with empty database
/etc/init.d/fhem start

# Pause
#read -n 1 -s

echo "Dump the Database ${TIMESTAMP}_$SOURCE_DB to the SQL Backup on NAS $BACKUP_SQL"
sqlite3 ${TIMESTAMP}_$SOURCE_DB .dump > $BACKUP_SQL
exitStat=$?
test $exitStat -eq 0 && echo "No error! Worked fine" || { echo "There was some error with Code $exitStat"; exit $exitStat; }

echo "Move the main Database  ${TIMESTAMP}_${SOURCE_DB}* to NAS $NAS_PATH"
for i in $( ls ${TIMESTAMP}_${SOURCE_DB}* ); do
mv ${i} $NAS_PATH
exitStat=$?
test $exitStat -eq 0 && echo "No error! Worked fine" || { echo "There was some error with Code $exitStat"; exit $exitStat; }
done
rm -f $TARGET_DB
exitStat=$?
test $exitStat -eq 0 && echo "No error! Worked fine" || { echo "There was some error with Code $exitStat"; exit $exitStat; }
echo "Restore the Database $TARGET_DB from the SQL Backup $BACKUP_SQL"
#cat $BACKUP_SQL | sed -e 's/\(\(BEGIN TRANSACTION;\)\|\(COMMIT;\)\)//g' | sqlite3 $TARGET_DB
sqlite3 $TARGET_DB ".read $BACKUP_SQL"
exitStat=$?
test $exitStat -eq 0 && echo "No error! Worked fine" || { echo "There was some error with Code $exitStat"; exit $exitStat; }


echo "Add the temporary database $SOURCE_DB entries into the restored one $TARGET_DB"
/etc/init.d/fhem stop
sqlite3 $SOURCE_DB .dump | sqlite3 $TARGET_DB

echo "Now move the merged database back to the source place. Keep copy of temporary database"
for i in $( ls ${SOURCE_DB}* ); do
mv $i ${TIMESTAMP}_temp_${i};
exitStat=$?
test $exitStat -eq 0 && echo "No error! Worked fine" || { echo "There was some error with Code $exitStat"; exit $exitStat; }
done

echo "Place the merged database back on the source place"
mv $TARGET_DB $SOURCE_DB;
exitStat=$?
test $exitStat -eq 0 && echo "No error! Worked fine" || { echo "There was some error with Code $exitStat"; exit $exitStat; }

chmod 777 $SOURCE_DB

/etc/init.d/fhem start


Ich hoffe das hilft den ein oder anderen von euch seine Datenbank zu reparieren. Kommentare und Verbesserungen sind immer willkommen.