diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 08d1682..6be9648 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -526,6 +526,8 @@ typedef struct XLogCtlData XLogwrtRqst LogwrtRqst; XLogRecPtr RedoRecPtr; /* a recent copy of Insert->RedoRecPtr */ uint32 ckptXidEpoch; /* nextXID & epoch of latest checkpoint */ + XLogRecPtr ckptPtrRec; /* LSN position of latest checkpoint + * record */ TransactionId ckptXid; XLogRecPtr asyncXactLSN; /* LSN of newest async commit/abort */ XLogRecPtr replicationSlotMinLSN; /* oldest LSN needed by any slot */ @@ -6316,6 +6318,7 @@ StartupXLOG(void) checkPoint.newestCommitTs); XLogCtl->ckptXidEpoch = checkPoint.nextXidEpoch; XLogCtl->ckptXid = checkPoint.nextXid; + XLogCtl->ckptPtrRec = checkPointLoc; /* * Initialize replication slots, before there's a chance to remove @@ -8476,10 +8479,11 @@ CreateCheckPoint(int flags) UpdateControlFile(); LWLockRelease(ControlFileLock); - /* Update shared-memory copy of checkpoint XID/epoch */ + /* Update shared-memory copy of checkpoint XID/epoch/LSN */ SpinLockAcquire(&XLogCtl->info_lck); XLogCtl->ckptXidEpoch = checkPoint.nextXidEpoch; XLogCtl->ckptXid = checkPoint.nextXid; + XLogCtl->ckptPtrRec = recptr; SpinLockRelease(&XLogCtl->info_lck); /* @@ -9278,6 +9282,7 @@ xlog_redo(XLogReaderState *record) SpinLockAcquire(&XLogCtl->info_lck); XLogCtl->ckptXidEpoch = checkPoint.nextXidEpoch; XLogCtl->ckptXid = checkPoint.nextXid; + XLogCtl->ckptPtrRec = lsn; SpinLockRelease(&XLogCtl->info_lck); /* @@ -9328,6 +9333,7 @@ xlog_redo(XLogReaderState *record) SpinLockAcquire(&XLogCtl->info_lck); XLogCtl->ckptXidEpoch = checkPoint.nextXidEpoch; XLogCtl->ckptXid = checkPoint.nextXid; + XLogCtl->ckptPtrRec = lsn; SpinLockRelease(&XLogCtl->info_lck); /* TLI should not change in an on-line checkpoint */ @@ -10610,6 +10616,22 @@ GetXLogInsertRecPtr(void) } /* + * Get start position of latest WAL record inserted + */ +XLogRecPtr +GetXLogPrevRecPtr(void) +{ + XLogCtlInsert *Insert = &XLogCtl->Insert; + uint64 prev_bytepos; + + SpinLockAcquire(&Insert->insertpos_lck); + prev_bytepos = Insert->PrevBytePos; + SpinLockRelease(&Insert->insertpos_lck); + + return XLogBytePosToRecPtr(prev_bytepos); +} + +/* * Get latest WAL write pointer */ XLogRecPtr @@ -10623,6 +10645,21 @@ GetXLogWriteRecPtr(void) } /* + * Get latest WAL checkpoint pointer + */ +XLogRecPtr +GetXLogCheckpointRecPtr(void) +{ + XLogRecPtr chkptr; + + SpinLockAcquire(&XLogCtl->info_lck); + chkptr = XLogCtl->ckptPtrRec; + SpinLockRelease(&XLogCtl->info_lck); + + return chkptr; +} + +/* * Returns the redo pointer of the last checkpoint or restartpoint. This is * the oldest point in WAL that we still need, if we have to restart recovery. */ diff --git a/src/backend/postmaster/bgwriter.c b/src/backend/postmaster/bgwriter.c index 65465d6..792c852 100644 --- a/src/backend/postmaster/bgwriter.c +++ b/src/backend/postmaster/bgwriter.c @@ -315,14 +315,23 @@ BackgroundWriterMain(void) LOG_SNAPSHOT_INTERVAL_MS); /* - * only log if enough time has passed and some xlog record has - * been inserted. + * Only log if enough time has passed, that some record has been + * inserted and that some progress has been done since last + * checkpoint. */ - if (now >= timeout && - last_snapshot_lsn != GetXLogInsertRecPtr()) + if (now >= timeout) { - last_snapshot_lsn = LogStandbySnapshot(); - last_snapshot_ts = now; + XLogRecPtr insert_lsn = GetXLogInsertRecPtr(); + XLogRecPtr checkpoint_lsn = GetXLogCheckpointRecPtr(); + XLogRecPtr previous_lsn = GetXLogPrevRecPtr(); + + if (last_snapshot_lsn != insert_lsn && + checkpoint_lsn != insert_lsn && + checkpoint_lsn != previous_lsn) + { + last_snapshot_ts = now; + last_snapshot_lsn = LogStandbySnapshot(); + } } } diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index 790ca66..9392a07 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -234,7 +234,9 @@ extern bool XLogInsertAllowed(void); extern void GetXLogReceiptTime(TimestampTz *rtime, bool *fromStream); extern XLogRecPtr GetXLogReplayRecPtr(TimeLineID *replayTLI); extern XLogRecPtr GetXLogInsertRecPtr(void); +extern XLogRecPtr GetXLogPrevRecPtr(void); extern XLogRecPtr GetXLogWriteRecPtr(void); +extern XLogRecPtr GetXLogCheckpointRecPtr(void); extern bool RecoveryIsPaused(void); extern void SetRecoveryPause(bool recoveryPause); extern TimestampTz GetLatestXTime(void);