]> granicus.if.org Git - postgresql/commitdiff
In standby mode, respect checkpoint_segments in addition to
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>
Wed, 9 Jun 2010 15:04:07 +0000 (15:04 +0000)
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>
Wed, 9 Jun 2010 15:04:07 +0000 (15:04 +0000)
checkpoint_timeout to trigger restartpoints. We used to deliberately only
do time-based restartpoints, because if checkpoint_segments is small we
would spend time doing restartpoints more often than really necessary.
But now that restartpoints are done in bgwriter, they're not as
disruptive as they used to be. Secondly, because streaming replication
stores the streamed WAL files in pg_xlog, we want to clean it up more
often to avoid running out of disk space when checkpoint_timeout is large
and checkpoint_segments small.

Patch by Fujii Masao, with some minor changes by me.

src/backend/access/transam/xlog.c
src/backend/replication/walreceiver.c

index 19f812456e94330547fc1a3b04d9d9254e0bbdf3..4718b538e899ce1be89c8a69ee846b21aa886ef5 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.418 2010/06/09 10:54:45 mha Exp $
+ * $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.419 2010/06/09 15:04:06 heikki Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -508,6 +508,9 @@ static bool reachedMinRecoveryPoint = false;
 
 static bool InRedo = false;
 
+/* Have we launched bgwriter during recovery? */
+static bool bgwriterLaunched = false;
+
 /*
  * Information logged when we detect a change in one of the parameters
  * important for Hot Standby.
@@ -550,6 +553,7 @@ static void CheckPointGuts(XLogRecPtr checkPointRedo, int flags);
 static bool XLogCheckBuffer(XLogRecData *rdata, bool doPageWrites,
                                XLogRecPtr *lsn, BkpBlock *bkpb);
 static bool AdvanceXLInsertBuffer(bool new_segment);
+static bool XLogCheckpointNeeded(uint32 logid, uint32 logseg);
 static void XLogWrite(XLogwrtRqst WriteRqst, bool flexible, bool xlog_switch);
 static bool InstallXLogFileSegment(uint32 *log, uint32 *seg, char *tmppath,
                                           bool find_free, int *max_advance,
@@ -1554,14 +1558,14 @@ AdvanceXLInsertBuffer(bool new_segment)
 /*
  * Check whether we've consumed enough xlog space that a checkpoint is needed.
  *
- * Caller must have just finished filling the open log file (so that
- * openLogId/openLogSeg are valid).  We measure the distance from RedoRecPtr
- * to the open log file and see if that exceeds CheckPointSegments.
+ * logid/logseg indicate a log file that has just been filled up (or read
+ * during recovery). We measure the distance from RedoRecPtr to logid/logseg
+ * and see if that exceeds CheckPointSegments.
  *
  * Note: it is caller's responsibility that RedoRecPtr is up-to-date.
  */
 static bool
-XLogCheckpointNeeded(void)
+XLogCheckpointNeeded(uint32 logid, uint32 logseg)
 {
        /*
         * A straight computation of segment number could overflow 32 bits. Rather
@@ -1577,8 +1581,8 @@ XLogCheckpointNeeded(void)
        old_segno = (RedoRecPtr.xlogid % XLogSegSize) * XLogSegsPerFile +
                (RedoRecPtr.xrecoff / XLogSegSize);
        old_highbits = RedoRecPtr.xlogid / XLogSegSize;
-       new_segno = (openLogId % XLogSegSize) * XLogSegsPerFile + openLogSeg;
-       new_highbits = openLogId / XLogSegSize;
+       new_segno = (logid % XLogSegSize) * XLogSegsPerFile + logseg;
+       new_highbits = logid / XLogSegSize;
        if (new_highbits != old_highbits ||
                new_segno >= old_segno + (uint32) (CheckPointSegments - 1))
                return true;
@@ -1782,10 +1786,10 @@ XLogWrite(XLogwrtRqst WriteRqst, bool flexible, bool xlog_switch)
                                 * update RedoRecPtr and recheck.
                                 */
                                if (IsUnderPostmaster &&
-                                       XLogCheckpointNeeded())
+                                       XLogCheckpointNeeded(openLogId, openLogSeg))
                                {
                                        (void) GetRedoRecPtr();
-                                       if (XLogCheckpointNeeded())
+                                       if (XLogCheckpointNeeded(openLogId, openLogSeg))
                                                RequestCheckpoint(CHECKPOINT_CAUSE_XLOG);
                                }
                        }
@@ -5653,7 +5657,6 @@ StartupXLOG(void)
        XLogRecord *record;
        uint32          freespace;
        TransactionId oldestActiveXID;
-       bool            bgwriterLaunched = false;
 
        /*
         * Read control file and check XLOG status looks valid.
@@ -7576,6 +7579,21 @@ CreateRestartPoint(int flags)
                return false;
        }
 
+       /*
+        * Update the shared RedoRecPtr so that the startup process can
+        * calculate the number of segments replayed since last restartpoint,
+        * and request a restartpoint if it exceeds checkpoint_segments.
+        *
+        * You need to hold WALInsertLock and info_lck to update it, although
+        * during recovery acquiring WALInsertLock is just pro forma, because
+        * there is no other processes updating Insert.RedoRecPtr.
+        */
+       LWLockAcquire(WALInsertLock, LW_EXCLUSIVE);
+       SpinLockAcquire(&xlogctl->info_lck);
+       xlogctl->Insert.RedoRecPtr = lastCheckPoint.redo;
+       SpinLockRelease(&xlogctl->info_lck);
+       LWLockRelease(WALInsertLock);
+
        if (log_checkpoints)
        {
                /*
@@ -9209,6 +9227,20 @@ XLogPageRead(XLogRecPtr *RecPtr, int emode, bool fetching_ckpt,
         */
        if (readFile >= 0 && !XLByteInSeg(*RecPtr, readId, readSeg))
        {
+               /*
+                * Signal bgwriter to start a restartpoint if we've replayed too
+                * much xlog since the last one.
+                */
+               if (StandbyMode && bgwriterLaunched)
+               {
+                       if (XLogCheckpointNeeded(readId, readSeg))
+                       {
+                               (void) GetRedoRecPtr();
+                               if (XLogCheckpointNeeded(readId, readSeg))
+                                       RequestCheckpoint(CHECKPOINT_CAUSE_XLOG);
+                       }
+               }
+
                close(readFile);
                readFile = -1;
                readSource = 0;
index 11abe6eb8b7f0a2e4f0f6ed87920d26f9ca55e8b..c5a6b315ebaf82d5493f0cb5fb97b588bfbd6402 100644 (file)
@@ -29,7 +29,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/replication/walreceiver.c,v 1.13 2010/06/09 00:54:39 ishii Exp $
+ *       $PostgreSQL: pgsql/src/backend/replication/walreceiver.c,v 1.14 2010/06/09 15:04:07 heikki Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -506,13 +506,6 @@ XLogWalRcvWrite(char *buf, Size nbytes, XLogRecPtr recptr)
                buf += byteswritten;
 
                LogstreamResult.Write = recptr;
-
-               /*
-                * XXX: Should we signal bgwriter to start a restartpoint if we've
-                * consumed too much xlog since the last one, like in normal
-                * processing? But this is not worth doing unless a restartpoint can
-                * be created independently from a checkpoint record.
-                */
        }
 }