Smail/docs/SQL跨引擎迁移补充验收.md
smail 4d9c938221
Some checks are pending
Security Checks / security (push) Waiting to run
修复跨引擎定长字符校验并补齐双SQL实机验收
2026-09-21 07:35:41 +08:00

91 lines
7.6 KiB
Markdown
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.

# SQL 跨引擎迁移补充验收
## 结论与范围
北京时间 2026 年 9 月 21 日,在云服务器新空数据隔离实例中,完成 MySQL → PostgreSQL、PostgreSQL → MySQL 的应用级迁移、内部重启、系统级进程重启及目标账号故障恢复。
- [✓] 保留迁移失败反例,以只读诊断定位定长字符填充差异。
- [✓] 确定性回归先失败后通过,不跳过表或降低完整性校验。
- [✓] 双 SQL 跨引擎切换、两类重启、目标不可用时拒绝启动及恢复。
- [✓] 两个方向均验证旧会话、历史邮件、新邮件、中文正文及附件。
- [✓] 源库无应用连接、源库逻辑内容不变;新增邮件仅进入目标库。
- [✓] 配置历史完整保留在目标业务库,没有生成 SQLite 文件。
- [✓] 云端新增专项零跳过;最新 Python 部署套件 136 项零跳过通过。
- [✓] 证据、源码、工具摘要、账号锁定及正式服务保护状态复核。
- [ ] 涉及 SQLite 的四个跨引擎应用级重启方向。
- [ ] SQL 复制中断、SQLite 提交及配置切换临界点恢复。
- [!] 浏览器、外部依赖、安全告警、凭据轮换及其他生产门禁尚未关闭。
**本记录只关闭明确列出的双 SQL 跨引擎项,不代表整个项目生产验收完成,也不是正式实例升级。**
## 缺陷定位与最小修复
旧候选在 `/var/tmp/smail-review-runtime-20260921-063341/` 的 MySQL → PostgreSQL 迁移中返回 HTTP 409,提示数据库数据校验未通过。目标数据复制已提交,但配置切换被拒绝;失败源库、目标库和日志均保留,没有通过重试覆盖既有目标。
只读原生 SQL 初步比较只能看到失败响应后可能变化的操作日志与会话时间,不能据此认定并发写入是原因。随后使用新建的最小 SELECT 权限账号、只读事务和生产摘要函数进行 Go 驱动级诊断,定位到 `verification_cleanup_state.lease_token`:MySQL 的定长字符读取结果与 PostgreSQL `BPCHAR` 填充后的驱动值不一致。
最终只读诊断位于 `/var/tmp/smail-review-diagnostic-20260921-070712/`。只输出表名、列名、类型、数量和差异标记,不输出行内容、凭据或摘要原文。诊断有意以非零退出报告差异,不算通过的验收。最初两类启动失败也保留:`PrivateTmp` 隐藏执行路径,以及隐藏正式家目录后驱动默认客户端证书路径不可访问。修正仅以本轮目录只读覆盖可见路径,正式 `/opt/smail` 仍被遮蔽;没有关闭 TLS、解锁原测试账号或改变正式服务。各次诊断账号均已锁定。
`backend/services/dbmigration/portable_data.go` 在行扫描后按**实际源引擎和列元数据**处理填充:
- 仅 MySQL `CHAR`、PostgreSQL `BPCHAR` 删除右侧 ASCII 空格填充。
- 复制与校验共用同一读取路径,支持 PostgreSQL 作为源库的反向迁移。
- 不裁剪前导空格、制表符、换行或非断行空格。
- 不改变 VARCHAR、TEXT、BLOB、BYTEA 或 SQLite 的值,即使 SQLite 列声明为 CHAR。
- NULL 与空字符串、实际令牌内容变更、变长文本或二进制尾部差异仍须区分。
- 全表复制、行数与摘要校验、失败不切配置等保护全部保留。
## 回归与构建
| 项目 | 结果与证据 |
| --- | --- |
| 修复前确定性反例 | `character-before.log`,六个扫描用例、两个摘要用例失败 |
| 修复后专项 | `character-after.log`,两个顶层测试、22 个子用例通过 |
| 本地迁移包 | `character-package.log`,退出零;可选 SQL 集成未配置,不能称零跳过 |
| 三轮专项竞态 | `character-race.log`,退出零;同样不扩大为可选 SQL 集成通过 |
| 云端新增专项 | `smail-review-ssl-apex-20260921/20260921-072942-character-fixed`,两个顶层测试、零跳过、退出零 |
| 本地全量后端及 overlay | `run-2026-09-20T23-31-05-653Z-37152`,66 个测试包、1136 个顶层测试、904 个子测试通过;35 个顶层与 12 个子测试跳过,另有 18 个无测试包 |
| 云端完整 Python 部署回归 | `/var/tmp/smail-review-python-20260921-072946/`,136 项、零跳过、退出零;运行 6.603 秒,内存峰值 46.7 MiB、交换零 |
全量后端的跳过包含缺少专用 SQL 连接、Windows 符号链接权限、本地管理员命名管道和浏览器夹具等条件;没有人为添加跳过或将它们计为通过。双 SQL 实机证据单独列在下节,不以这些可选测试的空运行代替。
候选重新编译后端,复用未改动的前端与 Linux 插件产物;不是本轮重新构建全部资产。构建基线为 `6f63a7e` 加本轮两个 Go 文件改动,611 个后端 Go 文件摘要保存于 `character-source-manifest.json`。
- 主程序 `smail-character`:`97ad202b67e57e6284d7707928cf4591a5d2d676344d7b67f003630242e28924`。
- Linux 测试二进制:`28e424f0a5b3663f43db55bcfd022bb3721dbb438d108184aede8b6af6d7ce96`。
- Python 部署回归日志:`c6efcb86c945ebf221652edc395133f2d454e3ef5942218591534353c61caf8d`。
## 双向实机结果
实例完整路径前缀为 `/var/tmp/smail-review-runtime-`。
| 项目 | MySQL → PostgreSQL | PostgreSQL → MySQL |
| --- | --- | --- |
| 实例目录后缀 | `20260921-072157` | `20260921-072510` |
| 内部重启前后 PID | `786894`,不变 | `787599`,不变 |
| 系统重启后 PID | `787300` | `787953` |
| 故障恢复后 PID | `787432` | `788077` |
| 三阶段源/目标连接数 | 均为 `0 / 3` | 均为 `0 / 3` |
| 目标账号锁定后启动 | failed,PID 为零,退出 1 | failed,PID 为零,退出 1 |
| 源/目标配置历史条数 | `1 / 1`,原始载荷和摘要一致 | `1 / 1`,原始载荷和摘要一致 |
| SQLite 文件数 | 零 | 零 |
| OOM、资源采集及清理错误 | 全部为零 | 全部为零 |
两轮均由正式 API 预览、迁移、提交配置并触发内部重启。待重启期间拒绝业务写入,内部重启保留原会话。系统级重启后 PID 与 InvocationID 改变。锁定目标账号模拟故障时,不回退源库、不改写目标配置;恢复账号后再验登录、SMTP 收信及 IMAP/POP3 读取历史和新增邮件。
迁移历史比较使用规范化的原始字节编码,同时检查载荷 SHA256;不是只比较条数或解析后的 JSON。源库逻辑指纹在后续业务及故障注入期间保持不变。每个实例只有目标库承载活动业务和配置历史,源库只是保留的离线证据。
## 证据与收尾复核
本地证据均位于 `test-log/production-remediation-20260921/`:
- 双向汇总:`cross-sql-results-20260921-072145.json`。
- 原始证据:`cross-sql-runtime-evidence/` 下对应两个实例,共 26 份有效文件。
- 独立复核:`cross-sql-recheck-20260921-073040.json`,重新核对本地与云端摘要、六个工具及 611 个后端源码摘要。
- 全量后端统计:`character-full-backend-result.json`,保留全部跳过名称。
- 云端部署回归:`python-linux-result-20260921-072946.json` 及对应完整日志。
独立查询数据库系统表确认四个源/目标账号均锁定;两个 PostgreSQL 账号均不可登录、没有建库权限、不是超级用户。两轮桥接、应用、网络锚点及诊断单元均已停止。正式 Smail、Nginx、MySQL、PostgreSQL、Scert、FDM 的 PID、InvocationID、重启次数保持一致,正式程序摘要仍为 `c14ef1c5ba1dc2096c312c8357039a7330c985cbeac90765aed01d8151e05e1f`。
用户已有的 `docs/云端全项目测试报告.md` 未编辑、未暂存,摘要仍为 `A142FAA660487656124A8BD4A3EF4F58ED80B3DEC0EDA4AAB0F20B8C3297FF08`。失败目标、离线源库和诊断证据未删除。