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

128 lines
4.2 KiB
Bash
Raw 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.

#!/usr/bin/env bash
# state.db 回滚脚本2026-09-03 主人 C 方案带的回滚保险2026-09-06 模式15 加固)
# **必须从独立终端跑**(不能从 gateway 内部跑,会被杀)
# 用法bash ~/.hermes/scripts/restore-state-db.sh [快照.db 或 含 state.db 的目录]
# (缺省用旧版 09-03 快照目录;传参可用 state-20260906-1800.db 这类 .backup 快照)
set -u
SNAP="/home/muc/.hermes/backups/state-db-snap-20260903_153655"
DB="/home/muc/.hermes/state.db"
WAL="/home/muc/.hermes/state.db-wal"
SHM="/home/muc/.hermes/state.db-shm"
JOBS="/home/muc/.hermes/cron/jobs.json"
# 参数化快照源:$1 可以是 *.db 文件,或含 state.db 的目录
SNAP_ARG="${1:-}"
LOG="/home/muc/.hermes/backups/state-db/restore-$(date +%Y%m%d_%H%M%S).log"
mkdir -p "$(dirname "$LOG")"
log() { echo "[$(date '+%F %T')] $*" | tee -a "$LOG"; }
# 🔒 2026-09-08 止血: lsof 零持有者 gate——任何进程持有 state.db 都拒绝继续
# 19:37 教训: 残留 hermes 进程挡修复; P1-1: gateway 在线第二写入者 = WAL 突破损坏)
HOLDERS=$(lsof "$DB" 2>/dev/null | awk 'NR>1 {print $1"("$2")"}' | sort -u | tr '\n' ' ')
if [ -n "$HOLDERS" ]; then
log "🔴 拒绝执行: state.db 仍被持有: $HOLDERS"
log " 先停止持有进程(含 hermes-gateway再重试。lsof 确认零持有者才可恢复。"
exit 3
fi
log "✅ lsof gate 通过: 零持有者"
# 解析快照源(放 log() 定义后,避免未定义函数调用)
SRC_DB=""
if [ -n "$SNAP_ARG" ]; then
if [ -f "$SNAP_ARG" ]; then
SRC_DB="$SNAP_ARG"
elif [ -f "$SNAP_ARG/state.db" ]; then
SRC_DB="$SNAP_ARG/state.db"
else
log "❌ 快照参数无效: $SNAP_ARG"
exit 2
fi
fi
if [ -z "$SRC_DB" ]; then
if [ ! -f "$SNAP/state.db" ]; then
log "❌ 快照不存在: $SNAP/state.db"
exit 2
fi
SRC_DB="$SNAP/state.db"
fi
log "✅ 快照 OK: $SRC_DB"
# 0. 停 gateway
log "[0/4] 停 gateway..."
systemctl --user stop hermes-gateway 2>&1 | tee -a "$LOG"
sleep 2
# 1. 原子替换(只还原 state.dbwal/shm 为瞬时文件一律清掉,避免旧帧污染)
log "[1/4] 还原 state.db来源: $SRC_DB..."
cp -a "$SRC_DB" "$DB"
rm -f "$WAL" "$SHM"
log "✅ state.db 还原完成(已清 stale WAL/SHM"
# 旧版目录快照附带 jobs.json 时还原(仅缺省模式;.db 文件快照不含 jobs
if [ -z "${SNAP_ARG:-}" ] && [ -f "$SNAP/jobs.json" ]; then
cp -a "$SNAP/jobs.json" "$JOBS"
log "✅ jobs.json 还原完成"
fi
# 1.5 强制 WAL + integrity 断言2026-09-06 模式15快照/.backup 产物默认 delete 头,
# 若直接启 gateway → 多连接并发抢 delete→WAL 转换 → disk I/O error 风暴 → FTS5 撕裂。
# 失败即中止,绝不带病启动。)
log "[1.5/4] 强制 journal_mode=WAL + integrity 断言..."
JM=$(python3 - "$DB" <<'PY'
import sqlite3, sys
con = sqlite3.connect(sys.argv[1], timeout=30)
try:
print(con.execute("PRAGMA journal_mode=WAL").fetchone()[0])
finally:
con.close()
PY
)
log " journal_mode = $JM ← 应为 wal"
if [ "$JM" != "wal" ]; then
log "❌ 强制 WAL 失败($JM),中止启动,请人工检查 $DB"
exit 2
fi
IC=$(python3 - "$DB" <<'PY'
import sqlite3, sys
con = sqlite3.connect(sys.argv[1], timeout=30)
try:
print(con.execute("PRAGMA integrity_check").fetchone()[0])
finally:
con.close()
PY
)
log " integrity_check = $IC ← 应为 ok"
if [ "$IC" != "ok" ]; then
log "❌ 切 WAL 后 integrity 异常($IC),中止启动"
exit 2
fi
# 2. 启 gateway3 次重试)
log "[2/4] 启 gateway3 次重试)..."
for i in 1 2 3; do
systemctl --user start hermes-gateway 2>&1 | tee -a "$LOG"
sleep 3
if systemctl --user is-active hermes-gateway >/dev/null 2>&1; then
log "✅ gateway 第 $i 次启动成功"
break
fi
log "⚠️ 第 $i 次启动未就绪,等待后重试"
sleep 3
done
# 3. 健康检查
log "[3/4] 健康检查..."
sleep 5
if systemctl --user is-active hermes-gateway >/dev/null 2>&1; then
log "✅ gateway ACTIVE回滚成功"
log "📋 主人请重新发起对话(小唯已失忆)"
exit 0
else
log "❌ gateway 还是没起来"
journalctl --user -u hermes-gateway -n 30 --no-pager 2>&1 | tee -a "$LOG"
exit 1
fi