deleter.go 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. package core
  2. import (
  3. "TsDB2/DB/core/index"
  4. "TsDB2/DB/core/index/btree"
  5. "TsDB2/DB/core/index/datapage"
  6. "TsDB2/DB/core/page"
  7. "TsDB2/DB/core/types"
  8. "encoding/binary"
  9. "runtime/debug"
  10. "sort"
  11. "sync"
  12. )
  13. // Deleter 删除操作对象
  14. type Deleter struct {
  15. table *Table
  16. where Condition
  17. }
  18. // Delete 返回删除操作对象
  19. func (table *Table) Delete() *Deleter {
  20. return &Deleter{table: table}
  21. }
  22. // Where 设置删除条件
  23. func (d *Deleter) Where(cond Condition) *Deleter {
  24. d.where = cond
  25. return d
  26. }
  27. // Exec 执行删除
  28. // SQLite 风格优化: 先软删除 DataPage 行 (极快), 再重建索引 (流式, 低内存)
  29. // 避免逐行级联删除 B+ 树的高昂开销
  30. func (d *Deleter) Exec() (int64, error) {
  31. // 找到主键索引
  32. var pkMeta *IndexMeta
  33. for i := range d.table.indexMeta.metas {
  34. m := &d.table.indexMeta.metas[i]
  35. if m.Flag&0x80 != 0 {
  36. continue
  37. }
  38. if m.IndexType == page.IndexTypePrimary || m.IndexType == page.IndexTypeTime {
  39. pkMeta = &d.table.indexMeta.metas[i]
  40. break
  41. }
  42. }
  43. if pkMeta == nil {
  44. return 0, nil
  45. }
  46. // 用 Scan 流式收集匹配行的 pkID (避免 Find 反序列化全行)
  47. pkIDs := make(map[uint64]bool)
  48. err := d.table.Query().Where(d.where).Scan(func(row []types.FieldValue) bool {
  49. for _, fv := range row {
  50. if v, ok := fv.Value.(uint64); ok {
  51. pkIDs[v] = true
  52. break
  53. }
  54. }
  55. return true
  56. })
  57. if err != nil {
  58. return 0, err
  59. }
  60. if len(pkIDs) == 0 {
  61. return 0, nil
  62. }
  63. // Phase 1: 软删除 DataPage 中的行 (只标记 DeletedFlag, 极快!)
  64. pkHandler, _ := index.Compose.GetHandler(pkMeta.IndexType)
  65. dpIDs := pkHandler.GetDataPageIDs(d.table.handle, pkMeta.EntryPage)
  66. var count int64
  67. pkKeyBE := make([]byte, 8) // 复用缓冲区
  68. for _, dpID := range dpIDs {
  69. dp, err := datapage.Load(d.table.handle, dpID)
  70. if err != nil {
  71. continue
  72. }
  73. changed := false
  74. rows := dp.GetAllRows()
  75. for _, storeRow := range rows {
  76. if len(storeRow) < 8 {
  77. continue
  78. }
  79. pkID := binary.BigEndian.Uint64(storeRow[:8])
  80. if pkIDs[pkID] {
  81. binary.BigEndian.PutUint64(pkKeyBE, pkID)
  82. if dp.DeleteByPK(pkKeyBE) {
  83. changed = true
  84. count++
  85. }
  86. }
  87. }
  88. if changed {
  89. dp.Save()
  90. }
  91. }
  92. // 释放 pkIDs 内存 (Phase 2 不需要)
  93. pkIDs = nil
  94. // Phase 2: 流式重建所有索引 (逐个索引从 DataPage 读取, 不缓存全部行)
  95. if err := d.rebuildIndexes(pkMeta, dpIDs); err != nil {
  96. return count, err
  97. }
  98. // 更新行数
  99. d.table.info.TotalRows -= uint64(count)
  100. d.table.saveTableInfo()
  101. // 失效缓存
  102. d.table.indexMeta.primaryDPs = nil
  103. return count, nil
  104. }
  105. // rebuildIndexes 批量重建所有索引
  106. // 主键索引: 顺序创建 DataPage + 批量构建 B+ 树 (避免逐行搜索)
  107. // 二级索引: 收集条目 → 排序 → 批量构建 B+ 树
  108. func (d *Deleter) rebuildIndexes(pkMeta *IndexMeta, dpIDs []uint32) error {
  109. fields := d.table.Field
  110. rowSize := int(d.table.info.RowSize)
  111. // 内存池: 复用行缓冲区
  112. rowPool := &sync.Pool{
  113. New: func() interface{} {
  114. b := make([]byte, 8+rowSize)
  115. return &b
  116. },
  117. }
  118. // ===== 重建主键索引: 顺序扫描 + 批量构建 =====
  119. var leafEntries [][]byte
  120. var curDP *datapage.DataPage
  121. var curDPID uint32
  122. for _, dpID := range dpIDs {
  123. dp, err := datapage.Load(d.table.handle, dpID)
  124. if err != nil {
  125. continue
  126. }
  127. rows := dp.GetAllRowsPooled(rowPool)
  128. for _, storeRow := range rows {
  129. if len(storeRow) < 8 {
  130. continue
  131. }
  132. rowData := storeRow[8:]
  133. indexKey := extractIndexKey(rowData, pkMeta, fields, d.table.activeVersion, d.table.versions)
  134. if indexKey == nil {
  135. continue
  136. }
  137. // 确保有可用的 DataPage
  138. if curDP == nil {
  139. curDP = datapage.New(d.table.handle)
  140. curDPID = curDP.PageID()
  141. }
  142. // 当前 DataPage 已满则创建新的
  143. if curDP.IsFull(uint32(len(storeRow))) {
  144. curDP = datapage.New(d.table.handle)
  145. curDPID = curDP.PageID()
  146. }
  147. curDP.AppendRow(storeRow)
  148. curDP.Save()
  149. // 收集叶条目: [pkID(8B BE) + dpID(4B BE)]
  150. pkID := binary.BigEndian.Uint64(storeRow[:8])
  151. pkKeyBE := make([]byte, 8)
  152. binary.BigEndian.PutUint64(pkKeyBE, pkID)
  153. entry := make([]byte, 12)
  154. copy(entry[:8], pkKeyBE)
  155. binary.BigEndian.PutUint32(entry[8:], curDPID)
  156. leafEntries = append(leafEntries, entry)
  157. }
  158. // 归还缓冲区到池
  159. for i := range rows {
  160. rowPool.Put(&rows[i])
  161. }
  162. }
  163. // 批量构建主键 B+ 树 (一次创建所有节点, 避免逐行搜索)
  164. pkMeta.EntryPage = btree.BuildFromSorted(leafEntries, d.table.handle)
  165. d.table.indexMeta.saveMeta(pkMeta)
  166. leafEntries = nil // 释放内存
  167. debug.FreeOSMemory()
  168. // ===== 重建每个二级索引: 收集 → 排序 → 批量构建 =====
  169. for i := range d.table.indexMeta.metas {
  170. m := &d.table.indexMeta.metas[i]
  171. if m.Flag&0x80 != 0 {
  172. continue
  173. }
  174. if m.IndexType == page.IndexTypePrimary || m.IndexType == page.IndexTypeTime {
  175. continue
  176. }
  177. // 收集所有二级索引条目
  178. var secEntries [][]byte
  179. for _, dpID := range dpIDs {
  180. dp, err := datapage.Load(d.table.handle, dpID)
  181. if err != nil {
  182. continue
  183. }
  184. rows := dp.GetAllRowsPooled(rowPool)
  185. for _, storeRow := range rows {
  186. if len(storeRow) < 8 {
  187. continue
  188. }
  189. pkID := binary.BigEndian.Uint64(storeRow[:8])
  190. rowData := storeRow[8:]
  191. secKey := extractIndexKey(rowData, m, fields, d.table.activeVersion, d.table.versions)
  192. if secKey == nil {
  193. continue
  194. }
  195. // 构建二级条目: [secKey + pkID(8B BE)]
  196. secEntry := make([]byte, len(secKey)+8)
  197. copy(secEntry[:len(secKey)], secKey)
  198. binary.BigEndian.PutUint64(secEntry[len(secKey):], pkID)
  199. secEntries = append(secEntries, secEntry)
  200. }
  201. for i := range rows {
  202. rowPool.Put(&rows[i])
  203. }
  204. }
  205. // 按 secKey 排序 (稳定排序保持同 key 的 pkID 顺序)
  206. sort.SliceStable(secEntries, func(i, j int) bool {
  207. ki := secEntries[i][:len(secEntries[i])-8]
  208. kj := secEntries[j][:len(secEntries[j])-8]
  209. return compareBytes(ki, kj) < 0
  210. })
  211. // 批量构建二级 B+ 树
  212. m.EntryPage = btree.SBTBuildFromSorted(secEntries, d.table.handle)
  213. d.table.indexMeta.saveMeta(m)
  214. secEntries = nil
  215. debug.FreeOSMemory()
  216. }
  217. return nil
  218. }
  219. // compareBytes 按字典序比较两个字节切片
  220. func compareBytes(a, b []byte) int {
  221. ml := len(a)
  222. if len(b) < ml {
  223. ml = len(b)
  224. }
  225. for i := 0; i < ml; i++ {
  226. if a[i] < b[i] {
  227. return -1
  228. }
  229. if a[i] > b[i] {
  230. return 1
  231. }
  232. }
  233. if len(a) < len(b) {
  234. return -1
  235. }
  236. if len(a) > len(b) {
  237. return 1
  238. }
  239. return 0
  240. }