PostgreSQL如何刪除使用的xlog文件

      網友投稿 950 2025-04-01

      一、問題


      經常會在復制的時候遇到這樣的問題,需要復制的xlog文件找不到了。那么xlog文件什么時候刪除?又會刪除多少保留多少個xlog文件?都有哪些xlog文件需要保留?本文將從原理上對這些問題進行解讀。

      二、原理

      每次checkpoint后都會根據需要刪除或者回收不再需要的xlog文件。

      1、首先估算兩次checkpoint之間產生的xlog量,根據這個量會計算出未來最大的日志文件號從而回收不再需要的文件將其重命名為未來即將使用的日志文件號:

      1.1 UpdateCheckPointDistanceEstimate估算checkpoint之前產生的日志量:

      if (CheckPointDistanceEstimate < nbytes)//上次估算量比這次估算的小,則更新為這次的估算量

      CheckPointDistanceEstimate = nbytes;

      else//否則,適當增加

      PostgreSQL如何刪除不使用的xlog文件

      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時: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?XLogRecPtrXLogBytePosToRecPtr(uint64?bytepos){????//bytepos:不包括xlog頁的頁頭等額外字節占用的大小 ????fullsegs?=?bytepos?/?UsableBytesInSegment; ????bytesleft?=?bytepos?%?UsableBytesInSegment;????/* ????1、如果bytesleft?=?XLOG_BLCKSZ-32,則表示定位不是第一頁 ????*/ ????if?(bytesleft?

      4、函數KeepLogSeg

      static?voidKeepLogSeg(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?

      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;

      }

      -------------------------------

      本文轉自yzs的專欄博客51CTO博客

      數據庫 postgresql

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:如何配置NFS?
      下一篇:word文檔刪除線怎么加
      相關文章
      国产国拍亚洲精品福利 | 亚洲一区二区三区不卡在线播放| 亚洲日本乱码在线观看| 久久综合亚洲色HEZYO国产| 亚洲国产午夜福利在线播放| 丰满亚洲大尺度无码无码专线 | 99久久国产亚洲综合精品| 亚洲人成免费电影| 亚洲va精品中文字幕| 中文字幕在线观看亚洲视频| 亚洲国产成a人v在线| 亚洲一区二区三区免费在线观看| 亚洲国产成人综合| 亚洲jjzzjjzz在线观看| 亚洲一区欧洲一区| 亚洲AV无码专区在线观看成人| 亚洲AV日韩AV无码污污网站| 亚洲a∨国产av综合av下载| 国产精品日本亚洲777| 亚洲国产人成中文幕一级二级| 亚洲成网777777国产精品| 亚洲国产a级视频| 久久久久亚洲AV无码专区桃色| 亚洲日韩欧洲乱码AV夜夜摸| 亚洲国产精品一区二区第一页 | 中文文字幕文字幕亚洲色| 亚洲永久在线观看| 久久亚洲精品无码av| 亚洲av区一区二区三| 国产亚洲大尺度无码无码专线| 亚洲日韩精品一区二区三区| 亚洲国产综合专区在线电影| 亚洲视频一区网站| 麻豆狠色伊人亚洲综合网站| 亚洲精品无码久久久久久| 亚洲国产精品无码久久青草 | 亚洲中文字幕第一页在线| 亚洲av中文无码乱人伦在线r▽ | 亚洲综合色一区二区三区小说| 亚洲a级片在线观看| 亚洲国产成人AV网站|