第五节 叶子节点页
叶子节点主要用来存储实际的数据,也就是key+value了。下面看看具体的key+value是如何设计的。
在boltdb中,每一对key/value在存储时,都有一份元素元信息,也就是leafPageElement。其中定义了key的长度、value的长度、具体存储的值距离元信息的偏移位置pos。
1. // leafPageElement represents a node on a leaf page.
2. // 叶子节点既存储key,也存储value
3. type leafPageElement struct {
4. flags uint32 //该值主要用来区分,是子桶叶子节点元素还是普通的key/value叶子节点元素。flags值为1时表示子桶。否则为key/value
5. pos uint32
6. ksize uint32
7. vsize uint32
8. }
10. // 叶子节点的key
11. // key returns a byte slice of the node key.
12. func (n *leafPageElement) key() []byte {
13. buf := (*[maxAllocSize]byte)(unsafe.Pointer(n))
14. // pos~ksize
15. return (*[maxAllocSize]byte)(unsafe.Pointer(&buf[n.pos]))[:n.ksize:n.ksize]
16. }
18. // 叶子节点的value
19. // value returns a byte slice of the node value.
20. func (n *leafPageElement) value() []byte {
21. buf := (*[maxAllocSize]byte)(unsafe.Pointer(n))
22. // key:pos~ksize
23. // value:pos+ksize~pos+ksize+vsize
24. return (*[maxAllocSize]byte)(unsafe.Pointer(&buf[n.pos+n.ksize]))[:n.vsize:n.vsize]
25. }
下面是具体在叶子节点的page中获取下标为index的某个key/value的元信息。根据其元信息,就可以进一步获取其存储的key和value的值了,具体方法可以看上面的key()和value()
1. // leafPageElement retrieves the leaf node by index
2. func (p *page) leafPageElement(index uint16) *leafPageElement {
3. n := &((*[0x7FFFFFF]leafPageElement)(unsafe.Pointer(&p.ptr)))[index]
5. // 最原始的指针:unsafe.Pointer(&p.ptr)
6. // 将其转为(*[0x7FFFFFF]leafPageElement)(unsafe.Pointer(&p.ptr))
7. // 然后再取第index个元素 ((*[0x7FFFFFF]leafPageElement)(unsafe.Pointer(&p.ptr)))[index]
8. // 最后返回该元素指针 &((*[0x7FFFFFF]leafPageElement)(unsafe.Pointer(&p.ptr)))[index]
10. // ((*[0x7FFFFFF]leafPageElement)(unsafe.Pointer(&p.ptr)))
11. // (*[0x7FFFFFF]leafPageElement)(unsafe.Pointer(&p.ptr))==>[]leafPageElement
12. // &leafElements[index]
13. return n
14. }
16. // leafPageElements retrieves a list of leaf nodes.
17. func (p *page) leafPageElements() []leafPageElement {
18. if p.count == 0 {
19. return nil
20. }
21. return ((*[0x7FFFFFF]leafPageElement)(unsafe.Pointer(&p.ptr)))[:]
22. }
下图展现的是叶子节点存储方式。

其具体叶子节点页page转换成node时的转变过程如同分支节点转换的方法一样,此处就不做赘述,可以参考2.1.3节介绍的read()和write()方法
