package core import ( "encoding/binary" "fmt" "time" ) // 数据库全局头页(PageID=0 固定) type HeaderPage struct { Magic [4]byte // 4 魔术字,识别文件类型 Version uint32 // 4 版本 PageSize uint32 // 4 每页大小(比如 4096) NextFreePage uint32 // 4 下一个可用空闲页 TablePage uint32 // 4 【唯一重要】表链起始页ID TableCount uint32 // 4 表数量 CreateTime int64 // 8 ModifyTime int64 // 8 FreePageStart uint32 // 4 空闲页链表头 FreePageCount uint32 // 4 空闲页数量 GlobalFlags uint64 // 8 全局状态 FirstWALPage uint32 // 4 未恢复的 WAL 链首页 ID (0=无待恢复WAL) LastWALPage uint32 // 4 WAL 链尾页 ID (追加写入用) NextTxnID uint64 // 8 下一个事务 ID ExtConfig [256]byte // 256 扩展配置 Comment [512]byte // 512 备注 // 填充对齐到整页(PageSize - 已用字节) _ [PageSize4K - 840]byte // 自动补齐 } // newPage 分配新页:优先从空闲链表取,没有则递增分配 func (header *HeaderPage) newPage() uint32 { if header.FreePageStart != 0 { // 从空闲链表头取一个页 pid := header.FreePageStart // 该页的前 4 字节存了下一个空闲页 ID(BigEndian) // 这里只是返回 pid,实际读取 next 需要外部传入 ReadPage // 所以 newPageWithReader 才是正确入口 return pid } pid := header.NextFreePage header.NextFreePage++ return pid } // newPageWithReader 带读页能力的分配(用于读空闲链表) func (header *HeaderPage) newPageWithReader(readPage func(uint32, []byte) error) uint32 { if header.FreePageStart != 0 { pid := header.FreePageStart buf := make([]byte, PageSize) if err := readPage(pid, buf); err == nil { // 前 4 字节是下一个空闲页 ID next := binary.BigEndian.Uint32(buf[:4]) header.FreePageStart = next header.FreePageCount-- } else { // 读失败,回退到递增分配 pid = header.NextFreePage header.NextFreePage++ } return pid } pid := header.NextFreePage header.NextFreePage++ return pid } // recyclePage 回收一个页到空闲链表 func (header *HeaderPage) recyclePage(pageID uint32, savePage func(uint32, []byte) error) { // 在该页前 4 字节写入当前链表头 buf := make([]byte, PageSize) binary.BigEndian.PutUint32(buf[:4], header.FreePageStart) header.FreePageStart = pageID header.FreePageCount++ _ = savePage(pageID, buf) } func newHeader(desc string) (*HeaderPage, error) { var comment [512]byte // 1. 安全判断:防止描述超长 if len(desc) > len(comment) { return nil, fmt.Errorf("描述字符串长度 %d 超过最大限制 %d", len(desc), len(comment)) } copy(comment[:], desc) // 2. 初始化头部(全部正确赋值,无遗漏、无坑) return &HeaderPage{ Magic: Magic, // 魔数 Version: Version, // 版本 PageSize: PageSize, // 页大小 NextFreePage: 2, // 下一个分配页从 2 开始(0=header, 1=table page 已预留) TablePage: 0, // 初始无表 TableCount: 0, // 表数量=0 CreateTime: time.Now().UnixNano(), // 纳秒时间戳 ModifyTime: time.Now().UnixNano(), FreePageStart: 0, // 初始无空闲页 FreePageCount: 0, // 空闲页数量=0 GlobalFlags: 0, // 无标志 ExtConfig: [256]byte{}, // 清空扩展配置 Comment: comment, // 数据库描述 }, nil }