fix: dts TS类型修复
This commit is contained in:
Vendored
+219
-30
@@ -3076,6 +3076,114 @@ class OPFSBackend {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* AriaEngine Page Header — 页面头部编解码
|
||||
* @module engine/aria/page/header
|
||||
*/
|
||||
/**
|
||||
* 初始化新页面的 Header。
|
||||
*/
|
||||
function initPageHeader(buf, pageId, type) {
|
||||
const view = new DataView(buf);
|
||||
view.setUint32(0, pageId, false);
|
||||
view.setUint8(4, type);
|
||||
view.setUint16(5, PAGE_HEADER_SIZE, false); // freeStart = header 之后
|
||||
view.setUint16(7, buf.byteLength, false); // freeEnd = 页面末尾
|
||||
view.setUint16(9, 0, false); // slotCount = 0
|
||||
view.setUint32(11, 0, false); // checksum = 0
|
||||
view.setUint8(15, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* AriaEngine File Manager — 页面文件管理 + PageIO 实现
|
||||
* @module engine/aria/store/file_manager
|
||||
*
|
||||
* 负责管理页面文件的生命周期:分配/释放页面 ID,读写页面。
|
||||
*/
|
||||
// ---------------------------------------------------------------------------
|
||||
// FileManager (implements PageIO)
|
||||
// ---------------------------------------------------------------------------
|
||||
class FileManager {
|
||||
constructor(backend) {
|
||||
this.nextPageId = 0;
|
||||
this.metaLoaded = false;
|
||||
this.dbName = '';
|
||||
this.backend = backend;
|
||||
}
|
||||
/** 初始化:从存储中读取元数据 */
|
||||
async init(dbName) {
|
||||
this.dbName = dbName;
|
||||
const meta = await this.backend.read('__aria_meta');
|
||||
if (meta && meta instanceof ArrayBuffer && meta.byteLength >= 4) {
|
||||
const view = new DataView(meta);
|
||||
this.nextPageId = view.getUint32(0, false);
|
||||
}
|
||||
else {
|
||||
this.nextPageId = 1;
|
||||
await this.saveMeta();
|
||||
}
|
||||
this.metaLoaded = true;
|
||||
}
|
||||
// ---- PageIO ----
|
||||
async readPage(pageId) {
|
||||
const key = `pg_${pageId}`;
|
||||
const data = await this.backend.read(key);
|
||||
if (!data) {
|
||||
// 第一次访问:创建新页面
|
||||
return this.createEmptyPage(pageId, PageType.DATA);
|
||||
}
|
||||
// 确保大小正确
|
||||
if (data.byteLength < PAGE_SIZE) {
|
||||
const padded = new ArrayBuffer(PAGE_SIZE);
|
||||
new Uint8Array(padded).set(new Uint8Array(data));
|
||||
return padded;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
async writePage(pageId, data) {
|
||||
const key = `pg_${pageId}`;
|
||||
await this.backend.write(key, data);
|
||||
}
|
||||
async allocatePageId() {
|
||||
const id = this.nextPageId++;
|
||||
await this.saveMeta();
|
||||
return id;
|
||||
}
|
||||
async freePageId(_pageId) {
|
||||
// 简化实现:不回收 pageId
|
||||
const key = `pg_${_pageId}`;
|
||||
await this.backend.delete(key);
|
||||
}
|
||||
// ---- 表页面分配 ----
|
||||
/**
|
||||
* 分配一个新的表元数据页面。
|
||||
*/
|
||||
async allocateTableRootPage() {
|
||||
const pageId = await this.allocatePageId();
|
||||
const data = new ArrayBuffer(PAGE_SIZE);
|
||||
initPageHeader(data, pageId, PageType.META);
|
||||
await this.writePage(pageId, data);
|
||||
return pageId;
|
||||
}
|
||||
// ---- 辅助 ----
|
||||
async saveMeta() {
|
||||
const buf = new ArrayBuffer(8);
|
||||
new DataView(buf).setUint32(0, this.nextPageId, false);
|
||||
await this.backend.write('__aria_meta', buf);
|
||||
}
|
||||
createEmptyPage(pageId, type) {
|
||||
const buf = new ArrayBuffer(PAGE_SIZE);
|
||||
initPageHeader(buf, pageId, type);
|
||||
return buf;
|
||||
}
|
||||
/** 清空所有数据 */
|
||||
async clearAll() {
|
||||
await this.backend.clear();
|
||||
this.nextPageId = 1;
|
||||
await this.saveMeta();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* AriaEngine MVCC — 多版本并发控制
|
||||
* @module engine/aria/transaction/mvcc
|
||||
@@ -3276,24 +3384,6 @@ class MVCCManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* AriaEngine Page Header — 页面头部编解码
|
||||
* @module engine/aria/page/header
|
||||
*/
|
||||
/**
|
||||
* 初始化新页面的 Header。
|
||||
*/
|
||||
function initPageHeader(buf, pageId, type) {
|
||||
const view = new DataView(buf);
|
||||
view.setUint32(0, pageId, false);
|
||||
view.setUint8(4, type);
|
||||
view.setUint16(5, PAGE_HEADER_SIZE, false); // freeStart = header 之后
|
||||
view.setUint16(7, buf.byteLength, false); // freeEnd = 页面末尾
|
||||
view.setUint16(9, 0, false); // slotCount = 0
|
||||
view.setUint32(11, 0, false); // checksum = 0
|
||||
view.setUint8(15, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* AriaEngine Page Format — 页面格式整合层
|
||||
* @module engine/aria/page/format
|
||||
@@ -3637,6 +3727,94 @@ class BufferPool {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* AriaEngine LZ4 Compression — 简化 LZ4 压缩/解压
|
||||
* @module engine/aria/compression/lz4
|
||||
*
|
||||
* Token 格式(1 字节):
|
||||
* hi 4bit = litLen (0-15)
|
||||
* lo 4bit = matchField (0-15, 实际匹配 = field+4)
|
||||
*
|
||||
* 字面量-匹配序列: [token] [litLen bytes] [2B LE offset]
|
||||
* 末尾纯字面量: [token with lo=0] [litLen bytes] ← 仅在流末尾出现
|
||||
*/
|
||||
const MIN_MATCH = 4;
|
||||
function compressLZ4(input) {
|
||||
if (input.byteLength < MIN_MATCH)
|
||||
return input;
|
||||
const maxOut = input.byteLength + (input.byteLength >> 8) + 32;
|
||||
const out = new Uint8Array(maxOut);
|
||||
let si = 0, di = 0;
|
||||
let litStart = 0;
|
||||
while (si < input.byteLength) {
|
||||
// 搜索最长 backward match
|
||||
let bestLen = 0, bestOff = 0;
|
||||
const searchStart = Math.max(0, si - 65535);
|
||||
for (let p = searchStart; p < si; p++) {
|
||||
let ml = 0;
|
||||
while (si + ml < input.byteLength && p + ml < si &&
|
||||
input[p + ml] === input[si + ml] && ml < 255)
|
||||
ml++;
|
||||
if (ml >= MIN_MATCH && ml > bestLen) {
|
||||
bestLen = ml;
|
||||
bestOff = si - p;
|
||||
}
|
||||
}
|
||||
if (bestLen >= MIN_MATCH && (si - litStart) <= 15) {
|
||||
// 有匹配 → 输出组合 token(字面量+匹配)
|
||||
const litLen = si - litStart;
|
||||
const matchField = Math.min(bestLen - MIN_MATCH, 15);
|
||||
out[di++] = ((litLen & 0x0F) << 4) | (matchField & 0x0F);
|
||||
for (let j = 0; j < litLen; j++)
|
||||
out[di++] = input[litStart + j];
|
||||
out[di++] = bestOff & 0xFF;
|
||||
out[di++] = (bestOff >> 8) & 0xFF;
|
||||
si += bestLen;
|
||||
litStart = si;
|
||||
}
|
||||
else {
|
||||
// 无匹配或字面量已满 15 → 继续累积(不单独输出,等下个匹配合并)
|
||||
si++;
|
||||
}
|
||||
}
|
||||
// 输出末尾纯字面量(matchField=0,无 offset)
|
||||
let remaining = si - litStart;
|
||||
while (remaining > 0) {
|
||||
const chunk = Math.min(remaining, 15);
|
||||
out[di++] = (chunk & 0x0F) << 4; // lo=0 表示无匹配/无 offset
|
||||
for (let j = 0; j < chunk; j++)
|
||||
out[di++] = input[litStart + j];
|
||||
remaining -= chunk;
|
||||
litStart += chunk;
|
||||
}
|
||||
return di >= input.byteLength ? input : out.slice(0, di);
|
||||
}
|
||||
function decompressLZ4(input, originalSize) {
|
||||
const out = new Uint8Array(originalSize);
|
||||
let si = 0, di = 0;
|
||||
while (si < input.byteLength && di < originalSize) {
|
||||
const token = input[si++];
|
||||
const litLen = (token >> 4) & 0x0F;
|
||||
const matchField = token & 0x0F;
|
||||
// 复制字面量
|
||||
for (let i = 0; i < litLen && si < input.byteLength && di < originalSize; i++) {
|
||||
out[di++] = input[si++];
|
||||
}
|
||||
if (di >= originalSize || si >= input.byteLength)
|
||||
break;
|
||||
// 非末尾 → 必有 offset + 匹配(即使 matchField==0 也复制 MIN_MATCH 字节)
|
||||
if (si + 1 < input.byteLength) {
|
||||
const offset = input[si++] | (input[si++] << 8);
|
||||
const matchLen = matchField + MIN_MATCH;
|
||||
for (let i = 0; i < matchLen && di < originalSize; i++) {
|
||||
out[di] = out[di - offset];
|
||||
di++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* AriaEngine — 自研页面式存储引擎主类
|
||||
* @module engine/aria/index
|
||||
@@ -3684,14 +3862,10 @@ class AriaEngine {
|
||||
this.backend = new MemoryBackend();
|
||||
}
|
||||
await this.backend.open(dbName);
|
||||
// 2a. 初始化 Buffer Pool(页面缓存)
|
||||
const pageIO = {
|
||||
readPage: async (pageId) => this.backend.read(`pg_${pageId}`),
|
||||
writePage: async (pageId, data) => this.backend.write(`pg_${pageId}`, data),
|
||||
allocatePageId: async () => Date.now(),
|
||||
freePageId: async () => { },
|
||||
};
|
||||
this.bufferPool = new BufferPool(pageIO, this.config.bufferPoolPages);
|
||||
// 2a. FileManager (PageIO 实现) + Buffer Pool
|
||||
const fileManager = new FileManager(this.backend);
|
||||
await fileManager.init(dbName);
|
||||
this.bufferPool = new BufferPool(fileManager, this.config.bufferPoolPages);
|
||||
// 2. 构建 SSTableStore
|
||||
const sstableStore = this.createSSTableStore();
|
||||
// 3. 初始化主 LSM(PK 索引)
|
||||
@@ -4030,7 +4204,7 @@ class AriaEngine {
|
||||
async beginTransaction() {
|
||||
if (this.currentTxnId)
|
||||
throw new DatabaseError('Transaction already in progress', 'TX_ACTIVE');
|
||||
this.currentTxnId = Date.now();
|
||||
this.currentTxnId = this.mvcc.beginTransaction();
|
||||
this.txnSnapshot = new Map();
|
||||
this.wal.append({
|
||||
type: WALRecordType.BEGIN,
|
||||
@@ -4052,6 +4226,7 @@ class AriaEngine {
|
||||
}
|
||||
}
|
||||
}
|
||||
this.mvcc.commitTransaction(this.currentTxnId);
|
||||
this.wal.append({
|
||||
type: WALRecordType.COMMIT,
|
||||
txnId: this.currentTxnId,
|
||||
@@ -4065,6 +4240,7 @@ class AriaEngine {
|
||||
async rollbackTransaction() {
|
||||
if (!this.currentTxnId)
|
||||
throw new DatabaseError('No active transaction', 'TX_NONE');
|
||||
this.mvcc.rollbackTransaction(this.currentTxnId);
|
||||
this.txnSnapshot = null;
|
||||
this.wal.append({
|
||||
type: WALRecordType.ROLLBACK,
|
||||
@@ -4214,12 +4390,25 @@ class AriaEngine {
|
||||
const META_KEY = '__aria_lsm_meta';
|
||||
return {
|
||||
save: async (id, data) => {
|
||||
const buf = data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength);
|
||||
let buf = data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength);
|
||||
// 压缩(若启用)
|
||||
if (this.config.compression) {
|
||||
const compressed = compressLZ4(new Uint8Array(buf));
|
||||
buf = compressed.buffer.slice(compressed.byteOffset, compressed.byteOffset + compressed.byteLength);
|
||||
}
|
||||
await this.backend.write(`sst_${id}`, buf);
|
||||
},
|
||||
load: async (id) => {
|
||||
const buf = await this.backend.read(`sst_${id}`);
|
||||
return buf ? new Uint8Array(buf) : null;
|
||||
const raw = await this.backend.read(`sst_${id}`);
|
||||
if (!raw)
|
||||
return null;
|
||||
let buf = new Uint8Array(raw);
|
||||
// 解压(若启用)
|
||||
if (this.config.compression) {
|
||||
const decompressed = decompressLZ4(buf, buf.length * 2); // 估计原始大小
|
||||
buf = decompressed;
|
||||
}
|
||||
return buf;
|
||||
},
|
||||
delete: async (id) => {
|
||||
await this.backend.delete(`sst_${id}`);
|
||||
|
||||
Reference in New Issue
Block a user