作用:根据当前的数据库状态(full_page_write、checkpoint、REPLICA IDENTITY等),把上述函数注册的数据进行筛选组装,最终形成完整的wal记录并写入到walbuff。

函数功能主要由XLogRecordAssemble()和XLogInsertRecord()完成。在XLogRegister*函数调用中已经将数据和buffer都注册了,这里只需要调用该函数带RMID和info进行wal记录写入到walbuff。

/* Insert an XLOG record having the specified RMID and info bytes, with the body of the record being the data and buffer references registered earlier with XLogRegister* calls.
* Returns XLOG pointer to end of record (beginning of next record).
* This can be used as LSN for data pages affected by the logged action.
* (LSN is the XLOG point up to which the XLOG must be flushed to disk
* before the data page can be written out. This implements the basic
* WAL rule "write the log before the data".) */
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info) {
XLogRecPtr EndPos;

/* XLogBeginInsert() must have been called. */
if (!begininsert_called) elog(ERROR, "XLogBeginInsert was not called");
/* The caller can set rmgr bits, XLR_SPECIAL_REL_UPDATE and XLR_CHECK_CONSISTENCY; the rest are reserved for use by me. */
if ((info & ~(XLR_RMGR_INFO_MASK | XLR_SPECIAL_REL_UPDATE | XLR_CHECK_CONSISTENCY)) != 0) elog(PANIC, "invalid xlog info mask %02X", info);
TRACE_POSTGRESQL_WAL_INSERT(rmid, info);

在bootstrap模式下,我们除了XLOG resources,其他任何东西都不会log,直接返回一个phony记录指针。

/* In bootstrap mode, we don't actually log anything but XLOG resources; return a phony record pointer. */
if (IsBootstrapProcessingMode() && rmid != RM_XLOG_ID) {
XLogResetInsertion();
EndPos = SizeOfXLogLongPHD; /* start of 1st chkpt record */
return EndPos;
}

XLogInsert函数主要执行的流程如下:

do {
XLogRecPtr RedoRecPtr;
bool doPageWrites;
XLogRecPtr fpw_lsn;
XLogRecData *rdt;
/* Get values needed to decide whether to do full-page writes. Since we don't yet have an insertion lock, these could change under us, but XLogInsertRecord will recheck them once it has a lock. */
GetFullPageWriteInfo(&RedoRecPtr, &doPageWrites);
rdt = XLogRecordAssemble(rmid, info, RedoRecPtr, doPageWrites, &fpw_lsn);
EndPos = XLogInsertRecord(rdt, fpw_lsn, curinsert_flags);
} while (EndPos == InvalidXLogRecPtr);

XLogResetInsertion();
return EndPos;
}

XLogRecordAssemble代码执行到这个函数的时候,所有的数据已经完成注册,目前wal记录的数据存储在①mainrdata_head②每一个注册的buff的rdata_head③每一个注册的buff的page字段中。这个函数就是要①②③中的数据组合到一起的过程。

XLogInsertRecord函数就是将XLogRecordAssemble()函数返回的hdr_rdt依次写到wal的内存中。

PostgreSQL数据库WAL——XLogInsert_database