一、为什么需要clog
PanweiDB的默认存储引擎有着独特的MVCC机制,由于其多版本的特性,在进行可见性判断时,需要获取事务的状态,即元组中 t_xmin 和 t_xmax 的状态,需要clog来记录事务的状态,从而判断其可见性。
内存里的访问远远快于磁盘读写,因此PanweiDB的很多机制都是运行时候在内存,然后定期持久化到磁盘。因此clog也有一块内存区域便于高效访问,即clog buffers,它也属于共享内存的这部分,平时更新clog是内存中进行的,然后满足条件后会调用pg_fsync刷数据到磁盘上的clog文件,或者等待checkpoint刷数据。数据库启动时会从磁盘的pg_xact目录下读取事务状态加载到clog buffers,并且运行过程中,vacuum会定时将不再使用的clog文件清理。
PanweiDB中通过clog来存储事务的状态。所以,当在PanweiDB中如果想要取消一个执行了很长时间的事务,基本上是瞬间完成的,而不是像Oracle中一样需要等到undo表空间中内容回滚完,因为PanweiDB里只需要将事务的状态由IN_PROGRESS修改为ABORTED即可。
二、clog的内容
在PanweiDB里定义了几种需要提交日志clog来记录事务的状态,从而判断其可见性,共有四种事务状态。分别是:IN_PROGRESS、COMMITED、ABORTED和SUB_COMMITED。例如事务正在运行中,那么它的状态就是IN_PROGRESS。全部是0是初始状态,SUB_COMMITTED状态表示已提交的子事务,其父事务尚未提交或中止。每个状态只需要两位(2 bit)就可以表示。因此四个事务的状态就占用了8 bit 即一个字节。
=4种事务状态=====
#define TRANSACTION_STATUS_IN_PROGRESS 0x00
#define TRANSACTION_STATUS_COMMITTED 0x01
#define TRANSACTION_STATUS_ABORTED 0x02
#define TRANSACTION_STATUS_SUB_COMMITTED 0x03
三、发生丢失clog的问题如何伪造clog恢复数据
某次数据库的主机发生了异常重启,等服务器以及数据库拉起之后,查询某张业务表的时候,发现直接报了确失clog的错误,这种情况下,表的数据其实还是在数据页里的,但是由于clog缺失了,数据库无法通过clog里的事务状态,来判断可见性,所以我们读不到这部分的数据。
如果有可用的备份,最简单的恢复方法无疑是通过物理备份和连续归档,做PITR恢复数据,但是如果没有可用备份的话,则可能需要其他的方式恢复,例如:伪造缺失的clog文件。
[SLRU] DETAIL: Could not open file “pg_clog/000000000000”: No such file or directory
查看对应数据目录下的pg_clog路径时,发现目录下只有一个00000000001C的文件,这明显缺失了很多clog文件,正常情况下,pg_clog文件是从000000000000开始,依次递增,是12位的十六进制数字组成,从000000000000到00000000001C应该总共29个文件。
因为缺失的文件暂时无法找回,而这些文件里记录了事务的状态信息,我们无法确认这里边每一个事物的状态,因此我们就以所有事务都可见,创建缺失的clog。可以用dd进行伪造这个数据块(数据块伪造全部提交)。
for i in {1..262144}; do printf '\125'; done > 000000000000
for i in {1..262144}; do printf '\125'; done > 000000000002
... ...
for i in {1..262144}; do printf '\125'; done > 00000000001B
使用如下命令查看创建的文件是否符合预期:
od -xv 000000000002 | head
od -xv 000000000002 | tail
如果大致结果如下,除第一列外,均为5555,则标志文件符合预期。
0000000 5555 5555 5555 5555 5555 5555 5555 5555
0000020 5555 5555 5555 5555 5555 5555 5555 5555
0000040 5555 5555 5555 5555 5555 5555 5555 5555
0000060 5555 5555 5555 5555 5555 5555 5555 5555
0000100 5555 5555 5555 5555 5555 5555 5555 5555
0000120 5555 5555 5555 5555 5555 5555 5555 5555
0000140 5555 5555 5555 5555 5555 5555 5555 5555
0000160 5555 5555 5555 5555 5555 5555 5555 5555
0000200 5555 5555 5555 5555 5555 5555 5555 5555
0000220 5555 5555 5555 5555 5555 5555 5555 5555
注意创建完文件后需要更改权限,把属主和权限更改为和原来的一致。否则可能识别不到文件。
全部伪造完之后,可以尝试重启数据库。再次查询之前查询报错的表,发现可以访问了,但是需要注意的是,这种方式,把所有的事务状态置为可见,可能引起表中存在重复数据,此方式恢复后,需要业务处理重复数据的问题。(第一首选肯定是用备份恢复)




