release: v0.5.1 — 存储后端生产级硬化(CRC-32/全库加密/WAL分片/页面化存储/多标签页锁/e2e)+ 深度审查修复(假实现接线/死代码清理)
This commit is contained in:
Vendored
+145
-62
@@ -1,3 +1,44 @@
|
||||
interface AriaEngineConfig {
|
||||
/** 页面大小(默认 4096) */
|
||||
pageSize?: number;
|
||||
/** Buffer Pool 页面数量(默认 256) */
|
||||
bufferPoolPages?: number;
|
||||
/** MemTable 刷盘阈值(默认 4MB) */
|
||||
memtableSizeThreshold?: number;
|
||||
/** LSM 层级之间的容量倍数(默认 10) */
|
||||
levelSizeMultiplier?: number;
|
||||
/** Bloom Filter 每 key 位数(默认 10) */
|
||||
bloomFilterBitsPerKey?: number;
|
||||
/** 是否启用 WAL(默认 true) */
|
||||
walEnabled?: boolean;
|
||||
/** WAL 同步模式 */
|
||||
walSyncMode?: 'full' | 'batch' | 'none';
|
||||
/** Checkpoint 间隔(操作数,默认 1000) */
|
||||
checkpointInterval?: number;
|
||||
/** 是否启用页面压缩(默认 false) */
|
||||
compression?: boolean;
|
||||
/** 存储后端 */
|
||||
storageBackend?: 'indexeddb' | 'opfs' | 'memory';
|
||||
/** WAL 大小阈值(字节,超过则强制 checkpoint,默认 16MB) */
|
||||
walSizeThreshold?: number;
|
||||
/** 最大内存预算(MB,默认 64) */
|
||||
maxMemoryMB?: number;
|
||||
/**
|
||||
* v0.4.5: 全库 AES-256-GCM 加密(backend 层透明加解密,WAL/SSTable/Schema/元数据全覆盖)。
|
||||
* 密钥由 PBKDF2(salt 持久化于库内 __aria_keymeta)派生,重启用同一密码即可解密。
|
||||
*/
|
||||
encryption?: {
|
||||
/** 加密密码 */
|
||||
password: string;
|
||||
};
|
||||
/**
|
||||
* v0.4.5: SSTable 页面化存储(4KB 页面 + BufferPool/FileManager 管理,LRU 缓存)。
|
||||
* 默认:storageBackend === 'opfs' 时自动启用(大文件随机读/写放大优化);
|
||||
* 显式 false 强制关闭(整 value 存储,兼容旧行为)。
|
||||
*/
|
||||
pageStorage?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* metona-sqlark Constants — 类型定义 / 默认配置 / 枚举
|
||||
* @module constants
|
||||
@@ -64,6 +105,11 @@ interface DatabaseConfig {
|
||||
debug?: boolean;
|
||||
/** 多标签页同步(v0.3.2):BroadcastChannel 广播表变更,其他标签页自动刷新 */
|
||||
multiTabSync?: boolean;
|
||||
/**
|
||||
* v0.4.5: AriaEngine 专属配置(mode='aria' 时透传):
|
||||
* walSyncMode / checkpointInterval / encryption / pageStorage / compression 等
|
||||
*/
|
||||
aria?: AriaEngineConfig;
|
||||
}
|
||||
/** Where 条件操作符 */
|
||||
type WhereOperator = '$eq' | '$ne' | '$gt' | '$gte' | '$lt' | '$lte' | '$in' | '$nin' | '$like' | '$and' | '$or' | '$not';
|
||||
@@ -118,7 +164,7 @@ interface MetonaPlugin {
|
||||
/** 销毁 */
|
||||
destroy(): void;
|
||||
}
|
||||
declare const VERSION = "0.4.4";
|
||||
declare const VERSION = "0.5.1";
|
||||
|
||||
/**
|
||||
* metona-sqlark Plugin — 插件系统
|
||||
@@ -350,7 +396,28 @@ interface CommitTransactionStatement {
|
||||
interface RollbackTransactionStatement {
|
||||
type: 'ROLLBACK';
|
||||
}
|
||||
type Statement = SelectStatement | SelectUnionStatement | ExplainStatement | InsertStatement | UpdateStatement | DeleteStatement | CreateTableStatement | DropTableStatement | AlterTableStatement | TruncateTableStatement | CreateIndexStatement | DropIndexStatement | BeginTransactionStatement | CommitTransactionStatement | RollbackTransactionStatement;
|
||||
/** SAVEPOINT name / ROLLBACK TO SAVEPOINT name / RELEASE SAVEPOINT name */
|
||||
interface SavepointStatement {
|
||||
type: 'SAVEPOINT';
|
||||
name: string;
|
||||
/** SAVE = 创建;ROLLBACK = 回滚到;RELEASE = 释放 */
|
||||
action: 'SAVE' | 'ROLLBACK' | 'RELEASE';
|
||||
}
|
||||
/** ANALYZE TABLE name — 收集表统计信息 */
|
||||
interface AnalyzeStatement {
|
||||
type: 'ANALYZE';
|
||||
table: string;
|
||||
}
|
||||
/** REINDEX TABLE name — 重建表二级索引 */
|
||||
interface ReindexStatement {
|
||||
type: 'REINDEX';
|
||||
table: string;
|
||||
}
|
||||
/** VACUUM — 压缩 LSM + 清理碎片 */
|
||||
interface VacuumStatement {
|
||||
type: 'VACUUM';
|
||||
}
|
||||
type Statement = SelectStatement | SelectUnionStatement | ExplainStatement | InsertStatement | UpdateStatement | DeleteStatement | CreateTableStatement | DropTableStatement | AlterTableStatement | TruncateTableStatement | CreateIndexStatement | DropIndexStatement | BeginTransactionStatement | CommitTransactionStatement | RollbackTransactionStatement | SavepointStatement | AnalyzeStatement | ReindexStatement | VacuumStatement;
|
||||
|
||||
/**
|
||||
* metona-sqlark Query Executor — AST 执行器
|
||||
@@ -363,8 +430,6 @@ declare class QueryExecutor {
|
||||
private engine;
|
||||
private maxRowsPerQuery;
|
||||
constructor(engine: IStorageEngine, maxRowsPerQuery?: number);
|
||||
/** 设置查询结果行数上限 */
|
||||
setMaxRowsPerQuery(max: number): void;
|
||||
execute(stmt: Statement): Promise<unknown>;
|
||||
/** 递归执行 UNION / UNION ALL,返回合并结果 */
|
||||
private executeSelectUnion;
|
||||
@@ -406,6 +471,14 @@ declare class QueryExecutor {
|
||||
private executeBegin;
|
||||
private executeCommit;
|
||||
private executeRollback;
|
||||
/** SAVEPOINT name / ROLLBACK TO SAVEPOINT name / RELEASE SAVEPOINT name */
|
||||
private executeSavepoint;
|
||||
/** ANALYZE TABLE name — 收集表统计信息 */
|
||||
private executeAnalyze;
|
||||
/** REINDEX TABLE name — 重建表二级索引 */
|
||||
private executeReindex;
|
||||
/** VACUUM — 压缩 LSM + 清理碎片 */
|
||||
private executeVacuum;
|
||||
/** 列列表是否包含 CASE WHEN 表达式 */
|
||||
private hasCaseColumn;
|
||||
/**
|
||||
@@ -456,14 +529,6 @@ declare class QueryExecutor {
|
||||
private resolveOperatorSubqueries;
|
||||
}
|
||||
|
||||
/**
|
||||
* metona-sqlark Query Builder — 链式查询构建器
|
||||
* @module query/builder
|
||||
*
|
||||
* 链式调用 → 构建 AST → 执行引擎操作。
|
||||
* 支持 JOIN(需要 Executor)。
|
||||
*/
|
||||
|
||||
declare class SelectQueryBuilder {
|
||||
private engine;
|
||||
private tableName;
|
||||
@@ -508,7 +573,9 @@ declare class UpdateQueryBuilder {
|
||||
private _updates;
|
||||
private _where;
|
||||
private onWrite?;
|
||||
constructor(engine: IStorageEngine, tableName: string, _updates: Record<string, unknown>, onWrite?: (table: string) => void);
|
||||
/** v0.5.1: CRUD hooks 触发回调 */
|
||||
private onHooks?;
|
||||
constructor(engine: IStorageEngine, tableName: string, _updates: Record<string, unknown>, onWrite?: (table: string) => void, onHooks?: (hook: HookName, args: unknown[]) => Promise<void>);
|
||||
where(condition: WhereCondition): this;
|
||||
execute(): Promise<number>;
|
||||
toAST(): UpdateStatement;
|
||||
@@ -518,17 +585,14 @@ declare class DeleteQueryBuilder {
|
||||
private tableName;
|
||||
private _where;
|
||||
private onWrite?;
|
||||
constructor(engine: IStorageEngine, tableName: string, onWrite?: (table: string) => void);
|
||||
/** v0.5.1: CRUD hooks 触发回调 */
|
||||
private onHooks?;
|
||||
constructor(engine: IStorageEngine, tableName: string, onWrite?: (table: string) => void, onHooks?: (hook: HookName, args: unknown[]) => Promise<void>);
|
||||
where(condition: WhereCondition): this;
|
||||
execute(): Promise<number>;
|
||||
toAST(): DeleteStatement;
|
||||
}
|
||||
|
||||
/**
|
||||
* metona-sqlark Table — 表操作 API
|
||||
* @module table/table
|
||||
*/
|
||||
|
||||
declare class Table<T = Record<string, unknown>> {
|
||||
readonly name: string;
|
||||
private engine;
|
||||
@@ -536,7 +600,9 @@ declare class Table<T = Record<string, unknown>> {
|
||||
private executor;
|
||||
/** 写入回调(多标签页广播,v0.3.2) */
|
||||
private onWrite?;
|
||||
constructor(engine: IStorageEngine, tableName: string, executor?: QueryExecutor, onWrite?: (table: string) => void);
|
||||
/** v0.5.1: CRUD 生命周期钩子触发回调(beforeInsert/afterInsert/... 真实接线) */
|
||||
private onHooks?;
|
||||
constructor(engine: IStorageEngine, tableName: string, executor?: QueryExecutor, onWrite?: (table: string) => void, onHooks?: (hook: HookName, args: unknown[]) => Promise<void>);
|
||||
getSchema(): Promise<TableSchema>;
|
||||
insert(row: T & Record<string, unknown>): Promise<string>;
|
||||
insertMany(rows: (T & Record<string, unknown>)[]): Promise<string[]>;
|
||||
@@ -637,6 +703,11 @@ declare class MetonaSqlark {
|
||||
importTable(tableName: string, data: Record<string, unknown>[]): Promise<string[]>;
|
||||
/** 导出整个数据库为 JSON */
|
||||
exportAll(): Promise<Record<string, Record<string, unknown>[]>>;
|
||||
/**
|
||||
* v0.5.1: 在线备份 — 导出全库一致性快照。
|
||||
* Aria 引擎走引擎级 backup()(MVCC 一致性视图);其余引擎回退 exportAll()。
|
||||
*/
|
||||
backup(): Promise<Record<string, Record<string, unknown>[]>>;
|
||||
private listeners;
|
||||
/** 订阅表变更 */
|
||||
subscribe(tableName: string, callback: (event: {
|
||||
@@ -654,6 +725,12 @@ declare class MetonaSqlark {
|
||||
broadcastChange(tableName: string): void;
|
||||
/** 写语句对应的表名(多标签页广播用) */
|
||||
private writeStatementTable;
|
||||
/**
|
||||
* v0.5.1: SQL 写语句触发 CRUD 生命周期钩子。
|
||||
* INSERT/UPDATE/DELETE 分别触发 beforeInsert/afterInsert、beforeUpdate/afterUpdate、
|
||||
* beforeDelete/afterDelete(参数与 Table API 路径一致)。
|
||||
*/
|
||||
private triggerStatementHooks;
|
||||
private migrations;
|
||||
/** 注册迁移 */
|
||||
addMigration(version: number, up: (db: MetonaSqlark) => Promise<void>): void;
|
||||
@@ -901,35 +978,6 @@ declare class OPFSEngine implements IStorageEngine {
|
||||
* 空表不再消失、索引标记/主键/约束完整;无 schema 记录的旧库从数据推断(兼容)。
|
||||
*/
|
||||
private loadExistingTables;
|
||||
/** 从 OPFS 加载表数据到内存缓存 */
|
||||
loadTableIntoMemory(tableName: string, schema: TableSchema): Promise<void>;
|
||||
}
|
||||
|
||||
interface AriaEngineConfig {
|
||||
/** 页面大小(默认 4096) */
|
||||
pageSize?: number;
|
||||
/** Buffer Pool 页面数量(默认 256) */
|
||||
bufferPoolPages?: number;
|
||||
/** MemTable 刷盘阈值(默认 4MB) */
|
||||
memtableSizeThreshold?: number;
|
||||
/** LSM 层级之间的容量倍数(默认 10) */
|
||||
levelSizeMultiplier?: number;
|
||||
/** Bloom Filter 每 key 位数(默认 10) */
|
||||
bloomFilterBitsPerKey?: number;
|
||||
/** 是否启用 WAL(默认 true) */
|
||||
walEnabled?: boolean;
|
||||
/** WAL 同步模式 */
|
||||
walSyncMode?: 'full' | 'batch' | 'none';
|
||||
/** Checkpoint 间隔(操作数,默认 1000) */
|
||||
checkpointInterval?: number;
|
||||
/** 是否启用页面压缩(默认 false) */
|
||||
compression?: boolean;
|
||||
/** 存储后端 */
|
||||
storageBackend?: 'indexeddb' | 'opfs' | 'memory';
|
||||
/** WAL 大小阈值(字节,超过则强制 checkpoint,默认 16MB) */
|
||||
walSizeThreshold?: number;
|
||||
/** 最大内存预算(MB,默认 64) */
|
||||
maxMemoryMB?: number;
|
||||
}
|
||||
|
||||
declare class AriaEngine implements IStorageEngine {
|
||||
@@ -941,6 +989,9 @@ declare class AriaEngine implements IStorageEngine {
|
||||
private backend;
|
||||
private opened;
|
||||
private dbName;
|
||||
private fileManager;
|
||||
private bufferPool;
|
||||
private dbLock;
|
||||
private schemas;
|
||||
private tablePKs;
|
||||
private opCounter;
|
||||
@@ -949,7 +1000,6 @@ declare class AriaEngine implements IStorageEngine {
|
||||
private currentTxnId;
|
||||
private txnSnapshot;
|
||||
private gcCounter;
|
||||
private bufferPool;
|
||||
constructor(config?: AriaEngineConfig);
|
||||
open(dbName: string, _version: number): Promise<void>;
|
||||
/** open 内部实现(错误包装在 open 外层) */
|
||||
@@ -957,9 +1007,15 @@ declare class AriaEngine implements IStorageEngine {
|
||||
close(): Promise<void>;
|
||||
/**
|
||||
* v0.4.2-fix: 崩溃恢复/自愈 — 校验并移除损坏 SSTable、截断 WAL、重建二级索引。
|
||||
* v0.4.5 增强:清理 OPFS 残留临时文件、清理孤儿页面(meta 未引用的 pg_ 文件)。
|
||||
* 应用层检测到异常后调用,无需删库重建。
|
||||
*/
|
||||
repair(): Promise<void>;
|
||||
/**
|
||||
* v0.4.5: 清理孤儿页面 — 扫描全部 pg_* 文件,未被任何 LSM 命名空间 meta 引用的删除。
|
||||
* 孤儿页面来自:崩溃中断的 compaction/删除流程(旧 SSTable 页面残留)。
|
||||
*/
|
||||
private cleanupOrphanPages;
|
||||
/**
|
||||
* v0.4.1: 重置数据库 — 清空全部数据与表结构(演示页刷新/重新初始化用)。
|
||||
* 清空存储后端、LSM、WAL、MVCC 与二级索引,后续可继续使用本实例。
|
||||
@@ -1044,6 +1100,8 @@ declare class AriaEngine implements IStorageEngine {
|
||||
* - id 序列独立(避免 v0.2.4 共享 id 空间导致的文件互相覆盖)
|
||||
*/
|
||||
private createSSTableStore;
|
||||
/** v0.4.5: 是否启用页面化物理存储(默认 OPFS 后端启用,显式配置可覆盖) */
|
||||
private isPageStorage;
|
||||
private applyWALRecord;
|
||||
/**
|
||||
* v0.3.3: DROP_TABLE 恢复 — 删除 schema 并清除主 LSM 中该表的所有残留数据。
|
||||
@@ -1084,21 +1142,10 @@ declare class AriaEngine implements IStorageEngine {
|
||||
compactedLevels: number;
|
||||
gcVersions: number;
|
||||
}>;
|
||||
/**
|
||||
* 查询优化器:估算各索引成本,选择最优方案
|
||||
*/
|
||||
estimateQueryCost(tableName: string, query: QueryPlan): {
|
||||
strategy: string;
|
||||
estimatedRows: number;
|
||||
};
|
||||
private ensureOpen;
|
||||
/** v0.4.2-fix: Aria 事务中 DDL 显式拒绝(结构变更无法通过行快照回滚) */
|
||||
private ensureNoDDLInTransaction;
|
||||
private ensureTable;
|
||||
/** Get the number of WAL records stored */
|
||||
private getWALCount;
|
||||
/** Set the number of WAL records stored */
|
||||
private setWALCount;
|
||||
}
|
||||
|
||||
declare class HybridEngine implements IStorageEngine {
|
||||
@@ -1234,6 +1281,13 @@ declare enum TokenType {
|
||||
THEN = "THEN",
|
||||
ELSE = "ELSE",
|
||||
END = "END",
|
||||
EXPLAIN = "EXPLAIN",
|
||||
ANALYZE = "ANALYZE",
|
||||
REINDEX = "REINDEX",
|
||||
VACUUM = "VACUUM",
|
||||
SAVEPOINT = "SAVEPOINT",
|
||||
RELEASE = "RELEASE",
|
||||
TO = "TO",
|
||||
IDENTIFIER = "IDENTIFIER",
|
||||
STRING = "STRING",
|
||||
NUMBER = "NUMBER",
|
||||
@@ -1286,6 +1340,13 @@ interface IStorageBackend {
|
||||
read(key: string): Promise<ArrayBuffer | null>;
|
||||
/** 写入数据块 */
|
||||
write(key: string, data: ArrayBuffer): Promise<void>;
|
||||
/**
|
||||
* 追加写入(v0.4.5 WAL 分片用,可选):
|
||||
* - OPFS 后端实现真追加(createWritable keepExistingData + seek,O(chunk))
|
||||
* - 未实现的后端由调用方回退 read+write(EncryptedBackend 包装时整体重写保正确性)
|
||||
* 语义:在 key 现有内容末尾追加 data;key 不存在时等同 write。
|
||||
*/
|
||||
append?(key: string, data: ArrayBuffer): Promise<void>;
|
||||
/**
|
||||
* 批量原子写入(v0.4.2-fix):多个 key 在单个底层事务中提交,
|
||||
* 中断时整体回滚,不留半写状态。WAL count 与记录同事务保证一致性。
|
||||
@@ -1312,7 +1373,17 @@ interface IStorageBackend {
|
||||
* 零外部依赖,纯浏览器文件系统 API。
|
||||
* 每个 key 对应 OPFS 目录下的一个二进制文件。
|
||||
*
|
||||
* 浏览器要求:Chrome 102+ / Edge 102+
|
||||
* 原子性与一致性保证(v0.4.5 固化):
|
||||
* - 单文件 write/append:createWritable 为 copy-on-write —— close 前崩溃旧文件保持不变,
|
||||
* close 后原子替换(单文件写入原子)
|
||||
* - 多文件 writeMany/deleteMany:OPFS 无跨文件事务,串行逐个落盘;调用方(WAL 分片)
|
||||
* 已改为单文件语义,多键操作仅用于一次性的 schema/meta 写入
|
||||
* - 所有写操作串行队列化(同源同进程顺序一致);单次任务失败不中断队列链,
|
||||
* 错误如实返回给该次调用的调用方
|
||||
* - close() 等待写队列排空后再释放目录句柄(杜绝 close 后挂起写丢失/读旧数据)
|
||||
* - open() 自动清理崩溃残留临时文件(Chromium createWritable 的 .crswap 等)
|
||||
*
|
||||
* 浏览器要求:Chrome 102+ / Edge 102+(Safari 15.2+ / Firefox 111+ 支持基础 OPFS)
|
||||
*/
|
||||
|
||||
declare class OPFSBackend implements IStorageBackend {
|
||||
@@ -1323,8 +1394,20 @@ declare class OPFSBackend implements IStorageBackend {
|
||||
open(name: string): Promise<void>;
|
||||
close(): Promise<void>;
|
||||
isOpen(): boolean;
|
||||
/** 清理崩溃残留的临时文件(open 时自动调用,repair 也可调用) */
|
||||
cleanupStaleFiles(): Promise<void>;
|
||||
read(key: string): Promise<ArrayBuffer | null>;
|
||||
/**
|
||||
* 单文件原子写:createWritable 为 copy-on-write,close 后原子替换;
|
||||
* 写入期间崩溃 → 旧文件保持(原子性由浏览器 OPFS 实现保证)。
|
||||
*/
|
||||
write(key: string, data: ArrayBuffer): Promise<void>;
|
||||
/**
|
||||
* v0.4.5: 真追加写 — createWritable(keepExistingData) + seek 到文件末尾。
|
||||
* 单文件 COW 原子(close 前崩溃旧文件保持),无需读旧内容即实现 O(chunk) 追加
|
||||
* (WAL 分片高频写入用)。
|
||||
*/
|
||||
append(key: string, data: ArrayBuffer): Promise<void>;
|
||||
/** v0.4.2-fix: 批量写入 — 串行队列内逐个落盘(OPFS 无跨文件事务,顺序保证一致) */
|
||||
writeMany(entries: Record<string, ArrayBuffer>): Promise<void>;
|
||||
delete(key: string): Promise<void>;
|
||||
|
||||
Reference in New Issue
Block a user