第二节 元数据页

每页有一个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

2. db.go

4. // write writes the meta onto a page.
5. func (m *meta) write(p *page) {
6. if m.root.root >= m.pgid {
7. panic(fmt.Sprintf("root bucket pgid (%d) above high water mark (%d)", m.root.root, m.pgid))
8. } else if m.freelist >= m.pgid {
9. panic(fmt.Sprintf("freelist pgid (%d) above high water mark (%d)", m.freelist, m.pgid))
10. }

12. // Page id is either going to be 0 or 1 which we can determine by the transaction ID.
13. //指定页id和页类型
14. p.id = pgid(m.txid % 2)
15. p.flags |= metaPageFlag

17. // Calculate the checksum.
18. m.checksum = m.sum64()
19. // 这儿p.meta()返回的是p.ptr的地址,因此通过copy之后,meta信息就放到page中了
20. m.copy(p.meta())
21. }

24. // copy copies one meta object to another.
25. func (m *meta) copy(dest *meta) {
26. *dest = *m
27. }

30. // generates the checksum for the meta.
31. func (m *meta) sum64() uint64 {
32. var h = fnv.New64a()
33. _, _ = h.Write((*[unsafe.Offsetof(meta{}.checksum)]byte)(unsafe.Pointer(m))[:])
34. return h.Sum64()
35. }

2. page->meta

1. page.go

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