fix(v0.8.0): 全量回归审查 —— 1 处 P0 数据丢失 + 4 处 P1 + 9 处 P2 根因修复
方法:四个对抗性子代理分头审查(数据正确性 / 文档宣称 vs 实现 / 公共 API 契约 / 测试质量),每条结论要求可复现证据;逐条复核 + 探针确认 + 变异验证(40 项全部 被对应用例拦住)。 P0:事务活跃期间 repair()/close()/周期 checkpoint 推进 WAL 水位 → 已 COMMIT 的 事务整批消失且恢复报告"干净"。根因 hasPendingFlushData()/computeDurableLsn() 不看 txnSnapshot;守卫此前只在 CheckpointManager 两个回调里。修复:守卫下沉到 computeDurableLsn() 与 advanceWalCheckpoint() 入口(唯一实现)。 P1: - WAL 前缀缺失丢弃整段活分片(回退上一代 manifest 时 kept 为空)→ 前缀缺失单独 记录,后缀照常重放;仅 fromLsn === 0 时才算真异常 - 孤儿回收门槛只看引擎层 dataLossSuspected,漏掉 LSM 层被丢的 SSTable → 统一 describeRecoveryDamage() 聚合判定(损坏时绝不删"引用不到"的文件) - vacuum() 逐层压缩绕过维护链 → vacuumLevels() 每层作为维护链任务执行 - reclaimRetiredNow() 无视在途读者(读者把"已退休"读成"文件损坏")→ 有读者时 退化为延迟回收 P2:WAL 记录级 CRC 损坏不计数不上报;旧格式表结构记录形状损坏静默当空库; bloomFilterBitsPerKey 配置被接受却完全不生效(构建器写死默认值,实现缺陷); 幽灵 meta;介质读故障等于文件损坏的语义无用例;manifest 回读校验两条守卫无用例; 文件名≠载荷世代判定无用例;pageIdWatermark 单调性无用例;分片号两条真实不变量 无用例。 覆盖率口径(第二处漏洞):interface.ts 混着三个运行时函数(cloneRow 等)却被 描述为"纯类型、不纳入统计" → 实现搬到 src/engine/row_clone.ts;搬完门禁真的 失败(functions 93.84% < 94%),补测退化路径后通过。 测试质量:3 条空壳用例改值级断言;1 条"全损坏"用例实际只走缓存 → 拆成两条真 用例;5 秒墙钟 race 改门控 + 失败上限;setTimeout 改 whenIdle();<= 收紧为 <。 变异脚本加固:正控(干净基线必须全绿)、编译失败/0 用例单独归类、300s 超时、 逐字节 sha256 恢复校验、O_EXCL 进程锁、锚点唯一性;变异 22 → 40 项。 文档两轮订正(16 + 11 条不成立宣称):MVCC 快照隔离、backup 一致性快照、 "空洞检测截断"、体积(251,109 B / gzip 63,145 B)、测试与覆盖率数字、 "5 种存储引擎"、Tree-shakable、错误码表补 16 个码、恢复报告字段、已知限制 (回退单向 / 多实例依赖 Web Locks / manifest 体积 / 尾部 WAL 分片不可识别)。 验证:常规套件 92 套件 / 1980 用例全绿;覆盖率 90.59 / 82.59 / 94.14 / 93.50 (阈值 90/82/94/93);e2e 14/14(真实 Chromium + OPFS + CDP 崩溃); 重型套件 4 套件 / 27 用例;变异 40/40;lint + 两份 tsc 干净;dist 已重建。
This commit is contained in:
Vendored
+38
-1
@@ -341,7 +341,13 @@ interface IStorageEngine {
|
||||
rollbackToSavepoint?(name: string): Promise<void>;
|
||||
/** 释放 Savepoint */
|
||||
releaseSavepoint?(name: string): Promise<void>;
|
||||
/** 在线备份:导出全库一致性快照 */
|
||||
/**
|
||||
* 在线备份:导出全库数据快照。
|
||||
*
|
||||
* v0.8.0(review 修正文档):返回的是**调用时刻逐表读取的结果**,不构成
|
||||
* "跨表一致性快照" —— 实现没有冻结全局版本(读取期间不会有并发写入时结果
|
||||
* 是一致的,但并发写入下不同表可能落在不同时间点)。
|
||||
*/
|
||||
backup?(): Promise<Record<string, Record<string, unknown>[]>>;
|
||||
/** 崩溃恢复自愈:校验并清理损坏数据、恢复一致性(检测到异常后调用,无需删库重建) */
|
||||
repair?(): Promise<void>;
|
||||
@@ -1652,6 +1658,8 @@ interface AriaRecoveryReport {
|
||||
dataLossSuspected: boolean;
|
||||
/** WAL 活跃区间内的分片空洞(已提交事务记录缺失) */
|
||||
walGaps: number[];
|
||||
/** v0.8.0:CRC 校验失败被跳过的 WAL 记录数(它们承载的写入已丢失) */
|
||||
droppedWALRecords: number;
|
||||
/** 本次打开是否从旧格式(__aria_lsm_meta/__aria_schemas)迁移而来 */
|
||||
legacyImported: boolean;
|
||||
/** 是否从更早的 manifest 世代回退(最新世代损坏) */
|
||||
@@ -1739,6 +1747,8 @@ declare class AriaEngine implements IStorageEngine {
|
||||
* 且 manifest 完整可信时才允许回收空间。
|
||||
*/
|
||||
private cleanupOrphanPages;
|
||||
/** v0.8.0:命名空间 → SSTable 文件 key 前缀(与 createSSTableStore 保持一致) */
|
||||
private sstableKeyPrefixes;
|
||||
/** v0.8.0: 读取某个 LSM 当前引用的层结构(诊断/孤儿回收用) */
|
||||
private getLsmLevels;
|
||||
/**
|
||||
@@ -1860,7 +1870,34 @@ declare class AriaEngine implements IStorageEngine {
|
||||
* 数据里没有"或反之的分裂状态。现在两者在同一次原子提交里生效。
|
||||
*/
|
||||
private persistSchemas;
|
||||
/**
|
||||
* v0.8.0(review 修复):表结构记录的**唯一**解析实现。
|
||||
*
|
||||
* 为什么必须集中且严格:结构记录有两种坏法 —— JSON 本身就坏了,或 JSON 合法但
|
||||
* 形状不对(数组 / null / 表名映射到非对象 / 列定义不是对象)。修复前只有
|
||||
* "JSON 坏"这一种会抛错,形状不对则被**静默忽略** → 打开后看不到任何表,
|
||||
* 表现为"库是空的"(与审计里"静默空库"同一类缺陷)。
|
||||
*
|
||||
* 判定原则:只要记录存在却不可用,就抛 ARIA_LEGACY_META_CORRUPT —— 宁可让
|
||||
* 调用方看到明确的损坏错误,也不假装这是一个没有表的空库。
|
||||
*/
|
||||
private parseSchemaRecord;
|
||||
/** 形状校验(与 parseSchemaRecord 分离:便于直接喂各种形状做单测) */
|
||||
private validateSchemaShape;
|
||||
private loadSchemas;
|
||||
/**
|
||||
* v0.8.0(review 修复): 本次打开/修复过程中出现过的**一切损坏迹象**。
|
||||
*
|
||||
* 为什么需要它而不是只看 `this.recoveryReport.dataLossSuspected`:
|
||||
* SSTable 被丢弃这一事实记录在**各 LSM** 的报告里,引擎层的 `dataLossSuspected`
|
||||
* 只在"WAL 水位已推进、被丢的数据没有 WAL 兜底"时才置位。于是"manifest 已被
|
||||
* 推进 + 某个 SSTable 因文件损坏被丢"这类**真损坏**会在引擎层看不到 —— 孤儿页
|
||||
* 回收就会照常执行,把在途/退休文件按"没人引用"删掉。
|
||||
*
|
||||
* 判定原则:只要有任何"曾经自愈/丢失/回退"的迹象,就一律不回收任何未被引用
|
||||
* 的文件(宁可留空间,也不可逆地删数据)。
|
||||
*/
|
||||
private describeRecoveryDamage;
|
||||
/**
|
||||
* v0.8.0: 恢复诊断(打开时被丢弃的 SSTable、WAL 空洞、是否怀疑数据丢失)。
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user