Files
MetonaSqlark/src/hybrid/index.ts
T
thzxx e6efa39d48
CI / test (20.x) (push) Successful in 9m58s
CI / test (18.x) (push) Successful in 10m0s
CI / test (22.x) (push) Successful in 10m0s
CI / test (24.x) (push) Successful in 9m56s
release: v0.2.1 生产加固 — WAL CRC/约束激活/Hybrid提交顺序/RESTRICT外键/浏览器兼容表/debug模式/onError回调
2026-07-27 20:47:30 +08:00

172 lines
5.3 KiB
TypeScript
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.
/**
* metona-sqlark Hybrid Engine — 内存 + 磁盘混合存储引擎
* @module hybrid/index
*
* 采用 write-through 策略:
* - 所有写操作同时写入内存和磁盘
* - 所有读操作直接从内存返回
* - 数据库打开时从磁盘加载数据到内存
*/
import type { IStorageEngine } from '../engine/interface';
import type { QueryPlan, TableSchema, DiskEngine } from '../constants';
import { DatabaseError } 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<void> {
// 先打开磁盘引擎
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<void> {
await this.memoryEngine.close();
await this.diskEngine.close();
}
isOpen(): boolean {
return this.memoryEngine.isOpen() && this.diskEngine.isOpen();
}
// ---- 表管理 ----
async createTable(schema: TableSchema): Promise<void> {
await this.memoryEngine.createTable(schema);
await this.diskEngine.createTable(schema);
}
async dropTable(tableName: string): Promise<void> {
await this.memoryEngine.dropTable(tableName);
await this.diskEngine.dropTable(tableName);
}
async hasTable(tableName: string): Promise<boolean> {
return this.memoryEngine.hasTable(tableName);
}
async getTableNames(): Promise<string[]> {
return this.memoryEngine.getTableNames();
}
async getTableSchema(tableName: string): Promise<TableSchema | null> {
return this.memoryEngine.getTableSchema(tableName);
}
// ---- CRUDwrite-through 策略) ----
async insert(tableName: string, rows: Record<string, unknown>[]): Promise<string[]> {
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<Record<string, unknown>[]> {
// 直接从内存读取
return this.memoryEngine.find(tableName, query);
}
async update(tableName: string, query: QueryPlan, updates: Record<string, unknown>): Promise<number> {
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<number> {
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<number> {
return this.memoryEngine.count(tableName, query);
}
async clear(tableName: string): Promise<void> {
await this.memoryEngine.clear(tableName);
await this.diskEngine.clear(tableName);
}
// ---- 事务 ----
async beginTransaction(): Promise<void> {
await this.memoryEngine.beginTransaction();
await this.diskEngine.beginTransaction();
}
async commitTransaction(): Promise<void> {
// 先写磁盘,保证持久化优先;磁盘失败则回滚内存
await this.diskEngine.commitTransaction();
try {
await this.memoryEngine.commitTransaction();
} catch {
// 内存提交失败时回滚磁盘
await this.diskEngine.rollbackTransaction();
throw new DatabaseError('Hybrid commit failed: memory engine error after disk commit', 'TX_COMMIT_ERROR');
}
}
async rollbackTransaction(): Promise<void> {
await this.memoryEngine.rollbackTransaction();
await this.diskEngine.rollbackTransaction();
}
// ---- 引擎信息 ----
/** 获取磁盘引擎类型 */
getDiskEngineType(): DiskEngine {
return this.diskEngineType;
}
/** 获取内存引擎(供内部使用) */
getMemoryEngine(): MemoryEngine {
return this.memoryEngine;
}
}