第二节 元数据页

每页有一个meta()方法,如果该页是元数据页的话,可以通过该方法来获取具体的元数据信息。

  1. // meta returns a pointer to the metadata section of the page.
  2. func (p *page) meta() *meta {
  3. // 将p.ptr转为meta信息
  4. return (*meta)(unsafe.Pointer(&p.ptr))
  5. }

详细的元数据信息定义如下:

  1. type meta struct {
  2. magic uint32 //魔数
  3. version uint32 //版本
  4. pageSize uint32 //page页的大小,该值和操作系统默认的页大小保持一致
  5. flags uint32 //保留值,目前貌似还没用到
  6. root bucket //所有小柜子bucket的根
  7. freelist pgid //空闲列表页的id
  8. pgid pgid //元数据页的id
  9. txid txid //最大的事务id
  10. checksum uint64 //用作校验的校验和
  11. }

下图展现的是元信息存储方式。

../imgs/元信息存储.png

下面我们重点关注该meta数据是如何写入到一页中的,以及如何从磁盘中读取meta信息并封装到meta中

1. meta->page

  1. db.go
  2. // write writes the meta onto a page.
  3. func (m *meta) write(p *page) {
  4. if m.root.root >= m.pgid {
  5. panic(fmt.Sprintf("root bucket pgid (%d) above high water mark (%d)", m.root.root, m.pgid))
  6. } else if m.freelist >= m.pgid {
  7. panic(fmt.Sprintf("freelist pgid (%d) above high water mark (%d)", m.freelist, m.pgid))
  8. }
  9. // Page id is either going to be 0 or 1 which we can determine by the transaction ID.
  10. //指定页id和页类型
  11. p.id = pgid(m.txid % 2)
  12. p.flags |= metaPageFlag
  13. // Calculate the checksum.
  14. m.checksum = m.sum64()
  15. // 这儿p.meta()返回的是p.ptr的地址,因此通过copy之后,meta信息就放到page中了
  16. m.copy(p.meta())
  17. }
  18. // copy copies one meta object to another.
  19. func (m *meta) copy(dest *meta) {
  20. *dest = *m
  21. }
  22. // generates the checksum for the meta.
  23. func (m *meta) sum64() uint64 {
  24. var h = fnv.New64a()
  25. _, _ = h.Write((*[unsafe.Offsetof(meta{}.checksum)]byte)(unsafe.Pointer(m))[:])
  26. return h.Sum64()
  27. }

2. page->meta

  1. page.go
  2. // meta returns a pointer to the metadata section of the page.
  3. func (p *page) meta() *meta {
  4. // 将p.ptr转为meta信息
  5. return (*meta)(unsafe.Pointer(&p.ptr))
  6. }