/** * metona-sqlark Hybrid Engine — 内存 + 磁盘混合存储引擎 * @module hybrid/index * * 采用 write-through 策略: * - 所有写操作同时写入内存和磁盘 * - 所有读操作直接从内存返回 * - 数据库打开时从磁盘加载数据到内存 */ import type { IStorageEngine } from '../engine/interface'; import type { QueryPlan, TableSchema, DiskEngine } from '../constants'; import { MemoryEngine } from '../engine/memory'; import { IndexedDBEngine } from '../engine/indexeddb'; import { OPFSEngine } from '../engine/opfs'; // --------------------------------------------------------------------------- // HybridEngine // --------------------------------------------------------------------------- export class HybridEngine implements IStorageEngine { readonly name = 'hybrid'; private memoryEngine: MemoryEngine; private diskEngine: IStorageEngine; private diskEngineType: DiskEngine; constructor(diskEngine: DiskEngine = 'indexeddb') { this.memoryEngine = new MemoryEngine(); this.diskEngineType = diskEngine; this.diskEngine = diskEngine === 'opfs' ? new OPFSEngine() : new IndexedDBEngine(); } // ---- 生命周期 ---- async open(dbName: string, version: number): Promise { // 先打开磁盘引擎 await this.diskEngine.open(dbName, version); // 再打开内存引擎 await this.memoryEngine.open(dbName, version); // 从磁盘加载现存表 const tableNames = await this.diskEngine.getTableNames(); for (const tableName of tableNames) { const schema = await this.diskEngine.getTableSchema(tableName); if (!schema) continue; // 在内存中创建表 await this.memoryEngine.createTable(schema); // 从磁盘加载数据到内存 const rows = await this.diskEngine.find(tableName, { table: tableName }); if (rows.length > 0) { try { await this.memoryEngine.insert(tableName, rows); } catch (e) { // eslint-disable-next-line no-console console.warn(`[metona-sqlark] Failed to load table "${tableName}" data from disk:`, e); } } } } async close(): Promise { await this.memoryEngine.close(); await this.diskEngine.close(); } isOpen(): boolean { return this.memoryEngine.isOpen() && this.diskEngine.isOpen(); } // ---- 表管理 ---- async createTable(schema: TableSchema): Promise { await this.memoryEngine.createTable(schema); await this.diskEngine.createTable(schema); } async dropTable(tableName: string): Promise { await this.memoryEngine.dropTable(tableName); await this.diskEngine.dropTable(tableName); } async hasTable(tableName: string): Promise { return this.memoryEngine.hasTable(tableName); } async getTableNames(): Promise { return this.memoryEngine.getTableNames(); } async getTableSchema(tableName: string): Promise { return this.memoryEngine.getTableSchema(tableName); } // ---- CRUD(write-through 策略) ---- async insert(tableName: string, rows: Record[]): Promise { const pks = await this.memoryEngine.insert(tableName, rows); // write-through: 同步写入磁盘 await this.diskEngine.insert(tableName, rows); return pks; } async find(tableName: string, query: QueryPlan): Promise[]> { // 直接从内存读取 return this.memoryEngine.find(tableName, query); } async update(tableName: string, query: QueryPlan, updates: Record): Promise { const count = await this.memoryEngine.update(tableName, query, updates); // write-through: 同步更新磁盘 await this.diskEngine.update(tableName, query, updates); return count; } async delete(tableName: string, query: QueryPlan): Promise { const count = await this.memoryEngine.delete(tableName, query); // write-through: 同步删除磁盘 await this.diskEngine.delete(tableName, query); return count; } async count(tableName: string, query?: QueryPlan): Promise { return this.memoryEngine.count(tableName, query); } async clear(tableName: string): Promise { await this.memoryEngine.clear(tableName); await this.diskEngine.clear(tableName); } // ---- 事务 ---- async beginTransaction(): Promise { await this.memoryEngine.beginTransaction(); await this.diskEngine.beginTransaction(); } async commitTransaction(): Promise { await this.memoryEngine.commitTransaction(); await this.diskEngine.commitTransaction(); } async rollbackTransaction(): Promise { await this.memoryEngine.rollbackTransaction(); await this.diskEngine.rollbackTransaction(); } // ---- 引擎信息 ---- /** 获取磁盘引擎类型 */ getDiskEngineType(): DiskEngine { return this.diskEngineType; } /** 获取内存引擎(供内部使用) */ getMemoryEngine(): MemoryEngine { return this.memoryEngine; } }