| 123456789101112131415161718192021222324252627282930313233343536373839404142434445 |
- package btree
- import (
- "sync"
- "TsDB2/DB/core/page"
- )
- // nodeBufPool 复用 B+ 节点页缓冲 (IndexPageSize)。
- //
- // 背景: 插入路径每行要沿 4 棵索引树 (主键 + 各二级索引) 逐层加载节点,
- // 旧实现每次 btLoad/sbtLoad/btNew 都 make([]byte, IndexPageSize) —— 实测
- // 5 万行灌数分配 ~15GB (约 300KB/行), 默认 GOGC 下平均每 17 行触发一轮
- // GC, GC 压力 (标记辅助 + STW) 吃掉约 1/3 的插入吞吐。
- //
- // 协议: 只在【调用方能证明节点已死】的位置 release; 搜索 / 删除等未标注
- // 归还的路径仍然各自分配, 行为与旧实现完全一致, 不影响正确性。
- //
- // 安全性依赖两点:
- // - btPathEntry 只存 nodePID/childIdx, 不持有节点引用;
- // - 跨函数传递的键 (btLeftmostKey / promote 的 promoKey/pk2/pkc) 都已
- // 拷贝出节点缓冲, 没有别名。
- //
- // 双重 release 会把同一缓冲交给两个持有者, 因此每个节点必须恰好归还一次;
- // 所有归还点都在单函数内的确定位置, 便于逐个核对。
- var nodeBufPool = sync.Pool{New: func() any { b := make([]byte, page.IndexPageSize); return &b }}
- func nodeBufGet() []byte { return *nodeBufPool.Get().(*[]byte) }
- // nodeBufPut 归还缓冲。长度不符的异常缓冲不进池, 宁可交给 GC。
- func nodeBufPut(buf []byte) {
- if len(buf) != page.IndexPageSize || cap(buf) < page.IndexPageSize {
- return
- }
- b := buf
- nodeBufPool.Put(&b)
- }
- // release 把节点的页缓冲归还池中。调用方必须保证此后不再访问该节点
- // (包括 info / entries —— 它们都是 buf 的视图)。
- func (n *btNode) release() {
- if n != nil {
- nodeBufPut(n.buf)
- }
- }
|