BlotDB 学习总结(二)

上一章学习 DB 文件是如何通过字节组织成具体的文件、如何进行读写,本章将继续学习

1.BoltDB 如何实现事务?

2.BlotDB 如何实现 MVCC?

首先 BoltDB 是通过 B+ 树来组织 page 的。其中 db 文件,pageid 为 0,1 页固定用于存储 meta 数据。而 BlotDB 也是通过 meta 来实现事务,在 BlotDB 中,只有 meta 数据写入成功数据才能被其他新事务可见(具体代码阅读 tx.go 和 db.go)。

事务

先来看看一个事务写事务的开启:

func (db *DB) Begin(writable bool) (*Tx, error) {
	if writable {
		return db.beginRWTx()
	}
	return db.beginTx()
}

func (db *DB) beginRWTx() (*Tx, error) {
	...
	t := &Tx{writable: true} //初始化一个写写事务
	t.init(db)
	db.rwtx = t
	db.freePages() //释放之前写事务产生是 pending 中的 ids,这样新事务可以直接利用这些空闲页
	return t, nil
}

func (tx *Tx) init(db *DB) {
	tx.db = db
	tx.pages = nil
	//拷贝元数据
	tx.meta = &meta{}
	db.meta().copy(tx.meta)

	tx.root = newBucket(tx) //新的bucket(一个 bucket 管理一个事务缓存的 page 数据,事务之间数据隔离)
	tx.root.bucket = &bucket{}
	*tx.root.bucket = tx.meta.root //这个包含两个值一个是 (root pgid) 查找数据时从哪个page开始查找,(sequence uint64) 事务ID,事务 ID 是递增的,每次开启写事务+1
	if tx.writable {
		tx.pages = make(map[pgid]*page) //这个保存事务过程涉及脏页(数据被修改过的),后续将这些数据刷入磁盘。
		tx.meta.txid += txid(1) //事务 ID+1
	}
}

上面代码是一个事务初始化的过程。其主要三点,一是释放空闲页,二是拷贝meta,三是初始化一个新的 Bucket,用于管理整个事务过程涉及的数据。

BlotDB 一个简单写数据的例子:

err = db.Update(func(tx *bolt.Tx) error {
	b := tx.Bucket([]byte("test"))
	if b != nil {
		err := b.Put([]byte("hello"), []byte("world"))
		if err != nil {
		}
	}
	return nil
})

db.Update 函数用于初始化事务(上述的流程),执行 func、提交或者滚回事务。func 中,Put 流程大概可以总结为:

1.根据指定 key,从 meta.root 记录的根页开始,生成B+ 快照,查找(B+ 树节点元素是已经根据key 进行来排序,所以可以通过二分法查找以提高查询效率)指定 key 不大于 B+ 树节点 key 的位置。查看过程具体可以阅读 cursor.go 中的 seek。比如已有节点是下图

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值