第五节 叶子节点页

叶子节点主要用来存储实际的数据,也就是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. }
  9. // 叶子节点的key
  10. // key returns a byte slice of the node key.
  11. func (n *leafPageElement) key() []byte {
  12. buf := (*[maxAllocSize]byte)(unsafe.Pointer(n))
  13. // pos~ksize
  14. return (*[maxAllocSize]byte)(unsafe.Pointer(&buf[n.pos]))[:n.ksize:n.ksize]
  15. }
  16. // 叶子节点的value
  17. // value returns a byte slice of the node value.
  18. func (n *leafPageElement) value() []byte {
  19. buf := (*[maxAllocSize]byte)(unsafe.Pointer(n))
  20. // key:pos~ksize
  21. // value:pos+ksize~pos+ksize+vsize
  22. return (*[maxAllocSize]byte)(unsafe.Pointer(&buf[n.pos+n.ksize]))[:n.vsize:n.vsize]
  23. }

下面是具体在叶子节点的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]
  4. // 最原始的指针:unsafe.Pointer(&p.ptr)
  5. // 将其转为(*[0x7FFFFFF]leafPageElement)(unsafe.Pointer(&p.ptr))
  6. // 然后再取第index个元素 ((*[0x7FFFFFF]leafPageElement)(unsafe.Pointer(&p.ptr)))[index]
  7. // 最后返回该元素指针 &((*[0x7FFFFFF]leafPageElement)(unsafe.Pointer(&p.ptr)))[index]
  8. // ((*[0x7FFFFFF]leafPageElement)(unsafe.Pointer(&p.ptr)))
  9. // (*[0x7FFFFFF]leafPageElement)(unsafe.Pointer(&p.ptr))==>[]leafPageElement
  10. // &leafElements[index]
  11. return n
  12. }
  13. // leafPageElements retrieves a list of leaf nodes.
  14. func (p *page) leafPageElements() []leafPageElement {
  15. if p.count == 0 {
  16. return nil
  17. }
  18. return ((*[0x7FFFFFF]leafPageElement)(unsafe.Pointer(&p.ptr)))[:]
  19. }

下图展现的是叶子节点存储方式。

../imgs/叶子节点存储.png

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