前面我们分开看了每一个步骤的具体函数,这里再通过一个简单insert语句的跟踪,来看看整体的流程。目前只看WAL相关的部分,因为insert整体涉及到非常多东西,有些是还没学习到的。
最简单的insert语句对应函数是 heap_insert,其中跟WAL相关的代码:
- XLogBeginInsert();
- XLogRegisterData((char *) &xlrec, SizeOfHeapInsert);
-
- xlhdr.t_infomask2 = heaptup->t_data->t_infomask2;
- xlhdr.t_infomask = heaptup->t_data->t_infomask;
- xlhdr.t_hoff = heaptup->t_data->t_hoff;
-
- /*
- * note we mark xlhdr as belonging to buffer; if XLogInsert decides to
- * write the whole page to the xlog, we don't need to store
- * xl_heap_header in the xlog.
- */
- XLogRegisterBuffer(0, buffer, REGBUF_STANDARD | bufflags);
- XLogRegisterBufData(0, (char *) &xlhdr, SizeOfHeapHeader);
- /* PG73FORMAT: write bitmap [+ padding] [+ oid] + data */
- XLogRegisterBufData(0,
- (char *) heaptup->t_data + SizeofHeapTupleHeader,
- heaptup->t_len - SizeofHeapTupleHeader);
-
- /* filtering by origin on a row level is much more efficient */
- XLogSetRecordFlags(XLOG_INCLUDE_ORIGIN);
-
- recptr = XLogInsert(RM_HEAP_ID, info);
-
- PageSetLSN(page, recptr);
会话1
- postgres=# create table t_insert(a int);
- CREATE TABLE
-
- postgres=# select pg_backend_pid();
-
- pg_backend_pid
- ----------------
- 8632
会话2
vscode跟踪8632进程
会话1
postgres=# insert into t_insert values(1);
加一个断点到WAL相关部分,点击继续
参数的xlrec为xl_heap_insert结构体(日志记录中的main data部分),因此这一步是在构建并注册main data数据到WAL记录中。
heaptup->t_data + SizeofHeapTupleHeader为实际元组
XLogInsert函数中调用日志组装函数XLogRecordAssemble 以及 XLogInsertRecord完成上述工作,最后返回的是写入的EndPos。
设置页面头PageLSN为recptr(即EndPos)。每个页面都会有PageLSN,页面中所有LSN<=Page LSN的WAL表示对应的操作都已经落盘。因此在崩溃恢复时,这些操作都不需要执行redo。
参考
https://blog.csdn.net/obvious__/article/details/119242908?spm=1001.2014.3001.5502
postgresql源码学习(23)—— 事务日志④-日志组装_Hehuyi_In的博客-CSDN博客_postgresql事务日志
https://blog.csdn.net/Hehuyi_In/article/details/125447500 postgresql源码学习(22)—— 事务日志③-日志的注册_Hehuyi_In的博客-CSDN博客