secondary.go 45 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464
  1. package btree
  2. import (
  3. "TsDB2/DB/core/page"
  4. "encoding/binary"
  5. "errors"
  6. "fmt"
  7. "unsafe"
  8. )
  9. // ======================== 二级 B+ 树索引操作 ========================
  10. // 叶节点 [key(keyLen) + PKID(8B)] entryLen = keyLen + 8
  11. // 内节点 [key(keyLen) + PKID(8B) + childPID(4B)] entryLen = keyLen + 12
  12. //
  13. // 全树条目按复合键 (key, pkID) 全局有序; 内部条目的前 keyLen+8 字节 = 其子树的
  14. // 最小复合键 [key|pkID] (分隔键), 末 4 字节 = 子页号。复合分隔键让 (key, pkID)
  15. // 的点路由精确成立: 删除/插入一次下降即命中目标叶, 不必在重复 key 跨越的兄弟
  16. // 子树间逐棵试探 (旧格式分隔键只有 key, Age 每值 2 万条跨几十个叶时删除退化为
  17. // 平均半个重复区段的页加载, 实测 ~2.5ms/行)。
  18. // 分裂: 统一 50/50 (不做顺序优化, 二级索引键可能非自增)
  19. // 合并: InnoDB 风格 — 删除后检查当前页+兄弟页能否放进一页
  20. // ----- 节点 I/O -----
  21. func sbtNew(handle page.HandleDb, isLeaf bool, entryLen int) *btNode {
  22. pid := handle.NewPage()
  23. buf := nodeBufGet()
  24. clear(buf) // 池化缓冲可能带旧节点数据, 条目区必须回到"新页=全零"语义
  25. info := (*page.IndexHead)(unsafe.Pointer(&buf[0]))
  26. info.Hdr.Type = page.IndexDataIndex
  27. info.Hdr.PageID = pid
  28. info.Hdr.UseSize = uint32(page.IndexHeadSize)
  29. info.IndexType = page.IndexTypeBTree
  30. info.EntryLen = uint16(entryLen)
  31. info.Count = 0
  32. if isLeaf {
  33. info.IsLeaf = 1
  34. }
  35. return &btNode{buf: buf, info: info, entries: buf[page.IndexHeadSize:]}
  36. }
  37. func sbtLoad(handle page.HandleDb, pid uint32) *btNode {
  38. if pid == 0 {
  39. return nil
  40. }
  41. buf := nodeBufGet()
  42. if err := handle.ReadPage(pid, buf); err != nil {
  43. nodeBufPut(buf)
  44. return nil
  45. }
  46. info := (*page.IndexHead)(unsafe.Pointer(&buf[0]))
  47. return &btNode{buf: buf, info: info, entries: buf[page.IndexHeadSize:]}
  48. }
  49. func sbtSave(handle page.HandleDb, n *btNode) {
  50. _ = handle.SavePage(n.info.Hdr.PageID, n.buf)
  51. }
  52. // ----- 条目操作 -----
  53. func sbtEntry(n *btNode, i int) []byte {
  54. el := int(n.info.EntryLen)
  55. return n.entries[i*el : (i+1)*el]
  56. }
  57. func sbtLeafKey(e []byte) []byte { return e[:len(e)-8] }
  58. func sbtPKID(e []byte) uint64 { return binary.BigEndian.Uint64(e[len(e)-8:]) }
  59. func sbtIntKey(e []byte) []byte { return e[:len(e)-12] } // 内部条目的 key 部分
  60. func sbtIntPKID(e []byte) uint64 { return binary.BigEndian.Uint64(e[len(e)-12:]) } // 内部条目的 pkID 部分
  61. func sbtChildPID(e []byte) uint32 { return binary.BigEndian.Uint32(e[len(e)-4:]) }
  62. func sbtSetChildPID(e []byte, pid uint32) { binary.BigEndian.PutUint32(e[len(e)-4:], pid) }
  63. func sbtCmp(a, b []byte) int {
  64. ml := len(a)
  65. if len(b) < ml {
  66. ml = len(b)
  67. }
  68. for i := 0; i < ml; i++ {
  69. if a[i] < b[i] {
  70. return -1
  71. }
  72. if a[i] > b[i] {
  73. return 1
  74. }
  75. }
  76. return 0
  77. }
  78. // sbtCmpKeyPK 复合键 (key, pkID) 的全序比较: 先比 key, 再比 pkID。
  79. func sbtCmpKeyPK(keyA []byte, pkA uint64, keyB []byte, pkB uint64) int {
  80. if c := sbtCmp(keyA, keyB); c != 0 {
  81. return c
  82. }
  83. switch {
  84. case pkA < pkB:
  85. return -1
  86. case pkA > pkB:
  87. return 1
  88. }
  89. return 0
  90. }
  91. // sbtNodeMinKey 返回节点最左条目的复合键 [key|pkID] (长度 keyLen+8)。
  92. // 叶节点取第一个条目本身 (叶条目就是 [key|pkID]); 内部节点取第一条目的前
  93. // EntryLen-4 字节 (即其子树的最小复合键)。该值用于维护
  94. // "父条目复合键 == 子树最小复合键" 不变式。
  95. func sbtNodeMinKey(n *btNode) []byte {
  96. if n == nil || n.info.Count == 0 {
  97. return nil
  98. }
  99. e := sbtEntry(n, 0)
  100. if n.isLeaf() {
  101. return e
  102. }
  103. return e[:len(e)-4]
  104. }
  105. // sbtFirstLeaf 沿最左分支下降, 返回以 pid 为根的子树中最左叶子页 ID (找不到返回 0)。
  106. func sbtFirstLeaf(handle page.HandleDb, pid uint32) uint32 {
  107. for pid != 0 {
  108. n := sbtLoad(handle, pid)
  109. if n == nil {
  110. return 0
  111. }
  112. if n.isLeaf() {
  113. return pid
  114. }
  115. if n.info.Count == 0 {
  116. return 0
  117. }
  118. pid = sbtChildPID(sbtEntry(n, 0))
  119. }
  120. return 0
  121. }
  122. // sbtLastLeaf 沿最右分支下降, 返回以 pid 为根的子树中最右叶子页 ID (找不到返回 0)。
  123. func sbtLastLeaf(handle page.HandleDb, pid uint32) uint32 {
  124. for pid != 0 {
  125. n := sbtLoad(handle, pid)
  126. if n == nil {
  127. return 0
  128. }
  129. if n.isLeaf() {
  130. return pid
  131. }
  132. if n.info.Count == 0 {
  133. return 0
  134. }
  135. pid = sbtChildPID(sbtEntry(n, int(n.info.Count)-1))
  136. }
  137. return 0
  138. }
  139. // sbtUnlinkSubtreeLeaves 把以 pid 为根的子树所覆盖的那一段叶子, 从叶子双向链表中整体摘除。
  140. // 仅在该子树已被确认 "完全为空" 时调用, 用于避免删除收尾阶段残留空叶子导致
  141. // "叶子链长度 != DFS 可达叶子数"。
  142. func sbtUnlinkSubtreeLeaves(handle page.HandleDb, pid uint32) {
  143. first := sbtFirstLeaf(handle, pid)
  144. if first == 0 {
  145. return
  146. }
  147. last := sbtLastLeaf(handle, pid)
  148. fl := sbtLoad(handle, first)
  149. ll := sbtLoad(handle, last)
  150. if fl == nil || ll == nil {
  151. return
  152. }
  153. pre := fl.info.Hdr.PrePage
  154. next := ll.info.Hdr.NextPage
  155. if pre != 0 {
  156. pr := sbtLoad(handle, pre)
  157. if pr != nil {
  158. pr.info.Hdr.NextPage = next
  159. sbtSave(handle, pr)
  160. }
  161. }
  162. if next != 0 {
  163. nl := sbtLoad(handle, next)
  164. if nl != nil {
  165. nl.info.Hdr.PrePage = pre
  166. sbtSave(handle, nl)
  167. }
  168. }
  169. }
  170. // ----- 内节点路由 -----
  171. func sbtRoute(n *btNode, key []byte) uint32 {
  172. cnt := int(n.info.Count)
  173. if cnt <= 0 {
  174. return 0 // 防御: 空节点不应作为路由节点
  175. }
  176. // 二分查找: 找最后一个 entry.key <= key 的位置
  177. left, right := 0, cnt-1
  178. result := 0
  179. for left <= right {
  180. mid := (left + right) / 2
  181. if sbtCmp(sbtIntKey(sbtEntry(n, mid)), key) <= 0 {
  182. result = mid
  183. left = mid + 1 // 继续向右找
  184. } else {
  185. right = mid - 1
  186. }
  187. }
  188. return sbtChildPID(sbtEntry(n, result))
  189. }
  190. func sbtChildIdx(n *btNode, key []byte) int {
  191. cnt := int(n.info.Count)
  192. if cnt <= 0 {
  193. return 0 // 防御: 空节点不应作为路由节点
  194. }
  195. // 二分查找: 找最后一个 entry.key <= key 的位置 (只按 key 路由)
  196. left, right := 0, cnt-1
  197. result := 0
  198. for left <= right {
  199. mid := (left + right) / 2
  200. if sbtCmp(sbtIntKey(sbtEntry(n, mid)), key) <= 0 {
  201. result = mid
  202. left = mid + 1 // 继续向右找
  203. } else {
  204. right = mid - 1
  205. }
  206. }
  207. return result
  208. }
  209. // sbtChildIdxPK 复合键路由: 找最后一个 "子树最小复合键 <= (key, pkID)" 的子树下标。
  210. //
  211. // 全树按 (key, pkID) 全局有序时, 各子树在复合键空间上是连续区间, 该路由唯一
  212. // 确定目标条目所在 (或应当插入) 的子树 —— 插入与 (key,pkID) 精确删除都用它,
  213. // 一次下降即可命中, 无需向左试探兄弟子树。
  214. func sbtChildIdxPK(n *btNode, key []byte, pkID uint64) int {
  215. cnt := int(n.info.Count)
  216. if cnt <= 0 {
  217. return 0 // 防御: 空节点不应作为路由节点
  218. }
  219. left, right := 0, cnt-1
  220. result := 0
  221. for left <= right {
  222. mid := (left + right) / 2
  223. e := sbtEntry(n, mid)
  224. if sbtCmpKeyPK(sbtIntKey(e), sbtIntPKID(e), key, pkID) <= 0 {
  225. result = mid
  226. left = mid + 1
  227. } else {
  228. right = mid - 1
  229. }
  230. }
  231. return result
  232. }
  233. // ----- 叶节点操作 -----
  234. func sbtInsEntry(n *btNode, entry []byte, pos int) {
  235. el := int(n.info.EntryLen)
  236. cnt := int(n.info.Count)
  237. // 整段后移一格 (块拷贝): 逐条目循环移位在千条目级叶上每插一条要搬千次,
  238. // 批量灌叶路径实测占 ~4% CPU; Go 的 copy 是 memmove 语义, 区间重叠安全。
  239. copy(n.entries[(pos+1)*el:(cnt+1)*el], n.entries[pos*el:cnt*el])
  240. copy(n.entries[pos*el:(pos+1)*el], entry)
  241. n.info.Count++
  242. n.info.Hdr.UseSize += uint32(el)
  243. }
  244. func sbtRmEntry(n *btNode, pos int) {
  245. el := int(n.info.EntryLen)
  246. cnt := int(n.info.Count)
  247. for i := pos; i < cnt-1; i++ {
  248. copy(sbtEntry(n, i), sbtEntry(n, i+1))
  249. }
  250. n.info.Count--
  251. n.info.Hdr.UseSize -= uint32(el)
  252. }
  253. func sbtLeafFind(n *btNode, key []byte) (int, bool) {
  254. el := int(n.info.EntryLen)
  255. cnt := int(n.info.Count)
  256. if cnt == 0 {
  257. return 0, false
  258. }
  259. left, right := 0, cnt-1
  260. for left <= right {
  261. mid := (left + right) / 2
  262. cmp := sbtCmp(sbtEntry(n, mid)[:el-8], key)
  263. if cmp == 0 {
  264. return mid, true
  265. } else if cmp < 0 {
  266. left = mid + 1
  267. } else {
  268. right = mid - 1
  269. }
  270. }
  271. return left, false
  272. }
  273. func sbtLeafPos(n *btNode, key []byte) int {
  274. pos, _ := sbtLeafFind(n, key)
  275. return pos
  276. }
  277. // sbtLeafLowerBound 返回第一个 key >= 目标 key 的条目下标 (leftmost lower_bound)。
  278. //
  279. // 二级索引允许重复 key, 同一 key 的条目在叶内是连续区段。普通二分 (sbtLeafFind)
  280. // 命中相等 key 时会立即返回, 落点可能位于区段中部; 若调用方只从落点向右扫描,
  281. // 就会漏掉落点左侧的重复条目。定位"相同 key 区段"的起点必须用本函数。
  282. func sbtLeafLowerBound(n *btNode, key []byte) int {
  283. el := int(n.info.EntryLen)
  284. cnt := int(n.info.Count)
  285. left, right := 0, cnt
  286. for left < right {
  287. mid := (left + right) / 2
  288. if sbtCmp(sbtEntry(n, mid)[:el-8], key) < 0 {
  289. left = mid + 1
  290. } else {
  291. right = mid
  292. }
  293. }
  294. return left
  295. }
  296. // sbtLeafLowerBoundPK 返回第一个复合键 (key, pkID) >= 目标的条目下标。
  297. //
  298. // 叶内条目按复合键有序 (重复 key 的条目按 pkID 排列), 因此插入定位与
  299. // (key, pkID) 精确查找都应使用本函数, 而不是"key 落点 + 同 key 区段线性扫描"。
  300. func sbtLeafLowerBoundPK(n *btNode, key []byte, pkID uint64) int {
  301. cnt := int(n.info.Count)
  302. left, right := 0, cnt
  303. for left < right {
  304. mid := (left + right) / 2
  305. e := sbtEntry(n, mid)
  306. if sbtCmpKeyPK(sbtLeafKey(e), sbtPKID(e), key, pkID) < 0 {
  307. left = mid + 1
  308. } else {
  309. right = mid
  310. }
  311. }
  312. return left
  313. }
  314. // sbtLeafHasKey 判断叶节点中是否存在等于 key 的条目 (基于 lower_bound 判定)
  315. func sbtLeafHasKey(n *btNode, key []byte) bool {
  316. el := int(n.info.EntryLen)
  317. pos := sbtLeafLowerBound(n, key)
  318. return pos < int(n.info.Count) && sbtCmp(sbtEntry(n, pos)[:el-8], key) == 0
  319. }
  320. // sbtLeftmostLeafForKey 返回"可能包含 key"的最左叶子页 ID。
  321. //
  322. // 内部节点的分隔键是子树的"最小键", sbtRoute 取"最后一个 分隔键<=key 的子树"。
  323. // 当同一 key 的条目因叶分裂而跨越相邻两叶 (左叶尾键 == 右叶首键) 时,
  324. // sbtRoute 只会落到右侧那一叶, 从而漏掉位于左叶尾部的重复条目。
  325. // 因此在路由落点的基础上, 沿叶子前驱链向左回溯: 只要前驱叶的最大键 >= key,
  326. // 该前驱叶就仍可能含有 key, 必须一并纳入扫描范围。
  327. func sbtLeftmostLeafForKey(rootPID uint32, key []byte, handle page.HandleDb) uint32 {
  328. pid := rootPID
  329. for pid != 0 {
  330. n := sbtLoad(handle, pid)
  331. if n == nil {
  332. return 0
  333. }
  334. if n.isLeaf() {
  335. break
  336. }
  337. pid = sbtRoute(n, key)
  338. }
  339. for pid != 0 {
  340. n := sbtLoad(handle, pid)
  341. if n == nil || n.info.Count == 0 {
  342. return 0
  343. }
  344. pre := n.info.Hdr.PrePage
  345. if pre == 0 {
  346. return pid
  347. }
  348. pn := sbtLoad(handle, pre)
  349. if pn == nil || pn.info.Count == 0 || pn.info.IsLeaf == 0 {
  350. return pid
  351. }
  352. el := int(n.info.EntryLen)
  353. lastKey := sbtEntry(pn, int(pn.info.Count)-1)[:el-8]
  354. if sbtCmp(lastKey, key) < 0 {
  355. return pid
  356. }
  357. pid = pre
  358. }
  359. return 0
  360. }
  361. // ======================== 按 key+pkID 精确删除 ========================
  362. // SBTDeleteWithPKID 删除指定 key + pkID 的条目(处理重复 key 场景)。
  363. //
  364. // 采用与 sbtDeleteRec 完全一致的递归下溢处理: 叶被删空时由父层 sbtHandleUnderflow
  365. // 借位/合并, 从而不会残留 "空叶可达" (否则会破坏 叶子链 == DFS 可达叶 的不变式,
  366. // 并让 sbtRoute 落到空叶导致查找失败)。
  367. func SBTDeleteWithPKID(rootPID uint32, key []byte, pkID uint64, handle page.HandleDb) (uint32, error) {
  368. if rootPID == 0 {
  369. return 0, page.ErrNotFound
  370. }
  371. found, err := sbtDeleteRecPK(rootPID, key, pkID, nil, handle)
  372. if err != nil {
  373. return rootPID, err
  374. }
  375. if !found {
  376. return rootPID, page.ErrNotFound
  377. }
  378. // 收尾归一化: 与 SBTDelete 一致
  379. newRoot := rootPID
  380. // 归一化过程中被跳过的旧根 (降高时旧根整体退役; 删空时旧根被换成新建空叶)。
  381. // 收集后在本函数末尾才归还, 避免 sbtNew 在同一轮里把这些页又分配回来。
  382. var retiredRoots []uint32
  383. for {
  384. n := sbtLoad(handle, newRoot)
  385. if n == nil || n.isLeaf() {
  386. break
  387. }
  388. if n.info.Count == 1 {
  389. childPID := sbtChildPID(sbtEntry(n, 0))
  390. if childPID == 0 {
  391. break
  392. }
  393. retiredRoots = append(retiredRoots, newRoot)
  394. newRoot = childPID
  395. continue
  396. }
  397. if n.info.Count == 0 {
  398. // n 必为内部节点 (循环开头已 break 叶子): 新建空叶要用叶条目长度
  399. // (内部 EntryLen keyLen+12 - 4 = keyLen+8)
  400. leaf := sbtNew(handle, true, int(n.info.EntryLen)-4)
  401. sbtSave(handle, leaf)
  402. retiredRoots = append(retiredRoots, newRoot)
  403. newRoot = leaf.pageID()
  404. }
  405. break
  406. }
  407. // 只归还退役的旧根自身: Count==1 时其子树仍是新根 (可达), 绝不能按子树回收;
  408. // Count==0 时该节点已是空内部节点, 其子页在上面的递归里已随空子树摘链归还。
  409. for _, pid := range retiredRoots {
  410. btReleasePage(handle, pid)
  411. }
  412. return newRoot, nil
  413. }
  414. // sbtDeleteRecPK 按 (key, pkID) 精确删除, 并复用 sbtDeleteRec 的下溢/合并/归一化流程。
  415. //
  416. // 内部节点的分隔键是子树的最小复合键 (key, pkID), 子树在复合键空间上是连续区间,
  417. // 因此 sbtChildIdxPK 一次路由即唯一确定目标条目所在的子树 —— 不再需要旧实现
  418. // "从 key 路由落点向左逐棵子树试探" 的兜底 (重复 key 跨几十个叶时那是平均半个
  419. // 重复区段的页加载)。
  420. func sbtDeleteRecPK(nodePID uint32, key []byte, pkID uint64, path []btPathEntry, handle page.HandleDb) (bool, error) {
  421. node := sbtLoad(handle, nodePID)
  422. if node == nil {
  423. return false, nil
  424. }
  425. el := int(node.info.EntryLen)
  426. if node.isLeaf() {
  427. return sbtDeleteLeafPK(node, key, pkID, path, handle), nil
  428. }
  429. if node.info.Count == 0 {
  430. return false, nil
  431. }
  432. ci := sbtChildIdxPK(node, key, pkID)
  433. childPID := sbtChildPID(sbtEntry(node, ci))
  434. newPath := make([]btPathEntry, len(path)+1)
  435. copy(newPath, path)
  436. newPath[len(path)] = btPathEntry{nodePID: nodePID, childIdx: ci}
  437. found, err := sbtDeleteRecPK(childPID, key, pkID, newPath, handle)
  438. if err != nil {
  439. return false, err
  440. }
  441. if !found {
  442. return false, nil
  443. }
  444. // 命中并已在该子树内删除: 处理本层的下溢/最小键/归一化 (与 sbtDeleteRec 相同)
  445. node = sbtLoad(handle, nodePID)
  446. if node == nil {
  447. return true, errors.New("sbt reload node failed")
  448. }
  449. if node.info.Count > 0 && ci < int(node.info.Count) && sbtChildPID(sbtEntry(node, ci)) == childPID {
  450. child := sbtLoad(handle, childPID)
  451. if child != nil {
  452. if child.info.Count == 0 {
  453. sbtHandleUnderflow(node, ci, handle)
  454. node = sbtLoad(handle, nodePID)
  455. if node == nil {
  456. return true, errors.New("sbt reload node failed after underflow")
  457. }
  458. } else {
  459. // 维护不变式: 父条目复合键 == 子树最小复合键 (删除叶子最小键后父键会变旧)
  460. copy(sbtEntry(node, ci)[:el-4], sbtNodeMinKey(child))
  461. }
  462. }
  463. }
  464. if !node.isLeaf() && node.info.Count == 1 {
  465. c0 := sbtChildPID(sbtEntry(node, 0))
  466. cn := sbtLoad(handle, c0)
  467. if cn != nil && cn.info.Count == 0 {
  468. sbtUnlinkSubtreeLeaves(handle, c0)
  469. node.info.Count = 0
  470. node.info.Hdr.UseSize = uint32(page.IndexHeadSize)
  471. sbtSave(handle, node)
  472. // c0 子树整段摘链后不再被任何父条目或叶子链引用, 连同其内部节点
  473. // 一并归还 —— 否则每删空一棵子树就漏掉一批索引页。
  474. btReleaseSubtree(handle, c0)
  475. return true, nil
  476. }
  477. }
  478. sbtSave(handle, node)
  479. return true, nil
  480. }
  481. // sbtDeleteLeafPK 在叶内删除指定 (key, pkID); 命中返回 true。
  482. // 下溢处理与 sbtDeleteRec 的叶分支保持一致。
  483. func sbtDeleteLeafPK(node *btNode, key []byte, pkID uint64, path []btPathEntry, handle page.HandleDb) bool {
  484. el := int(node.info.EntryLen)
  485. cnt := int(node.info.Count)
  486. // 叶内条目按复合键有序: 复合下界一次定位, 无需同 key 区段线性扫描
  487. pos := sbtLeafLowerBoundPK(node, key, pkID)
  488. if pos >= cnt {
  489. return false
  490. }
  491. entry := sbtEntry(node, pos)
  492. if sbtCmp(sbtLeafKey(entry), key) != 0 || sbtPKID(entry) != pkID {
  493. return false
  494. }
  495. sbtRmEntry(node, pos)
  496. if node.info.Count == 0 && len(path) == 0 {
  497. sbtSave(handle, node)
  498. return true
  499. }
  500. sbtSave(handle, node)
  501. if len(path) > 0 && node.info.Count > 0 {
  502. sbtTryMerge(handle, path, node, el)
  503. }
  504. return true
  505. }
  506. // ======================== 查找所有相同 key 的 pkID ========================
  507. // SBTSearchAll 查找相同 key 下的所有 pkID
  508. func SBTSearchAll(rootPID uint32, key []byte, handle page.HandleDb) ([]uint64, bool) {
  509. if rootPID == 0 {
  510. return nil, false
  511. }
  512. var result []uint64
  513. for pid := sbtLeftmostLeafForKey(rootPID, key, handle); pid != 0; {
  514. n := sbtLoad(handle, pid)
  515. if n == nil {
  516. return nil, false
  517. }
  518. el := int(n.info.EntryLen)
  519. cnt := int(n.info.Count)
  520. // 用 leftmost lower_bound 定位相同 key 区段起点, 避免漏掉左侧重复条目
  521. pos := sbtLeafLowerBound(n, key)
  522. if pos < cnt {
  523. if sbtCmp(sbtEntry(n, pos)[:el-8], key) != 0 {
  524. break // 已越过相同 key 区段
  525. }
  526. // 收集本叶中所有相同 key 的 pkID
  527. for i := pos; i < cnt; i++ {
  528. entry := sbtEntry(n, i)
  529. if sbtCmp(entry[:el-8], key) != 0 {
  530. break
  531. }
  532. result = append(result, sbtPKID(entry))
  533. }
  534. }
  535. pid = n.info.Hdr.NextPage
  536. }
  537. if len(result) == 0 {
  538. return nil, false
  539. }
  540. return result, true
  541. }
  542. // ======================== 搜索 ========================
  543. func SBTSearch(rootPID uint32, key []byte, handle page.HandleDb) (uint64, bool) {
  544. if rootPID == 0 {
  545. return 0, false
  546. }
  547. // 从左起第一个可能含 key 的叶子开始, 沿 NextPage 右扫, 返回最左(最小 pkID)的条目
  548. for pid := sbtLeftmostLeafForKey(rootPID, key, handle); pid != 0; {
  549. n := sbtLoad(handle, pid)
  550. if n == nil {
  551. return 0, false
  552. }
  553. el := int(n.info.EntryLen)
  554. cnt := int(n.info.Count)
  555. pos := sbtLeafLowerBound(n, key)
  556. if pos < cnt {
  557. if sbtCmp(sbtEntry(n, pos)[:el-8], key) == 0 {
  558. return sbtPKID(sbtEntry(n, pos)), true
  559. }
  560. return 0, false // 已越过相同 key 区段
  561. }
  562. pid = n.info.Hdr.NextPage
  563. }
  564. return 0, false
  565. }
  566. // ======================== 范围扫描 ========================
  567. func SBTRangeScan(rootPID uint32, handle page.HandleDb,
  568. startKey, endKey []byte, startInc, endInc bool, reverse bool,
  569. callback func(row []byte) bool) error {
  570. if rootPID == 0 {
  571. return nil
  572. }
  573. if !reverse {
  574. cur := rootPID
  575. if startKey != nil {
  576. // 必须用 sbtLeftmostLeafForKey 定位"可能含 startKey 的最左叶"。
  577. // sbtRoute 找的是"最后一个分隔键 <= startKey 的子树", 落点是该 key 区段的
  578. // 最右叶; 当同一 key 因叶分裂跨越相邻两叶 (左叶尾键 == 右叶首键) 时,
  579. // 左侧叶子里的重复条目会被整段跳过 —— 等值查询 (startKey == endKey)
  580. // 表现为只返回最右叶那部分: 实测每键 2500 条只回 256 条, 每键 1000 条只回 184 条。
  581. // 全范围扫描 (startKey == nil) 不受影响, 故只有带边界的查询出错。
  582. cur = sbtLeftmostLeafForKey(rootPID, startKey, handle)
  583. } else {
  584. for {
  585. n := sbtLoad(handle, cur)
  586. if n == nil {
  587. return nil
  588. }
  589. if n.isLeaf() {
  590. break
  591. }
  592. // startKey 为空时, 显式路由到最左叶 (跟随第一个子节点)
  593. cur = sbtChildPID(sbtEntry(n, 0))
  594. }
  595. }
  596. for cur != 0 {
  597. n := sbtLoad(handle, cur)
  598. if n == nil {
  599. break
  600. }
  601. if n.info.Hdr.Type != page.IndexDataIndex {
  602. return fmt.Errorf("btree: 正向范围扫描遇到非索引页 pid=%d type=%d, 叶子链已损坏",
  603. n.info.Hdr.PageID, n.info.Hdr.Type)
  604. }
  605. el := int(n.info.EntryLen)
  606. for i := 0; i < int(n.info.Count); i++ {
  607. entry := sbtEntry(n, i)
  608. key := entry[:el-8]
  609. if endKey != nil {
  610. cmp := sbtCmp(key, endKey)
  611. if cmp > 0 || (cmp == 0 && !endInc) {
  612. return nil
  613. }
  614. }
  615. if startKey != nil {
  616. cmp := sbtCmp(key, startKey)
  617. if cmp < 0 || (cmp == 0 && !startInc) {
  618. continue
  619. }
  620. }
  621. pkID := entry[el-8:]
  622. if !callback(pkID) {
  623. return nil
  624. }
  625. }
  626. cur = n.info.Hdr.NextPage
  627. }
  628. } else {
  629. // 反向: 路由到 endKey 或最右叶, 沿 PrePage 遍历
  630. cur := rootPID
  631. if endKey != nil {
  632. for {
  633. n := sbtLoad(handle, cur)
  634. if n == nil {
  635. return nil
  636. }
  637. if n.isLeaf() {
  638. break
  639. }
  640. cur = sbtRoute(n, endKey)
  641. }
  642. } else {
  643. for {
  644. n := sbtLoad(handle, cur)
  645. if n == nil {
  646. return nil
  647. }
  648. if n.isLeaf() {
  649. break
  650. }
  651. cur = sbtChildPID(sbtEntry(n, int(n.info.Count)-1))
  652. }
  653. }
  654. for cur != 0 {
  655. n := sbtLoad(handle, cur)
  656. if n == nil {
  657. break
  658. }
  659. if n.info.Hdr.Type != page.IndexDataIndex {
  660. return fmt.Errorf("btree: 反向范围扫描遇到非索引页 pid=%d type=%d, 叶子链已损坏",
  661. n.info.Hdr.PageID, n.info.Hdr.Type)
  662. }
  663. el := int(n.info.EntryLen)
  664. for i := int(n.info.Count) - 1; i >= 0; i-- {
  665. entry := sbtEntry(n, i)
  666. key := entry[:el-8]
  667. if startKey != nil {
  668. cmp := sbtCmp(key, startKey)
  669. if cmp < 0 || (cmp == 0 && !startInc) {
  670. return nil
  671. }
  672. }
  673. if endKey != nil {
  674. cmp := sbtCmp(key, endKey)
  675. if cmp > 0 || (cmp == 0 && !endInc) {
  676. continue
  677. }
  678. }
  679. pkID := entry[el-8:]
  680. if !callback(pkID) {
  681. return nil
  682. }
  683. }
  684. cur = n.info.Hdr.PrePage
  685. }
  686. }
  687. return nil
  688. }
  689. // ======================== 插入 ========================
  690. func SBTInsert(rootPID uint32, entry []byte, handle page.HandleDb) (uint32, error) {
  691. el := len(entry)
  692. if rootPID == 0 {
  693. leaf := sbtNew(handle, true, el)
  694. sbtInsEntry(leaf, entry, 0)
  695. sbtSave(handle, leaf)
  696. newRoot := leaf.pageID()
  697. leaf.release()
  698. return newRoot, nil
  699. }
  700. var path []btPathEntry
  701. cur := rootPID
  702. for {
  703. n := sbtLoad(handle, cur)
  704. if n == nil {
  705. return rootPID, errors.New("sbt load failed")
  706. }
  707. if n.isLeaf() {
  708. key := entry[:el-8]
  709. pkID := sbtPKID(entry)
  710. // 叶内条目按复合键 (key, pkID) 有序: 复合下界一次定位插入位置
  711. ip := sbtLeafLowerBoundPK(n, key, pkID)
  712. if int(n.info.Hdr.UseSize)+el <= btSplitThreshold() {
  713. sbtInsEntry(n, entry, ip)
  714. sbtSave(handle, n)
  715. if ip == 0 {
  716. // 新条目成为本叶最小复合键: 沿路径向上同步
  717. // "父条目复合键 == 子树最小复合键"
  718. for i := len(path) - 1; i >= 0; i-- {
  719. p := path[i]
  720. pb := sbtLoad(handle, p.nodePID)
  721. if pb == nil || p.childIdx < 0 || p.childIdx >= int(pb.info.Count) {
  722. break
  723. }
  724. pbe := sbtEntry(pb, p.childIdx)
  725. copy(pbe[:len(pbe)-4], entry) // entry 本身就是 [key|pkID]
  726. sbtSave(handle, pb)
  727. pb.release()
  728. if p.childIdx != 0 {
  729. break
  730. }
  731. }
  732. }
  733. n.release()
  734. return rootPID, nil
  735. }
  736. cnt := int(n.info.Count)
  737. total := cnt + 1
  738. all := make([]byte, total*el)
  739. if ip > 0 {
  740. copy(all, n.entries[:ip*el])
  741. }
  742. copy(all[ip*el:], entry)
  743. if cnt > ip {
  744. copy(all[(ip+1)*el:], n.entries[ip*el:cnt*el])
  745. }
  746. // 分裂点: 左叶保留 [0,mid), 右叶保留 [mid,total)
  747. mid := splitPoint(total, SBTSplitCfg, false)
  748. rl := sbtNew(handle, true, el)
  749. rc := total - mid
  750. copy(rl.entries, all[mid*el:total*el])
  751. rl.info.Count = uint32(rc)
  752. rl.info.Hdr.UseSize = uint32(page.IndexHeadSize) + uint32(rc*el)
  753. rl.info.Hdr.NextPage = n.info.Hdr.NextPage
  754. rl.info.Hdr.PrePage = n.info.Hdr.PageID
  755. n.info.Hdr.NextPage = rl.info.Hdr.PageID
  756. copy(n.entries, all[:mid*el])
  757. n.info.Count = uint32(mid)
  758. n.info.Hdr.UseSize = uint32(page.IndexHeadSize) + uint32(mid*el)
  759. sbtSave(handle, n)
  760. sbtSave(handle, rl)
  761. if rl.info.Hdr.NextPage != 0 {
  762. nl := sbtLoad(handle, rl.info.Hdr.NextPage)
  763. if nl != nil {
  764. nl.info.Hdr.PrePage = rl.info.Hdr.PageID
  765. sbtSave(handle, nl)
  766. nl.release()
  767. }
  768. }
  769. // 提升的分隔复合键 = 右叶首条目 [key|pkID] (rl 已在内存, 无需再下降)
  770. pkc := append([]byte(nil), sbtEntry(rl, 0)...)
  771. nr, err := sbtPromote(handle, rootPID, path, n.info.Hdr.PageID, pkc, rl.info.Hdr.PageID, el)
  772. n.release()
  773. rl.release()
  774. return nr, err
  775. }
  776. // 插入同样按复合键路由: 子树在复合键空间上是连续区间, key 路由可能
  777. // 落到重复 key 区段右半的子树, 会破坏全局 (key, pkID) 有序性
  778. ci := sbtChildIdxPK(n, entry[:el-8], sbtPKID(entry))
  779. cpid := sbtChildPID(sbtEntry(n, ci))
  780. path = append(path, btPathEntry{nodePID: cur, childIdx: ci})
  781. n.release()
  782. cur = cpid
  783. }
  784. }
  785. // sbtPromote 把分裂出的右节点 (及其最小复合键 promoComposite) 插入父层, 必要时
  786. // 递归分裂。leafEl 是叶条目长度 keyLen+8; 内部条目长度恒为 leafEl+4
  787. // ([key | pkID(8) | childPID(4)])。promoComposite 长度 = leafEl ([key|pkID])。
  788. func sbtPromote(handle page.HandleDb, rootPID uint32, path []btPathEntry, leftPID uint32, promoComposite []byte, rightPID uint32, leafEl int) (uint32, error) {
  789. iel := leafEl + 4
  790. promoKey := promoComposite[:len(promoComposite)-8]
  791. promoPK := binary.BigEndian.Uint64(promoComposite[len(promoComposite)-8:])
  792. if len(path) == 0 {
  793. nr := sbtNew(handle, false, iel)
  794. ln := sbtLoad(handle, leftPID)
  795. if ln == nil {
  796. nr.release()
  797. return rootPID, errors.New("sbt promote: left load failed")
  798. }
  799. le := make([]byte, iel)
  800. copy(le[:iel-4], sbtNodeMinKey(ln)) // leftPID 可能是叶或内部节点, 取其子树最小复合键
  801. ln.release()
  802. sbtSetChildPID(le, leftPID)
  803. re := make([]byte, iel)
  804. copy(re[:iel-4], promoComposite)
  805. sbtSetChildPID(re, rightPID)
  806. sbtInsEntry(nr, le, 0)
  807. sbtInsEntry(nr, re, 1)
  808. sbtSave(handle, nr)
  809. newRoot := nr.pageID()
  810. nr.release()
  811. return newRoot, nil
  812. }
  813. pi := len(path) - 1
  814. parent := sbtLoad(handle, path[pi].nodePID)
  815. if parent == nil {
  816. return rootPID, errors.New("sbt parent load failed")
  817. }
  818. ci := path[pi].childIdx
  819. cnt := int(parent.info.Count)
  820. pos := cnt
  821. for i := ci + 1; i < cnt; i++ {
  822. pe := sbtEntry(parent, i)
  823. if sbtCmpKeyPK(sbtIntKey(pe), sbtIntPKID(pe), promoKey, promoPK) >= 0 {
  824. pos = i
  825. break
  826. }
  827. }
  828. for i := cnt; i > pos; i-- {
  829. copy(sbtEntry(parent, i), sbtEntry(parent, i-1))
  830. }
  831. ne := make([]byte, iel)
  832. copy(ne[:iel-4], promoComposite)
  833. sbtSetChildPID(ne, rightPID)
  834. copy(sbtEntry(parent, pos), ne)
  835. parent.info.Count++
  836. parent.info.Hdr.UseSize += uint32(iel)
  837. if int(parent.info.Hdr.UseSize)+iel <= btSplitThreshold() {
  838. sbtSave(handle, parent)
  839. parent.release()
  840. return rootPID, nil
  841. }
  842. cnt = int(parent.info.Count)
  843. mid := splitPoint(cnt, SBTSplitCfg, false)
  844. // 分裂点取 mid: 左半保留 [0,mid), 右半保留 [mid,cnt)。
  845. // 不能丢掉 entry[mid] (否则它指向的整棵子树会不可达)。
  846. rn := sbtNew(handle, false, iel)
  847. rc := cnt - mid
  848. if rc > 0 {
  849. copy(rn.entries, parent.entries[mid*iel:cnt*iel])
  850. }
  851. rn.info.Count = uint32(rc)
  852. rn.info.Hdr.UseSize = uint32(page.IndexHeadSize) + uint32(rc*iel)
  853. parent.info.Count = uint32(mid)
  854. parent.info.Hdr.UseSize = uint32(page.IndexHeadSize) + uint32(mid*iel)
  855. sbtSave(handle, parent)
  856. sbtSave(handle, rn)
  857. // 提升的分隔复合键 = 右节点首条目的复合键 (其子树的最小复合键)
  858. e0 := sbtEntry(rn, 0)
  859. pk2 := make([]byte, iel-4)
  860. copy(pk2, e0[:iel-4])
  861. ret, err := sbtPromote(handle, rootPID, path[:pi], parent.info.Hdr.PageID, pk2, rn.info.Hdr.PageID, leafEl)
  862. parent.release()
  863. rn.release()
  864. return ret, err
  865. }
  866. // ======================== 删除 ========================
  867. func SBTDelete(rootPID uint32, key []byte, handle page.HandleDb) (uint32, error) {
  868. if rootPID == 0 {
  869. return 0, page.ErrNotFound
  870. }
  871. newRoot, err := sbtDeleteRec(rootPID, key, nil, handle)
  872. if err != nil {
  873. return rootPID, err
  874. }
  875. // 收尾归一化:
  876. // - 根为内部节点且只剩 1 个子节点 -> 用该子节点作为新根 (继续向上收缩)
  877. // - 根为内部节点且已无条目 (整棵树被删空) -> 换成一个全新的空叶子,
  878. // 避免留下 "空内部节点" 这种会让查找读到脏数据的状态
  879. // 归一化过程中被跳过的旧根 (降高时旧根整体退役; 删空时旧根被换成新建空叶)。
  880. // 收集后在本函数末尾才归还, 避免 sbtNew 在同一轮里把这些页又分配回来。
  881. var retiredRoots []uint32
  882. for {
  883. n := sbtLoad(handle, newRoot)
  884. if n == nil || n.isLeaf() {
  885. break
  886. }
  887. if n.info.Count == 1 {
  888. childPID := sbtChildPID(sbtEntry(n, 0))
  889. if childPID == 0 {
  890. break
  891. }
  892. retiredRoots = append(retiredRoots, newRoot)
  893. newRoot = childPID
  894. continue
  895. }
  896. if n.info.Count == 0 {
  897. // 此时 n 必为内部节点 (循环开头已 break 叶子), 其 EntryLen 是内部条目
  898. // 长度 keyLen+12; 新建空叶要用叶条目长度 keyLen+8
  899. leaf := sbtNew(handle, true, int(n.info.EntryLen)-4)
  900. sbtSave(handle, leaf)
  901. retiredRoots = append(retiredRoots, newRoot)
  902. newRoot = leaf.pageID()
  903. }
  904. break
  905. }
  906. // 只归还退役的旧根自身: Count==1 时其子树仍是新根 (可达), 绝不能按子树回收;
  907. // Count==0 时该节点已是空内部节点, 其子页在上面的递归里已随空子树摘链归还。
  908. for _, pid := range retiredRoots {
  909. btReleasePage(handle, pid)
  910. }
  911. return newRoot, nil
  912. }
  913. // sbtDeleteRec 按 key 删除 (删除该 key 的一条条目), 并做下溢/合并/归一化。
  914. func sbtDeleteRec(nodePID uint32, key []byte, path []btPathEntry, handle page.HandleDb) (uint32, error) {
  915. node := sbtLoad(handle, nodePID)
  916. if node == nil {
  917. return nodePID, page.ErrNotFound
  918. }
  919. el := int(node.info.EntryLen)
  920. if node.isLeaf() {
  921. pos, ok := sbtLeafFind(node, key)
  922. if !ok {
  923. return nodePID, page.ErrNotFound
  924. }
  925. sbtRmEntry(node, pos)
  926. if node.info.Count == 0 && len(path) == 0 {
  927. sbtSave(handle, node)
  928. return nodePID, nil
  929. }
  930. sbtSave(handle, node)
  931. if len(path) > 0 && node.info.Count > 0 {
  932. sbtTryMerge(handle, path, node, el)
  933. }
  934. return nodePID, nil
  935. }
  936. ci := sbtChildIdx(node, key)
  937. childPID := sbtChildPID(sbtEntry(node, ci))
  938. newPath := make([]btPathEntry, len(path)+1)
  939. copy(newPath, path)
  940. newPath[len(path)] = btPathEntry{nodePID: nodePID, childIdx: ci}
  941. if _, err := sbtDeleteRec(childPID, key, newPath, handle); err != nil {
  942. return nodePID, err
  943. }
  944. // 递归过程中子节点可能触发合并, 而合并会单独加载并保存本节点。
  945. // 这里必须重新加载, 否则后面用过期副本保存会把合并结果覆盖掉 (数据重复/条目丢失)。
  946. node = sbtLoad(handle, nodePID)
  947. if node == nil {
  948. return nodePID, errors.New("sbt reload node failed")
  949. }
  950. if node.info.Count > 0 {
  951. // 仅当原 child 条目仍在本节点的 ci 位置时才处理
  952. // (若该条目已被合并移除, 则说明子树已被兄弟吸收, 无需再处理)
  953. if ci >= 0 && ci < int(node.info.Count) && sbtChildPID(sbtEntry(node, ci)) == childPID {
  954. child := sbtLoad(handle, childPID)
  955. if child != nil {
  956. if child.info.Count == 0 {
  957. sbtHandleUnderflow(node, ci, handle)
  958. // 借位/合并会直接改写本节点并保存, 必须重新加载
  959. node = sbtLoad(handle, nodePID)
  960. if node == nil {
  961. return nodePID, errors.New("sbt reload node failed after underflow")
  962. }
  963. } else {
  964. // 维护不变式: 父条目复合键 == 子树最小复合键
  965. // (删除叶子的最小键后, 父条目键会变旧)
  966. copy(sbtEntry(node, ci)[:el-4], sbtNodeMinKey(child))
  967. }
  968. }
  969. }
  970. }
  971. // 归一化: 内部节点若只剩一个 "已空" 的子节点 (没有兄弟可合并), 则该节点本身
  972. // 也变空。此时必须把该空子树整段从叶子链摘除并让本节点变为空 (Count=0),
  973. // 由上层继续向上收缩。否则会残留 "空内部节点", 破坏路由/查找。
  974. if !node.isLeaf() && node.info.Count == 1 {
  975. c0 := sbtChildPID(sbtEntry(node, 0))
  976. cn := sbtLoad(handle, c0)
  977. if cn != nil && cn.info.Count == 0 {
  978. sbtUnlinkSubtreeLeaves(handle, c0)
  979. node.info.Count = 0
  980. node.info.Hdr.UseSize = uint32(page.IndexHeadSize)
  981. sbtSave(handle, node)
  982. // c0 子树整段摘链后不再被任何父条目或叶子链引用, 连同其内部节点
  983. // 一并归还 —— 否则每删空一棵子树就漏掉一批索引页。
  984. btReleaseSubtree(handle, c0)
  985. return nodePID, nil
  986. }
  987. }
  988. if node.info.Count == 0 {
  989. sbtSave(handle, node)
  990. return nodePID, nil
  991. }
  992. sbtSave(handle, node)
  993. return nodePID, nil
  994. }
  995. func sbtTryMerge(handle page.HandleDb, path []btPathEntry, node *btNode, el int) {
  996. if len(path) == 0 {
  997. return
  998. }
  999. nodePID := node.info.Hdr.PageID
  1000. pp := path[len(path)-1].nodePID
  1001. parent := sbtLoad(handle, pp)
  1002. if parent == nil {
  1003. return
  1004. }
  1005. ci := -1
  1006. for i := 0; i < int(parent.info.Count); i++ {
  1007. if sbtChildPID(sbtEntry(parent, i)) == node.info.Hdr.PageID {
  1008. ci = i
  1009. break
  1010. }
  1011. }
  1012. if ci < 0 {
  1013. return
  1014. }
  1015. if ci > 0 {
  1016. leftPID := sbtChildPID(sbtEntry(parent, ci-1))
  1017. left := sbtLoad(handle, leftPID)
  1018. if left != nil && left.isLeaf() {
  1019. combined := uint32(page.IndexHeadSize) + (left.info.Count+node.info.Count)*uint32(el)
  1020. threshold := uint32(btSplitThreshold())
  1021. if combined <= threshold {
  1022. rc := int(node.info.Count)
  1023. copy(left.entries[int(left.info.Count)*el:], node.entries[:rc*el])
  1024. left.info.Count += node.info.Count
  1025. left.info.Hdr.UseSize += uint32(rc * el)
  1026. left.info.Hdr.NextPage = node.info.Hdr.NextPage
  1027. sbtSave(handle, left)
  1028. if left.info.Hdr.NextPage != 0 {
  1029. nl := sbtLoad(handle, left.info.Hdr.NextPage)
  1030. if nl != nil {
  1031. nl.info.Hdr.PrePage = leftPID
  1032. sbtSave(handle, nl)
  1033. }
  1034. }
  1035. sbtRmEntry(parent, ci)
  1036. sbtSave(handle, parent)
  1037. // node 的条目已全部并入 left, 且指向 node 的父条目已被摘除,
  1038. // 叶子链也已改接到 left 的 NextPage —— node 页至此彻底不可达。
  1039. btReleasePage(handle, nodePID)
  1040. return
  1041. }
  1042. }
  1043. }
  1044. if ci < int(parent.info.Count)-1 {
  1045. rightPID := sbtChildPID(sbtEntry(parent, ci+1))
  1046. right := sbtLoad(handle, rightPID)
  1047. if right != nil && right.isLeaf() {
  1048. combined := uint32(page.IndexHeadSize) + (node.info.Count+right.info.Count)*uint32(el)
  1049. threshold := uint32(btSplitThreshold())
  1050. if combined <= threshold {
  1051. rc := int(right.info.Count)
  1052. copy(node.entries[int(node.info.Count)*el:], right.entries[:rc*el])
  1053. node.info.Count += right.info.Count
  1054. node.info.Hdr.UseSize += uint32(rc * el)
  1055. node.info.Hdr.NextPage = right.info.Hdr.NextPage
  1056. sbtSave(handle, node)
  1057. if node.info.Hdr.NextPage != 0 {
  1058. nl := sbtLoad(handle, node.info.Hdr.NextPage)
  1059. if nl != nil {
  1060. nl.info.Hdr.PrePage = node.info.Hdr.PageID
  1061. sbtSave(handle, nl)
  1062. }
  1063. }
  1064. sbtRmEntry(parent, ci+1)
  1065. sbtSave(handle, parent)
  1066. // right 的条目已全部并入 node, 且指向 right 的父条目已摘除,
  1067. // 叶子链也已改接到 node 的 NextPage —— right 页至此彻底不可达。
  1068. btReleasePage(handle, rightPID)
  1069. return
  1070. }
  1071. }
  1072. }
  1073. }
  1074. // sbtHandleUnderflow 处理空/下溢子节点: 先尝试向兄弟借位, 否则与兄弟合并。
  1075. // 不接收 el 参数 —— child/兄弟与父节点的条目长度可能不同 (叶 keyLen+8,
  1076. // 内部 keyLen+12), 一律从各节点自身的 EntryLen 取。
  1077. func sbtHandleUnderflow(parent *btNode, childIdx int, handle page.HandleDb) {
  1078. childPID := sbtChildPID(sbtEntry(parent, childIdx))
  1079. child := sbtLoad(handle, childPID)
  1080. if child == nil {
  1081. return
  1082. }
  1083. if childIdx > 0 {
  1084. leftPID := sbtChildPID(sbtEntry(parent, childIdx-1))
  1085. leftSib := sbtLoad(handle, leftPID)
  1086. if leftSib != nil && int(leftSib.info.Count) > 1 {
  1087. borrowed := append([]byte(nil), sbtEntry(leftSib, int(leftSib.info.Count)-1)...)
  1088. sbtRmEntry(leftSib, int(leftSib.info.Count)-1)
  1089. // 左兄弟的最后一条被移到 child 首部
  1090. sbtInsEntry(child, borrowed, 0)
  1091. // child 的最小复合键变成 borrowed; 左兄弟最小复合键不变
  1092. pe := sbtEntry(parent, childIdx)
  1093. copy(pe[:len(pe)-4], sbtNodeMinKey(child))
  1094. pe = sbtEntry(parent, childIdx-1)
  1095. copy(pe[:len(pe)-4], sbtNodeMinKey(leftSib))
  1096. sbtSave(handle, leftSib)
  1097. sbtSave(handle, child)
  1098. sbtSave(handle, parent)
  1099. return
  1100. }
  1101. }
  1102. if childIdx < int(parent.info.Count)-1 {
  1103. rightPID := sbtChildPID(sbtEntry(parent, childIdx+1))
  1104. rightSib := sbtLoad(handle, rightPID)
  1105. if rightSib != nil && int(rightSib.info.Count) > 1 {
  1106. borrowed := append([]byte(nil), sbtEntry(rightSib, 0)...)
  1107. sbtRmEntry(rightSib, 0)
  1108. // 右兄弟的首条被追加到 child 尾部: child 的最小复合键不变
  1109. sbtInsEntry(child, borrowed, int(child.info.Count))
  1110. pe := sbtEntry(parent, childIdx)
  1111. copy(pe[:len(pe)-4], sbtNodeMinKey(child))
  1112. // 右兄弟失去首条后最小复合键变化, 更新其父条目
  1113. pe = sbtEntry(parent, childIdx+1)
  1114. copy(pe[:len(pe)-4], sbtNodeMinKey(rightSib))
  1115. sbtSave(handle, rightSib)
  1116. sbtSave(handle, child)
  1117. sbtSave(handle, parent)
  1118. return
  1119. }
  1120. }
  1121. if childIdx > 0 {
  1122. sbtMergeChildren(handle, parent, childIdx-1)
  1123. } else if childIdx < int(parent.info.Count)-1 {
  1124. sbtMergeChildren(handle, parent, childIdx)
  1125. }
  1126. }
  1127. // sbtMergeChildren 把 sepIdx+1 指向的右子树并入 sepIdx 指向的左子树。
  1128. // 条目长度从 left 节点自身的 EntryLen 取 (左右同为叶或同为内部节点)。
  1129. func sbtMergeChildren(handle page.HandleDb, parent *btNode, sepIdx int) {
  1130. leftPID := sbtChildPID(sbtEntry(parent, sepIdx))
  1131. rightPID := sbtChildPID(sbtEntry(parent, sepIdx+1))
  1132. left := sbtLoad(handle, leftPID)
  1133. right := sbtLoad(handle, rightPID)
  1134. if left == nil || right == nil {
  1135. return
  1136. }
  1137. // 注意: 本实现的父条目键是 "子树最小键的副本", 不是经典 B+ 树里独立的分隔键。
  1138. // 因此合并内部节点时, 直接把右兄弟的条目追加到左兄弟即可,
  1139. // 绝不能把 parent[sepIdx] 下放 (那会写出一条指向左兄弟自身的自引用条目)。
  1140. el := int(left.info.EntryLen)
  1141. rc := int(right.info.Count)
  1142. copy(left.entries[int(left.info.Count)*el:], right.entries[:rc*el])
  1143. left.info.Count += right.info.Count
  1144. left.info.Hdr.UseSize += uint32(rc * el)
  1145. if left.isLeaf() {
  1146. left.info.Hdr.NextPage = right.info.Hdr.NextPage
  1147. }
  1148. sbtSave(handle, left)
  1149. if left.isLeaf() && left.info.Hdr.NextPage != 0 {
  1150. nl := sbtLoad(handle, left.info.Hdr.NextPage)
  1151. if nl != nil {
  1152. nl.info.Hdr.PrePage = leftPID
  1153. sbtSave(handle, nl)
  1154. }
  1155. }
  1156. sbtRmEntry(parent, sepIdx+1)
  1157. sbtSetChildPID(sbtEntry(parent, sepIdx), leftPID)
  1158. // 左节点若原本是空节点, 合并后其最小复合键变为右兄弟的最小复合键, 必须同步
  1159. // 父条目, 否则会出现 "父键 != 子树最小复合键", 破坏路由。
  1160. if left.info.Count > 0 {
  1161. pe := sbtEntry(parent, sepIdx)
  1162. copy(pe[:len(pe)-4], sbtNodeMinKey(left))
  1163. }
  1164. sbtSave(handle, parent)
  1165. // right 的条目已全部并入 left, 父条目 sepIdx+1 已摘除 (叶子链在上面的
  1166. // NextPage/PrePage 重接中已绕过 right) —— right 子树至此彻底不可达。
  1167. btReleasePage(handle, rightPID)
  1168. }
  1169. // SBTBuildFromSorted 从已排序的条目批量构建二级 B+ 树 (自底向上)
  1170. // entries: 每个条目 = [key(keyLen) + pkID(8B)], 必须按复合键 (key, pkID) 升序排列
  1171. // (只按 key 排序不够: 复合分隔键的路由/二分要求叶内同 key 条目也按 pkID 有序)
  1172. // 返回新树根 pageID
  1173. //
  1174. // 内存优化: 避免逐行 B+ 树搜索 (每次 sbtLoad 16KB), 改为顺序创建所有节点
  1175. func SBTBuildFromSorted(entries [][]byte, handle page.HandleDb) uint32 {
  1176. if len(entries) == 0 {
  1177. return 0
  1178. }
  1179. el := len(entries[0]) // entry len: keyLen + 8
  1180. keyLen := el - 8
  1181. maxPerLeaf := maxLeafEntries(el)
  1182. type childInfo struct {
  1183. pid uint32
  1184. firstKey []byte // 该子树最小 key (keyLen 字节)
  1185. firstPK uint64 // 该子树最小 pkID
  1186. }
  1187. var children []childInfo
  1188. var prevLeafPID uint32
  1189. // 构建叶节点 (带链表链接)
  1190. for i := 0; i < len(entries); {
  1191. end := i + maxPerLeaf
  1192. if end > len(entries) {
  1193. end = len(entries)
  1194. }
  1195. leaf := sbtNew(handle, true, el)
  1196. for j := i; j < end; j++ {
  1197. dst := sbtEntry(leaf, int(leaf.info.Count))
  1198. copy(dst, entries[j])
  1199. leaf.info.Count++
  1200. leaf.info.Hdr.UseSize += uint32(el)
  1201. }
  1202. leaf.info.Hdr.PrePage = prevLeafPID
  1203. sbtSave(handle, leaf)
  1204. if prevLeafPID != 0 {
  1205. prevLeaf := sbtLoad(handle, prevLeafPID)
  1206. if prevLeaf != nil {
  1207. prevLeaf.info.Hdr.NextPage = leaf.pageID()
  1208. sbtSave(handle, prevLeaf)
  1209. }
  1210. }
  1211. prevLeafPID = leaf.pageID()
  1212. fk := make([]byte, keyLen)
  1213. copy(fk, entries[i][:keyLen])
  1214. children = append(children, childInfo{pid: leaf.pageID(), firstKey: fk, firstPK: sbtPKID(entries[i])})
  1215. i = end
  1216. }
  1217. if len(children) == 1 {
  1218. return children[0].pid
  1219. }
  1220. // 自底向上构建内部节点
  1221. // 路由约定 (sbtRoute/sbtChildIdx): 找最后一个 分隔复合键 <= 搜索复合键 的子树
  1222. // 内部节点条目: [child.firstKey | child.firstPK | child.pid]
  1223. // 即 entry[i] 的前 keyLen+8 字节 = child[i] 子树的最小复合键
  1224. intEl := el + 4 // 内部条目 = [key | pkID(8) | childPID(4)]
  1225. maxPerInt := maxLeafEntries(intEl)
  1226. for len(children) > 1 {
  1227. var parents []childInfo
  1228. for i := 0; i < len(children); {
  1229. end := i + maxPerInt
  1230. if end > len(children) {
  1231. end = len(children)
  1232. }
  1233. node := sbtNew(handle, false, intEl)
  1234. for j := i; j < end; j++ {
  1235. e := make([]byte, intEl)
  1236. // entry[j] 前 keyLen+8 字节 = 该 child 子树的最小复合键
  1237. copy(e[:keyLen], children[j].firstKey)
  1238. binary.BigEndian.PutUint64(e[keyLen:keyLen+8], children[j].firstPK)
  1239. sbtSetChildPID(e, children[j].pid)
  1240. dst := sbtEntry(node, int(node.info.Count))
  1241. copy(dst, e)
  1242. node.info.Count++
  1243. node.info.Hdr.UseSize += uint32(intEl)
  1244. }
  1245. sbtSave(handle, node)
  1246. parents = append(parents, childInfo{
  1247. pid: node.pageID(),
  1248. firstKey: children[i].firstKey,
  1249. firstPK: children[i].firstPK,
  1250. })
  1251. i = end
  1252. }
  1253. children = parents
  1254. }
  1255. return children[0].pid
  1256. }
  1257. // ======================== 二级叶批量插入 ========================
  1258. // SBTBulkInsert 批量插入二级索引条目。entries 是 [key|pkID] 定长条目的有序串
  1259. // (按复合键 (key, pkID) 升序, 调用方排序), el 为条目长度 (keyLen+8)。
  1260. //
  1261. // 思路: 排序批量对叶做"顺序扫描式"填充 —— 驻留叶加载一次, 条目在页内定位插入;
  1262. // 目标叶单调右移 (整批有序), 沿叶链走而不是逐条从根下降。每张叶加载/落盘各一次,
  1263. // 单条 SBTInsert 兜底只发生在三种边角: 叶满要分裂、条目成为叶最小键 (父键同步)、
  1264. // 链尾之后还有更大键 —— 分裂/提升/同步全套复用既有逻辑。
  1265. //
  1266. // 正确性关键: 驻留叶的可用区间是 [叶首条目, 上界), 上界 = 右邻叶首条目 (叶链
  1267. // NextPage)。判定"该不该留在当前叶"必须用上界, 不能用"大于叶末条"—— 后者会在
  1268. // 条目越过右邻叶首键时仍然往左叶追加, 破坏父层路由 (该条目从此按键查不到)。
  1269. // 批量键与既有数据交错 (少基数键的翻页灌数) 恰好整批落进叶中段, 走页内定位插入,
  1270. // 不再退化成逐条单插。
  1271. func SBTBulkInsert(rootPID uint32, entries []byte, el int, handle page.HandleDb) (uint32, error) {
  1272. if el <= 12 || len(entries)%el != 0 {
  1273. return rootPID, errors.New("sbt bulk insert: bad entry layout")
  1274. }
  1275. n := len(entries) / el
  1276. if n == 0 {
  1277. return rootPID, nil
  1278. }
  1279. th := btSplitThreshold()
  1280. var leaf *btNode
  1281. var upper []byte // 驻留叶复合键上界 (右邻叶首条目的副本); nil = 最右叶 (上界无穷)
  1282. // upperOf 计算叶的上界。副本必须复制出来 —— 右邻叶还回缓冲池后内存会被复用。
  1283. // 空叶 (Count==0, 健康树上不应出现) 一律当"无上界", 交给后续单条兜底修正。
  1284. upperOf := func(nd *btNode) []byte {
  1285. if nd.info.Hdr.NextPage == 0 {
  1286. return nil
  1287. }
  1288. nl := sbtLoad(handle, nd.info.Hdr.NextPage)
  1289. if nl == nil || nl.info.Count == 0 {
  1290. if nl != nil {
  1291. nl.release()
  1292. }
  1293. return nil
  1294. }
  1295. up := make([]byte, el)
  1296. copy(up, sbtEntry(nl, 0))
  1297. nl.release()
  1298. return up
  1299. }
  1300. flushLeaf := func() {
  1301. if leaf != nil {
  1302. sbtSave(handle, leaf)
  1303. if rootPID == 0 {
  1304. rootPID = leaf.pageID()
  1305. }
  1306. leaf.release()
  1307. leaf = nil
  1308. }
  1309. }
  1310. // descend 按复合键从根下降到 ent 所属叶 (与 SBTInsert 的路由约定一致), 并取上界。
  1311. descend := func(ent []byte) error {
  1312. cur := rootPID
  1313. for {
  1314. nd := sbtLoad(handle, cur)
  1315. if nd == nil {
  1316. return errors.New("sbt bulk insert: load failed")
  1317. }
  1318. if nd.isLeaf() {
  1319. leaf = nd
  1320. upper = upperOf(nd)
  1321. return nil
  1322. }
  1323. ci := sbtChildIdxPK(nd, ent[:el-8], sbtPKID(ent))
  1324. cur = sbtChildPID(sbtEntry(nd, ci))
  1325. nd.release()
  1326. }
  1327. }
  1328. // stepTo 沿叶链从 from 走到第一张非空叶 (或链尾) 并驻留。
  1329. // 调用方随后用上界复查, ent 仍越界就再走一步。
  1330. stepTo := func(from uint32) error {
  1331. cur := from
  1332. for {
  1333. nd := sbtLoad(handle, cur)
  1334. if nd == nil {
  1335. return errors.New("sbt bulk insert: chain load failed")
  1336. }
  1337. if nd.info.Count > 0 || nd.info.Hdr.NextPage == 0 {
  1338. leaf = nd
  1339. upper = upperOf(nd)
  1340. return nil
  1341. }
  1342. cur = nd.info.Hdr.NextPage // 空叶没有承载键, 直接跳过
  1343. nd.release()
  1344. }
  1345. }
  1346. for i := 0; i < n; i++ {
  1347. ent := entries[i*el : (i+1)*el]
  1348. if leaf == nil {
  1349. if rootPID == 0 {
  1350. leaf = sbtNew(handle, true, el)
  1351. upper = nil
  1352. } else if err := descend(ent); err != nil {
  1353. return rootPID, err
  1354. }
  1355. }
  1356. // 越过驻留叶上界: 目标叶在右侧。落盘驻留叶后沿叶链右移 (比重新下降省
  1357. // 2/3 页加载); 链走尽了重新下降, 让路由把后续大键送进(新的)最右叶。
  1358. for upper != nil && sbtCmp(ent, upper) >= 0 {
  1359. next := leaf.info.Hdr.NextPage
  1360. flushLeaf()
  1361. if next == 0 {
  1362. break
  1363. }
  1364. if err := stepTo(next); err != nil {
  1365. return rootPID, err
  1366. }
  1367. }
  1368. if leaf == nil {
  1369. if err := descend(ent); err != nil {
  1370. return rootPID, err
  1371. }
  1372. }
  1373. if int(leaf.info.Hdr.UseSize)+el > th {
  1374. // 叶满: 落盘驻留叶, 单条兜底 (分裂/提升/叶链维护全套)
  1375. flushLeaf()
  1376. nr, err := SBTInsert(rootPID, ent, handle)
  1377. if err != nil {
  1378. return rootPID, err
  1379. }
  1380. rootPID = nr
  1381. continue
  1382. }
  1383. cnt := int(leaf.info.Count)
  1384. ip := sbtLeafLowerBoundPK(leaf, ent[:el-8], sbtPKID(ent))
  1385. if ip == 0 && cnt > 0 {
  1386. // 新条目将成为叶最小复合键: "父条目复合键 == 子树最小复合键"不变式
  1387. // 需要沿路径向上同步, 交给单条路径 (整批有序, 只可能发生在批首条目)
  1388. flushLeaf()
  1389. nr, err := SBTInsert(rootPID, ent, handle)
  1390. if err != nil {
  1391. return rootPID, err
  1392. }
  1393. rootPID = nr
  1394. continue
  1395. }
  1396. sbtInsEntry(leaf, ent, ip)
  1397. }
  1398. flushLeaf()
  1399. return rootPID, nil
  1400. }