Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 3d80a1e

Browse files
committed
Fix logic to skip checkpoint if no records have been inserted.
After the WAL format changes, the calculation of the size of a checkpoint record became incorrect. Instead of trying to fix the math, check that the previous record, i.e. the xl_prev value that we'd write for the next record, matches the last checkpoint's redo pointer. That way it's not dependent on the size of the checkpoint record at all. The old logic was actually slightly wrong all along: if the previous checkpoint record crossed a page boundary, the page headers threw off the record size calculation, and the checkpoint was not skipped. The new checkpoint would not cross a page boundary, so this only resulted in at most one extra checkpoint after the system became idle. The new logic fixes that. (It's not worth fixing in backbranches). However, it makes some sense to try to keep the latest checkpoint contained fully in a page, or at least in a single WAL segment, just on general robustness grounds. If something goes awfully wrong, it's more likely that you can recover the latest WAL segment, than the last two WAL segments. So I added an extra check that the checkpoint is not skipped if the previous checkpoint crossed a WAL segment. Reported by Jeff Janes.
1 parent 9fa8b0e commit 3d80a1e

File tree

1 file changed

+9
-7
lines changed
  • src/backend/access/transam

1 file changed

+9
-7
lines changed

src/backend/access/transam/xlog.c

+9-7
Original file line numberDiff line numberDiff line change
@@ -7903,6 +7903,7 @@ CreateCheckPoint(int flags)
79037903
uint32 freespace;
79047904
XLogRecPtr PriorRedoPtr;
79057905
XLogRecPtr curInsert;
7906+
XLogRecPtr prevPtr;
79067907
VirtualTransactionId *vxids;
79077908
int nvxids;
79087909

@@ -7988,6 +7989,7 @@ CreateCheckPoint(int flags)
79887989
*/
79897990
WALInsertLockAcquireExclusive();
79907991
curInsert = XLogBytePosToRecPtr(Insert->CurrBytePos);
7992+
prevPtr = XLogBytePosToRecPtr(Insert->PrevBytePos);
79917993

79927994
/*
79937995
* If this isn't a shutdown or forced checkpoint, and we have not inserted
@@ -7999,17 +8001,17 @@ CreateCheckPoint(int flags)
79998001
* (Perhaps it'd make even more sense to checkpoint only when the previous
80008002
* checkpoint record is in a different xlog page?)
80018003
*
8002-
* We have to make two tests to determine that nothing has happened since
8003-
* the start of the last checkpoint: current insertion point must match
8004-
* the end of the last checkpoint record, and its redo pointer must point
8005-
* to itself.
8004+
* If the previous checkpoint crossed a WAL segment, however, we create
8005+
* the checkpoint anyway, to have the latest checkpoint fully contained in
8006+
* the new segment. This is for a little bit of extra robustness: it's
8007+
* better if you don't need to keep two WAL segments around to recover the
8008+
* checkpoint.
80068009
*/
80078010
if ((flags & (CHECKPOINT_IS_SHUTDOWN | CHECKPOINT_END_OF_RECOVERY |
80088011
CHECKPOINT_FORCE)) == 0)
80098012
{
8010-
if (curInsert == ControlFile->checkPoint +
8011-
MAXALIGN(SizeOfXLogRecord + sizeof(CheckPoint)) &&
8012-
ControlFile->checkPoint == ControlFile->checkPointCopy.redo)
8013+
if (prevPtr == ControlFile->checkPointCopy.redo &&
8014+
prevPtr / XLOG_SEG_SIZE == curInsert / XLOG_SEG_SIZE)
80138015
{
80148016
WALInsertLockRelease();
80158017
LWLockRelease(CheckpointLock);

0 commit comments

Comments
 (0)