datapage.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503
  1. package datapage
  2. import (
  3. "TsDB2/DB/core/page"
  4. "encoding/binary"
  5. "errors"
  6. "sync"
  7. "unsafe"
  8. )
  9. // PageSize 索引页大小 (避免导入 index 包造成循环依赖)
  10. const PageSize = 16384
  11. var (
  12. errNotFound = errors.New("key not found")
  13. errRowTooLarge = errors.New("row too large, need heap overflow")
  14. )
  15. // =============================================================================
  16. // 统一 DataPage — 所有需要独立数据页的索引类型共享
  17. //
  18. // 磁盘布局:
  19. // [PageHdr(18B) + Count(4B) + Min(8B) + Max(8B)] = 38B header
  20. // [len(4B) + rowData] ... = 行数据区
  21. //
  22. // len 最高位 (0x80000000) 为软删除标志
  23. // Min/Max 存储 rowData 前 8 字节的最小/最大值 (BigEndian 比较)
  24. // =============================================================================
  25. // HdrSize 数据页头部大小: PageHdr(18) + Count(4) + Min(8) + Max(8) = 38
  26. const HdrSize = uint32(unsafe.Sizeof(page.PageHdr{})) + 4 + 8 + 8
  27. // DeletedFlag 软删除标志 (长度字段最高位)
  28. const DeletedFlag uint32 = 0x80000000
  29. // DataPage 统一数据页
  30. type DataPage struct {
  31. handle page.HandleDb
  32. pageID uint32
  33. buf []byte
  34. count uint32
  35. dataEnd uint32
  36. }
  37. // ======================== 页 I/O ========================
  38. // New 创建一个新的空数据页
  39. func New(handle page.HandleDb) *DataPage {
  40. pid := handle.NewPage()
  41. buf := make([]byte, PageSize)
  42. hdr := (*page.PageHdr)(unsafe.Pointer(&buf[0]))
  43. hdr.Type = page.DataIndex
  44. hdr.PageID = pid
  45. hdr.UseSize = HdrSize
  46. return &DataPage{handle: handle, pageID: pid, buf: buf, count: 0, dataEnd: HdrSize}
  47. }
  48. // Load 从磁盘加载指定页
  49. func Load(handle page.HandleDb, pageID uint32) (*DataPage, error) {
  50. buf := make([]byte, PageSize)
  51. if err := handle.ReadPage(pageID, buf); err != nil {
  52. return nil, err
  53. }
  54. hdr := (*page.PageHdr)(unsafe.Pointer(&buf[0]))
  55. cnt := *(*uint32)(unsafe.Pointer(&buf[unsafe.Sizeof(page.PageHdr{})]))
  56. return &DataPage{
  57. handle: handle, pageID: pageID, buf: buf,
  58. count: cnt, dataEnd: hdr.UseSize,
  59. }, nil
  60. }
  61. // Save 持久化到磁盘
  62. func (dp *DataPage) Save() {
  63. (*page.PageHdr)(unsafe.Pointer(&dp.buf[0])).UseSize = dp.dataEnd
  64. *(*uint32)(unsafe.Pointer(&dp.buf[unsafe.Sizeof(page.PageHdr{})])) = dp.count
  65. _ = dp.handle.SavePage(dp.pageID, dp.buf)
  66. }
  67. // PageID 返回当前页 ID
  68. func (dp *DataPage) PageID() uint32 { return dp.pageID }
  69. // Count 返回行计数
  70. func (dp *DataPage) Count() uint32 { return dp.count }
  71. // IsFull 判断是否有足够空间追加新行
  72. func (dp *DataPage) IsFull(rowSize uint32) bool {
  73. return dp.dataEnd+rowSize+4 >= uint32(len(dp.buf))
  74. }
  75. // ======================== Min/Max 维护 ========================
  76. // minOffset Min 字段在 buf 中的偏移
  77. func minOffset() uint32 { return uint32(unsafe.Sizeof(page.PageHdr{})) + 4 }
  78. // maxOffset Max 字段在 buf 中的偏移
  79. func maxOffset() uint32 { return uint32(unsafe.Sizeof(page.PageHdr{})) + 4 + 8 }
  80. // getMin 读取当前 Min 值
  81. func (dp *DataPage) getMin() uint64 {
  82. return binary.BigEndian.Uint64(dp.buf[minOffset():])
  83. }
  84. // getMax 读取当前 Max 值
  85. func (dp *DataPage) getMax() uint64 {
  86. return binary.BigEndian.Uint64(dp.buf[maxOffset():])
  87. }
  88. // MinPK 返回页内最小 pkID (Min 字段的公开访问)
  89. func (dp *DataPage) MinPK() uint64 { return dp.getMin() }
  90. // MaxPK 返回页内最大 pkID (Max 字段的公开访问)
  91. func (dp *DataPage) MaxPK() uint64 { return dp.getMax() }
  92. // updateMinMax 追加行后更新 Min/Max (取 rowData 前 8 字节 BigEndian 比较)
  93. func (dp *DataPage) updateMinMax(rowData []byte) {
  94. if len(rowData) < 8 {
  95. return
  96. }
  97. val := binary.BigEndian.Uint64(rowData[:8])
  98. if dp.count <= 1 {
  99. // 第一行 (或刚从 0 变 1), 直接设置
  100. binary.BigEndian.PutUint64(dp.buf[minOffset():], val)
  101. binary.BigEndian.PutUint64(dp.buf[maxOffset():], val)
  102. return
  103. }
  104. curMin := dp.getMin()
  105. curMax := dp.getMax()
  106. if val < curMin {
  107. binary.BigEndian.PutUint64(dp.buf[minOffset():], val)
  108. }
  109. if val > curMax {
  110. binary.BigEndian.PutUint64(dp.buf[maxOffset():], val)
  111. }
  112. }
  113. // ======================== 行操作 ========================
  114. // AppendRow 追加一行
  115. // storeRow 格式: [pkID(8B LE) + rowData] 或纯 rowData, 由调用方决定
  116. func (dp *DataPage) AppendRow(storeRow []byte) {
  117. off := dp.dataEnd
  118. binary.LittleEndian.PutUint32(dp.buf[off:], uint32(len(storeRow)))
  119. off += 4
  120. copy(dp.buf[off:], storeRow)
  121. off += uint32(len(storeRow))
  122. dp.dataEnd = off
  123. dp.count++
  124. // 更新 Min/Max: 取 storeRow 前 8 字节
  125. dp.updateMinMax(storeRow)
  126. }
  127. // FindRowByPK 按 pkID 查找 (pkKeyBE 为 BigEndian, 匹配 storedRow[0:8])
  128. // 优化: 行按 pkID 顺序存储, 找到 pkID > target 时提前终止
  129. func (dp *DataPage) FindRowByPK(pkKeyBE []byte) ([]byte, bool) {
  130. keyPK := binary.BigEndian.Uint64(pkKeyBE[:8])
  131. off := HdrSize
  132. for i := uint32(0); i < dp.count; i++ {
  133. rowLen, deleted, rowStart, ok := dp.nextRow(off)
  134. if !ok {
  135. return nil, false
  136. }
  137. off = rowStart + rowLen
  138. if deleted {
  139. continue
  140. }
  141. if rowLen >= 8 {
  142. rowPK := binary.BigEndian.Uint64(dp.buf[rowStart : rowStart+8])
  143. if rowPK == keyPK {
  144. result := make([]byte, rowLen)
  145. copy(result, dp.buf[rowStart:rowStart+rowLen])
  146. return result, true
  147. }
  148. if rowPK > keyPK {
  149. // 行按 pkID 顺序, 当前行 pkID > 目标, 后续行更大, 提前终止
  150. return nil, false
  151. }
  152. }
  153. }
  154. return nil, false
  155. }
  156. // FindRowByIndexKey 按 rowData 中指定偏移处的 8 字节匹配
  157. // indexKeyBE 为 BigEndian 编码的索引键
  158. // storedOffset 为 storedRow 中比较的起始偏移
  159. func (dp *DataPage) FindRowByIndexKey(indexKeyBE []byte, storedOffset int) ([]byte, bool) {
  160. keyVal := binary.BigEndian.Uint64(indexKeyBE[:8])
  161. off := HdrSize
  162. for i := uint32(0); i < dp.count; i++ {
  163. rowLen, deleted, rowStart, ok := dp.nextRow(off)
  164. if !ok {
  165. return nil, false
  166. }
  167. off = rowStart + rowLen
  168. if deleted {
  169. continue
  170. }
  171. if int(rowLen) > storedOffset+8 {
  172. rowVal := binary.BigEndian.Uint64(dp.buf[rowStart+uint32(storedOffset) : rowStart+uint32(storedOffset)+8])
  173. if rowVal == keyVal {
  174. result := make([]byte, rowLen)
  175. copy(result, dp.buf[rowStart:rowStart+rowLen])
  176. return result, true
  177. }
  178. }
  179. }
  180. return nil, false
  181. }
  182. // DeleteByPK 按 pkID 软删除, 返回是否找到
  183. func (dp *DataPage) DeleteByPK(pkKeyBE []byte) bool {
  184. keyPK := binary.BigEndian.Uint64(pkKeyBE[:8])
  185. off := HdrSize
  186. for i := uint32(0); i < dp.count; i++ {
  187. rowLen, deleted, rowStart, ok := dp.nextRow(off)
  188. if !ok {
  189. return false
  190. }
  191. lenOff := off
  192. off = rowStart + rowLen
  193. if deleted {
  194. continue
  195. }
  196. if rowLen >= 8 {
  197. rowPK := binary.BigEndian.Uint64(dp.buf[rowStart : rowStart+8])
  198. if rowPK == keyPK {
  199. binary.LittleEndian.PutUint32(dp.buf[lenOff:], rowLen|DeletedFlag)
  200. return true
  201. }
  202. }
  203. }
  204. return false
  205. }
  206. // DeleteByIndexKey 按 rowData 中指定偏移处的 8 字节匹配并软删除
  207. func (dp *DataPage) DeleteByIndexKey(indexKeyBE []byte, storedOffset int) bool {
  208. keyVal := binary.BigEndian.Uint64(indexKeyBE[:8])
  209. off := HdrSize
  210. for i := uint32(0); i < dp.count; i++ {
  211. rowLen, deleted, rowStart, ok := dp.nextRow(off)
  212. if !ok {
  213. return false
  214. }
  215. lenOff := off
  216. off = rowStart + rowLen
  217. if deleted {
  218. continue
  219. }
  220. if int(rowLen) > storedOffset+8 {
  221. rowVal := binary.BigEndian.Uint64(dp.buf[rowStart+uint32(storedOffset) : rowStart+uint32(storedOffset)+8])
  222. if rowVal == keyVal {
  223. binary.LittleEndian.PutUint32(dp.buf[lenOff:], rowLen|DeletedFlag)
  224. return true
  225. }
  226. }
  227. }
  228. return false
  229. }
  230. // UpdateByPK 按 pkID 原地更新行数据 (newStoreRow 格式同 AppendRow)
  231. func (dp *DataPage) UpdateByPK(pkKeyBE []byte, newStoreRow []byte) error {
  232. keyPK := binary.BigEndian.Uint64(pkKeyBE[:8])
  233. off := HdrSize
  234. for i := uint32(0); i < dp.count; i++ {
  235. rowLen, deleted, rowStart, ok := dp.nextRow(off)
  236. if !ok {
  237. break
  238. }
  239. off = rowStart + rowLen
  240. if deleted {
  241. continue
  242. }
  243. if rowLen >= 8 {
  244. rowPK := binary.BigEndian.Uint64(dp.buf[rowStart : rowStart+8])
  245. if rowPK == keyPK {
  246. if uint32(len(newStoreRow)) <= rowLen {
  247. copy(dp.buf[rowStart:], newStoreRow)
  248. for j := uint32(len(newStoreRow)); j < rowLen; j++ {
  249. dp.buf[rowStart+j] = 0
  250. }
  251. dp.Save()
  252. return nil
  253. }
  254. return errRowTooLarge
  255. }
  256. }
  257. }
  258. return errNotFound
  259. }
  260. // FindAndUpdateByIndexKey 按 rowData 偏移匹配找到行后, 用 newStoreRow 原地更新
  261. func (dp *DataPage) FindAndUpdateByIndexKey(indexKeyBE []byte, storedOffset int, newStoreRow []byte) error {
  262. keyVal := binary.BigEndian.Uint64(indexKeyBE[:8])
  263. off := HdrSize
  264. for i := uint32(0); i < dp.count; i++ {
  265. rowLen, deleted, rowStart, ok := dp.nextRow(off)
  266. if !ok {
  267. break
  268. }
  269. off = rowStart + rowLen
  270. if deleted {
  271. continue
  272. }
  273. if int(rowLen) > storedOffset+8 {
  274. rowVal := binary.BigEndian.Uint64(dp.buf[rowStart+uint32(storedOffset) : rowStart+uint32(storedOffset)+8])
  275. if rowVal == keyVal {
  276. if uint32(len(newStoreRow)) <= rowLen {
  277. copy(dp.buf[rowStart:], newStoreRow)
  278. for j := uint32(len(newStoreRow)); j < rowLen; j++ {
  279. dp.buf[rowStart+j] = 0
  280. }
  281. dp.Save()
  282. return nil
  283. }
  284. return errRowTooLarge
  285. }
  286. }
  287. }
  288. return errNotFound
  289. }
  290. // AllDeleted 检查是否所有行都已删除
  291. func (dp *DataPage) AllDeleted() bool {
  292. off := HdrSize
  293. for i := uint32(0); i < dp.count; i++ {
  294. rowLen, deleted, rowStart, ok := dp.nextRow(off)
  295. if !ok {
  296. return true
  297. }
  298. if !deleted {
  299. return false
  300. }
  301. off = rowStart + rowLen
  302. }
  303. return true
  304. }
  305. // GetAllRows 返回所有未删除的行
  306. func (dp *DataPage) GetAllRows() [][]byte {
  307. var result [][]byte
  308. off := HdrSize
  309. for i := uint32(0); i < dp.count; i++ {
  310. rowLen, deleted, rowStart, ok := dp.nextRow(off)
  311. if !ok {
  312. break
  313. }
  314. off = rowStart + rowLen
  315. if deleted {
  316. continue
  317. }
  318. row := make([]byte, rowLen)
  319. copy(row, dp.buf[rowStart:rowStart+rowLen])
  320. result = append(result, row)
  321. }
  322. return result
  323. }
  324. // GetAllRowsPooled 同 GetAllRows, 但从 sync.Pool 获取缓冲区
  325. // 调用方处理完后必须将每个 []byte 归还给 pool
  326. func (dp *DataPage) GetAllRowsPooled(pool *sync.Pool) [][]byte {
  327. var result [][]byte
  328. off := HdrSize
  329. for i := uint32(0); i < dp.count; i++ {
  330. rowLen, deleted, rowStart, ok := dp.nextRow(off)
  331. if !ok {
  332. break
  333. }
  334. off = rowStart + rowLen
  335. if deleted {
  336. continue
  337. }
  338. // 从池中获取缓冲区, 避免 make 分配
  339. bp := pool.Get().(*[]byte)
  340. buf := *bp
  341. copy(buf[:rowLen], dp.buf[rowStart:rowStart+rowLen])
  342. result = append(result, buf[:rowLen])
  343. }
  344. return result
  345. }
  346. // GetAllRowsReversed 返回所有未删除行,顺序反转(最后一行在前)
  347. func (dp *DataPage) GetAllRowsReversed() [][]byte {
  348. rows := dp.GetAllRows()
  349. for i, j := 0, len(rows)-1; i < j; i, j = i+1, j-1 {
  350. rows[i], rows[j] = rows[j], rows[i]
  351. }
  352. return rows
  353. }
  354. // ======================== 内部辅助 ========================
  355. // nextRow 解析下一行: 返回 (数据长度, 是否已删除, 数据起始偏移, 是否有效)
  356. func (dp *DataPage) nextRow(off uint32) (rowLen uint32, deleted bool, rowStart uint32, ok bool) {
  357. if off+4 > dp.dataEnd {
  358. return 0, false, 0, false
  359. }
  360. rawLen := binary.LittleEndian.Uint32(dp.buf[off:])
  361. deleted = rawLen&DeletedFlag != 0
  362. rowLen = rawLen & ^DeletedFlag
  363. rowStart = off + 4
  364. if rowStart+rowLen > dp.dataEnd {
  365. return 0, false, 0, false
  366. }
  367. return rowLen, deleted, rowStart, true
  368. }
  369. // ======================== IDateEntry 接口实现 ========================
  370. // 供时序索引等扁平链模式使用
  371. // IDateEntryDataPage 包装 DataPage 使其实现 IDateEntry 接口
  372. // FindDataPage 回调负责从 indexEntries 中找到目标 DataPageID
  373. type IDateEntryDataPage struct {
  374. FindDataPage func(indexEntries []byte, entryLen int, count int, key []byte) uint32
  375. }
  376. func (d *IDateEntryDataPage) Insert(handle page.HandleDb, indexEntries []byte, entryLen int, count int, key []byte, pkID uint64, rowData []byte) error {
  377. dpID := d.FindDataPage(indexEntries, entryLen, count, key)
  378. var dp *DataPage
  379. if dpID == 0 {
  380. dp = New(handle)
  381. } else {
  382. var err error
  383. dp, err = Load(handle, dpID)
  384. if err != nil {
  385. return err
  386. }
  387. }
  388. if dp.IsFull(uint32(8 + len(rowData))) {
  389. dp.Save()
  390. dp = New(handle)
  391. }
  392. storeRow := make([]byte, 8+len(rowData))
  393. binary.BigEndian.PutUint64(storeRow[:8], pkID)
  394. copy(storeRow[8:], rowData)
  395. dp.AppendRow(storeRow)
  396. dp.Save()
  397. return nil
  398. }
  399. func (d *IDateEntryDataPage) Search(handle page.HandleDb, indexEntries []byte, entryLen int, key []byte) ([]byte, bool) {
  400. n := len(indexEntries) / entryLen
  401. dpID := d.FindDataPage(indexEntries, entryLen, n, key)
  402. if dpID == 0 {
  403. return nil, false
  404. }
  405. dp, err := Load(handle, dpID)
  406. if err != nil {
  407. return nil, false
  408. }
  409. // 时序索引: 时间戳在 rowData 前 8 字节, 即 storedRow 偏移 8
  410. return dp.FindRowByIndexKey(key, 9)
  411. }
  412. func (d *IDateEntryDataPage) Update(handle page.HandleDb, indexEntries []byte, entryLen int, key []byte, pkID uint64, rowData []byte) error {
  413. n := len(indexEntries) / entryLen
  414. dpID := d.FindDataPage(indexEntries, entryLen, n, key)
  415. if dpID == 0 {
  416. return errors.New("row not found")
  417. }
  418. dp, err := Load(handle, dpID)
  419. if err != nil {
  420. return err
  421. }
  422. storeRow := make([]byte, 8+len(rowData))
  423. binary.BigEndian.PutUint64(storeRow[:8], pkID)
  424. copy(storeRow[8:], rowData)
  425. return dp.FindAndUpdateByIndexKey(key, 8, storeRow)
  426. }
  427. func (d *IDateEntryDataPage) Delete(handle page.HandleDb, indexEntries []byte, entryLen int, key []byte) error {
  428. n := len(indexEntries) / entryLen
  429. dpID := d.FindDataPage(indexEntries, entryLen, n, key)
  430. if dpID == 0 {
  431. return errors.New("row not found")
  432. }
  433. dp, err := Load(handle, dpID)
  434. if err != nil {
  435. return err
  436. }
  437. deleted := dp.DeleteByIndexKey(key, 8)
  438. if !deleted {
  439. return errors.New("row not found")
  440. }
  441. if dp.AllDeleted() {
  442. if handle.FreePage != nil {
  443. handle.FreePage(dp.pageID)
  444. }
  445. } else {
  446. dp.Save()
  447. }
  448. return nil
  449. }
  450. func (d *IDateEntryDataPage) CreateDataPage(handle page.HandleDb, key []byte, rowData []byte) (uint32, error) {
  451. dp := New(handle)
  452. storeRow := make([]byte, 8+len(rowData))
  453. if len(rowData) >= 8 {
  454. copy(storeRow[:8], rowData[:8])
  455. }
  456. copy(storeRow[8:], rowData)
  457. dp.AppendRow(storeRow)
  458. dp.Save()
  459. return dp.pageID, nil
  460. }