一个PostgreSQL后端进程产生数据写入后,一定会先写入wal,具体流程是①通过一些高级接口注册wal数据,②将注册的wal数据重组为一个数据链表,③将数据链表中的数据拷贝到wal页buffer中,④是将wal页buffer刷写到磁盘中。在这个博客中将详细描述①过程。
XLogRegisterData
函数作用:
负责注册生成日志记录的数据,每调用一次就会在rdatas数组中占用一个槽位。
函数用途:
①将本条wal记录的特殊结构体数据注册到wal记录,比如XLOG_HEAP_INSERT子类型的xl_heap_insert结构体。
②将一些旧元组数据注册到wal记录,比如执行update语句的旧元组数据、delete语句的旧元组数据。
实现过程:
找到rdatas数组中第一个空的的位置,将传入的参数赋值给这个空位置
数据结构
/* An array of XLogRecData structs, to hold registered data. */
static XLogRecData *rdatas; // 长度为XLR_NORMAL_RDATAS的数组,用来保存日志数据信息
static int num_rdatas; /* entries currently used */
static int max_rdatas; /* allocated size */
/* A chain of XLogRecDatas to hold the "main data" of a WAL record, registered with XLogRegisterData(...). */
static XLogRecData *mainrdata_head; // 注册数据的槽头指针
static XLogRecData *mainrdata_last = (XLogRecData *) &mainrdata_head; // 注册数据的槽尾指针
static uint32 mainrdata_len; /* total # of bytes in chain */
执行流程
void XLogRegisterData(char *data, int len) {
XLogRecData *rdata;
Assert(begininsert_called);
if (num_rdatas >= max_rdatas) elog(ERROR, "too much WAL data");
rdata = &rdatas[num_rdatas++]; // 获取一个槽位
rdata->data = data; // 关联数据
rdata->len = len;
/* we use the mainrdata_last pointer to track the end of the chain, so no need to clear 'next' here. */
mainrdata_last->next = rdata; // 移动尾指针
mainrdata_last = rdata;
mainrdata_len += len;
}