/** * AriaEngine Page Format — 页面格式整合层 * @module engine/aria/page/format * * 组合 Header / Slot / Tuple 操作,提供统一的页面管理接口。 */ import { PAGE_SIZE, PageType, type PageHandle } from '../types'; import { initPageHeader, decodePageHeader, encodePageHeader, getSlotCount, getPageId, } from './header'; import { allocateSlot, freeSlot, readSlotData, getAllSlots } from './slot'; import { encodeTuple, decodeTuple } from './tuple'; // --------------------------------------------------------------------------- // 页面创建 // --------------------------------------------------------------------------- /** 创建一个新的空页面 */ export function createPage(pageId: number, type: PageType): PageHandle { const data = new ArrayBuffer(PAGE_SIZE); initPageHeader(data, pageId, type); return { pageId, type, data, dirty: true, pins: 0, prev: null, next: null, lastAccess: Date.now(), }; } /** 从 ArrayBuffer 恢复页面句柄 */ export function pageFromBuffer( pageId: number, buffer: ArrayBuffer, ): PageHandle { return { pageId, type: new DataView(buffer).getUint8(4) as PageType, data: buffer, dirty: false, pins: 0, prev: null, next: null, lastAccess: Date.now(), }; } // --------------------------------------------------------------------------- // 行操作(页面级) // --------------------------------------------------------------------------- /** * 插入一行到页面,返回 slot 索引,空间不足返回 -1。 */ export function pageInsertRow( page: PageHandle, row: Record, columnOrder: string[], columnTypes: Record, ): number { const encoded = encodeTuple(row, columnOrder, columnTypes); const slotIdx = allocateSlot(page.data, encoded); if (slotIdx >= 0) { page.dirty = true; page.lastAccess = Date.now(); } return slotIdx; } /** * 读取指定 slot 的行数据并解码。 */ export function pageReadRow( page: PageHandle, slotIndex: number, columnOrder: string[], columnTypes: Record, ): Record | null { const slotData = readSlotData(page.data, slotIndex); if (!slotData) return null; return decodeTuple(slotData, columnOrder, columnTypes); } /** * 读取页面中的所有行。 */ export function pageReadAllRows( page: PageHandle, columnOrder: string[], columnTypes: Record, ): Record[] { const rows: Record[] = []; const slotCount = getSlotCount(page.data); for (let i = 0; i < slotCount; i++) { const row = pageReadRow(page, i, columnOrder, columnTypes); if (row) rows.push(row); } return rows; } /** * 标记 slot 为已删除。 */ export function pageDeleteRow(page: PageHandle, slotIndex: number): void { freeSlot(page.data, slotIndex); page.dirty = true; page.lastAccess = Date.now(); } /** * 重写指定 slot 的行数据。 */ export function pageUpdateRow( page: PageHandle, slotIndex: number, row: Record, columnOrder: string[], columnTypes: Record, ): void { // 先标记旧 slot 为删除 pageDeleteRow(page, slotIndex); // 分配新 slot,可能会在不同位置 const newSlot = pageInsertRow(page, row, columnOrder, columnTypes); // 注意:调用者需要自行维护 slot index → pk 的映射 } // --------------------------------------------------------------------------- // 校验和 // --------------------------------------------------------------------------- /** 简单 CRC32(使用预先计算的查找表简化) */ export function computeChecksum(data: ArrayBuffer): number { const view = new Uint8Array(data); let hash = 0; for (let i = 0; i < view.byteLength; i++) { hash = ((hash << 5) - hash + view[i]) | 0; } return hash >>> 0; } /** 更新页面的校验和字段 */ export function updateChecksum(page: PageHandle): void { // 先清零校验和字段 const view = new DataView(page.data); view.setUint32(11, 0, false); // 计算校验和 const cksum = computeChecksum(page.data); view.setUint32(11, cksum, false); } /** 验证页面校验和 */ export function verifyChecksum(page: PageHandle): boolean { const stored = new DataView(page.data).getUint32(11, false); // 临时清零 new DataView(page.data).setUint32(11, 0, false); const computed = computeChecksum(page.data); new DataView(page.data).setUint32(11, stored, false); return stored === computed; }