PostgreSQL怎么删去不运用的xlog文件51CTO博客 - 牛牛娱乐

PostgreSQL怎么删去不运用的xlog文件51CTO博客

2019年03月05日10时51分40秒 | 作者: 飞莲 | 标签: 文件,删去,运用 | 浏览: 837

一、问题
常常会在仿制的时分遇到这样的问题,需求仿制的xlog文件找不到了。那么xlog文件什么时分删去?又会删去多少保存多少个xlog文件?都有哪些xlog文件需求保存?本文将从原理上对这些问题进行解读。

二、原理
每次checkpoint后都会依据需求删去或许收回不再需求的xlog文件。
1、首要预算两次checkpoint之间发生的xlog量,依据这个量管帐算出未来最大的日志文件号然后收回不再需求的文件将其重命名为未来行将运用的日志文件号:
1.1 UpdateCheckPointDistanceEstimate预算checkpoint之前发生的日志量:
    if (CheckPointDistanceEstimate < nbytes)//前次预算量比这次预算的小,则更新为这次的预算量
        CheckPointDistanceEstimate = nbytes;
    else//不然,恰当增加
        CheckPointDistanceEstimate =(0.90 CheckPointDistanceEstimate + 0.10 (double) nbytes);
2、核算上一次checkpoint时,地点的文件段号_logSegNo:
    XLByteToSeg(PriorRedoPtr, _logSegNo);
3、核算需求保存的文件段号:从该段号_logSegNo开端的文件都不能被删去,之前的需求删去或收回:依据备机恳求以及wal_keep_segments核算KeepLogSeg(recptr, &_logSegNo);

4、遍历pg_wal目录下的一切xlog文件,进行删去:RemoveOldXlogFiles
4.1 越过时间线进行比较,假如pg_wal目录下的文件比_logSegNo小则被删去或收回。那么什么条件下次被收回?
RemoveXlogFile
4.2 核算收回文件重命名的未来最大文件段号recycleSegNo:
    1)假如本次是榜首次checkpoint,则未来最大段号recycleSegNo=当时段文件号+10
    2)不然调用函数XLOGfileslop核算:
        2.1 预算下一次checkpoint结束时日志方位:
            distance=(2.0+checkpoint_completion_target)CheckPointDistanceEstimate
            distance
=1.1
            recycleSegNo = (XLogSegNo) ceil(((double) PriorRedoPtr + distance) / XLOG_SEG_SIZE);
        2.2 minSegNo = PriorRedoPtr / XLOG_SEG_SIZE + ConvertToXSegs(min_wal_size_mb) - 1;
            maxSegNo = PriorRedoPtr / XLOG_SEG_SIZE + ConvertToXSegs(max_wal_size_mb) - 1;
        2.3 if (recycleSegNo < minSegNo)
                recycleSegNo = minSegNo;
            if (recycleSegNo > maxSegNo)
                recycleSegNo = maxSegNo;
4.3 假如当时段文件号endlogSegNo < recycleSegNo,则调用InstallXLogFileSegment进行收回:
    1)在endlogSegNo和recycleSegNo之间找一个free slot num,即没有该段文件号的xlog文件
    2)将需求删去的文件名命名为该free slot号的文件名
    3)假如没有找到free slot则直接删去该文件
RemoveXlogFile

三、代码流程
1、checkpoint顶层函数CreateCheckPoint:


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;
  }

  /* dont 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
RemoveOldXlogFiles(XLogSegNo segno, XLogRecPtr PriorRedoPtr, XLogRecPtr endptr)
{
//首要获取xlog目录
xldir = AllocateDir(XLOGDIR);
if (xldir NULL)
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not open write-ahead log directory \"%s\": %m",
XLOGDIR)));

/*
 构建一个log文件名,用于判别,该文件之前的xlog能够删去。用不到时间线,所以能够运用0
 */
XLogFileName(lastoff, 0, 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, PriorRedoPtr, endptr);
    }
  }
}

}

6、函数RemoveXlogFile

RemoveXlogFile(const char *segname, XLogRecPtr PriorRedoPtr, 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
InstallXLogFileSegment(XLogSegNo segno, char tmppath,
bool find_free, XLogSegNo max_segno,
bool use_lock)
{
XLogFilePath(path, ThisTimeLineID, segno);
/

  • We want to be sure that only one process does this at a time.
    */
    if (use_lock)
    LWLockAcquire(ControlFileLock, LW_EXCLUSIVE);

    if (!find_free)
    {
    / Force installation: get rid of any pre-existing segment file /
    durable_unlink(path, DEBUG1);//删去文件并耐久化到磁盘
    }else{
    / Find a free slot to put it in /
    while (stat(path, &stat_buf) 0){//获取文件信息并保存到stat_buf中,成功回来0
    //在segno和max_segno之间找一个闲暇的段号,即目录中没有这个段号的xlog文件
    if ((segno) >= max_segno){
    /
    Failed to find a free slot within specified range /
    if (use_lock)
    LWLockRelease(ControlFileLock);
    return false;
    }
    (
    segno)++;
    XLogFilePath(path, ThisTimeLineID, segno);
    }
    }
    if (durable_link_or_rename(tmppath, path, LOG) != 0){//将tmppath重命名为path并耐久化
    if (use_lock)
    LWLockRelease(ControlFileLock);
    /
    durable_link_or_rename already emitted log message */
    return false;
    }
    if (use_lock)
    LWLockRelease(ControlFileLock);
    return true;
    }

版权声明
本文来源于网络,版权归原作者所有,其内容与观点不代表牛牛娱乐立场。转载文章仅为传播更有价值的信息,如采编人员采编有误或者版权原因,请与我们联系,我们核实后立即修改或删除。

猜您喜欢的文章