release: v0.5.1 — 存储后端生产级硬化(CRC-32/全库加密/WAL分片/页面化存储/多标签页锁/e2e)+ 深度审查修复(假实现接线/死代码清理)
This commit is contained in:
@@ -1,111 +1,104 @@
|
||||
/**
|
||||
* AriaEngine File Manager — 页面文件管理 + PageIO 实现
|
||||
* @module engine/aria/store/file_manager
|
||||
*
|
||||
* 负责管理页面文件的生命周期:分配/释放页面 ID,读写页面。
|
||||
*/
|
||||
|
||||
import type { IStorageBackend } from './backend';
|
||||
import type { PageIO } from '../buffer/pool';
|
||||
import { PAGE_SIZE, PageType } from '../types';
|
||||
import { initPageHeader } from '../page/header';
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// FileManager (implements PageIO)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export class FileManager implements PageIO {
|
||||
private backend: IStorageBackend;
|
||||
private nextPageId = 0;
|
||||
private metaLoaded = false;
|
||||
private dbName = '';
|
||||
|
||||
constructor(backend: IStorageBackend) {
|
||||
this.backend = backend;
|
||||
}
|
||||
|
||||
/** 初始化:从存储中读取元数据 */
|
||||
async init(dbName: string): Promise<void> {
|
||||
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: number): Promise<ArrayBuffer | null> {
|
||||
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: number, data: ArrayBuffer): Promise<void> {
|
||||
const key = `pg_${pageId}`;
|
||||
await this.backend.write(key, data);
|
||||
}
|
||||
|
||||
async allocatePageId(): Promise<number> {
|
||||
const id = this.nextPageId++;
|
||||
await this.saveMeta();
|
||||
return id;
|
||||
}
|
||||
|
||||
async freePageId(_pageId: number): Promise<void> {
|
||||
// 简化实现:不回收 pageId
|
||||
const key = `pg_${_pageId}`;
|
||||
await this.backend.delete(key);
|
||||
}
|
||||
|
||||
// ---- 表页面分配 ----
|
||||
|
||||
/**
|
||||
* 分配一个新的表元数据页面。
|
||||
*/
|
||||
async allocateTableRootPage(): Promise<number> {
|
||||
const pageId = await this.allocatePageId();
|
||||
const data = new ArrayBuffer(PAGE_SIZE);
|
||||
initPageHeader(data, pageId, PageType.META);
|
||||
await this.writePage(pageId, data);
|
||||
return pageId;
|
||||
}
|
||||
|
||||
// ---- 辅助 ----
|
||||
|
||||
private async saveMeta(): Promise<void> {
|
||||
const buf = new ArrayBuffer(8);
|
||||
new DataView(buf).setUint32(0, this.nextPageId, false);
|
||||
await this.backend.write('__aria_meta', buf);
|
||||
}
|
||||
|
||||
private createEmptyPage(pageId: number, type: PageType): ArrayBuffer {
|
||||
const buf = new ArrayBuffer(PAGE_SIZE);
|
||||
initPageHeader(buf, pageId, type);
|
||||
return buf;
|
||||
}
|
||||
|
||||
/** 清空所有数据 */
|
||||
async clearAll(): Promise<void> {
|
||||
await this.backend.clear();
|
||||
this.nextPageId = 1;
|
||||
await this.saveMeta();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* AriaEngine File Manager — 页面文件管理 + PageIO 实现
|
||||
* @module engine/aria/store/file_manager
|
||||
*
|
||||
* 负责管理页面文件的生命周期:分配/释放页面 ID,读写页面。
|
||||
*/
|
||||
|
||||
import type { IStorageBackend } from './backend';
|
||||
import type { PageIO } from '../buffer/pool';
|
||||
import { PAGE_SIZE, PageType } from '../types';
|
||||
import { initPageHeader } from '../page/header';
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// FileManager (implements PageIO)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export class FileManager implements PageIO {
|
||||
private backend: IStorageBackend;
|
||||
private nextPageId = 0;
|
||||
private metaLoaded = false;
|
||||
private dbName = '';
|
||||
|
||||
constructor(backend: IStorageBackend) {
|
||||
this.backend = backend;
|
||||
}
|
||||
|
||||
/** 初始化:从存储中读取元数据 */
|
||||
async init(dbName: string): Promise<void> {
|
||||
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: number): Promise<ArrayBuffer | null> {
|
||||
const key = `pg_${pageId}`;
|
||||
const data = await this.backend.read(key);
|
||||
if (!data) {
|
||||
// v0.4.5: 页面总是先分配(allocatePageId 持久化)后写入 —— 读取缺失页面视为损坏
|
||||
// (此前返回空页面会静默掩盖页面丢失,页面化 SSTable 依赖 null 触发自愈清理)
|
||||
return null;
|
||||
}
|
||||
|
||||
// 确保大小正确
|
||||
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: number, data: ArrayBuffer): Promise<void> {
|
||||
const key = `pg_${pageId}`;
|
||||
await this.backend.write(key, data);
|
||||
}
|
||||
|
||||
async allocatePageId(): Promise<number> {
|
||||
const id = this.nextPageId++;
|
||||
await this.saveMeta();
|
||||
return id;
|
||||
}
|
||||
|
||||
/** v0.4.5: 批量分配页面 ID(一次 meta 持久化,避免页面化 SSTable 保存时逐页写 meta) */
|
||||
async allocatePageIds(count: number): Promise<number[]> {
|
||||
if (count <= 0) return [];
|
||||
const ids: number[] = [];
|
||||
const start = this.nextPageId;
|
||||
this.nextPageId += count;
|
||||
for (let i = 0; i < count; i++) ids.push(start + i);
|
||||
await this.saveMeta();
|
||||
return ids;
|
||||
}
|
||||
|
||||
async freePageId(_pageId: number): Promise<void> {
|
||||
// 简化实现:不回收 pageId
|
||||
const key = `pg_${_pageId}`;
|
||||
await this.backend.delete(key);
|
||||
}
|
||||
|
||||
// ---- 辅助 ----
|
||||
|
||||
private async saveMeta(): Promise<void> {
|
||||
const buf = new ArrayBuffer(8);
|
||||
new DataView(buf).setUint32(0, this.nextPageId, false);
|
||||
await this.backend.write('__aria_meta', buf);
|
||||
}
|
||||
|
||||
/** 清空所有数据 */
|
||||
async clearAll(): Promise<void> {
|
||||
await this.backend.clear();
|
||||
this.nextPageId = 1;
|
||||
await this.saveMeta();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user