|
@@ -265,88 +265,10 @@ func strBtBorrowFromLeft(handle page.HandleDb, left, right *btNode, entryLen int
|
|
|
|
|
|
|
|
// ======================== 公开 API ========================
|
|
// ======================== 公开 API ========================
|
|
|
|
|
|
|
|
-// StrBTInsert 插入字符串索引条目
|
|
|
|
|
|
|
+// StrBTInsert 插入字符串索引条目(委托给 SBTInsert)
|
|
|
func StrBTInsert(rootPID uint32, entry []byte, handle page.HandleDb) (uint32, error) {
|
|
func StrBTInsert(rootPID uint32, entry []byte, handle page.HandleDb) (uint32, error) {
|
|
|
- el := len(entry)
|
|
|
|
|
- if rootPID == 0 {
|
|
|
|
|
- leaf := strBtNew(handle, true, el)
|
|
|
|
|
- copy(strBtEntry(leaf, 0), entry)
|
|
|
|
|
- leaf.info.Count = 1
|
|
|
|
|
- leaf.info.Hdr.UseSize = uint32(page.IndexHeadSize) + uint32(el)
|
|
|
|
|
- strBtSave(handle, leaf)
|
|
|
|
|
- return leaf.pageID(), nil
|
|
|
|
|
- }
|
|
|
|
|
- var path []btPathEntry
|
|
|
|
|
- cur := rootPID
|
|
|
|
|
- for {
|
|
|
|
|
- n := strBtLoad(handle, cur)
|
|
|
|
|
- if n == nil {
|
|
|
|
|
- return rootPID, errors.New("strBt load failed")
|
|
|
|
|
- }
|
|
|
|
|
- if n.isLeaf() {
|
|
|
|
|
- key := entry[:el-8]
|
|
|
|
|
- ip := strBtLeafPos(n, key)
|
|
|
|
|
- // 允许重复键,插入到相同 key 的条目之后
|
|
|
|
|
- for ip < int(n.info.Count) && strBtCmp(strBtLeafKey(strBtEntry(n, ip)), key) == 0 {
|
|
|
|
|
- ip++
|
|
|
|
|
- }
|
|
|
|
|
- if int(n.info.Hdr.UseSize)+el <= btSplitThreshold() {
|
|
|
|
|
- // 有空间,直接插入
|
|
|
|
|
- if ip < int(n.info.Count) {
|
|
|
|
|
- // 移动后续条目
|
|
|
|
|
- cnt := int(n.info.Count)
|
|
|
|
|
- for i := cnt; i > ip; i-- {
|
|
|
|
|
- copy(strBtEntry(n, i), strBtEntry(n, i-1))
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- copy(strBtEntry(n, ip), entry)
|
|
|
|
|
- n.info.Count++
|
|
|
|
|
- n.info.Hdr.UseSize += uint32(el)
|
|
|
|
|
- strBtSave(handle, n)
|
|
|
|
|
- return rootPID, 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:], entry)
|
|
|
|
|
- if cnt > ip {
|
|
|
|
|
- copy(all[(ip+1)*el:], n.entries[ip*el:cnt*el])
|
|
|
|
|
- }
|
|
|
|
|
- mid := total / 2
|
|
|
|
|
- rl := strBtNew(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)
|
|
|
|
|
- strBtSave(handle, n)
|
|
|
|
|
- strBtSave(handle, rl)
|
|
|
|
|
- if rl.info.Hdr.NextPage != 0 {
|
|
|
|
|
- nl := strBtLoad(handle, rl.info.Hdr.NextPage)
|
|
|
|
|
- if nl != nil {
|
|
|
|
|
- nl.info.Hdr.PrePage = rl.info.Hdr.PageID
|
|
|
|
|
- strBtSave(handle, nl)
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- // 使用右子树最左叶的第一个 key 作为 promoKey
|
|
|
|
|
- pk := strBtLeftmostKey(handle, rl.info.Hdr.PageID, el)
|
|
|
|
|
- nr, err := strBtPromote(handle, rootPID, path, n.info.Hdr.PageID, pk, rl.info.Hdr.PageID, el)
|
|
|
|
|
- return nr, err
|
|
|
|
|
- }
|
|
|
|
|
- ci := strBtChildIdx(n, entry[:el-8])
|
|
|
|
|
- cpid := strBtChildPID(strBtEntry(n, ci))
|
|
|
|
|
- path = append(path, btPathEntry{nodePID: cur, childIdx: ci})
|
|
|
|
|
- cur = cpid
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ // 直接复用经过验证的 SBTInsert 实现
|
|
|
|
|
+ return SBTInsert(rootPID, entry, handle)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// StrBTSearch 查找字符串索引
|
|
// StrBTSearch 查找字符串索引
|
|
@@ -382,8 +304,10 @@ func strBtLeftmostKey(handle page.HandleDb, nodePID uint32, el int) []byte {
|
|
|
if n.isLeaf() {
|
|
if n.isLeaf() {
|
|
|
e := strBtEntry(n, 0)
|
|
e := strBtEntry(n, 0)
|
|
|
keyLen := el - 8 // 叶节点 key 长度
|
|
keyLen := el - 8 // 叶节点 key 长度
|
|
|
- result := make([]byte, el-4) // 内节点条目需要 el-4 字节的 key
|
|
|
|
|
|
|
+ // 返回完整的内节点条目长度的 key,后面补0
|
|
|
|
|
+ result := make([]byte, el-4)
|
|
|
copy(result, e[:keyLen])
|
|
copy(result, e[:keyLen])
|
|
|
|
|
+ // 剩余字节自动初始化为0
|
|
|
return result
|
|
return result
|
|
|
}
|
|
}
|
|
|
cur = strBtChildPID(strBtEntry(n, 0))
|
|
cur = strBtChildPID(strBtEntry(n, 0))
|