IndexMetaPage.go 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587
  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. "TsDB2/DB/core/util"
  9. "encoding/binary"
  10. "unsafe"
  11. )
  12. // 🔥 最终对接版:只存索引定义 + 指向你的 IndexPage
  13. type IndexMeta struct {
  14. IndexName [TableNameSize]byte
  15. IndexType page.IndexType
  16. FieldCnt byte // 列的数量
  17. FieldIDs [16]byte // 列
  18. EntryPage uint32 // ✅ 你的 IndexPage 首页ID
  19. PrevMetaID uint32 // 上一个
  20. NextMetaID uint32 // 下一个
  21. Flag byte // 标志位
  22. }
  23. type IndexMetaPage struct {
  24. hdr page.PageHdr
  25. metas []IndexMeta
  26. handle page.HandleDb
  27. hdrSize uint32
  28. metaSize uint32
  29. lastPageID uint32
  30. primaryLink map[string]string // 二级索引名 → 一级索引名
  31. primaryDPs []uint32 // 主键 B+ 树所有 DataPage ID 缓存
  32. }
  33. // 初始化
  34. func (im *IndexMetaPage) Init(pageID uint32) {
  35. im.hdrSize = uint32(unsafe.Sizeof(page.PageHdr{}))
  36. im.metaSize = uint32(unsafe.Sizeof(IndexMeta{}))
  37. im.metas = make([]IndexMeta, 0)
  38. im.hdr.PageID = pageID
  39. im.hdr.Type = page.IndexMetaIndex
  40. im.hdr.NextPage = 0
  41. if pageID == 0 {
  42. return
  43. }
  44. for pageID != 0 {
  45. im.lastPageID = pageID
  46. buf := make([]byte, PageSize)
  47. if err := im.handle.ReadPage(pageID, buf); err != nil {
  48. break
  49. }
  50. hdr := (*page.PageHdr)(unsafe.Pointer(&buf[0]))
  51. offset := im.hdrSize
  52. for offset+im.metaSize <= hdr.UseSize {
  53. m := (*IndexMeta)(unsafe.Pointer(&buf[offset]))
  54. if m.Flag&0x80 == 0 {
  55. im.metas = append(im.metas, *m)
  56. }
  57. offset += im.metaSize
  58. }
  59. pageID = hdr.NextPage
  60. }
  61. }
  62. // PageID 返回索引元数据页 ID (调试用)
  63. func (im *IndexMetaPage) PageID() uint32 { return im.hdr.PageID }
  64. // HdrSize 返回页头大小 (调试用)
  65. func (im *IndexMetaPage) HdrSize() uint32 { return im.hdrSize }
  66. // 创建索引(纯元数据,不碰IndexPage)
  67. func (im *IndexMetaPage) CreateIndex(indexName string, itype page.IndexType, fieldIDs []byte) (*IndexMeta, error) {
  68. fc := byte(len(fieldIDs))
  69. if fc == 0 || fc > 16 {
  70. return nil, ErrIndexFieldCount
  71. }
  72. for _, m := range im.metas {
  73. if util.BytesToString(m.IndexName[:]) == indexName && m.Flag&0x80 == 0 {
  74. return nil, ErrIndexExists
  75. }
  76. }
  77. var m IndexMeta
  78. copy(m.IndexName[:], indexName)
  79. m.IndexType = itype
  80. m.FieldCnt = fc
  81. copy(m.FieldIDs[:fc], fieldIDs)
  82. m.Flag = 0
  83. m.EntryPage = 0
  84. var buf []byte
  85. var hdr *page.PageHdr
  86. if im.hdr.PageID == 0 {
  87. pid := im.handle.NewPage()
  88. buf, hdr = im.InitHeader(pid)
  89. im.hdr.PageID = pid
  90. im.lastPageID = pid
  91. } else {
  92. buf = make([]byte, PageSize)
  93. im.handle.ReadPage(im.lastPageID, buf)
  94. hdr = (*page.PageHdr)(unsafe.Pointer(&buf[0]))
  95. }
  96. offset := hdr.UseSize
  97. if offset+im.metaSize > PageSize {
  98. newID := im.handle.NewPage()
  99. newBuf, newHdr := im.InitHeader(newID)
  100. hdr.NextPage = newID
  101. im.handle.SavePage(im.lastPageID, buf) // 保存下当前页 不然就被新开的页替换了
  102. im.lastPageID = newID
  103. buf = newBuf
  104. hdr = newHdr
  105. offset = im.hdrSize
  106. }
  107. dst := (*IndexMeta)(unsafe.Pointer(&buf[offset]))
  108. *dst = m
  109. hdr.UseSize = offset + im.metaSize
  110. im.handle.SavePage(im.lastPageID, buf)
  111. im.metas = append(im.metas, m)
  112. return &m, nil
  113. }
  114. // 查找单个索引
  115. func (im *IndexMetaPage) FindIndex(idxName string) (*IndexMeta, bool) {
  116. for i := range im.metas {
  117. m := &im.metas[i]
  118. if util.BytesToString(m.IndexName[:]) == idxName && m.Flag&0x80 == 0 {
  119. return m, true
  120. }
  121. }
  122. return nil, false
  123. }
  124. // 删除索引
  125. func (im *IndexMetaPage) DropIndex(idxName string) error {
  126. cur := im.hdr.PageID
  127. for cur != 0 {
  128. buf := make([]byte, PageSize)
  129. im.handle.ReadPage(cur, buf)
  130. hdr := (*page.PageHdr)(unsafe.Pointer(&buf[0]))
  131. offset := im.hdrSize
  132. for offset+im.metaSize <= hdr.UseSize {
  133. m := (*IndexMeta)(unsafe.Pointer(&buf[offset]))
  134. if util.BytesToString(m.IndexName[:]) == idxName && m.Flag&0x80 == 0 {
  135. m.Flag |= 0x80
  136. im.handle.SavePage(cur, buf)
  137. for i := range im.metas {
  138. if util.BytesToString(im.metas[i].IndexName[:]) == idxName {
  139. im.metas = append(im.metas[:i], im.metas[i+1:]...)
  140. break
  141. }
  142. }
  143. return nil
  144. }
  145. offset += im.metaSize
  146. }
  147. cur = hdr.NextPage
  148. }
  149. return ErrIndexNotFound
  150. }
  151. func (im *IndexMetaPage) InitHeader(pageID uint32) ([]byte, *page.PageHdr) {
  152. buf := make([]byte, PageSize)
  153. hdr := (*page.PageHdr)(unsafe.Pointer(&buf[0]))
  154. hdr.Type = page.IndexMetaIndex
  155. hdr.PageID = pageID
  156. hdr.UseSize = uint32(unsafe.Sizeof(*hdr))
  157. im.handle.SavePage(pageID, buf)
  158. return buf, hdr
  159. }
  160. // ======================== 高层索引操作 ========================
  161. func (im *IndexMetaPage) buildPrimaryLink() {
  162. im.primaryLink = make(map[string]string)
  163. var primaryName string
  164. for _, m := range im.metas {
  165. if m.Flag&0x80 != 0 {
  166. continue
  167. }
  168. name := util.BytesToString(m.IndexName[:])
  169. if m.IndexType == page.IndexTypePrimary || m.IndexType == page.IndexTypeTime {
  170. primaryName = name
  171. } else {
  172. if primaryName != "" {
  173. im.primaryLink[name] = primaryName
  174. }
  175. }
  176. }
  177. }
  178. func (im *IndexMetaPage) findIndexMetaByName(name string) *IndexMeta {
  179. for i := range im.metas {
  180. if util.BytesToString(im.metas[i].IndexName[:]) == name && im.metas[i].Flag&0x80 == 0 {
  181. return &im.metas[i]
  182. }
  183. }
  184. return nil
  185. }
  186. func (im *IndexMetaPage) getPrimaryFor(secName string) *IndexMeta {
  187. if im.primaryLink == nil {
  188. im.buildPrimaryLink()
  189. }
  190. if primName, ok := im.primaryLink[secName]; ok {
  191. return im.findIndexMetaByName(primName)
  192. }
  193. return nil
  194. }
  195. func (im *IndexMetaPage) saveMeta(m *IndexMeta) {
  196. cur := im.hdr.PageID
  197. for cur != 0 {
  198. buf := make([]byte, PageSize)
  199. im.handle.ReadPage(cur, buf)
  200. hdr := (*page.PageHdr)(unsafe.Pointer(&buf[0]))
  201. offset := im.hdrSize
  202. for offset+im.metaSize <= hdr.UseSize {
  203. dst := (*IndexMeta)(unsafe.Pointer(&buf[offset]))
  204. if util.BytesToString(dst.IndexName[:]) == util.BytesToString(m.IndexName[:]) {
  205. *dst = *m
  206. im.handle.SavePage(cur, buf)
  207. return
  208. }
  209. offset += im.metaSize
  210. }
  211. cur = hdr.NextPage
  212. }
  213. }
  214. // extractIndexKey 从行数据中提取索引键 (版本感知)
  215. // rowData 格式: [schemaVer(1B)] [field_data...]
  216. func extractIndexKey(rowData []byte, meta *IndexMeta, fields []types.FieldInfo, activeVer byte, versions []SchemaVersion) []byte {
  217. if meta.FieldCnt == 0 || len(rowData) < 1 {
  218. return nil
  219. }
  220. fieldIdx := int(meta.FieldIDs[0])
  221. // 从 rowData 读取该行的 schema 版本
  222. ver := rowData[0]
  223. var sv *SchemaVersion
  224. for i := range versions {
  225. if versions[i].Version == ver {
  226. sv = &versions[i]
  227. break
  228. }
  229. }
  230. if sv == nil {
  231. return nil
  232. }
  233. // 按该版本的字段顺序计算偏移
  234. off := 1 // 跳过 schemaVer
  235. for _, idx := range sv.FieldIndices {
  236. if int(idx) == fieldIdx {
  237. keyLen := int(getFieldSize(fields[fieldIdx].FieldType))
  238. if off+keyLen > len(rowData) {
  239. return nil
  240. }
  241. key := make([]byte, keyLen)
  242. copy(key, rowData[off:off+keyLen])
  243. return key
  244. }
  245. off += int(getFieldSize(fields[idx].FieldType))
  246. }
  247. return nil
  248. }
  249. // InsertRow 插入行到所有索引
  250. func (im *IndexMetaPage) InsertRow(fields []types.FieldInfo, pkID uint64, rowData []byte, activeVer byte, versions []SchemaVersion) error {
  251. im.primaryDPs = nil // 插入可能创建新 DataPage, 失效缓存
  252. for i := range im.metas {
  253. m := &im.metas[i]
  254. if m.Flag&0x80 != 0 {
  255. continue
  256. }
  257. handler, ok := index.Compose.GetHandler(m.IndexType)
  258. if !ok {
  259. continue
  260. }
  261. indexKey := extractIndexKey(rowData, m, fields, activeVer, versions)
  262. if indexKey == nil {
  263. continue
  264. }
  265. entryPage := m.EntryPage
  266. _, err := handler.Insert(im.handle, &entryPage, indexKey, pkID, rowData, len(indexKey))
  267. if err != nil {
  268. return err
  269. }
  270. if entryPage != m.EntryPage {
  271. m.EntryPage = entryPage
  272. im.saveMeta(m)
  273. }
  274. }
  275. return nil
  276. }
  277. // SearchByIndex 通过索引搜索
  278. func (im *IndexMetaPage) SearchByIndex(idxName string, indexKey []byte, fields []types.FieldInfo) ([]byte, bool) {
  279. meta := im.findIndexMetaByName(idxName)
  280. if meta == nil {
  281. return nil, false
  282. }
  283. handler, ok := index.Compose.GetHandler(meta.IndexType)
  284. if !ok {
  285. return nil, false
  286. }
  287. result, found := handler.Search(im.handle, meta.EntryPage, indexKey, len(indexKey))
  288. if !found {
  289. return nil, false
  290. }
  291. if meta.IndexType == page.IndexTypePrimary || meta.IndexType == page.IndexTypeTime {
  292. return result, true
  293. }
  294. // 二级索引: result 是 8B BigEndian pkID, 需要回查主键
  295. pkID := binary.BigEndian.Uint64(result)
  296. return im.ResolveByPK(pkID, fields)
  297. }
  298. // ResolveByPK 通过主键ID (pkID) 查找行数据
  299. // 注意: pkID 是自增计数器, 不一定等于主键索引字段值
  300. // 因此不能直接用 pkID 搜索主键 B+ 树 (B+ 树 key = 索引字段值)
  301. // 必须扫描所有 DataPage 按存储的 pkID 匹配
  302. func (im *IndexMetaPage) ResolveByPK(pkID uint64, fields []types.FieldInfo) ([]byte, bool) {
  303. pkKeyBE := make([]byte, 8)
  304. binary.BigEndian.PutUint64(pkKeyBE, pkID)
  305. for _, m := range im.metas {
  306. if m.Flag&0x80 != 0 {
  307. continue
  308. }
  309. if m.IndexType == page.IndexTypePrimary {
  310. // 主键 B+ 树: DataPage 按 pkID 顺序, 用二分查找定位目标页
  311. if im.primaryDPs == nil {
  312. im.primaryDPs = btree.GetDataPageIDs(im.handle, m.EntryPage)
  313. }
  314. targetPK := binary.BigEndian.Uint64(pkKeyBE)
  315. // 二分查找: 找第一个 MaxPK >= targetPK 的 DataPage
  316. left, right := 0, len(im.primaryDPs)-1
  317. for left <= right {
  318. mid := (left + right) / 2
  319. dp, err := datapage.Load(im.handle, im.primaryDPs[mid])
  320. if err != nil || dp.Count() == 0 {
  321. // 空页, 跳过 (但不影响二分逻辑)
  322. left = mid + 1
  323. continue
  324. }
  325. if dp.MaxPK() < targetPK {
  326. // 当前页的最大 pkID < 目标, 目标在右侧
  327. left = mid + 1
  328. } else {
  329. // 当前页的最大 pkID >= 目标, 可能是目标页, 继续向左找
  330. right = mid - 1
  331. }
  332. }
  333. // left 指向第一个可能包含目标的 DataPage
  334. if left >= 0 && left < len(im.primaryDPs) {
  335. dp, err := datapage.Load(im.handle, im.primaryDPs[left])
  336. if err == nil && dp.Count() > 0 {
  337. if targetPK >= dp.MinPK() && targetPK <= dp.MaxPK() {
  338. if storedRow, ok := dp.FindRowByPK(pkKeyBE); ok {
  339. return storedRow, true
  340. }
  341. }
  342. }
  343. }
  344. return nil, false
  345. }
  346. if m.IndexType == page.IndexTypeTime {
  347. // 时序索引: 遍历条目链找到 DataPage
  348. curPageID := m.EntryPage
  349. for curPageID != 0 {
  350. buf := make([]byte, PageSize)
  351. if err := im.handle.ReadPage(curPageID, buf); err != nil {
  352. break
  353. }
  354. hdr := (*page.IndexHead)(unsafe.Pointer(&buf[0]))
  355. entryLen := int(hdr.EntryLen)
  356. count := int(hdr.Count)
  357. entries := buf[page.IndexHeadSize : page.IndexHeadSize+count*entryLen]
  358. for i := 0; i < count; i++ {
  359. dpID := binary.BigEndian.Uint32(entries[i*entryLen+entryLen-4:])
  360. if dpID != 0 {
  361. dp, err := datapage.Load(im.handle, dpID)
  362. if err == nil {
  363. if storedRow, ok := dp.FindRowByPK(pkKeyBE); ok {
  364. return storedRow, true
  365. }
  366. }
  367. }
  368. }
  369. curPageID = hdr.Hdr.NextPage
  370. }
  371. return nil, false
  372. }
  373. }
  374. return nil, false
  375. }
  376. // DeleteByKey 通过索引删除行(级联处理二级索引)
  377. func (im *IndexMetaPage) DeleteByKey(idxName string, indexKey []byte, fields []types.FieldInfo, activeVer byte, versions []SchemaVersion) error {
  378. im.primaryDPs = nil // 删除可能释放 DataPage, 失效缓存
  379. if im.primaryLink == nil {
  380. im.buildPrimaryLink()
  381. }
  382. meta := im.findIndexMetaByName(idxName)
  383. if meta == nil {
  384. return page.ErrNotFound
  385. }
  386. handler, ok := index.Compose.GetHandler(meta.IndexType)
  387. if !ok {
  388. return page.ErrNotFound
  389. }
  390. if meta.IndexType == page.IndexTypePrimary || meta.IndexType == page.IndexTypeTime {
  391. // 主键/时序索引: 先读取行数据用于级联删除二级索引
  392. var rowData []byte
  393. if meta.IndexType == page.IndexTypePrimary {
  394. if data, found := handler.Search(im.handle, meta.EntryPage, indexKey, len(indexKey)); found {
  395. rowData = data
  396. }
  397. }
  398. entryPage := meta.EntryPage
  399. err := handler.Delete(im.handle, &entryPage, indexKey, len(indexKey))
  400. if entryPage != meta.EntryPage {
  401. meta.EntryPage = entryPage
  402. im.saveMeta(meta)
  403. }
  404. // 级联删除二级索引
  405. if rowData != nil {
  406. // PrimaryHandler 返回的 rowData 包含 8B LE pkID 前缀, 需要剥离
  407. origRow := rowData
  408. if len(origRow) > 8 {
  409. origRow = origRow[8:]
  410. }
  411. primName := util.BytesToString(meta.IndexName[:])
  412. for i := range im.metas {
  413. m := &im.metas[i]
  414. if m.Flag&0x80 != 0 {
  415. continue
  416. }
  417. secName := util.BytesToString(m.IndexName[:])
  418. if linkedPrim, ok := im.primaryLink[secName]; ok && linkedPrim == primName {
  419. secHandler, ok := index.Compose.GetHandler(m.IndexType)
  420. if ok {
  421. secKey := extractIndexKey(origRow, m, fields, activeVer, versions)
  422. if secKey != nil {
  423. secEntryPage := m.EntryPage
  424. secHandler.Delete(im.handle, &secEntryPage, secKey, len(secKey))
  425. if secEntryPage != m.EntryPage {
  426. m.EntryPage = secEntryPage
  427. im.saveMeta(m)
  428. }
  429. }
  430. }
  431. }
  432. }
  433. }
  434. return err
  435. }
  436. // 二级索引: 先查 pkID, 删主键, 再删二级
  437. pkIDBuf, found := handler.Search(im.handle, meta.EntryPage, indexKey, len(indexKey))
  438. if !found {
  439. return page.ErrNotFound
  440. }
  441. pkID := binary.BigEndian.Uint64(pkIDBuf)
  442. // 找主键索引删除
  443. primMeta := im.getPrimaryFor(idxName)
  444. if primMeta != nil {
  445. primHandler, ok := index.Compose.GetHandler(primMeta.IndexType)
  446. if ok {
  447. pkKey := make([]byte, 8)
  448. binary.BigEndian.PutUint64(pkKey, pkID)
  449. entryPage := primMeta.EntryPage
  450. switch primMeta.IndexType {
  451. case page.IndexTypePrimary:
  452. // 主键 B+ 树: 用 DeleteByPK 按 pkID 匹配
  453. primHandler.(*index.PrimaryHandler).DeleteByPK(im.handle, &entryPage, pkID)
  454. case page.IndexTypeTime:
  455. // 时序索引: 遍历所有条目, 从 DataPage 按 pkID 删除
  456. curPageID := entryPage
  457. for curPageID != 0 {
  458. buf := make([]byte, page.IndexPageSize)
  459. if err := im.handle.ReadPage(curPageID, buf); err != nil {
  460. break
  461. }
  462. hdr := (*page.IndexHead)(unsafe.Pointer(&buf[0]))
  463. entryLen := int(hdr.EntryLen)
  464. count := int(hdr.Count)
  465. entries := buf[page.IndexHeadSize : page.IndexHeadSize+count*entryLen]
  466. for i := 0; i < count; i++ {
  467. dpID := binary.BigEndian.Uint32(entries[i*entryLen+entryLen-4:])
  468. if dpID != 0 {
  469. if dp, err := datapage.Load(im.handle, dpID); err == nil {
  470. if dp.DeleteByPK(pkKey) {
  471. if dp.AllDeleted() {
  472. if im.handle.FreePage != nil {
  473. im.handle.FreePage(dpID)
  474. }
  475. } else {
  476. dp.Save()
  477. }
  478. goto timeDeleteDone
  479. }
  480. }
  481. }
  482. }
  483. curPageID = hdr.Hdr.NextPage
  484. }
  485. timeDeleteDone:
  486. }
  487. if entryPage != primMeta.EntryPage {
  488. primMeta.EntryPage = entryPage
  489. im.saveMeta(primMeta)
  490. }
  491. }
  492. }
  493. // 删二级索引条目
  494. entryPage := meta.EntryPage
  495. err := handler.Delete(im.handle, &entryPage, indexKey, len(indexKey))
  496. if entryPage != meta.EntryPage {
  497. meta.EntryPage = entryPage
  498. im.saveMeta(meta)
  499. }
  500. return err
  501. }
  502. // UpdateByKey 通过索引更新行(级联处理二级索引)
  503. func (im *IndexMetaPage) UpdateByKey(idxName string, indexKey []byte, newRowData []byte, pkID uint64, fields []types.FieldInfo, activeVer byte, versions []SchemaVersion) error {
  504. if im.primaryLink == nil {
  505. im.buildPrimaryLink()
  506. }
  507. // 更新主键索引中的行数据
  508. for i := range im.metas {
  509. m := &im.metas[i]
  510. if m.Flag&0x80 != 0 {
  511. continue
  512. }
  513. if m.IndexType == page.IndexTypePrimary || m.IndexType == page.IndexTypeTime {
  514. handler, ok := index.Compose.GetHandler(m.IndexType)
  515. if ok {
  516. // 主键/时序索引始终使用 pkID(8B BE) 作为 B+ 树 key
  517. primKey := make([]byte, 8)
  518. binary.BigEndian.PutUint64(primKey, pkID)
  519. entryPage := m.EntryPage
  520. handler.Update(im.handle, &entryPage, primKey, newRowData, pkID, 8)
  521. if entryPage != m.EntryPage {
  522. m.EntryPage = entryPage
  523. im.saveMeta(m)
  524. }
  525. }
  526. break
  527. }
  528. }
  529. // 更新二级索引(如果索引键变了需要删旧插新)
  530. for i := range im.metas {
  531. m := &im.metas[i]
  532. if m.Flag&0x80 != 0 {
  533. continue
  534. }
  535. if m.IndexType == page.IndexTypePrimary || m.IndexType == page.IndexTypeTime {
  536. continue
  537. }
  538. handler, ok := index.Compose.GetHandler(m.IndexType)
  539. if !ok {
  540. continue
  541. }
  542. newKey := extractIndexKey(newRowData, m, fields, activeVer, versions)
  543. if newKey == nil {
  544. continue
  545. }
  546. entryPage := m.EntryPage
  547. handler.Update(im.handle, &entryPage, newKey, newRowData, pkID, len(newKey))
  548. if entryPage != m.EntryPage {
  549. m.EntryPage = entryPage
  550. im.saveMeta(m)
  551. }
  552. }
  553. return nil
  554. }