/** * KVStoreEngine — 大规模压力测试(10 万级) * * 验证生产级可靠性: * 1. 10 万 key 批量写入 + checkpoint + 重开全量验证 * 2. 混合操作(insert/update/delete)5 万级 + 崩溃模拟(不 checkpoint 断开)→ 重开验证已确认写入 * 3. 多 checkpoint 循环下数据不丢 */ import { KVStoreEngine } from '../../src/engine/kvstore_engine'; import { SharedMemoryBackend } from '../../src/engine/kvstore/shared_memory_medium'; import { createSchema } from '../../src/table/schema'; let counter = 0; function uniqueDB(): string { return `stress-${Date.now()}-${++counter}-${Math.random().toString(36).slice(2, 6)}`; } beforeEach(() => { SharedMemoryBackend.clearRegistry(); }); describe('KVStoreEngine — 10 万级压力', () => { it('10 万 key 写入 + checkpoint + 重开全量验证', async () => { const dbName = uniqueDB(); const engine = new KVStoreEngine(new SharedMemoryBackend()); await engine.open(dbName, 1); await engine.createTable(createSchema('big', { id: { type: 'string', primaryKey: true }, val: { type: 'number' }, name: { type: 'string' }, })); const TOTAL = 100000; // 分批写入(每批 1000) for (let batch = 0; batch < TOTAL / 1000; batch++) { const rows = [] as Record[]; for (let i = 0; i < 1000; i++) { const idx = batch * 1000 + i; rows.push({ id: `k${idx}`, val: idx, name: `User${idx}` }); } await engine.insert('big', rows); // 每 20 批 checkpoint 一次 if ((batch + 1) % 20 === 0) { await (engine as any).kv.checkpoint(); } } expect(await engine.count('big')).toBe(TOTAL); await engine.close(); // 重开:全量验证 const engine2 = new KVStoreEngine(new SharedMemoryBackend()); await engine2.open(dbName, 1); expect(await engine2.count('big')).toBe(TOTAL); // 抽样验证 for (const id of ['k0', 'k49999', 'k99999', 'k12345']) { const rows = await engine2.find('big', { table: 'big', where: { id } }); expect(rows).toHaveLength(1); expect(Number(rows[0].val)).toBe(Number(id.slice(1))); } await engine2.close(); }, 120000); it('5 万混合操作 + 崩溃模拟(不 checkpoint)→ 重开全部已确认写入可见', async () => { const dbName = uniqueDB(); const engine = new KVStoreEngine(new SharedMemoryBackend()); await engine.open(dbName, 1); await engine.createTable(createSchema('ops', { id: { type: 'string', primaryKey: true }, val: { type: 'number' }, })); let seed = 42; const rand = () => { seed = (seed * 1103515245 + 12345) & 0x7fffffff; return seed / 0x7fffffff; }; const confirmed = new Map(); const TOTAL = 50000; for (let i = 0; i < TOTAL; i++) { const r = rand(); const id = `k${Math.floor(rand() * 20000)}`; if (r < 0.6) { const val = Math.floor(rand() * 1000000); try { await engine.insert('ops', [{ id, val }]); confirmed.set(id, val); } catch (e) { if ((e as { code?: string }).code !== 'DUPLICATE_KEY') throw e; } } else if (r < 0.8) { const val = Math.floor(rand() * 1000000); await engine.update('ops', { table: 'ops', where: { id } }, { val }); if (confirmed.has(id)) confirmed.set(id, val); } else { await engine.delete('ops', { table: 'ops', where: { id } }); confirmed.delete(id); } // 每 5000 次 checkpoint if ((i + 1) % 5000 === 0) { await (engine as any).kv.checkpoint(); } } // 崩溃模拟:直接断开(不 close → 数据在 KVStore 日志/快照) await engine.close(); const engine2 = new KVStoreEngine(new SharedMemoryBackend()); await engine2.open(dbName, 1); expect(await engine2.count('ops')).toBe(confirmed.size); // 抽样验证值 let sampled = 0; for (const [id, val] of confirmed) { if (sampled++ > 1000) break; const rows = await engine2.find('ops', { table: 'ops', where: { id } }); expect(rows[0].val).toBe(val); } await engine2.close(); }, 120000); it('多次 checkpoint 循环(500 次)数据不丢', async () => { const dbName = uniqueDB(); const engine = new KVStoreEngine(new SharedMemoryBackend(), 0); await engine.open(dbName, 1); await engine.createTable(createSchema('t', { id: { type: 'string', primaryKey: true }, v: { type: 'number' }, })); for (let i = 0; i < 500; i++) { await engine.insert('t', [{ id: `k${i}`, v: i }]); await (engine as any).kv.checkpoint(); } await engine.close(); const engine2 = new KVStoreEngine(new SharedMemoryBackend(), 0); await engine2.open(dbName, 1); expect(await engine2.count('t')).toBe(500); const last = await engine2.find('t', { table: 't', where: { id: 'k499' } }); expect(last[0].v).toBe(499); await engine2.close(); }, 60000); });