自顶向下阅读 BadgerDB 源码
目录
DB
Open
初始化配置和资源, 返回一个
DB对象
| |
流程分析
- 检查和设置选项
- 目录创建与锁定
- 初始化
DB结构体 - 根据配置初始化块缓存和索引缓存
- 启动后台任务:
monitorCacheupdateSize- 非只读情况下启动
flushMemtable doWriteslistenForValueThresholdUpdate- 非内存模式下启动
waitOnGC listenForupdates
Update
BadgerDB 通过
Update 方法进行写新数据/更新已有数据/删除数据使用示例
Update方法接受一个func(txn *badger.Txn) error类型的参数, 用于在事务中进行写操作
| |
流程分析
| |
- 检查是否
db是否已经关闭 - 如果处于托管事务模式, 直接panic, 因为
Update方法只能在 非托管模式下使用 - 创建
非只读事务txn - 执行
fn(txn *badger.Txn) error函数 - 提交事务
View
BadgerDB 通过
View 方法进行读数据使用示例
| |
流程分析
| |
- 检查是否
db是否已经关闭 - 检查是否处于托管模式
- 托管事务: 调用
NewTransactionAt创建只读事务 - 非托管事务: 调用
NewTransaction创建只读事务
- 托管事务: 调用
- 执行
fn(txn *badger.Txn) error函数
只读事务中只能进行读操作, 不能进行写操作
Txn
| |
txn.Get
方法签名: func (txn *Txn) Get(key []byte) (item *Item, rerr error)
- 使用
len(key) == 0一并处理[]byte{}和nil这两种情况 - 如果事务被丢弃, 返回
ErrDiscardedTxn错误 - 判断key是否是被ban掉的key:
bannedNsKey = []byte("!badger!banned") - 如果事务是可写事务,
- 如果在写缓存
pendingWrites中查找相同的key, 并且相等- 如果已经被删除或过期, 返回
ErrKeyNotFound错误 - 构造
item并返回. 值得注意的是这里标记了一个状态:item.status = prefetched
- 如果已经被删除或过期, 返回
- 记录这次读操作
- 如果在写缓存
- 将
key构造为内部带时间戳的查找key, 从存储层db中查找- 如果获取失败, 返回错误
- 如果获取成功, 判断下是否已经被删除或过期
- 构造
item并返回
txn.Set / txn.SetEntry
调用关系:
Set(key, val []byte) -> SetEntry(e *Entry) -> modify(e *Entry)
实现逻辑如下, 主要分为前置条件检查和缓冲区写入
- 判断当前事务类型, 是否是更新事务
- 判断当前事务是否已经被丢弃
- 判断插入的
key是否为空, 从这里可以看出不能Set空的key - 判断当前
key是否包含内置的badgerPrefix - 判断当前
key的大小是否大于maxKeySize=65000(写死的). 这个值是否有特殊含义尚不清楚 - 判断
value的大小是否超过ValueLogFileSize - 检查在内存模式下,
value的大小是否超过了value的阈值 - 如果开启冲突检测, 记录
key的哈希到conflictKeys这个集合中 - 如果当前key存在, 已经被写入过一次了, 并且旧版本和新版本不同(ManagedMode, 用户可以手动指定每一条写入的版本号, 这个是合法的), 将旧的entry保存到
duplicateWrites中 - 如果不存在或已经存在, 但是版本号相同, 将当前
key和entry写入缓冲区中(直接覆盖)
为了性能, 使用的是key和value的引用, 事务结束之前不能修改底层数组
txn.Delete
调用链:
Delete(key []byte) -> modify(e *Entry)
func (txn *Txn) Delete(key []byte) error {
e := &Entry{
Key: key,
meta: bitDelete, // 通过标记位来表示已被删除
}
return txn.modify(e)
}Delete操作比较简单, 需要注意的是注释中的一些点:
- 在此时间戳之前的读取不受影响. 旧事务可以读到被删除之前的旧值, 新的读事务遇到这个带有
bitDelete标记的最新版本也能知道被删除 - 为了性能优化, 当前事务并没有复制
key, 而是持有引用, 所以当前事务结束之前, 不能修改key的底层数组
txn.Commit
Update 和 View 都是先创建事务, 然后执行Set,Delete,Get等, 最后提交事务. 接下来我们分析下如何创建, 销毁, 提交事务.