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