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的插入,以及该资源管理器其他信息
-
TRACE、LOG_DEBUG与elog的区别
- TRACE和LOG_DEBUG不会影响数据库运行,用于调试、定位bug;
elog可能导致数据库停止等操作,比如错误级别为PANIC
- TRACE和LOG_DEBUG不会影响数据库运行,用于调试、定位bug;
-
-
如果当前处于bootstrap下且资源管理器ID不等于XLOG的资源管理器
-
函数宏 定义
- BootstrapProcessing:表示系统正在执行bootstrap过程,这是创建模板数据库的过程,发生在数据库系统首次初始化时。 InitProcessing:表示系统正在初始化过程中,但这不是引导过程。这可能是指数据库系统安装或更新后的初始化步骤。 NormalProcessing:表示系统处于正常处理模式,即数据库正在接受读写请求并正常运行。
-
rmid != RM_XLOG_ID
- 不等于XLOG的资源管理器ID
-
重置构造的缓冲区
-
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
再次重置缓冲区
并返回日志记录的最终结束位置
作者介绍
薛炬,移动云数据库工程师,负责云原生数据库He3DB的研发。