XLogInsert
函数主体参数
XLogRecPtr
XLogInsert(RmgrId rmid, uint8 info)
{
}
-
RmgrId rmid
- uint8类型的别名参数。唯一标识触发WAL记录生成的不同资源管理器
(Resource Manager ID)
- uint8类型的别名参数。唯一标识触发WAL记录生成的不同资源管理器
-
uint8 info
- 资源管理器其他额外信息
函数主题流程
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);/** 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;}do{XLogRecPtr RedoRecPtr;bool doPageWrites;bool topxid_included = false;XLogRecPtr fpw_lsn;XLogRecData *rdt;int num_fpi = 0;/** 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, &num_fpi, &topxid_included);EndPos = XLogInsertRecord(rdt, fpw_lsn, curinsert_flags, num_fpi,topxid_included);} while (EndPos == InvalidXLogRecPtr);XLogResetInsertion();return EndPos;
}
- typedef uint64 XLogRecPtr;日志记录位置的64位无符号整数- elog会写到日志中初始值: begininsert_called = false;该变量关联到XLogBeginInsert函数- 刚开始为false,XLogBeginInsert中将其设为true作用:确保一定要走XLogBeginInsert函数
-
检测info信息中是否包含无效的位,如果有,报PANIC错误,这是最高错误级别,需要立即停止所有操作并重启数据库
-
追踪记录哪个资源管理器用了WAL的插入,以及该资源管理器其他信息
-
如果当前处于bootstrap下且资源管理器ID不等于XLOG的资源管理器
void
XLogResetInsertion(void)
{int i;for (i = 0; i < max_registered_block_id; i++)registered_buffers[i].in_use = false;num_rdatas = 0;max_registered_block_id = 0;mainrdata_len = 0;mainrdata_last = (XLogRecData *) &mainrdata_head;curinsert_flags = 0;begininsert_called = false;
}
- 解释- max_registered_block_id:当前已注册的最大缓冲区ID- 已注册的缓冲区信息结构体- 该循环,确保已注册的缓冲区都标记为未使用- 1)SizeOfXLogLongPHD利用MAXALIGN结合页头部数据的大小来对齐大小
2)用EndPos指向这个对齐后大小的开始位置,并返回这个位置EndPos
-
GetFullPageWriteInfo(&RedoRecPtr, &doPageWrites);
- 获得全页写的信息
-
XLogRecordAssemble函数
- Xlog记录信息的组装
-
XLogInsertRecord函数
- 将 rdt 指向的日志记录插入到 WAL 中,并返回 EndPos,该值表示这个日志记录在 WAL 中的结束位置(即下一个日志记录应该开始的位置)。这个结束位置对于后续的日志记录插入和恢复过程都是非常重要的。
-
do while循环不断的将日志插入WAL中,直到返回的EndPos位置为InvalidXLogRecPtr
再次重置缓冲区
并返回日志记录的最终结束位置