第一节 boltdb的物理页page结构
在boltdb中,一个db对应一个真实的磁盘文件。而在具体的文件中,boltdb又是按照以page为单位来读取和写入数据的,也就是说所有的数据在磁盘上都是按照页(page)来存储的,而此处的页大小是保持和操作系统对应的内存页大小一致,也就是4k。
每页由两部分数据组成:页头数据+真实数据,页头信息占16个字节,下面的页的结构定义
type pgid uint64
type page struct {
// 页id 8字节
id pgid
// flags:页类型,可以是分支,叶子节点,元信息,空闲列表 2字节,该值的取值详细参见下面描述
flags uint16
// 个数 2字节,统计叶子节点、非叶子节点、空闲列表页的个数
count uint16
// 4字节,数据是否有溢出,主要在空闲列表上有用
overflow uint32
// 真实的数据
ptr uintptr
}
其中,ptr是一个无类型指针,它就是表示每页中真实的存储的数据地址。而其余的几个字段(id、flags、count、overflow)为我们前面提到的页头信息。
下图展现的是boltdb中page的数据存储方式。
在boltdb中,它把页划分为四类:
page页类型 | 类型定义 | 类型值 | 用途 |
---|---|---|---|
分支节点页 | branchPageFlag | 0x01 | 存储索引信息(页号、元素key值) |
叶子节点页 | leafPageFlag | 0x02 | 存储数据信息(页号、插入的key值、插入的value值) |
元数据页 | metaPageFlag | 0x04 | 存储数据库的元信息,例如空闲列表页id、放置桶的根页等 |
空闲列表页 | freelistPageFlag | 0x10 | 存储哪些页是空闲页,可以用来后续分配空间时,优先考虑分配 |
boltdb通过定义的常量来描述
// 页头的大小:16字节
const pageHeaderSize = int(unsafe.Offsetof(((*page)(nil)).ptr))
const minKeysPerPage = 2
//分支节点页中每个元素所占的大小
const branchPageElementSize = int(unsafe.Sizeof(branchPageElement{}))
//叶子节点页中每个元素所占的大小
const leafPageElementSize = int(unsafe.Sizeof(leafPageElement{}))
const (
branchPageFlag = 0x01 //分支节点页类型
leafPageFlag = 0x02 //叶子节点页类型
metaPageFlag = 0x04 //元数据页类型
freelistPageFlag = 0x10 //空闲列表页类型
)
同时每页都有一个方法来判断该页的类型,我们可以清楚的看到每页时通过其flags字段来标识页的类型。
// typ returns a human readable page type string used for debugging.
func (p *page) typ() string {
if (p.flags & branchPageFlag) != 0 {
return "branch"
} else if (p.flags & leafPageFlag) != 0 {
return "leaf"
} else if (p.flags & metaPageFlag) != 0 {
return "meta"
} else if (p.flags & freelistPageFlag) != 0 {
return "freelist"
}
return fmt.Sprintf("unknown<%02x>", p.flags)
}
下面我们一一对其数据结构进行分析。
当前内容版权归 jaydenwen123 或其关联方所有,如需对内容或内容相关联开源项目进行关注与资助,请访问 jaydenwen123 .