fix: v0.6.0 复查修正 — KVStore 快照损坏水位 bug(metaSeq 误跳日志)+ 快照损坏测试盲区修复(此前篡改未生效)+ metaSeq 回归测试 + KVStoreEngine 真实浏览器 e2e(3 用例)+ 版本/配置文档校准
This commit is contained in:
@@ -122,28 +122,54 @@ describe('KVStore — 持久化与崩溃恢复', () => {
|
||||
await kv2.close();
|
||||
});
|
||||
|
||||
it('快照损坏 → 全量日志重放自愈(数据不丢)', async () => {
|
||||
it('快照损坏 → 全量日志重放:日志数据保留,快照唯一副本丢失(自愈不崩)', async () => {
|
||||
const dbName = uniqueDB();
|
||||
const medium = new SharedMemoryBackend();
|
||||
const kv1 = new KVStore(medium, 0);
|
||||
await kv1.open(dbName);
|
||||
await kv1.putMany({ a: enc('AAA'), b: enc('BBB') });
|
||||
await kv1.checkpoint();
|
||||
await kv1.put('c', enc('CCC'));
|
||||
await kv1.checkpoint(); // 快照成为 a/b 的唯一副本(日志已截断)
|
||||
await kv1.put('c', enc('CCC')); // 日志中(seq=2)
|
||||
await kv1.close();
|
||||
|
||||
// 篡改快照(模拟损坏)
|
||||
const snap = await medium.read('__kv_snapshot');
|
||||
// 篡改快照(close 后介质不可用,重新打开访问"磁盘")
|
||||
const disk = new SharedMemoryBackend();
|
||||
await disk.open(dbName);
|
||||
const snap = await disk.read('__kv_snapshot');
|
||||
expect(snap).not.toBeNull();
|
||||
const corrupted = new Uint8Array(snap as ArrayBuffer);
|
||||
corrupted[20] ^= 0xff;
|
||||
await medium.write('__kv_snapshot', corrupted.buffer as ArrayBuffer);
|
||||
corrupted[20] ^= 0xff; // 破坏 entry 长度字段 → CRC/边界校验失败
|
||||
await disk.write('__kv_snapshot', corrupted.buffer as ArrayBuffer);
|
||||
|
||||
const kv2 = new KVStore(medium, 0);
|
||||
await kv2.open(dbName);
|
||||
// 快照损坏 → 全量日志重放
|
||||
// 快照损坏 → 全量日志重放:c(日志中)保留;a/b(快照唯一副本)丢失
|
||||
expect(await kv2.exists('a')).toBe(false);
|
||||
expect(await kv2.exists('b')).toBe(false);
|
||||
expect(dec(await kv2.get('c'))).toBe('CCC');
|
||||
await kv2.close();
|
||||
});
|
||||
|
||||
it('回归:快照完好但 meta.seq 超前 → 日志不被 metaSeq 跳过(水位只信任快照)', async () => {
|
||||
const dbName = uniqueDB();
|
||||
const medium = new SharedMemoryBackend();
|
||||
const kv1 = new KVStore(medium, 0);
|
||||
await kv1.open(dbName);
|
||||
await kv1.put('a', enc('AAA'));
|
||||
await kv1.checkpoint(); // 快照 seq=1,meta seq=1,日志截断
|
||||
await kv1.put('b', enc('BBB')); // 日志 seq=2
|
||||
await kv1.close();
|
||||
|
||||
// 手工把 meta.seq 改大(模拟异常状态:meta 比日志内容超前)
|
||||
const disk = new SharedMemoryBackend();
|
||||
await disk.open(dbName);
|
||||
await disk.write('__kv_meta', new TextEncoder().encode(JSON.stringify({ seq: 999 })).buffer);
|
||||
|
||||
const kv2 = new KVStore(medium, 0);
|
||||
await kv2.open(dbName);
|
||||
// 快照完好(seq=1)→ 水位=1 → 日志 seq2 应用;meta.seq=999 不参与水位判断
|
||||
expect(dec(await kv2.get('a'))).toBe('AAA');
|
||||
expect(dec(await kv2.get('b'))).toBe('BBB');
|
||||
expect(dec(await kv2.get('c'))).toBe('CCC');
|
||||
await kv2.close();
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user