解码原理
1. 基本原理
数据库的WAL=replica时,cminer就可以解码数据,但在这个模式下,当删除一条记录或update一条记录时,在WAL日志中并没有这一行在更新之前的数据。如何找到这个旧行的数据呢?这是靠“full page image”的原理,PostgreSQL防止坏块,数据快第一次变更时,会把变更之前的数据快存入到WAL日志中,这一行再次变化时,不会再把这个数据快存到WAL中,直到发生一次checkpoint之后,这个数据块发生一次变化后,又会把整个数据块记录到WAL中。从这个原理可以知道:当删除一行之后,我们顺着WAL,往前找,总是可以找到这一行所在块的变更之前的整个数据库,从而找出这个数据块中这一行更新之前的数据。
解码程序开始解码后会把“full page image”的数据块缓存到middle_path参数指定的目录下的fpi子目录下。解码程序停止后,会删除“full page image”缓存数据。所以从原理上说,解码程序停止后,重新开始后至少要从上次的checkpoint点开始解码,而不能从上次解码停止时的LSN开始,否则无法重建“full page image”数据。
所以在表cminer_decode_position中记录了三个点:
- 上次解码之前的一个checkpoint点
- 上次解码的LSN
- 上次解码的最旧事务的开始LSN
postgres=# select * from cminer_decode_position;
checkpoint_lsn | checkpoint_timeline | decode_lsn | decode_timeline | oldest_trans_begin_lsn | oldest_trans_timeline
----------------+---------------------+------------+-----------------+------------------------+-----------------------
3/E71A5B30 | 1 | 3/E71A5C10 | 1 | 3/E71A5C10 | 1
(1 row)
解码程序是从上面这个表的checkpoint_lsn的位置开始读取WAL日志的,当一直到“decode_lsn”这段数据中,上次已经输出到out_path参数指定的目录中的数据不会重复输出。
2. 第一次运行是解码的位置点的确定原理
运行解码程序,需要运行SQL的函数cminer_init_decode_lsn()来确定第一次运行的解码点。
select cminer_init_decode_lsn();
查找的原理是,扫描参数wal_path目录下的WAL文件,找到这些文件中的第一个checkpoint,然后把这个点的位置记录到表cminer_decode_position的checkpoint_lsn和decode_lsn字段上。
当然我们也可以手工通过pg_waldump确定checkpoint点,手工直接更新表cminer_decode_position的中位置,这样可以更灵活的配置解码的点。