通过前面源码分析,我们差不多了解了boltdb的核心数据结构了,逻辑视图上是通过Bucket组建的嵌套结构来管理数据的,每一层都可以存储一一系列key和value,也是使用boltdb的用户需要关注的。物理视图上是通过node来定义B+树来管理磁盘页的。下面我们详细分析下它们在内存以及磁盘上 存储结构。
先从磁盘上的存储结构开始,每一个boltdb对应一个文件,文件按照 page size(一般为 4096 Bytes) 划分为 page。它有三个特殊的page和通用的存储page组成,分别是:
在构成B+树的page中又可以分成两类页面,分支页和叶子页。
type page struct {
id pgid // page id
flags uint16 // 区分不同类型的 page
count uint16 // page data 中的数据个数
overflow uint32 // 若单个 page 大小不够,会分配多个 page
ptr uintptr // 存放 page data 的起始地址
}
ptr 是保存数据的起始地址,不同类型 page 保存的数据格式也不同,共有4种 page, 通过 flags 区分:
meta page: 存放 db 的 meta data。
freelist page: 存放 db 的空闲 page。
branch page: 存放 branch node 的数据。
leaf page: 存放 leaf node 的数据。
// 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)
}
node是B+ 树的单个结点,访问结点时首先将 page 的内容转换为内存中的 node,每个 node 对应一个或多个连续的 page。重点关注下page结构提字段的属性。
从磁盘解析出上述原始结构后,我们还需要根据页面类型,解析出ptr指向的具体数据,将它放入inodes,并根据inodes的具体信息,来进行对应的node的初始化操作,如果是叶子node,需要将对应的key和value取出来,根据value的类型判断是不是嵌套的Bucket;如果是branch节点,需要根据key对应的pageid加载对应的page获取孩子节点。
每种类型的页面中具体存储的数据结构定义如下:
叶子页
// leafPageElement represents a node on a leaf page.
type leafPageElement struct {
flags uint32
pos uint32
ksize uint32
vsize uint32
}
分支页
// branchPageElement represents a node on a branch page.
type branchPageElement struct {
pos uint32
ksize uint32
pgid pgid
}
meta页
type meta struct {
magic uint32
version uint32
pageSize uint32
flags uint32
root bucket
freelist pgid
pgid pgid
txid txid
checksum uint64
}
freelist
// freelist represents a list of all pages that are available for allocation.
// It also tracks pages that have been freed but are still in use by open transactions.
type freelist struct {
ids []pgid // all free and available free page ids.
pending map[txid][]pgid // mapping of soon-to-be free page ids by tx.
cache map[pgid]bool // fast lookup of all free and pending page ids.
}
而PageInfo定义类页头信息
// PageInfo represents human readable information about a page.
type PageInfo struct {
ID int
Type string
Count int
OverflowCount int
}
本文分享自 golang算法架构leetcode技术php 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!