暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Postgres逻辑解码中HeapTuple的行为

原创 Yongtao 2023-04-19
373

零、前言

本文主要分析Postgres 9.4的代码,以及Postgre 12.12和GPDB 7的代码,后两者代码相同。目前GPDB7尚不支持逻辑解码。

一、为了支持逻辑解码Postgres对WAL做了哪些修改

Postgres 9.4引入逻辑解码的功能。对XLog修改的commit link: Add new wal_level, logical, sufficient for logical decoding.

简单分析其中的代码,代码来自Postgres 9.4:

RelationPutHeapTuple(relation, buffer, heaptup) // 把HeapTuple信息放入Buffer bool need_tuple_data; // 是否需要HeapTuple need_tuple_data = RelationIsLogicallyLogged(relation); // 逻辑日志则需要HeapTuple rdata[1].buffer = need_tuple_data ? InvalidBuffer : buffer; // 逻辑日志则给rdata[1]赋值为HeapTuple,物理日志为空

可以得出结论,逻辑日志需要把HeapTuple写入WAL,但是物理日志不需要。这是为了支持逻辑解码对WAL做的最大改动。事实上,这个commit以前没有逻辑日志,但是也把HeapTuple写到物理日志里去了,具体原因目前不知,但也因此过渡的十分平滑。

二、HeapTuple信息写入WAL的流程

为了更方便和GPDB7做对比,以下代码来自Postgres 12.12的heap_insert()函数。
XLogRegisterData()用来向XLOG写入main_data。
XLogRegisterBufData()用来想XLOG写入HeapTuple(可能还有其它功能)。

void heap_insert(Relation relation, HeapTuple tup, CommandId cid, int options, BulkInsertState bistate, TransactionId xid) { HeapTuple heaptup; heaptup = heap_prepare_insert(relation, tup, xid, cid, options, isFrozen); if (needwal) // 是否需要写WAL { xl_heap_insert xlrec; xl_heap_header xlhdr; XLogRecPtr recptr; Page page = BufferGetPage(buffer); uint8 info = XLOG_HEAP_INSERT; // 写入日志前的准备 XLogBeginInsert(); // 注册生成日志相关的数据 // XLogRegisterData()用来向XLOG写入main_data。 XLogRegisterData((char *) &xlrec, SizeOfHeapInsert); XLogRegisterBuffer(0, buffer, REGBUF_STANDARD | bufflags); XLogRegisterBufData(0, (char *) &xlhdr, SizeOfHeapHeader); // XLogRegisterBufData()用来想XLOG写入HeapTuple。 XLogRegisterBufData(0, (char *) heaptup->t_data + SizeofHeapTupleHeader, heaptup->t_len - SizeofHeapTupleHeader); // 执行日志插入,写入到缓冲区,目前尚未落盘 recptr = XLogInsert(RM_HEAP_ID, info); // 设置page的LSN PageSetLSN(page, recptr); } }

三、HeapTuple信息被逻辑解码的流程

XLogReaderState是用于读取XLog信息的结构体,以下只列出两个主要变量。main_data存储XLog的基本信息,HeapTuple信息会被存储在blocks中。

struct XLogReaderState { char *main_data; /* record's main data portion */ /* information about blocks referenced by the record. */ DecodedBkpBlock blocks[XLR_MAX_BLOCK_ID + 1]; };

XLogRecGetData()可以获取XLogReaderState中的main_data,与上述XLogRegisterData()是一对。
XLogRecGetBlockData()可以获取XLogReaderState中的blocks,与上述XLogRegisterBufData()是一对。

static void DecodeInsert(LogicalDecodingContext *ctx, XLogRecordBuffer *buf) { Size datalen; char *tupledata; Size tuplelen; XLogReaderState *r = buf->record; xl_heap_insert *xlrec; // XLogRecGetData()可以获取XLogReaderState中的main_data。 // 也就是物理日志里需要的协助准确定位的信息 xlrec = (xl_heap_insert *) XLogRecGetData(r); memcpy(&change->data.tp.relnode, &target_node, sizeof(RelFileNode)); // XLogRecGetBlockData()可以获取XLogReaderState中的blocks。 // 此处获取的信息事实上就是HeapTuple相关信息 tupledata = XLogRecGetBlockData(r, 0, &datalen); tuplelen = datalen - SizeOfHeapHeader; change->data.tp.newtuple = ReorderBufferGetTupleBuf(ctx->reorder, tuplelen); // 解码相关信息,获取HeapTuple DecodeXLogTuple(tupledata, datalen, change->data.tp.newtuple); }
最后修改时间:2023-04-19 14:20:33
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论