| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273 |
- package btree
- import (
- "TsDB2/DB/core/index/datapage"
- "TsDB2/DB/core/page"
- "encoding/binary"
- "errors"
- "fmt"
- "unsafe"
- )
- // btNode B+ 鏍戣妭鐐?(raw bytes + page.IndexHead 鎸囬拡, 鏃?IndexPage 瀵硅薄)
- type btNode struct {
- buf []byte // 瀹屾暣椤电紦鍐插尯
- info *page.IndexHead // 鎸囧悜 buf 澶撮儴鐨?page.IndexHead 鎸囬拡
- entries []byte // buf[page.IndexHeadSize:] 鏉$洰鍖哄煙
- }
- func (n *btNode) isLeaf() bool { return n.info.IsLeaf == 1 }
- func (n *btNode) pageID() uint32 { return n.info.Hdr.PageID }
- // btPathEntry 璁板綍 B+ 鏍?descent 璺緞
- type btPathEntry struct {
- nodePID uint32
- childIdx int
- }
- // btSplitThreshold 璁$畻鍒嗚闃堝€?
- func btSplitThreshold() int {
- ff := page.BTreeFillFactor
- if ff < 50 {
- ff = 50
- }
- if ff > 100 {
- ff = 100
- }
- return int(page.IndexPageSize) * ff / 100
- }
- // ======================== 鑺傜偣 I/O ========================
- func btLoad(handle page.HandleDb, pid uint32) *btNode {
- if pid == 0 {
- return nil
- }
- buf := make([]byte, page.IndexPageSize)
- if err := handle.ReadPage(pid, buf); err != nil {
- return nil
- }
- info := (*page.IndexHead)(unsafe.Pointer(&buf[0]))
- return &btNode{buf: buf, info: info, entries: buf[page.IndexHeadSize:]}
- }
- func btSave(handle page.HandleDb, n *btNode) {
- _ = handle.SavePage(n.info.Hdr.PageID, n.buf)
- }
- func btNew(handle page.HandleDb, isLeaf bool, entryLen int) *btNode {
- pid := handle.NewPage()
- buf := make([]byte, page.IndexPageSize)
- info := (*page.IndexHead)(unsafe.Pointer(&buf[0]))
- info.Hdr.Type = page.IndexDataIndex
- info.Hdr.PageID = pid
- info.Hdr.UseSize = uint32(page.IndexHeadSize)
- info.IndexType = page.IndexTypePrimary
- info.EntryLen = uint16(entryLen)
- info.Count = 0
- if isLeaf {
- info.IsLeaf = 1
- }
- return &btNode{buf: buf, info: info, entries: buf[page.IndexHeadSize:]}
- }
- // ======================== 鏉$洰鎿嶄綔 ========================
- func btEntry(n *btNode, i int) []byte {
- el := int(n.info.EntryLen)
- return n.entries[i*el : (i+1)*el]
- }
- func btKey(e []byte) []byte { return e[:len(e)-4] }
- func btPID(e []byte) uint32 { return binary.BigEndian.Uint32(e[len(e)-4:]) }
- func btSetPID(e []byte, p uint32) { binary.BigEndian.PutUint32(e[len(e)-4:], p) }
- func btCmp(a, b []byte) int {
- ml := len(a)
- if len(b) < ml {
- ml = len(b)
- }
- for i := 0; i < ml; i++ {
- if a[i] < b[i] {
- return -1
- }
- if a[i] > b[i] {
- return 1
- }
- }
- if len(a) < len(b) {
- return -1
- }
- if len(a) > len(b) {
- return 1
- }
- return 0
- }
- func btRoute(n *btNode, key []byte) uint32 {
- cnt := int(n.info.Count)
- if cnt <= 0 {
- return 0 // 防御: 空节点不应作为路由节点
- }
- // 二分查找: 找最后一个 entry.key <= key 的位置 (与二级 B+ 树统一 <= 约定)
- left, right := 0, cnt-1
- result := 0
- for left <= right {
- mid := (left + right) / 2
- if btCmp(btKey(btEntry(n, mid)), key) <= 0 {
- result = mid
- left = mid + 1 // 继续向右找
- } else {
- right = mid - 1
- }
- }
- return btPID(btEntry(n, result))
- }
- // maxLeafEntries 单个叶节点最大条目数
- func maxLeafEntries(entryLen int) int {
- threshold := btSplitThreshold()
- available := threshold - page.IndexHeadSize
- if available <= 0 {
- return 1
- }
- return available / entryLen
- }
- // BuildFromSorted 从已排序的叶条目批量构建 B+ 树 (自底向上)
- // leafEntries: 每个条目 = [key(8B) + dpID(4B BE)], 已按 key 升序排列
- // 返回新树根 pageID
- //
- // 内存优化: 避免逐行 B+ 树搜索 (每次 btLoad 16KB), 改为顺序创建所有节点
- func BuildFromSorted(leafEntries [][]byte, handle page.HandleDb) uint32 {
- if len(leafEntries) == 0 {
- return 0
- }
- el := 12 // entry len: 8 key + 4 pid
- maxPerLeaf := maxLeafEntries(el)
- // ---- 构建叶节点层 ----
- type childInfo struct {
- pid uint32
- firstKey []byte // 该子树第一个 key (用于 > 路由)
- }
- var children []childInfo
- var prevLeafPID uint32
- // 将条目分组到叶节点 (带链表链接)
- for i := 0; i < len(leafEntries); {
- end := i + maxPerLeaf
- if end > len(leafEntries) {
- end = len(leafEntries)
- }
- leaf := btNew(handle, true, el)
- for j := i; j < end; j++ {
- src := leafEntries[j]
- dst := btEntry(leaf, int(leaf.info.Count))
- copy(dst, src)
- leaf.info.Count++
- leaf.info.Hdr.UseSize += uint32(el)
- }
- // 设置叶节点链表链接
- leaf.info.Hdr.PrePage = prevLeafPID
- if prevLeafPID != 0 {
- // 更新前一个叶节点的 NextPage
- // 注意: 前一个叶节点已经保存, 需要重新加载并更新
- // 但我们可以在保存前就设置好 NextPage
- }
- btSave(handle, leaf)
- // 更新前一个叶节点的 NextPage 指向当前叶
- if prevLeafPID != 0 {
- prevLeaf := btLoad(handle, prevLeafPID)
- if prevLeaf != nil {
- prevLeaf.info.Hdr.NextPage = leaf.pageID()
- btSave(handle, prevLeaf)
- }
- }
- prevLeafPID = leaf.pageID()
- children = append(children, childInfo{
- pid: leaf.pageID(),
- firstKey: leafEntries[i][:8],
- })
- i = end
- }
- if len(children) == 1 {
- return children[0].pid
- }
- // ---- 自底向上构建内部节点 ----
- // 路由约定 (btRoute): 找最后一个 entry.key <= searchKey
- // 内部节点条目: entry[i] = (child[i].firstKey, child[i].pid)
- // 即 entry[i].key = 该子树最左叶的第一个 key
- intEl := 12
- maxPerInt := maxLeafEntries(intEl)
- for len(children) > 1 {
- var parents []childInfo
- for i := 0; i < len(children); {
- end := i + maxPerInt
- if end > len(children) {
- end = len(children)
- }
- node := btNew(handle, false, intEl)
- for j := i; j < end; j++ {
- e := make([]byte, intEl)
- // 分隔键 = 该 child 的第一个 key
- copy(e[:intEl-4], children[j].firstKey)
- btSetPID(e, children[j].pid)
- dst := btEntry(node, int(node.info.Count))
- copy(dst, e)
- node.info.Count++
- node.info.Hdr.UseSize += uint32(intEl)
- }
- btSave(handle, node)
- parents = append(parents, childInfo{
- pid: node.pageID(),
- firstKey: children[i].firstKey,
- })
- i = end
- }
- children = parents
- }
- return children[0].pid
- }
- func btChildIdx(n *btNode, key []byte) int {
- el := int(n.info.EntryLen)
- cnt := int(n.info.Count)
- // 二分查找: 找最后一个 entry.key <= key 的位置 (与二级 B+ 树统一 <= 约定)
- left, right := 0, cnt-1
- result := 0
- for left <= right {
- mid := (left + right) / 2
- if btCmp(btEntry(n, mid)[:el-4], key) <= 0 {
- result = mid
- left = mid + 1 // 继续向右找
- } else {
- right = mid - 1
- }
- }
- return result
- }
- func btInsEntry(n *btNode, entry []byte, pos int) {
- el := int(n.info.EntryLen)
- cnt := int(n.info.Count)
- for i := cnt; i > pos; i-- {
- copy(btEntry(n, i), btEntry(n, i-1))
- }
- copy(btEntry(n, pos), entry)
- n.info.Count++
- n.info.Hdr.UseSize += uint32(el)
- }
- func btRmEntry(n *btNode, pos int) {
- el := int(n.info.EntryLen)
- cnt := int(n.info.Count)
- for i := pos; i < cnt-1; i++ {
- copy(btEntry(n, i), btEntry(n, i+1))
- }
- n.info.Count--
- n.info.Hdr.UseSize -= uint32(el)
- }
- func btLeafFind(n *btNode, key []byte) (int, bool) {
- el := int(n.info.EntryLen)
- cnt := int(n.info.Count)
- for i := 0; i < cnt; i++ {
- if btCmp(btEntry(n, i)[:el-4], key) == 0 {
- return i, true
- }
- }
- return 0, false
- }
- func btLeafPos(n *btNode, key []byte) int {
- el := int(n.info.EntryLen)
- cnt := int(n.info.Count)
- for i := 0; i < cnt; i++ {
- if btCmp(btEntry(n, i)[:el-4], key) >= 0 {
- return i
- }
- }
- return cnt
- }
- // btLeftmostKey 获取子树最左叶的第一个 key(用于 promoKey)
- func btLeftmostKey(handle page.HandleDb, nodePID uint32) []byte {
- cur := nodePID
- for {
- n := btLoad(handle, cur)
- if n == nil {
- return nil
- }
- if n.isLeaf() {
- if n.info.Count == 0 {
- return nil
- }
- e := btEntry(n, 0)
- key := make([]byte, len(btKey(e)))
- copy(key, btKey(e))
- return key
- }
- // 非叶节点,继续向左下遍历
- cur = btPID(btEntry(n, 0))
- }
- }
- // ======================== B+ 鏍戞悳绱?========================
- func BTreePKSearch(rootPID uint32, key []byte, handle page.HandleDb) (uint32, bool) {
- if rootPID == 0 {
- return 0, false
- }
- cur := rootPID
- for {
- n := btLoad(handle, cur)
- if n == nil {
- return 0, false
- }
- if n.isLeaf() {
- pos, ok := btLeafFind(n, key)
- if !ok {
- return 0, false
- }
- return btPID(btEntry(n, pos)), true
- }
- cur = btRoute(n, key)
- }
- }
- // ======================== B+ 鏍戝彾瀛愯妭鐐瑰畾浣?========================
- // BTreeFindLeftmostLeaf 浠庢牴鑺傜偣璺敱鍒版渶宸﹀彾鑺傜偣锛岃繑鍥炲彾鑺傜偣 pageID
- func BTreeFindLeftmostLeaf(rootPID uint32, handle page.HandleDb) uint32 {
- cur := rootPID
- for {
- n := btLoad(handle, cur)
- if n == nil {
- return 0
- }
- if n.isLeaf() {
- return n.info.Hdr.PageID
- }
- cur = btPID(btEntry(n, 0))
- }
- }
- // BTreeFindRightmostLeaf 浠庢牴鑺傜偣璺敱鍒版渶鍙冲彾鑺傜偣锛岃繑鍥炲彾鑺傜偣 pageID
- func BTreeFindRightmostLeaf(rootPID uint32, handle page.HandleDb) uint32 {
- cur := rootPID
- for {
- n := btLoad(handle, cur)
- if n == nil {
- return 0
- }
- if n.isLeaf() {
- return n.info.Hdr.PageID
- }
- cur = btPID(btEntry(n, int(n.info.Count)-1))
- }
- }
- // ======================== B+ 鏍戣寖鍥存壂鎻?========================
- // BTreePKRangeScan 涓婚敭 B+ 鏍戣寖鍥存壂鎻?
- func BTreePKRangeScan(rootPID uint32, handle page.HandleDb,
- startKey, endKey []byte, startInc, endInc bool, reverse bool,
- callback func(row []byte) bool) error {
- if rootPID == 0 {
- return nil
- }
- if !reverse {
- // 正向: 路由到 startKey 所在叶, 沿 NextPage 遍历
- cur := rootPID
- for {
- n := btLoad(handle, cur)
- if n == nil {
- return nil
- }
- if n.isLeaf() {
- break
- }
- cur = btRoute(n, startKey)
- }
- for cur != 0 {
- n := btLoad(handle, cur)
- if n == nil {
- break
- }
- for i := 0; i < int(n.info.Count); i++ {
- entry := btEntry(n, i)
- key := btKey(entry)
- if endKey != nil {
- cmp := btCmp(key, endKey)
- if cmp > 0 || (cmp == 0 && !endInc) {
- return nil
- }
- }
- if startKey != nil {
- cmp := btCmp(key, startKey)
- if cmp < 0 || (cmp == 0 && !startInc) {
- continue
- }
- }
- dpID := btPID(entry)
- dp, err := datapage.Load(handle, dpID)
- if err != nil {
- continue
- }
- // 每个 B+ 树条目精确匹配一行 (FindRowByIndexKey 按索引键过滤)
- if row, ok := dp.FindRowByIndexKey(key, 9); ok {
- if !callback(row) {
- return nil
- }
- }
- }
- cur = n.info.Hdr.NextPage
- }
- } else {
- // 反向: 路由到 endKey 所在叶(或最右叶), 沿 PrePage 遍历
- cur := rootPID
- if endKey != nil {
- for {
- n := btLoad(handle, cur)
- if n == nil {
- return nil
- }
- if n.isLeaf() {
- break
- }
- cur = btRoute(n, endKey)
- }
- } else {
- cur = BTreeFindRightmostLeaf(rootPID, handle)
- }
- for cur != 0 {
- n := btLoad(handle, cur)
- if n == nil {
- break
- }
- for i := int(n.info.Count) - 1; i >= 0; i-- {
- entry := btEntry(n, i)
- key := btKey(entry)
- if startKey != nil {
- cmp := btCmp(key, startKey)
- if cmp < 0 || (cmp == 0 && !startInc) {
- return nil
- }
- }
- if endKey != nil {
- cmp := btCmp(key, endKey)
- if cmp > 0 || (cmp == 0 && !endInc) {
- continue
- }
- }
- dpID := btPID(entry)
- dp, err := datapage.Load(handle, dpID)
- if err != nil {
- continue
- }
- if row, ok := dp.FindRowByIndexKey(key, 9); ok {
- if !callback(row) {
- return nil
- }
- }
- }
- cur = n.info.Hdr.PrePage
- }
- }
- return nil
- }
- // ======================== B+ 鏍戞彃鍏?========================
- func BTreePKInsert(rootPID uint32, key []byte, dpID uint32, handle page.HandleDb) (uint32, uint32, bool, error) {
- if rootPID == 0 {
- el := 12
- leaf := btNew(handle, true, el)
- e := make([]byte, el)
- copy(e[:8], key)
- btSetPID(e, dpID)
- btInsEntry(leaf, e, 0)
- btSave(handle, leaf)
- return leaf.pageID(), 0, false, nil
- }
- var path []btPathEntry
- cur := rootPID
- for {
- n := btLoad(handle, cur)
- if n == nil {
- return rootPID, 0, false, errors.New("load failed")
- }
- if n.isLeaf() {
- pos, found := btLeafFind(n, key)
- if found {
- return rootPID, btPID(btEntry(n, pos)), true, nil
- }
- el := 12
- ne := make([]byte, el)
- copy(ne[:8], key)
- btSetPID(ne, dpID)
- ip := btLeafPos(n, key)
- if int(n.info.Hdr.UseSize)+el <= btSplitThreshold() {
- btInsEntry(n, ne, ip)
- btSave(handle, n)
- return rootPID, 0, false, nil
- }
- cnt := int(n.info.Count)
- total := cnt + 1
- all := make([]byte, total*el)
- if ip > 0 {
- copy(all, n.entries[:ip*el])
- }
- copy(all[ip*el:], ne)
- if cnt > ip {
- copy(all[(ip+1)*el:], n.entries[ip*el:cnt*el])
- }
- mid := total / 2
- // <= 路由约定: 左子叶所有 key 必须严格小于右子叶第一个 key (promoKey)
- // 如果 all[mid-1].key == all[mid].key, 右移 mid 直到分隔
- for mid < total-1 {
- if btCmp(all[(mid-1)*el:mid*el-4], all[mid*el:(mid+1)*el-4]) < 0 {
- break
- }
- mid++
- }
- rl := btNew(handle, true, el)
- rc := total - mid
- copy(rl.entries, all[mid*el:total*el])
- rl.info.Count = uint32(rc)
- rl.info.Hdr.UseSize = uint32(page.IndexHeadSize) + uint32(rc*el)
- rl.info.Hdr.NextPage = n.info.Hdr.NextPage
- rl.info.Hdr.PrePage = n.info.Hdr.PageID
- n.info.Hdr.NextPage = rl.info.Hdr.PageID
- copy(n.entries, all[:mid*el])
- n.info.Count = uint32(mid)
- n.info.Hdr.UseSize = uint32(page.IndexHeadSize) + uint32(mid*el)
- btSave(handle, n)
- btSave(handle, rl)
- if rl.info.Hdr.NextPage != 0 {
- nl := btLoad(handle, rl.info.Hdr.NextPage)
- if nl != nil {
- nl.info.Hdr.PrePage = rl.info.Hdr.PageID
- btSave(handle, nl)
- }
- }
- // 使用右子树最左叶的第一个 key 作为 promoKey
- pk := btLeftmostKey(handle, rl.info.Hdr.PageID)
- nr, err := btPromote(handle, rootPID, path, n.info.Hdr.PageID, pk, rl.info.Hdr.PageID)
- return nr, 0, false, err
- }
- ci := btChildIdx(n, key)
- cpid := btPID(btEntry(n, ci))
- path = append(path, btPathEntry{nodePID: cur, childIdx: ci})
- cur = cpid
- }
- }
- func btPromote(handle page.HandleDb, rootPID uint32, path []btPathEntry, leftPID uint32, promoKey []byte, rightPID uint32) (uint32, error) {
- if len(path) == 0 {
- el := 12
- nr := btNew(handle, false, el)
- leftKey := btLeftmostKey(handle, leftPID)
- le := make([]byte, el)
- copy(le[:8], leftKey)
- btSetPID(le, leftPID)
- re := make([]byte, el)
- copy(re[:8], promoKey)
- btSetPID(re, rightPID)
- btInsEntry(nr, le, 0)
- btInsEntry(nr, re, 1)
- btSave(handle, nr)
- return nr.pageID(), nil
- }
- pi := len(path) - 1
- parent := btLoad(handle, path[pi].nodePID)
- if parent == nil {
- return rootPID, errors.New("parent load failed")
- }
- ci := path[pi].childIdx
- el := int(parent.info.EntryLen)
- // ⭐ FIX: 叶子分裂后, 左子树的最小 key 可能已变化
- // 必须更新 parent[ci].key = 左子树的新最小 key
- newLeftKey := btLeftmostKey(handle, leftPID)
- if newLeftKey == nil {
- return rootPID, errors.New("leftmost key failed")
- }
- // 更新 parent[ci] 的 key 和 PID
- copy(btEntry(parent, ci)[:el-4], newLeftKey)
- btSetPID(btEntry(parent, ci), leftPID)
- // 更新 key 后, parent[ci..] 可能不再有序
- // 需要将 parent[ci] 冒泡到正确位置, 然后插入 (promoKey, rightPID)
- // 1. 冒泡 parent[ci] 到正确位置 (如果 newLeftKey > parent[ci+1].key)
- for i := ci; i+1 < int(parent.info.Count); i++ {
- if btCmp(btKey(btEntry(parent, i)), btKey(btEntry(parent, i+1))) <= 0 {
- break // 已有序
- }
- // 交换 parent[i] 和 parent[i+1]
- tmp := make([]byte, el)
- copy(tmp, btEntry(parent, i))
- copy(btEntry(parent, i), btEntry(parent, i+1))
- copy(btEntry(parent, i+1), tmp)
- }
- // 2. 在排序位置插入 (promoKey, rightPID)
- newPos := int(parent.info.Count)
- for i := ci; i < int(parent.info.Count); i++ {
- if btCmp(btKey(btEntry(parent, i)), promoKey) >= 0 {
- newPos = i
- break
- }
- }
- for i := int(parent.info.Count); i > newPos; i-- {
- copy(btEntry(parent, i), btEntry(parent, i-1))
- }
- ne := make([]byte, el)
- copy(ne[:el-4], promoKey)
- btSetPID(ne, rightPID)
- copy(btEntry(parent, newPos), ne)
- parent.info.Count++
- parent.info.Hdr.UseSize += uint32(el)
- if int(parent.info.Hdr.UseSize)+el <= btSplitThreshold() {
- btSave(handle, parent)
- return rootPID, nil
- }
- cnt := int(parent.info.Count)
- mid := cnt / 2
- rn := btNew(handle, false, el)
- rc := cnt - mid
- copy(rn.entries, parent.entries[mid*el:cnt*el])
- rn.info.Count = uint32(rc)
- rn.info.Hdr.UseSize = uint32(page.IndexHeadSize) + uint32(rc*el)
- parent.info.Count = uint32(mid)
- parent.info.Hdr.UseSize = uint32(page.IndexHeadSize) + uint32(mid*el)
- btSave(handle, parent)
- btSave(handle, rn)
- pk2 := make([]byte, 8)
- copy(pk2, btKey(btEntry(rn, 0)))
- return btPromote(handle, rootPID, path[:pi], parent.info.Hdr.PageID, pk2, rn.info.Hdr.PageID)
- }
- // ======================== B+ 鏍戝垹闄?(閫掑綊 + 鍚堝苟/鍊熶綅) ========================
- func BTreePKDelete(rootPID uint32, key []byte, handle page.HandleDb) (uint32, uint32, error) {
- if rootPID == 0 {
- return 0, 0, page.ErrNotFound
- }
- delDP, err := btDeleteRec(rootPID, key, nil, handle)
- if err != nil {
- return rootPID, delDP, err
- }
- n := btLoad(handle, rootPID)
- if n != nil && n.info.Count == 0 {
- if !n.isLeaf() && n.info.Count == 0 {
- return rootPID, delDP, nil
- }
- }
- return rootPID, delDP, nil
- }
- func btDeleteRec(nodePID uint32, key []byte, path []btPathEntry, handle page.HandleDb) (uint32, error) {
- node := btLoad(handle, nodePID)
- if node == nil {
- return nodePID, page.ErrNotFound
- }
- el := int(node.info.EntryLen)
- if node.isLeaf() {
- pos, ok := btLeafFind(node, key)
- if !ok {
- return nodePID, page.ErrNotFound
- }
- delDP := btPID(btEntry(node, pos))
- btRmEntry(node, pos)
- if node.info.Count == 0 && len(path) == 0 {
- btSave(handle, node)
- return delDP, nil
- }
- btSave(handle, node)
- if len(path) > 0 && node.info.Count > 0 {
- btTryMerge(handle, path, node, el)
- }
- return delDP, nil
- }
- ci := btChildIdx(node, key)
- childPID := btPID(btEntry(node, ci))
- newPath := make([]btPathEntry, len(path)+1)
- copy(newPath, path)
- newPath[len(path)] = btPathEntry{nodePID: nodePID, childIdx: ci}
- delDP, err := btDeleteRec(childPID, key, newPath, handle)
- if err != nil {
- return delDP, err
- }
- node = btLoad(handle, nodePID)
- if node == nil {
- return delDP, errors.New("reload node failed")
- }
- if node.info.Count > 0 {
- ci2 := btChildIdx(node, key)
- if ci2 >= 0 && ci2 < int(node.info.Count) {
- cpID := btPID(btEntry(node, ci2))
- child := btLoad(handle, cpID)
- if child != nil && child.info.Count == 0 {
- btHandleUnderflow(node, ci2, el, handle)
- }
- }
- }
- if node.info.Count == 0 {
- return delDP, nil
- }
- btSave(handle, node)
- return delDP, nil
- }
- func btTryMerge(handle page.HandleDb, path []btPathEntry, node *btNode, el int) {
- if len(path) == 0 {
- return
- }
- pp := path[len(path)-1].nodePID
- parent := btLoad(handle, pp)
- if parent == nil {
- return
- }
- ci := -1
- for i := 0; i < int(parent.info.Count); i++ {
- if btPID(btEntry(parent, i)) == node.info.Hdr.PageID {
- ci = i
- break
- }
- }
- if ci < 0 {
- return
- }
- if ci > 0 {
- leftPID := btPID(btEntry(parent, ci-1))
- left := btLoad(handle, leftPID)
- if left != nil && left.isLeaf() {
- combined := uint32(page.IndexHeadSize) + (left.info.Count+node.info.Count)*uint32(el)
- threshold := uint32(btSplitThreshold())
- if combined <= threshold {
- rc := int(node.info.Count)
- copy(left.entries[int(left.info.Count)*el:], node.entries[:rc*el])
- left.info.Count += node.info.Count
- left.info.Hdr.UseSize += uint32(rc * el)
- left.info.Hdr.NextPage = node.info.Hdr.NextPage
- btSave(handle, left)
- if left.info.Hdr.NextPage != 0 {
- nl := btLoad(handle, left.info.Hdr.NextPage)
- if nl != nil {
- nl.info.Hdr.PrePage = leftPID
- btSave(handle, nl)
- }
- }
- btRmEntry(parent, ci)
- btSave(handle, parent)
- return
- }
- }
- }
- if ci < int(parent.info.Count)-1 {
- rightPID := btPID(btEntry(parent, ci+1))
- right := btLoad(handle, rightPID)
- if right != nil && right.isLeaf() {
- combined := uint32(page.IndexHeadSize) + (node.info.Count+right.info.Count)*uint32(el)
- threshold := uint32(btSplitThreshold())
- if combined <= threshold {
- rc := int(right.info.Count)
- copy(node.entries[int(node.info.Count)*el:], right.entries[:rc*el])
- node.info.Count += right.info.Count
- node.info.Hdr.UseSize += uint32(rc * el)
- node.info.Hdr.NextPage = right.info.Hdr.NextPage
- btSave(handle, node)
- if node.info.Hdr.NextPage != 0 {
- nl := btLoad(handle, node.info.Hdr.NextPage)
- if nl != nil {
- nl.info.Hdr.PrePage = node.info.Hdr.PageID
- btSave(handle, nl)
- }
- }
- btRmEntry(parent, ci+1)
- btSave(handle, parent)
- return
- }
- }
- }
- }
- func btHandleUnderflow(parent *btNode, childIdx int, el int, handle page.HandleDb) {
- childPID := btPID(btEntry(parent, childIdx))
- child := btLoad(handle, childPID)
- if child == nil {
- return
- }
- if childIdx > 0 {
- leftPID := btPID(btEntry(parent, childIdx-1))
- leftSib := btLoad(handle, leftPID)
- if leftSib != nil && int(leftSib.info.Count) > 1 {
- borrowed := make([]byte, el)
- copy(borrowed, btEntry(leftSib, int(leftSib.info.Count)-1))
- btRmEntry(leftSib, int(leftSib.info.Count)-1)
- btInsEntry(child, borrowed, 0)
- copy(btEntry(parent, childIdx)[:8], btKey(btEntry(child, 0)))
- btSave(handle, leftSib)
- btSave(handle, child)
- btSave(handle, parent)
- return
- }
- }
- if childIdx < int(parent.info.Count)-1 {
- rightPID := btPID(btEntry(parent, childIdx+1))
- rightSib := btLoad(handle, rightPID)
- if rightSib != nil && int(rightSib.info.Count) > 1 {
- borrowed := make([]byte, el)
- copy(borrowed, btEntry(rightSib, 0))
- btRmEntry(rightSib, 0)
- btInsEntry(child, borrowed, int(child.info.Count))
- copy(btEntry(parent, childIdx)[:8], btKey(btEntry(rightSib, 0)))
- btSave(handle, rightSib)
- btSave(handle, child)
- btSave(handle, parent)
- return
- }
- }
- if childIdx > 0 {
- btMergeChildren(handle, parent, childIdx-1, el)
- } else if childIdx < int(parent.info.Count)-1 {
- btMergeChildren(handle, parent, childIdx, el)
- }
- }
- func btMergeChildren(handle page.HandleDb, parent *btNode, sepIdx int, el int) {
- leftPID := btPID(btEntry(parent, sepIdx))
- rightPID := btPID(btEntry(parent, sepIdx+1))
- left := btLoad(handle, leftPID)
- right := btLoad(handle, rightPID)
- if left == nil || right == nil {
- return
- }
- if left.isLeaf() {
- rc := int(right.info.Count)
- copy(left.entries[int(left.info.Count)*el:], right.entries[:rc*el])
- left.info.Count += right.info.Count
- left.info.Hdr.UseSize += uint32(rc * el)
- left.info.Hdr.NextPage = right.info.Hdr.NextPage
- } else {
- sepEntry := make([]byte, el)
- copy(sepEntry, btEntry(parent, sepIdx))
- rc := int(right.info.Count)
- off := int(left.info.Count) * el
- copy(left.entries[off:], sepEntry)
- off += el
- copy(left.entries[off:], right.entries[:rc*el])
- left.info.Count += 1 + right.info.Count
- left.info.Hdr.UseSize += uint32((1 + rc) * el)
- }
- btSave(handle, left)
- if left.isLeaf() && left.info.Hdr.NextPage != 0 {
- nl := btLoad(handle, left.info.Hdr.NextPage)
- if nl != nil {
- nl.info.Hdr.PrePage = leftPID
- btSave(handle, nl)
- }
- }
- btRmEntry(parent, sepIdx+1)
- btSetPID(btEntry(parent, sepIdx), leftPID)
- btSave(handle, parent)
- }
- // ======================== DataPage 鎿嶄綔 ========================
- // FindSpaceInLeaf 鍦ㄥ彾鑺傜偣涓壘鍒版湁绌洪棿鐨?DataPage
- func FindSpaceInLeaf(handle page.HandleDb, rootPID uint32, rowSize uint32, key []byte) (uint32, bool) {
- cur := rootPID
- for {
- n := btLoad(handle, cur)
- if n == nil {
- return 0, false
- }
- if n.isLeaf() {
- pos := btLeafPos(n, key)
- if pos >= int(n.info.Count) {
- pos = int(n.info.Count) - 1
- }
- if pos < 0 {
- return 0, false
- }
- dpID := btPID(btEntry(n, pos))
- dp, err := datapage.Load(handle, dpID)
- if err == nil && !dp.IsFull(rowSize) {
- return dpID, true
- }
- if n.info.Hdr.PrePage != 0 {
- prevN := btLoad(handle, n.info.Hdr.PrePage)
- if prevN != nil && prevN.isLeaf() && prevN.info.Count > 0 {
- prevDPID := btPID(btEntry(prevN, int(prevN.info.Count)-1))
- prevDP, err := datapage.Load(handle, prevDPID)
- if err == nil && !prevDP.IsFull(rowSize) {
- return prevDPID, true
- }
- }
- }
- if n.info.Hdr.NextPage != 0 {
- nextN := btLoad(handle, n.info.Hdr.NextPage)
- if nextN != nil && nextN.isLeaf() && nextN.info.Count > 0 {
- nextDPID := btPID(btEntry(nextN, 0))
- nextDP, err := datapage.Load(handle, nextDPID)
- if err == nil && !nextDP.IsFull(rowSize) {
- return nextDPID, true
- }
- }
- }
- return 0, false
- }
- cur = btRoute(n, key)
- }
- }
- // FindLastLeafDP 路由到目标叶子, 检查最后一个条目的 DataPage 是否有空间
- // 只检查路由目标叶子, 不跨叶子查找 (保证 B+ 树不变性)
- func FindLastLeafDP(handle page.HandleDb, rootPID uint32, rowSize uint32, key []byte) (uint32, bool) {
- cur := rootPID
- for {
- n := btLoad(handle, cur)
- if n == nil {
- return 0, false
- }
- if n.isLeaf() {
- if n.info.Count == 0 {
- return 0, false
- }
- // 检查最后一个条目的 DataPage
- lastIdx := int(n.info.Count) - 1
- dpID := btPID(btEntry(n, lastIdx))
- dp, err := datapage.Load(handle, dpID)
- if err == nil && !dp.IsFull(rowSize) {
- return dpID, true
- }
- return 0, false
- }
- cur = btRoute(n, key)
- }
- }
- // GetDataPageIDs 返回所有 DataPage ID (去重, 用于全表扫描)
- func GetDataPageIDs(handle page.HandleDb, rootPID uint32) []uint32 {
- if rootPID == 0 {
- return nil
- }
- var dpIDs []uint32
- seen := make(map[uint32]bool)
- cur := rootPID
- for {
- n := btLoad(handle, cur)
- if n == nil {
- break
- }
- if n.isLeaf() {
- break
- }
- cur = btPID(btEntry(n, 0))
- }
- for cur != 0 {
- n := btLoad(handle, cur)
- if n == nil {
- break
- }
- for i := 0; i < int(n.info.Count); i++ {
- dpID := btPID(btEntry(n, i))
- if !seen[dpID] {
- seen[dpID] = true
- dpIDs = append(dpIDs, dpID)
- }
- }
- cur = n.info.Hdr.NextPage
- }
- return dpIDs
- }
- // ScanAllLeavesForPK 扫描所有叶子查找 pkID(LE)
- func ScanAllLeavesForPK(rootPID uint32, handle page.HandleDb, pkKeyBE []byte) ([]byte, bool) {
- if rootPID == 0 {
- return nil, false
- }
- cur := rootPID
- for {
- n := btLoad(handle, cur)
- if n == nil {
- return nil, false
- }
- if n.isLeaf() {
- break
- }
- cur = btPID(btEntry(n, 0))
- }
- for cur != 0 {
- n := btLoad(handle, cur)
- if n == nil {
- break
- }
- for i := 0; i < int(n.info.Count); i++ {
- dpID := btPID(btEntry(n, i))
- dp, err := datapage.Load(handle, dpID)
- if err == nil {
- if rowData, ok := dp.FindRowByPK(pkKeyBE); ok {
- return rowData, true
- }
- }
- }
- cur = n.info.Hdr.NextPage
- }
- return nil, false
- }
- // ScanAndDelete 扫描所有叶子按 indexKey 删除
- func ScanAndDelete(rootPID uint32, handle page.HandleDb, indexKey, pkKeyBE []byte) error {
- if rootPID == 0 {
- return page.ErrNotFound
- }
- cur := rootPID
- for {
- n := btLoad(handle, cur)
- if n == nil {
- return page.ErrNotFound
- }
- if n.isLeaf() {
- break
- }
- cur = btPID(btEntry(n, 0))
- }
- for cur != 0 {
- n := btLoad(handle, cur)
- if n == nil {
- break
- }
- for i := 0; i < int(n.info.Count); i++ {
- dpID := btPID(btEntry(n, i))
- dp, err := datapage.Load(handle, dpID)
- if err == nil {
- deleted := false
- if dp.DeleteByIndexKey(indexKey, 8) {
- deleted = true
- } else if dp.DeleteByPK(pkKeyBE) {
- deleted = true
- }
- if deleted {
- if dp.AllDeleted() {
- newRoot, _, err := BTreePKDelete(rootPID, indexKey, handle)
- if err != nil {
- return err
- }
- _ = newRoot
- } else {
- dp.Save()
- }
- return nil
- }
- }
- }
- cur = n.info.Hdr.NextPage
- }
- return page.ErrNotFound
- }
- // ScanAndDeleteByPK 扫描所有叶子按 pkID 删除
- func ScanAndDeleteByPK(rootPID uint32, handle page.HandleDb, pkKeyBE []byte) error {
- if rootPID == 0 {
- return page.ErrNotFound
- }
- cur := rootPID
- for {
- n := btLoad(handle, cur)
- if n == nil {
- return page.ErrNotFound
- }
- if n.isLeaf() {
- break
- }
- cur = btPID(btEntry(n, 0))
- }
- for cur != 0 {
- n := btLoad(handle, cur)
- if n == nil {
- break
- }
- for i := 0; i < int(n.info.Count); i++ {
- dpID := btPID(btEntry(n, i))
- dp, err := datapage.Load(handle, dpID)
- if err == nil {
- if dp.DeleteByPK(pkKeyBE) {
- if dp.AllDeleted() {
- newRoot, _, err := BTreePKDelete(rootPID, pkKeyBE, handle)
- if err != nil {
- return err
- }
- _ = newRoot
- } else {
- dp.Save()
- }
- return nil
- }
- }
- }
- cur = n.info.Hdr.NextPage
- }
- return page.ErrNotFound
- }
- // ScanAndUpdate 扫描所有叶子按 pkID 更新
- func ScanAndUpdate(rootPID uint32, handle page.HandleDb, pkKeyBE, storeRowData []byte) error {
- if rootPID == 0 {
- return page.ErrNotFound
- }
- cur := rootPID
- for {
- n := btLoad(handle, cur)
- if n == nil {
- return page.ErrNotFound
- }
- if n.isLeaf() {
- break
- }
- cur = btPID(btEntry(n, 0))
- }
- for cur != 0 {
- n := btLoad(handle, cur)
- if n == nil {
- break
- }
- for i := 0; i < int(n.info.Count); i++ {
- dpID := btPID(btEntry(n, i))
- dp, err := datapage.Load(handle, dpID)
- if err == nil {
- if err := dp.UpdateByPK(pkKeyBE, storeRowData); err == nil {
- dp.Save()
- return nil
- }
- }
- }
- cur = n.info.Hdr.NextPage
- }
- return page.ErrNotFound
- }
- // BTreeValidate 检查 B+ 树内部节点条目排序
- func BTreeValidate(handle page.HandleDb, rootPID uint32) []string {
- var issues []string
- if rootPID == 0 {
- return issues
- }
- var check func(pid uint32, depth int)
- check = func(pid uint32, depth int) {
- n := btLoad(handle, pid)
- if n == nil {
- issues = append(issues, fmt.Sprintf("d=%d: load fail pid=%d", depth, pid))
- return
- }
- cnt := int(n.info.Count)
- if n.isLeaf() {
- for i := 1; i < cnt; i++ {
- pk := btKey(btEntry(n, i-1))
- ck := btKey(btEntry(n, i))
- if btCmp(pk, ck) >= 0 {
- issues = append(issues, fmt.Sprintf("d=%d leaf=%d: unsorted [%d]>=[%d]", depth, pid, i-1, i))
- }
- }
- return
- }
- for i := 1; i < cnt; i++ {
- pk := btKey(btEntry(n, i-1))
- ck := btKey(btEntry(n, i))
- if btCmp(pk, ck) > 0 {
- issues = append(issues, fmt.Sprintf("d=%d int=%d: UNSORTED [%d]>[%d]", depth, pid, i-1, i))
- }
- }
- for i := 0; i < cnt; i++ {
- childPID := btPID(btEntry(n, i))
- check(childPID, depth+1)
- }
- }
- check(rootPID, 0)
- return issues
- }
- // BTreeTraceSearch 搜索并打印路由路径
- func BTreeTraceSearch(rootPID uint32, key []byte, handle page.HandleDb) {
- if rootPID == 0 {
- fmt.Println("Tree is empty")
- return
- }
- cur := rootPID
- depth := 0
- for {
- n := btLoad(handle, cur)
- if n == nil {
- fmt.Printf(" d=%d: LOAD FAIL pid=%d\n", depth, cur)
- return
- }
- el := int(n.info.EntryLen)
- cnt := int(n.info.Count)
- if n.isLeaf() {
- fk := uint64(0)
- lk := uint64(0)
- if cnt > 0 {
- fk = binary.BigEndian.Uint64(btKey(btEntry(n, 0)))
- lk = binary.BigEndian.Uint64(btKey(btEntry(n, cnt-1)))
- }
- pos, found := btLeafFind(n, key)
- fmt.Printf(" d=%d LEAF pid=%d cnt=%d first=%d last=%d pos=%d found=%v\n",
- depth, cur, cnt, fk, lk, pos, found)
- return
- }
- fmt.Printf(" d=%d INT pid=%d cnt=%d [", depth, cur, cnt)
- for i := 0; i < cnt; i++ {
- k := binary.BigEndian.Uint64(btEntry(n, i)[:el-4])
- p := btPID(btEntry(n, i))
- if i > 0 {
- fmt.Printf(", ")
- }
- if i < 3 || i >= cnt-2 {
- fmt.Printf("(k=%d,p=%d)", k, p)
- } else if i == 3 {
- fmt.Printf("...")
- }
- }
- fmt.Printf("]\n")
- ci := btChildIdx(n, key)
- fmt.Printf(" btChildIdx(%d) = %d\n", binary.BigEndian.Uint64(key), ci)
- cur = btPID(btEntry(n, ci))
- depth++
- }
- }
- // CollectAllPageIDs 收集 B+ 树所有页 ID (包括内部节点和叶子节点)
- // 用于 DropTable 时释放所有 B+ 树占用的页
- func CollectAllPageIDs(handle page.HandleDb, rootPID uint32) []uint32 {
- if rootPID == 0 {
- return nil
- }
- var pages []uint32
- // BFS 遍历所有节点
- queue := []uint32{rootPID}
- for len(queue) > 0 {
- pid := queue[0]
- queue = queue[1:]
- pages = append(pages, pid)
- n := btLoad(handle, pid)
- if n == nil {
- continue
- }
- if !n.isLeaf() {
- // 内部节点: 收集所有子节点
- for i := 0; i < int(n.info.Count); i++ {
- childPID := btPID(btEntry(n, i))
- if childPID != 0 {
- queue = append(queue, childPID)
- }
- }
- }
- }
- return pages
- }
|