PostgreSQL如何删除不使用的xlog文件
|
一、问题
经常会在复制的时候遇到这样的问题,需要复制的xlog文件找不到了。那么xlog文件什么时候删除?又会删除多少保留多少个xlog文件?都有哪些xlog文件需要保留?本文将从原理上对这些问题进行解读。 二、原理
4、遍历pg_wal目录下的所有xlog文件,进行删除:RemoveOldXlogFiles 三、代码流程 CreateCheckPoint:
XLogCtlInsert *Insert = &XLogCtl->Insert;//标识插入的位置
curInsert = XLogBytePosToRecPtr(Insert->CurrBytePos);//添加页头大小后的位置
//(((curInsert) % XLOG_BLCKSZ == 0) ? 0 : (XLOG_BLCKSZ - (curInsert) % XLOG_BLCKSZ))
freespace = INSERT_FREESPACE(curInsert);//curInsert所在页是否有空闲空间
if (freespace == 0){
if (curInsert % XLogSegSize == 0)//正好一个xlog段文件用完,即将使用下一个段文件,则跳过36字节
curInsert += SizeOfXLogLongPHD;//36字节
else//xlog段文件中正好一页用完,即将使用下一页,则跳过20字节
curInsert += SizeOfXLogShortPHD;//20字节
}
checkPoint.redo = curInsert;//xlog文件上,实际的即将插入位置
RedoRecPtr = XLogCtl->Insert.RedoRecPtr = checkPoint.redo;
...
//插入checkpoint记录后末尾位置,即下一个xlog开始的位置
recptr = XLogInsert(RM_XLOG_ID,shutdown ? XLOG_CHECKPOINT_SHUTDOWN :XLOG_CHECKPOINT_ONLINE);
...
PriorRedoPtr = ControlFile->checkPointCopy.redo;//上一次checkpoint的起始位置
...
if (PriorRedoPtr != InvalidXLogRecPtr){//上一次checkpoint开始到这一次checkpoint开始,产生的XLOG大小为入参
/*
CheckPointDistanceEstimate:
1、CheckPointDistanceEstimate<RedoRecPtr - PriorRedoPtr时:RedoRecPtr - PriorRedoPtr
2、CheckPointDistanceEstimate>=RedoRecPtr - PriorRedoPtr时:0.9*CheckPointDistanceEstimate+0.1*(RedoRecPtr - PriorRedoPtr)
*/
UpdateCheckPointDistanceEstimate(RedoRecPtr - PriorRedoPtr);
//_logSegNo = (PriorRedoPtr) / XLogSegSize
XLByteToSeg(PriorRedoPtr,_logSegNo);
KeepLogSeg(recptr,&_logSegNo);
_logSegNo--;
RemoveOldXlogFiles(_logSegNo,PriorRedoPtr,recptr);
2、两个宏定义 #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
static void /*
构建一个log文件名,用于判断,该文件之前的xlog可以删除。用不到时间线,所以可以使用0
*/
XLogFileName(lastoff,segno);
while ((xlde = ReadDir(xldir,XLOGDIR)) != NULL){
/* 忽略非xlog文件 */
if (!IsXLogFileName(xlde->d_name) &&
!IsPartialXLogFileName(xlde->d_name))
continue;
/*
1、跳过时间线进行比较
*/
if (strcmp(xlde->d_name + 8,lastoff + 8) <= 0){
if (XLogArchiveCheckDone(xlde->d_name)){//如果没有开启归档:总是TRUE;否则,归档完成后才为TRUE
/* Update the last removed location in shared memory first */
//XLogCtl->lastRemovedSegNo = segno;
UpdateLastRemovedPtr(xlde->d_name);
RemoveXlogFile(xlde->d_name,endptr);
}
}
}
} 6、函数RemoveXlogFile RemoveXlogFile(const char *segname,XLogRecPtr endptr) XLByteToSeg(endptr,endlogSegNo);
if (PriorRedoPtr == InvalidXLogRecPtr)
recycleSegNo = endlogSegNo + 10;
else
recycleSegNo = XLOGfileslop(PriorRedoPtr);
snprintf(path,MAXPGPATH,XLOGDIR "/%s",segname);
if (endlogSegNo <= recycleSegNo &&
lstat(path,&statbuf) == 0 && S_ISREG(statbuf.st_mode) &&
InstallXLogFileSegment(&endlogSegNo,path,true,recycleSegNo,true))
{
endlogSegNo++;
}else{
rc = durable_unlink(path,LOG);
}
} 7、函数InstallXLogFileSegment static bool
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |

