#define UsableBytesInPage (XLOG_BLCKSZ - SizeOfXLogShortPHD)//注意:不是文件第一页
#define UsableBytesInSegment ((XLOG_SEG_SIZE / XLOG_BLCKSZ) * UsableBytesInPage - (SizeOfXLogLongPHD - SizeOfXLogShortPHD))
3、函数XLogBytePosToRecPtr
static XLogRecPtr
XLogBytePosToRecPtr(uint64 bytepos)
{
//bytepos:不包括xlog页的页头等额外字节占用的大小
fullsegs = bytepos / UsableBytesInSegment;
bytesleft = bytepos % UsableBytesInSegment;
/*
1、如果bytesleft < XLOG_BLCKSZ-32,则表示定位到第一页上,则文件偏移值跳过第一页页头大小
2、如果bytesleft >= XLOG_BLCKSZ-32,则表示定位不是第一页
*/
if (bytesleft < XLOG_BLCKSZ - SizeOfXLogLongPHD){
/* fits on first page of segment */
seg_offset = bytesleft + SizeOfXLogLongPHD;
}else{
/* account for the first page on segment with long header */
seg_offset = XLOG_BLCKSZ;//先跳过第一页
bytesleft -= XLOG_BLCKSZ - SizeOfXLogLongPHD;//去掉第一页存放XLOG的大小
fullpages = bytesleft / UsableBytesInPage;//剩下的需要几个页
bytesleft = bytesleft % UsableBytesInPage;//剩下的偏移
// 文件偏移=第一页大小+剩下的几个页大小+剩下的偏移+最后一页的页头
seg_offset += fullpages * XLOG_BLCKSZ + bytesleft + SizeOfXLogShortPHD;
}
//result=(fullsegs) * XLOG_SEG_SIZE + seg_offset
XLogSegNoOffsetToRecPtr(fullsegs, seg_offset, result);
return result;
}
4、函数KeepLogSeg
static void
KeepLogSeg(XLogRecPtr recptr, XLogSegNo *logSegNo)
{
//segno为当前xlog即将插入位置在第几个文件上
XLByteToSeg(recptr, segno);
//XLogCtl->replicationSlotMinLSN;备机上请求预留的最小值?
keep = XLogGetReplicationSlotMinimumLSN();
/* compute limit for wal_keep_segments first */
if (wal_keep_segments > 0){
/*
首先计算wal_keep_segments得到的限制:
1、比如wal_keep_segments值是10,若当前insert的位置的文件号segno为5,那么向前推进到1
2、否则向前推进wal_keep_segments后的segno前的可删除
*/
if (segno <= wal_keep_segments)
segno = 1;
else
segno = segno - wal_keep_segments;
}
/* then check whether slots limit removal further */
//计算slots限制,如果其算出的值小于wal_keep_segments计算出的值,则需要使用slotSegNo,slots还有用,不能删除
if (max_replication_slots > 0 && keep != InvalidXLogRecPtr){
XLByteToSeg(keep, slotSegNo);
if (slotSegNo <= 0)
segno = 1;
else if (slotSegNo < segno)
segno = slotSegNo;
}
/* don't delete WAL segments newer than the calculated segment */
if (segno < *logSegNo)
*logSegNo = segno;
//note:
//如果计算出的segno比上次checkpoint时的文件号logSegNo还有小,则取这次计算的segno
//如果计算出的segno比上次checkpoint时的文件号logSegNo大,则取上次checkpoint时的文件号。
//因为恢复时如果是主机,读取最新checkpoint记录失败后,会读取上一次checkpoint记录,如果上次checkpoint的文件被删除,这里就读取不到记录了
}
5、函数RemoveOldXlogFiles