|
|
@@ -1,18 +1,30 @@
|
|
|
package core
|
|
|
|
|
|
import (
|
|
|
+ "cmp"
|
|
|
+ "encoding/binary"
|
|
|
+ "slices"
|
|
|
+ "sync"
|
|
|
+
|
|
|
"git.ycl.pub/yl32940/TsDB2/DB/core/index"
|
|
|
"git.ycl.pub/yl32940/TsDB2/DB/core/index/btree"
|
|
|
"git.ycl.pub/yl32940/TsDB2/DB/core/index/datapage"
|
|
|
"git.ycl.pub/yl32940/TsDB2/DB/core/page"
|
|
|
"git.ycl.pub/yl32940/TsDB2/DB/core/types"
|
|
|
- "cmp"
|
|
|
- "encoding/binary"
|
|
|
- "runtime/debug"
|
|
|
- "slices"
|
|
|
- "sync"
|
|
|
)
|
|
|
|
|
|
+// asyncFreeMemory 把 FreeOSMemory() 丢到后台 goroutine 执行, 不阻塞 VACUUM 主流程。
|
|
|
+//
|
|
|
+// 之前每 rebuild 完一个索引就同步 asyncFreeMemory() —— 大表 (百万行 + 多索引)
|
|
|
+// VACUUM 时 GC 峰值可达数秒, 用户侧直接超时。后台化后 VACUUM 主线程立即返回,
|
|
|
+// GC 由 Go scheduler 在空闲时调度; 若未来需要可加参数开关禁用。
|
|
|
+func asyncFreeMemory() {
|
|
|
+ go func() {
|
|
|
+ defer func() { _ = recover() }()
|
|
|
+ asyncFreeMemory()
|
|
|
+ }()
|
|
|
+}
|
|
|
+
|
|
|
// Deleter 删除操作对象
|
|
|
type Deleter struct {
|
|
|
table *Table
|
|
|
@@ -34,7 +46,7 @@ func (d *Deleter) Where(cond Condition) *Deleter {
|
|
|
// SQLite 风格优化: 先软删除 DataPage 行 (极快), 再重建索引 (流式, 低内存)
|
|
|
// 避免逐行级联删除 B+ 树的高昂开销
|
|
|
func (d *Deleter) Exec() (int64, error) {
|
|
|
- defer d.table.db.lockOp()() // 批量删除全程串行; 内部 scanWithPKID/重建索引同 goroutine 重入
|
|
|
+ defer d.table.db.lockOp()() // 批量删除全程串行; 内部 scanWithPKID/重建索引同 goroutine 重入
|
|
|
defer d.table.db.beginOp()() // 软删 + 全索引重建是一个操作, 中途阈值提交会切成半成品
|
|
|
// 找到主键索引
|
|
|
var pkMeta *IndexMeta
|
|
|
@@ -230,7 +242,7 @@ func (d *Deleter) rebuildIndexes(pkMeta *IndexMeta, dpIDs []uint32) error {
|
|
|
// 必须晚于建树: 否则这些页会先被 NewPage 拿去分给新树, 而这里还要按旧树结构遍历。
|
|
|
d.releaseOldTree(pkMeta, oldPKRoot)
|
|
|
leafEntries = nil // 释放内存
|
|
|
- debug.FreeOSMemory()
|
|
|
+ asyncFreeMemory()
|
|
|
|
|
|
// ===== 重建每个二级索引: 收集 → 排序 → 批量构建 =====
|
|
|
for i := range d.table.indexMeta.metas {
|
|
|
@@ -292,7 +304,7 @@ func (d *Deleter) rebuildIndexes(pkMeta *IndexMeta, dpIDs []uint32) error {
|
|
|
// 同上: 新结构就位后归还旧结构的全部页。
|
|
|
d.releaseOldTree(m, oldSecRoot)
|
|
|
secEntries = nil
|
|
|
- debug.FreeOSMemory()
|
|
|
+ asyncFreeMemory()
|
|
|
}
|
|
|
|
|
|
return nil
|