Alter命令导致pg_class元数据紊乱问题定位

问题现象

最近,一同事执行alter table脚本(表很多,7万多张表),执行完毕后,发现部分表无法访问,报错信息如下:

ERROR:  could not find tuple for relation xxx

通过gdb调试发现,是通过主表查找toast表时出了问题,找不到对应的toast表信息。通过查询pg_class表,发现如下图所示的异常。

pg_class元数据异常

如上图所以,pg_class行记录的infomask与clog状态冲突。事务306626 clog中标记已提交,pg_class行记录ctid(6870,1),(6867,54)却标记HEAP_MAX_INVALID(正确的标记应该为HEAP_MAX_COMMITTED)

问题分析

查询日志可见是90125进程标记的ctid(6870,1),(6867,54)行记录的infomask。

这里写图片描述

通过上下文日志,可见该进程是AutoVacuum进程。

这里写图片描述

通过日志,可见306626进程clog提交发生在infomask改变之后。这也就意味着,infomask标记时306626事务不在snapshot中,继而查询本地clog文件,而当时的clog状态并未标记提交,故infomask标记为HEAP_MAX_INVALID。

这里写图片描述

接下来的问题就是:既然infomask标记时,事务306626在clog中并未提交,那么,为什么AutoVacuum进程MVCC时的snapshot却不包含事务306626。通过日志可见,最后一次snapshot(是CatalogSnapshot) = {xmin:306628 xmax:306628}。且存在日志:Record transaction commit 306627。

这里写图片描述

的确根据snapshot,306626不在活跃事务列表中,那么,infomask的标记必然需要从clog文件中读取。此处,是一个问题:为什么306626既不在活跃事务列表中,也不在clog中标记提交?

根据目前AntDB的snapshot逻辑,CatalogSnapshot是从节点本地获取而不是从AGTM全局获取,因此时本地的latestCompletedXid = 306627,故snapshot的xmax=306628(306627 + 1),这也就是确定了snapshot的上限,接着应该是通过遍历ProcArray构造snapshot的下限(即xmin),但是,通过snapshot可以看出,xmin=306628,也就是说此时306626不在ProcArray中,同时clog中也没有提交

Title: CatalogSnapshot中不存在306626事务分析序列图

CN->AGTM: 请求事务号
AGTM-->CN: 分配事务号306626
DN_AutoVacuum->AGTM: 请求事务号
AGTM-->DN_AutoVacuum: 分配事务号306627
Note over DN_AutoVacuum: 执行事务306627
Note over DN_AutoVacuum: 提交事务306627
Note over DN_AutoVacuum: 本地获取事务快照\nCatalogSnapshot{306628:306628}
CN->DN: 请求开启事务306626
Note over DN: 开启事务306626
Note over DN: 执行事务306626
Note over DN_AutoVacuum: 根据事务快照扫描pg_class系统表\n并对306626影响的Tuple修改infomask
CN->DN: 请求提交事务306626
Note over DN: 提交事务306626
DN-->CN: DN成功提交事务306626

问题修正

通过上述分析,可以确定的是从节点本地获取的CatalogSnapshot用于系统表的MVCC判断的确是不准确的,那么,CatalogSnapshot采用全局快照(即从AGTM获取Sanpshot)是不是准确的呢?按照,此方法修正后,的确不再出现此类问题。

Title: 获取全局CatalogSnapshot序列图

CN->AGTM: 请求事务号
AGTM-->CN: 分配事务号306626
DN_AutoVacuum->AGTM: 请求事务号
AGTM-->DN_AutoVacuum: 分配事务号306627
Note over DN_AutoVacuum: 执行事务306627
Note over DN_AutoVacuum: 提交事务306627
DN_AutoVacuum->AGTM: 请求事务快照
AGTM-->DN_AutoVacuum: 下发事务快照CatalogSnapshot{306626:306628:306626}
CN->DN: 请求开启事务306626
Note over DN: 开启事务306626
Note over DN: 执行事务306626
Note over DN_AutoVacuum: 根据事务快照扫描pg_class系统表\n但不会根据此时的CLOG修改306626\n影响的Tuple的infomask
CN->DN: 请求提交事务306626
Note over DN: 提交事务306626
DN-->CN: DN成功提交事务306626

后来,通过对比pg9.3与9.6版本,发现CatalogSnapshot在9.3中是不存在的,而且对系统表的MVCC判断也没有用到Snapshot,这也就能解释,为什么在AntDB2.2(基于PG9.3)版本却没有出现类似问题。

猜你喜欢

转载自my.oschina.net/zaclu/blog/1810690