xiaowei-system/scripts/snapshot-state-db.sh

78 lines
2.8 KiB
Bash
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/bash
# snapshot-state-db.sh — state.db 定时健康快照2026-09-03 创建)
# 2026-09-09 修复:原用 /usr/bin/sqlite3 (CLI 3.45.1,有 WAL-reset bug #69784) 对 WAL 库做
# .backup + journal_mode=WAL → 反复触发 delivery_obligations 索引损坏9/7/9/8/9/9 三连坏真凶)。
# hermes_state.py 明确定义 3.7.0~3.51.2 为 vulnerable3.45.1 在危险区间。
# 现全部改用 python3 sqlite3 (3.53.1,修复版,与 gateway 同版本)。
# 保留最近 8 份;损坏恢复时用最近的快照。
set -uo pipefail
DB=/home/muc/.hermes/state.db
SNAP_DIR=/home/muc/.hermes/backups/state-db-snap
KEEP=8
TS=$(date +%Y%m%d-%H%M)
LOG=/tmp/state-db-snap.log
mkdir -p "$SNAP_DIR"
# 0. 版本自检:拒绝 vulnerable 老 CLI防止将来 PATH 变化回退到 /usr/bin/sqlite3
PYVER=$(python3 -c 'import sqlite3; print(sqlite3.sqlite_version)')
case "$PYVER" in
3.51.3|3.51.*|3.5[2-9].*|3.6[0-9].*|4.*)
;;
*)
echo "[$(date '+%H:%M:%S')] ❌ python3 sqlite3 版本 $PYVER 有 WAL-reset bug拒绝快照" | tee -a "$LOG"
exit 1
;;
esac
# 1. 在线一致性快照python3 同版本 .backup与 gateway 一致)
if ! python3 - "$DB" "$SNAP_DIR/state-$TS.db" <<'PY' >>"$LOG" 2>&1
import sqlite3, sys
src = sqlite3.connect(sys.argv[1], timeout=30)
dst = sqlite3.connect(sys.argv[2], timeout=30)
try:
src.backup(dst)
finally:
dst.close(); src.close()
PY
then
echo "[$(date '+%H:%M:%S')] ❌ state.db 快照失败" | tee -a "$LOG"
rm -f "$SNAP_DIR/state-$TS.db"
exit 1
fi
# 2. 验证快照健康python3 只读)
CHECK=$(python3 - "$SNAP_DIR/state-$TS.db" <<'PY' 2>&1
import sqlite3, sys
c = sqlite3.connect(f"file:{sys.argv[1]}?mode=ro", uri=True, timeout=30)
print(c.execute("PRAGMA integrity_check").fetchone()[0])
c.close()
PY
)
if [ "$CHECK" != "ok" ]; then
echo "[$(date '+%H:%M:%S')] ⚠️ 快照 integrity=$CHECK(删除坏快照)" | tee -a "$LOG"
rm -f "$SNAP_DIR/state-$TS.db"
exit 1
fi
# 2.5 快照切 WAL 模式2026-09-06 模式15.backup 产物默认 delete 头,直接拿去恢复会触发
# gateway 启动 delete→WAL 转换风暴 → FTS5 撕裂;让快照生而 WAL恢复链全程无转换
JM=$(python3 - "$SNAP_DIR/state-$TS.db" <<'PY' 2>&1
import sqlite3, sys
c = sqlite3.connect(sys.argv[1], timeout=30)
print(c.execute("PRAGMA journal_mode=WAL").fetchone()[0])
c.close()
PY
)
if [ "$JM" != "wal" ]; then
echo "[$(date '+%H:%M:%S')] ⚠️ 快照切 WAL 失败 ($JM),删除该快照" | tee -a "$LOG"
rm -f "$SNAP_DIR/state-$TS.db"
exit 1
fi
# 3. 清理旧快照(保留最近 KEEP 份)
ls -1t "$SNAP_DIR"/state-*.db 2>/dev/null | tail -n +$((KEEP+1)) | xargs -r rm -f
echo "[$(date '+%H:%M:%S')] ✅ 快照 state-$TS.db (integrity=ok, 保留 $(ls "$SNAP_DIR"/state-*.db 2>/dev/null | wc -l) 份)" >> "$LOG"