Commit d9fadbf1 authored by Michael Paquier's avatar Michael Paquier

Fix calculation for WAL segment recycling and removal

Commit 4b0d28de has removed the prior checkpoint and related
facilities but has left WAL recycling based on the LSN of the prior
checkpoint, which causes incorrect calculations for WAL removal and
recycling for max_wal_size and min_wal_size.  This commit changes things
so as the base calculation point is the last checkpoint generated.

Reported-by: Kyotaro Horiguchi
Author: Kyotaro Horiguchi
Reviewed-by: Michael Paquier
Discussion: https://postgr.es/m/20180723.135748.42558387.horiguchi.kyotaro@lab.ntt.co.jp
Backpatch: 11-, where the prior checkpoint has been removed.
parent 1bc180cd
...@@ -888,8 +888,8 @@ static int emode_for_corrupt_record(int emode, XLogRecPtr RecPtr); ...@@ -888,8 +888,8 @@ static int emode_for_corrupt_record(int emode, XLogRecPtr RecPtr);
static void XLogFileClose(void); static void XLogFileClose(void);
static void PreallocXlogFiles(XLogRecPtr endptr); static void PreallocXlogFiles(XLogRecPtr endptr);
static void RemoveTempXlogFiles(void); static void RemoveTempXlogFiles(void);
static void RemoveOldXlogFiles(XLogSegNo segno, XLogRecPtr PriorRedoPtr, XLogRecPtr endptr); static void RemoveOldXlogFiles(XLogSegNo segno, XLogRecPtr RedoRecPtr, XLogRecPtr endptr);
static void RemoveXlogFile(const char *segname, XLogRecPtr PriorRedoPtr, XLogRecPtr endptr); static void RemoveXlogFile(const char *segname, XLogRecPtr RedoRecPtr, XLogRecPtr endptr);
static void UpdateLastRemovedPtr(char *filename); static void UpdateLastRemovedPtr(char *filename);
static void ValidateXLOGDirectoryStructure(void); static void ValidateXLOGDirectoryStructure(void);
static void CleanupBackupHistory(void); static void CleanupBackupHistory(void);
...@@ -2287,7 +2287,7 @@ assign_checkpoint_completion_target(double newval, void *extra) ...@@ -2287,7 +2287,7 @@ assign_checkpoint_completion_target(double newval, void *extra)
* XLOG segments? Returns the highest segment that should be preallocated. * XLOG segments? Returns the highest segment that should be preallocated.
*/ */
static XLogSegNo static XLogSegNo
XLOGfileslop(XLogRecPtr PriorRedoPtr) XLOGfileslop(XLogRecPtr RedoRecPtr)
{ {
XLogSegNo minSegNo; XLogSegNo minSegNo;
XLogSegNo maxSegNo; XLogSegNo maxSegNo;
...@@ -2299,9 +2299,9 @@ XLOGfileslop(XLogRecPtr PriorRedoPtr) ...@@ -2299,9 +2299,9 @@ XLOGfileslop(XLogRecPtr PriorRedoPtr)
* correspond to. Always recycle enough segments to meet the minimum, and * correspond to. Always recycle enough segments to meet the minimum, and
* remove enough segments to stay below the maximum. * remove enough segments to stay below the maximum.
*/ */
minSegNo = PriorRedoPtr / wal_segment_size + minSegNo = RedoRecPtr / wal_segment_size +
ConvertToXSegs(min_wal_size_mb, wal_segment_size) - 1; ConvertToXSegs(min_wal_size_mb, wal_segment_size) - 1;
maxSegNo = PriorRedoPtr / wal_segment_size + maxSegNo = RedoRecPtr / wal_segment_size +
ConvertToXSegs(max_wal_size_mb, wal_segment_size) - 1; ConvertToXSegs(max_wal_size_mb, wal_segment_size) - 1;
/* /*
...@@ -2316,7 +2316,7 @@ XLOGfileslop(XLogRecPtr PriorRedoPtr) ...@@ -2316,7 +2316,7 @@ XLOGfileslop(XLogRecPtr PriorRedoPtr)
/* add 10% for good measure. */ /* add 10% for good measure. */
distance *= 1.10; distance *= 1.10;
recycleSegNo = (XLogSegNo) ceil(((double) PriorRedoPtr + distance) / recycleSegNo = (XLogSegNo) ceil(((double) RedoRecPtr + distance) /
wal_segment_size); wal_segment_size);
if (recycleSegNo < minSegNo) if (recycleSegNo < minSegNo)
...@@ -3899,12 +3899,12 @@ RemoveTempXlogFiles(void) ...@@ -3899,12 +3899,12 @@ RemoveTempXlogFiles(void)
/* /*
* Recycle or remove all log files older or equal to passed segno. * Recycle or remove all log files older or equal to passed segno.
* *
* endptr is current (or recent) end of xlog, and PriorRedoRecPtr is the * endptr is current (or recent) end of xlog, and RedoRecPtr is the
* redo pointer of the previous checkpoint. These are used to determine * redo pointer of the last checkpoint. These are used to determine
* whether we want to recycle rather than delete no-longer-wanted log files. * whether we want to recycle rather than delete no-longer-wanted log files.
*/ */
static void static void
RemoveOldXlogFiles(XLogSegNo segno, XLogRecPtr PriorRedoPtr, XLogRecPtr endptr) RemoveOldXlogFiles(XLogSegNo segno, XLogRecPtr RedoRecPtr, XLogRecPtr endptr)
{ {
DIR *xldir; DIR *xldir;
struct dirent *xlde; struct dirent *xlde;
...@@ -3947,7 +3947,7 @@ RemoveOldXlogFiles(XLogSegNo segno, XLogRecPtr PriorRedoPtr, XLogRecPtr endptr) ...@@ -3947,7 +3947,7 @@ RemoveOldXlogFiles(XLogSegNo segno, XLogRecPtr PriorRedoPtr, XLogRecPtr endptr)
/* Update the last removed location in shared memory first */ /* Update the last removed location in shared memory first */
UpdateLastRemovedPtr(xlde->d_name); UpdateLastRemovedPtr(xlde->d_name);
RemoveXlogFile(xlde->d_name, PriorRedoPtr, endptr); RemoveXlogFile(xlde->d_name, RedoRecPtr, endptr);
} }
} }
} }
...@@ -4021,14 +4021,14 @@ RemoveNonParentXlogFiles(XLogRecPtr switchpoint, TimeLineID newTLI) ...@@ -4021,14 +4021,14 @@ RemoveNonParentXlogFiles(XLogRecPtr switchpoint, TimeLineID newTLI)
/* /*
* Recycle or remove a log file that's no longer needed. * Recycle or remove a log file that's no longer needed.
* *
* endptr is current (or recent) end of xlog, and PriorRedoRecPtr is the * endptr is current (or recent) end of xlog, and RedoRecPtr is the
* redo pointer of the previous checkpoint. These are used to determine * redo pointer of the last checkpoint. These are used to determine
* whether we want to recycle rather than delete no-longer-wanted log files. * whether we want to recycle rather than delete no-longer-wanted log files.
* If PriorRedoRecPtr is not known, pass invalid, and the function will * If RedoRecPtr is not known, pass invalid, and the function will recycle,
* recycle, somewhat arbitrarily, 10 future segments. * somewhat arbitrarily, 10 future segments.
*/ */
static void static void
RemoveXlogFile(const char *segname, XLogRecPtr PriorRedoPtr, XLogRecPtr endptr) RemoveXlogFile(const char *segname, XLogRecPtr RedoRecPtr, XLogRecPtr endptr)
{ {
char path[MAXPGPATH]; char path[MAXPGPATH];
#ifdef WIN32 #ifdef WIN32
...@@ -4042,10 +4042,10 @@ RemoveXlogFile(const char *segname, XLogRecPtr PriorRedoPtr, XLogRecPtr endptr) ...@@ -4042,10 +4042,10 @@ RemoveXlogFile(const char *segname, XLogRecPtr PriorRedoPtr, XLogRecPtr endptr)
* Initialize info about where to try to recycle to. * Initialize info about where to try to recycle to.
*/ */
XLByteToSeg(endptr, endlogSegNo, wal_segment_size); XLByteToSeg(endptr, endlogSegNo, wal_segment_size);
if (PriorRedoPtr == InvalidXLogRecPtr) if (RedoRecPtr == InvalidXLogRecPtr)
recycleSegNo = endlogSegNo + 10; recycleSegNo = endlogSegNo + 10;
else else
recycleSegNo = XLOGfileslop(PriorRedoPtr); recycleSegNo = XLOGfileslop(RedoRecPtr);
snprintf(path, MAXPGPATH, XLOGDIR "/%s", segname); snprintf(path, MAXPGPATH, XLOGDIR "/%s", segname);
...@@ -8706,6 +8706,7 @@ CreateCheckPoint(int flags) ...@@ -8706,6 +8706,7 @@ CreateCheckPoint(int flags)
bool shutdown; bool shutdown;
CheckPoint checkPoint; CheckPoint checkPoint;
XLogRecPtr recptr; XLogRecPtr recptr;
XLogSegNo _logSegNo;
XLogCtlInsert *Insert = &XLogCtl->Insert; XLogCtlInsert *Insert = &XLogCtl->Insert;
uint32 freespace; uint32 freespace;
XLogRecPtr PriorRedoPtr; XLogRecPtr PriorRedoPtr;
...@@ -9073,21 +9074,20 @@ CreateCheckPoint(int flags) ...@@ -9073,21 +9074,20 @@ CreateCheckPoint(int flags)
smgrpostckpt(); smgrpostckpt();
/* /*
* Delete old log files and recycle them * Update the average distance between checkpoints if the prior checkpoint
* exists.
*/ */
if (PriorRedoPtr != InvalidXLogRecPtr) if (PriorRedoPtr != InvalidXLogRecPtr)
{
XLogSegNo _logSegNo;
/* Update the average distance between checkpoints. */
UpdateCheckPointDistanceEstimate(RedoRecPtr - PriorRedoPtr); UpdateCheckPointDistanceEstimate(RedoRecPtr - PriorRedoPtr);
/* Trim from the last checkpoint, not the last - 1 */ /*
XLByteToSeg(RedoRecPtr, _logSegNo, wal_segment_size); * Delete old log files, those no longer needed for last checkpoint to
KeepLogSeg(recptr, &_logSegNo); * prevent the disk holding the xlog from growing full.
_logSegNo--; */
RemoveOldXlogFiles(_logSegNo, PriorRedoPtr, recptr); XLByteToSeg(RedoRecPtr, _logSegNo, wal_segment_size);
} KeepLogSeg(recptr, &_logSegNo);
_logSegNo--;
RemoveOldXlogFiles(_logSegNo, RedoRecPtr, recptr);
/* /*
* Make more log segments if needed. (Do this after recycling old log * Make more log segments if needed. (Do this after recycling old log
...@@ -9253,6 +9253,11 @@ CreateRestartPoint(int flags) ...@@ -9253,6 +9253,11 @@ CreateRestartPoint(int flags)
XLogRecPtr lastCheckPointEndPtr; XLogRecPtr lastCheckPointEndPtr;
CheckPoint lastCheckPoint; CheckPoint lastCheckPoint;
XLogRecPtr PriorRedoPtr; XLogRecPtr PriorRedoPtr;
XLogRecPtr receivePtr;
XLogRecPtr replayPtr;
TimeLineID replayTLI;
XLogRecPtr endptr;
XLogSegNo _logSegNo;
TimestampTz xtime; TimestampTz xtime;
/* /*
...@@ -9395,68 +9400,60 @@ CreateRestartPoint(int flags) ...@@ -9395,68 +9400,60 @@ CreateRestartPoint(int flags)
LWLockRelease(ControlFileLock); LWLockRelease(ControlFileLock);
/* /*
* Delete old log files (those no longer needed even for previous * Update the average distance between checkpoints/restartpoints if the
* checkpoint/restartpoint) to prevent the disk holding the xlog from * prior checkpoint exists.
* growing full.
*/ */
if (PriorRedoPtr != InvalidXLogRecPtr) if (PriorRedoPtr != InvalidXLogRecPtr)
{
XLogRecPtr receivePtr;
XLogRecPtr replayPtr;
TimeLineID replayTLI;
XLogRecPtr endptr;
XLogSegNo _logSegNo;
/* Update the average distance between checkpoints/restartpoints. */
UpdateCheckPointDistanceEstimate(RedoRecPtr - PriorRedoPtr); UpdateCheckPointDistanceEstimate(RedoRecPtr - PriorRedoPtr);
XLByteToSeg(PriorRedoPtr, _logSegNo, wal_segment_size); /*
* Delete old log files, those no longer needed for last restartpoint to
/* * prevent the disk holding the xlog from growing full.
* Get the current end of xlog replayed or received, whichever is */
* later. XLByteToSeg(RedoRecPtr, _logSegNo, wal_segment_size);
*/
receivePtr = GetWalRcvWriteRecPtr(NULL, NULL);
replayPtr = GetXLogReplayRecPtr(&replayTLI);
endptr = (receivePtr < replayPtr) ? replayPtr : receivePtr;
KeepLogSeg(endptr, &_logSegNo); /*
_logSegNo--; * Retreat _logSegNo using the current end of xlog replayed or received,
* whichever is later.
*/
receivePtr = GetWalRcvWriteRecPtr(NULL, NULL);
replayPtr = GetXLogReplayRecPtr(&replayTLI);
endptr = (receivePtr < replayPtr) ? replayPtr : receivePtr;
KeepLogSeg(endptr, &_logSegNo);
_logSegNo--;
/* /*
* Try to recycle segments on a useful timeline. If we've been * Try to recycle segments on a useful timeline. If we've been promoted
* promoted since the beginning of this restartpoint, use the new * since the beginning of this restartpoint, use the new timeline chosen
* timeline chosen at end of recovery (RecoveryInProgress() sets * at end of recovery (RecoveryInProgress() sets ThisTimeLineID in that
* ThisTimeLineID in that case). If we're still in recovery, use the * case). If we're still in recovery, use the timeline we're currently
* timeline we're currently replaying. * replaying.
* *
* There is no guarantee that the WAL segments will be useful on the * There is no guarantee that the WAL segments will be useful on the
* current timeline; if recovery proceeds to a new timeline right * current timeline; if recovery proceeds to a new timeline right after
* after this, the pre-allocated WAL segments on this timeline will * this, the pre-allocated WAL segments on this timeline will not be used,
* not be used, and will go wasted until recycled on the next * and will go wasted until recycled on the next restartpoint. We'll live
* restartpoint. We'll live with that. * with that.
*/ */
if (RecoveryInProgress()) if (RecoveryInProgress())
ThisTimeLineID = replayTLI; ThisTimeLineID = replayTLI;
RemoveOldXlogFiles(_logSegNo, PriorRedoPtr, endptr); RemoveOldXlogFiles(_logSegNo, RedoRecPtr, endptr);
/* /*
* Make more log segments if needed. (Do this after recycling old log * Make more log segments if needed. (Do this after recycling old log
* segments, since that may supply some of the needed files.) * segments, since that may supply some of the needed files.)
*/ */
PreallocXlogFiles(endptr); PreallocXlogFiles(endptr);
/* /*
* ThisTimeLineID is normally not set when we're still in recovery. * ThisTimeLineID is normally not set when we're still in recovery.
* However, recycling/preallocating segments above needed * However, recycling/preallocating segments above needed ThisTimeLineID
* ThisTimeLineID to determine which timeline to install the segments * to determine which timeline to install the segments on. Reset it now,
* on. Reset it now, to restore the normal state of affairs for * to restore the normal state of affairs for debugging purposes.
* debugging purposes. */
*/ if (RecoveryInProgress())
if (RecoveryInProgress()) ThisTimeLineID = 0;
ThisTimeLineID = 0;
}
/* /*
* Truncate pg_subtrans if possible. We can throw away all data before * Truncate pg_subtrans if possible. We can throw away all data before
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment