使用

    1)首先需要将 wal_level这个配置参数设置为logical,并保证max_replication_slots至少为1。

    2)创建Logical Replication Slot。Logical Decoding利用了Logical Replication Slot来获取和Decode日志。关于Physical Replication Slot我们在上期中有详细介绍,而Logical Replication Slot与Physical Replication Slot的数据结构类似。创建一个Logical Replication Slot的命令如下:

    3)解析日志。

    pg_logical_slot_peek_changes返回数据中的第二行记录了我们所做的INSERT操作(只有在事务提交后,才能看到这些修改)。而我们通过pg_xlogdump可以看到原来的WAL日志记录为:

    也就是说,Logical Decoding把这条日志,反解析成一个“table public.test: INSERT: col[integer]:2”字符串。其实如果对输出插件稍作修改,可以直接解析成可执行的SQL语句:“INSERT INTO public.test (col) VALUES(2)“

    原理

    追踪一下pg_logical_slot_peek_changes的调用链,不难看到Decoding的整个过程。在pg_logical_slot_get_changes_guts中,从restart_lsn(即上次的最后读取后,剩下的事务中最先开始的事务对应的LSN)开始,先用XLogReadRecord函数(注意,会先从cache里面读取日志,如果cache里面没有,则会到磁盘中的日志段里面读取)获取一个日志记录,存入结构体XLogRecord,紧接着用LogicalDecodingProcessRecord做Decode。如此循环,直到读完日志或到达指定点。

    LogicalDecodingProcessRecord是解析日志的关键。它在内存中维护一个哈希表(LogicalDecodingContext->reorder->by_txn),存放正在处理的事务信息。在处理每个日志记录时,如果遇到一个BEGIN操作,就在哈希表中插入相应事务。而只有在遇到COMMIT操作的时候,才会把整个事务的所有语句解析出来(调用ReorderBufferCommit)。这个过程中,它要为每个事务维护一个快照(Snapshot)。每次有事务做COMMIT都要更新一下这个快照。这样,等到事务COMMIT时,它的快照是最新的,可以用来访问系统表,得到如relation node id与relation名字之间的对应关系等信息,从而完成Decode。需要说明的是,LogicalDecodingProcessRecord在维护快照时做了优化:因为Decode过程只需要访问系统表,所以快照中只保留了那些更新了系统表的事务。

    输出Decode后日志的过程,都在DecodeCommit调用的ReorderBufferCommit函数中。在ReorderBufferCommit中,调用了输出插件的apply_change等回调函数,会将日志信息打印成我们最终看到的字符串,这样就完成了Decode。