IT@程序员猿媛

CockroachDB事务代码解读

2019-04-23  本文已影响12人  贺大伟

Coordinator

CockroachDB从执行层面起始于client.TXN

它包含四个比较关键的字段:

Typ:事务类型,有rootTXN,leafTXN。OLTP一般都是rootTXN,而leafTXN一般用于DistSQL,两者的核心区别是leafTXN不需要维护与事务记录的心跳。

ID:事务的唯一ID。

Sender:负责将请求分发给数据所在的store。

userPriority:事务优先级,一般是随机分配一个优先级。

Client.TXN有提供丰富的读写API,包括batch。调用RUN方法就可以完成一个事务的提交

Txn的Send方法对client是透明的,Send的底层是一个Sender接口

Client.TXN对应的接口实现是TxnCoordSender.

TxnCoordSender由TxnCoordSenderFactory产生。

在创建TxnCoordSender就会注册启动事务心跳维持等处理,详情可以参看代码细节。

TxnCoordSender的底层调用CrossRangeTxnWrapperSender,而CrossRangeTxnWrapperSender的底层调用的是DistSender。

在DistSender中,会根据range范围重新分组batch中的request,分别发送给指定的range副本。

事务中有两个特殊的request,

BeginTransactionRequest:用于保存事务记录。

EndTransactionRequest:用于告知参与事务的各个range副本,事务需要结束(commit/abort)。在事务提交或者中止时,每一个参与的range都需要这样一条消息。

Storage

Replica

CockroachDB中所有的请求都通过注册的方式预定义执行逻辑,因此阅读代码的时候想找一个请求在storage上如何执行的,直接在如下目录中查询你需要的请求即可。

Replica的核心执行逻辑有read和write,对于事务我们只需要关注这两个逻辑基本就足够了。

Replica的总入口sendWithRangeID如下:

首先我们看看写的处理逻辑

Step 1. 确认写的数据的span,即下图中collectSpans,它根据batch请求中的key的范围获得一个[]span。这个spans用于确认replica是否可以满足这个batch的全部写请求,即replica的range范围是否覆盖spans。

Step 2. 申请latch,这一步的目的是获得对spans内的数据用于排他性写的权利,这里的目的是防止写写冲突。同时也是为了防止读事务读取到提交到一半的数据。这个思想跟badger中事务冲突的解决思想是一致的。

Step 3. 确认replica是否持有lease,只有持有有效的lease的replica才有写的权限。

Step 4. 修正事务的maxtimestamp,修正的目标是约束maxtimestamp,这个值与事务的提交时间戳差值越大,事务冲突的概率越高,在事务开始的时候默认maxtimestamp=timestamp+maxoffset(500ms),如果节点之间时钟误差不大,通过这个函数可以修正。

Step 5. 通过timestamp cache的高水位线或者事务本地的候选提交时间戳

Step 6. 提交raft执行

Step 7. 等待执行结果,返回结果。

 

现在我们看看读的逻辑

Step 1. 首先确认replica是否持有有效的lease。

Step 2. 修正事务的maxtimestamp

Step 3. 申请latch,这里需要说明一下,事务读与读之间不存在冲突,因此申请latch并不阻塞读事务,但是会阻塞写事务。写事务会阻塞所有的读事务。

Step 4. Replica的读有读锁,endCmds.done()的调用一定要在读锁释放之前调用,这主要是为了保证读操作和update

timestamp cache(endCmds.done中会更新timestamp cache)的一致性。

Step 5. 确认replica是否满足read的范围

Step 6. 执行读操作

Step 7. 如果读取过程发现没有提交的数据,需要帮忙清理。

至此我们基本讲述完了事务的读写。

上一篇 下一篇

猜你喜欢

热点阅读