GaussDB CLOG拆分处理可见性判断

GaussDB CLOG拆分处理可见性判断

在这里插入图片描述
snapshot.xmin:获取快照时记录当前活跃的最小的xidsnapshot.snapshotcsn:当前最新提交的CSN号 + 1如上图6所示,xid对于当前快照是否可见的简化有步骤如下:

(1) xid < snapshot.xmin,事务在快照开始前已经结束,根据CLOG状态判断是否提交:CLOG显示已提交,可见;否则,不可见。

(2) xid≥snapshot.xmin,事务在快照开始前未结束,根据CSNLOG读取xid对应的CSN。

(3) 如果CSN已提交,即CSN≥3,没有子事务标志,没有正在提交标志。如果CSN< snapshot.snapshotcsn,则可见,否则不可见。

(4) 如果CSN正在提交,则等待事务结束,重入(3)判断。

(5) 其他情况,不可见。
在这里插入图片描述

图7为新节点快照可见性判断流程图。bucketxid:bucket粒度,在当前库,新节点产生的最小xidbucketcsn:bucket粒度,在当前库,来自源节点的最大CSNbucket上线后,CLOG和数据文件已搬迁,CSNLOG未搬迁。CLOG拆分后对可见性判断:老快照判断迁移数据的可见性:报错。因为CSNLOG未搬迁,无法读取CSN号;老快照判断新数据的可见性:元组是在bucket上线后插入的,即tuple.xmin > bucketxid。不可见;新快照判断迁移数据的可见性:通过CLOG;新快照判断新数据的可见性:正常可见性判断逻辑;

在这里插入图片描述
如上图8所示,新节点的每个bucket粒度的xid可以看成两段。左边一段是从源节点迁移过来的,也就是搬迁的CLOG中记录的。它的最大值next_xid是源节点下一个写事务分配的xid,最小值是最小活跃xid , 是源节点当前最小的需要通过CLOG读取事务状态的xid。

Vaccum操作会清理掉页面中小于最小活跃xid的值,如果事务提交,则改为FROZEN_XACT_ID(2),表示对所有快照可见。如果事务回滚,则清理掉对应元组。右边一段是新节点业务生成的,最小的xid是bucket在第一个库的上线事务对应的id,记为bucketxid。这个值可以在pg_hashbucket系统表的bucketxid列获取。如果不调整xid, 那么新节点业务生成的xid和从源节搬迁过来的xid就有重合的问题,导致可见性判断错误。

例如DN1为源节点,DN2为新节点。重分布前,bucket1的xid100的状态在DN1是已提交。DN2的xid没有调整,是从3开始分配的。bucket1在DN2上线后,使用xid100,并且状态为已回滚。那么在DN2读取迁移数据中的xid100提交状态错误。

xid调整流程

在加节点过程中,会调整新节点下一个要分配的xid,图9为xid调整流程图。

在这里插入图片描述
根据源节点下一个要分配的xid(对应图中的next_xid)和业务对xid的消耗量计算新节点的预期xid计算exp_xid。计算下一步调整到的xid为next_step_xid = min(exp_xid, 新节点next_xid + 10亿)。这里需要分步调整xid。页面的xid取值范围依赖当前的最小活跃xid。如果一次设置为预期值,最小活跃事务号没有办法及时更新,则新设置的xid可能会超过已有页面的xid合法表达范围,出现写业务报错。

如果新节点next_xid < exp_xid,设置新节点next_xid为next_step_xid,并等待当前活跃事务的最小值推进,更新next_step_xid,直到next_xid不小于预期值。

bucket锁

类似于常规锁的表锁,对于hashbucket表,物理文件是库级bucket化的,扩容过程也是按照bucket级别上线的,因此引入一种新型的锁——bucket锁,每个bucket对应一把锁。只有用户业务的场景,DML和DDL业务间的并发仍然通过表锁实现,所有业务都拿bucket的一级锁。当用户扩容时,此时会发生bucket文件的搬迁,同时实现元数据从老节点下线,新节点上线的动作,此时需要通过bucket锁对用户业务做互斥。

因此,bucket锁主要用在hashbucket在线扩容期间bucket在新节点上线时和在线业务做互斥,保证业务数据正确。新增如下的语法来实现这一功能:

LOCK BUCKETS(bucketlist) IN LOCK_MODE [CANCELABLE];

其中,bucketlist如0,1,2,3表示次轮上线的bucket桶号,取值范围0-1023;LOCK_MODE只有两种级别:ACCESS SHARE MODE和ACCESS EXCLUSIVE MODE增加可选项[CANCELABLE]表示是否通过cancel用户业务而保证扩容拿到锁。在线业务和扩容的交互如下图10所示:

在这里插入图片描述
t1时刻:对bucket 0操作的DML在上线事务之前的拿锁成功,数据重分布上线事务拿bucket 0的8级锁处于等待状态,排在数据重分布上线事务之后其它线程对于bucket 0的访问等在上线事务的8级锁上。

t2时刻:排在上线事务之前的用户业务放锁,上线事务持8级锁成功,之后所有访问bucket 0的用户业务均阻塞。

t3时刻:bucket 0在老节点下线,新节点上线,用户业务拿到bucket 0的锁获取最新的数据分布方式。

如果CN上能确定当前操作的bucket,则在CN上拿对应bucket的1级锁,如果不能确定则在DN上拿锁,通过前文提到过的pg_hashbucket记录的bucketlist进行过滤。扩容上线的LOCK BUCKETS语句现在执行CN拿锁成功再发送到其它所有CN和DN拿锁,全部成功则成功。

posted @ 2025-02-18 10:17  喜酱喜酱  阅读(0)  评论(0)    收藏  举报