package core import ( "TsDB2/DB/core/index/btree" "TsDB2/DB/core/page" "TsDB2/DB/core/types" "TsDB2/DB/core/util" "unsafe" ) type TablePage struct { hdr page.PageHdr tables []*Table handle page.HandleDb hdrSize uint32 // hdr 的大小 tableInfoSize uint32 // 表头大小 lastPageID uint32 // 最后一页 } // NewTablePage 创建表页管理器 func NewTablePage(handle page.HandleDb) *TablePage { return &TablePage{ handle: handle, hdrSize: uint32(unsafe.Sizeof(page.PageHdr{})), tableInfoSize: uint32(unsafe.Sizeof(TableInfo{})), } } // Tables 获取所有表 func (t *TablePage) Tables() []*Table { return t.tables } // LastPageID 获取最后页ID func (t *TablePage) LastPageID() uint32 { return t.lastPageID } // Init 初始化表页:从磁盘读取所有表 + 所有字段(支持跨页存储) func (t *TablePage) Init(pageID uint32) { t.tables = make([]*Table, 0) t.hdrSize = uint32(unsafe.Sizeof(page.PageHdr{})) t.tableInfoSize = uint32(unsafe.Sizeof(TableInfo{})) t.hdr.PageID = pageID t.hdr.Type = page.TableIndex t.hdr.NextPage = 0 t.lastPageID = 0 if pageID == 0 { return } for pageID != 0 { t.lastPageID = pageID pageBuf := make([]byte, PageSize) if err := t.handle.ReadPage(pageID, pageBuf); err != nil { break } pageHdr := (*page.PageHdr)(unsafe.Pointer(&pageBuf[0])) offset := t.hdrSize for offset+t.tableInfoSize <= pageHdr.UseSize { info := (*TableInfo)(unsafe.Pointer(&pageBuf[offset])) if util.IsHighBitSet(info.Flag) { offset += t.tableInfoSize + uint32(info.FieldAllocateSize) continue } activeVer, masterFields, versions, fieldOffset := readSchema( t.handle, pageID, uint16(offset+t.tableInfoSize), info.FieldAllocateSize) indexMate := &IndexMetaPage{ handle: t.handle, } indexMate.Init(info.FirstIndexID) t.tables = append(t.tables, &Table{ info: info, Field: masterFields, handle: t.handle, indexMeta: indexMate, tablePageID: pageID, tableStartOffset: offset, curOffset: fieldOffset, activeVersion: activeVer, versions: versions, }) offset += t.tableInfoSize + uint32(info.FieldAllocateSize) } pageID = pageHdr.NextPage } } // =========================================================================== // ✅ Create 完整正确(字段数量全是 byte,255上限) // =========================================================================== func (t *TablePage) Create(name string, fields []types.FieldInfo) (*Table, error) { fieldCount := byte(len(fields)) if len(name) > TableNameSize { return nil, ErrTableNameTooLong } for _, tb := range t.tables { if util.BytesToString(tb.info.Name[:]) == name && !util.IsHighBitSet(tb.info.Flag) { return nil, ErrTableExists } } if fieldCount == 0 || int(fieldCount)+1 >= MaxFieldSize { return nil, ErrInvalidFieldCount } realFieldSize := uint32(1) // 字段数量:1字节(byte) for _, f := range fields { realFieldSize += 2 + uint32(len(f.FieldName)) } allocateSize := realFieldSize * 2 if allocateSize < MinFieldAllocateSize { allocateSize = MinFieldAllocateSize } if allocateSize > PageSize { return nil, ErrFieldAllocateTooLarge } var pageBuf []byte var pageHdr *page.PageHdr if t.hdr.PageID == 0 { pid := t.handle.NewPage() pageBuf, pageHdr = t.InitHeader(pid) t.hdr.PageID = pid t.lastPageID = pid } else { pageBuf = make([]byte, PageSize) t.handle.ReadPage(t.lastPageID, pageBuf) pageHdr = (*page.PageHdr)(unsafe.Pointer(&pageBuf[0])) } // 当前已经使用了的 offset := pageHdr.UseSize // 这个表总共需要多少空间 required := t.tableInfoSize + uint32(allocateSize) // 表空间不足就创建新的页存表 if offset+required > PageSize { newPID := t.handle.NewPage() newBuf, newHdr := t.InitHeader(newPID) pageHdr.NextPage = newPID t.handle.SavePage(t.lastPageID, pageBuf) // 保存旧页的 NextPage 更新 t.lastPageID = newPID pageBuf = newBuf pageHdr = newHdr offset = t.hdrSize } info := (*TableInfo)(unsafe.Pointer(&pageBuf[offset])) copy(info.Name[:], name) info.Flag = 0 info.FieldCount = fieldCount info.ActiveFieldCount = fieldCount // 初始时实际字段数等于总字段数 info.RowSize = types.CalcRowSize(fields) info.FieldAllocateSize = uint16(allocateSize) info.TotalRows = 0 // 创建数据页 dataPID := t.handle.NewPage() info.FirstData = dataPID info.LastData = dataPID dataBuf := make([]byte, PageSize) dHdr := (*page.PageHdr)(unsafe.Pointer(&dataBuf[0])) dHdr.Type = page.DataIndex dHdr.PageID = dataPID dHdr.UseSize = t.hdrSize t.handle.SavePage(dataPID, dataBuf) // 创建堆页 heapPID := t.handle.NewPage() info.FirstHeap = heapPID info.LastHeap = heapPID heapBuf := make([]byte, PageSize) hHdr := (*page.PageHdr)(unsafe.Pointer(&heapBuf[0])) hHdr.Type = page.HeapIndex hHdr.PageID = heapPID hHdr.UseSize = t.hdrSize t.handle.SavePage(heapPID, heapBuf) indexMate := &IndexMetaPage{ handle: t.handle, } // 创建索引元数据 indexPID := t.handle.NewPage() indexMate.Init(indexPID) indexMate.InitHeader(indexPID) info.FirstIndexID = indexPID info.LastIndexID = indexPID // ========================== // 写新版 schema 字段定义链 // 格式: [activeVer(1B)] [masterCount(1B)] [type+len+name]×N [verCount(1B)] [ver1...] // ========================== fieldOff := offset + t.tableInfoSize wo := fieldOff // activeVer = 1 pageBuf[wo] = 1 wo++ // masterCount pageBuf[wo] = fieldCount wo++ // master fields masterIndices := make([]byte, fieldCount) for i, f := range fields { pageBuf[wo] = byte(f.FieldType) pageBuf[wo+1] = byte(len(f.FieldName)) wo += 2 copy(pageBuf[wo:], f.FieldName) wo += uint32(len(f.FieldName)) masterIndices[i] = byte(i) } // verCount = 1 pageBuf[wo] = 1 wo++ // version 1 definition pageBuf[wo] = 1 // verNo wo++ pageBuf[wo] = fieldCount wo++ copy(pageBuf[wo:], masterIndices) wo += uint32(len(masterIndices)) pageHdr.UseSize = offset + required t.handle.SavePage(t.lastPageID, pageBuf) // 构建初始 SchemaVersion initialVersions := []SchemaVersion{{Version: 1, FieldIndices: masterIndices}} newTable := Table{ info: info, Field: fields, handle: t.handle, indexMeta: indexMate, tablePageID: t.lastPageID, tableStartOffset: offset, curOffset: FieldOffset{PageID: t.lastPageID, StartOffset: uint16(fieldOff), EndOffset: uint16(wo - fieldOff)}, activeVersion: 1, versions: initialVersions, } t.tables = append(t.tables, &newTable) return &newTable, nil } // =========================================================================== // ✅ Drop 删除表并回收所有页 // =========================================================================== func (t *TablePage) Drop(name string) error { pageID := t.hdr.PageID for pageID != 0 { buf := make([]byte, PageSize) if err := t.handle.ReadPage(pageID, buf); err != nil { return err } hdr := (*page.PageHdr)(unsafe.Pointer(&buf[0])) offset := t.hdrSize for offset+t.tableInfoSize <= hdr.UseSize { info := (*TableInfo)(unsafe.Pointer(&buf[offset])) if util.BytesToString(info.Name[:]) == name && !util.IsHighBitSet(info.Flag) { // 找到该表在内存中的 Table 对象,获取其索引元数据 var tableEntry *Table for _, tb := range t.tables { if util.BytesToString(tb.info.Name[:]) == name && !util.IsHighBitSet(tb.info.Flag) { tableEntry = tb break } } // 回收该表所有页 (用该表自己的 indexMeta.metas,不遍历共享的 IndexMeta 页链) t.recycleTablePages(info, tableEntry) // 软删除标记 info.Flag = util.SetHighBit(info.Flag) t.handle.SavePage(pageID, buf) for i := range t.tables { if util.BytesToString(t.tables[i].info.Name[:]) == name { t.tables = append(t.tables[:i], t.tables[i+1:]...) break } } return nil } offset += t.tableInfoSize + uint32(info.FieldAllocateSize) } pageID = hdr.NextPage } return ErrTableNotFound } // recycleTablePages 回收表的所有页 (B+树页、DataPage页、Heap页) // 注意: IndexMeta 页是所有表共享的,不能释放! func (t *TablePage) recycleTablePages(info *TableInfo, tableEntry *Table) { if t.handle.FreePage == nil { return } var pagesToFree []uint32 // 1. 用该表自己的 indexMeta.metas 收集 B+ 树页和 DataPage // 不遍历共享的 IndexMeta 页链,避免误释放其他表的索引页 if tableEntry != nil && tableEntry.indexMeta != nil { for i := range tableEntry.indexMeta.metas { m := &tableEntry.indexMeta.metas[i] if m.Flag&0x80 != 0 || m.EntryPage == 0 { continue } // 收集 B+ 树所有节点页 (内部节点+叶子节点) btPages := btree.CollectAllPageIDs(t.handle, m.EntryPage) pagesToFree = append(pagesToFree, btPages...) // 只有主键/时序索引的叶子节点存 DataPage ID // 二级索引叶子存的是 PKID(8B),不是 DataPage ID! if m.IndexType == page.IndexTypePrimary || m.IndexType == page.IndexTypeTime { dpIDs := btree.GetDataPageIDs(t.handle, m.EntryPage) pagesToFree = append(pagesToFree, dpIDs...) } } } // 2. 收集 Heap 页链 (溢出页) heapID := info.FirstHeap for heapID != 0 { buf := make([]byte, PageSize) if err := t.handle.ReadPage(heapID, buf); err != nil { break } hdr := (*page.PageHdr)(unsafe.Pointer(&buf[0])) nextHeap := hdr.NextPage pagesToFree = append(pagesToFree, heapID) heapID = nextHeap } // 3. 收集 Overflow 页链 oflowID := info.FirstOverflow for oflowID != 0 { buf := make([]byte, PageSize) if err := t.handle.ReadPage(oflowID, buf); err != nil { break } hdr := (*page.PageHdr)(unsafe.Pointer(&buf[0])) nextOflow := hdr.NextPage pagesToFree = append(pagesToFree, oflowID) oflowID = nextOflow } // 4. 统一释放所有页 for _, pid := range pagesToFree { t.handle.FreePage(pid) } } func (t *TablePage) Find(name string) (*Table, bool) { for i := range t.tables { tb := t.tables[i] if util.BytesToString(tb.info.Name[:]) == name && !util.IsHighBitSet(tb.info.Flag) { return tb, true } } return nil, false } // InitHeader 初始化头部信息 func (t *TablePage) InitHeader(pageID uint32) ([]byte, *page.PageHdr) { newBuf := make([]byte, PageSize) newHdr := (*page.PageHdr)(unsafe.Pointer(&newBuf[0])) newHdr.Type = page.TableIndex newHdr.PageID = pageID newHdr.UseSize = uint32(unsafe.Sizeof(*newHdr)) t.handle.SavePage(pageID, newBuf) return newBuf, newHdr }