| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104 |
- 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
- }
|