]> granicus.if.org Git - postgresql/commitdiff
Fix archive_cleanup_command.
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>
Mon, 19 Nov 2012 08:02:25 +0000 (10:02 +0200)
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>
Mon, 19 Nov 2012 08:14:20 +0000 (10:14 +0200)
When I moved ExecuteRecoveryCommand() from xlog.c to xlogarchive.c, I didn't
realize that it's called from the checkpoint process, not the startup
process. I tried to use InRedo variable to decide whether or not to attempt
cleaning up the archive (must not do so before we have read the initial
checkpoint record), but that variable is only valid within the startup
process.

Instead, let ExecuteRecoveryCommand() always clean up the archive, and add
an explicit argument to RestoreArchivedFile() to say whether that's allowed
or not. The caller knows better.

Reported by Erik Rijkers, diagnosis by Fujii Masao. Only 9.3devel is
affected.

src/backend/access/transam/timeline.c
src/backend/access/transam/xlog.c
src/backend/access/transam/xlogarchive.c
src/include/access/xlog_internal.h

index f3632c572a75d5f4d327a58a90a69a142e23392b..6006d3d98d15ba4135042a1d90ff67fc8a13b24f 100644 (file)
@@ -64,7 +64,7 @@ readTimeLineHistory(TimeLineID targetTLI)
        if (InArchiveRecovery)
        {
                TLHistoryFileName(histfname, targetTLI);
-               RestoreArchivedFile(path, histfname, "RECOVERYHISTORY", 0);
+               RestoreArchivedFile(path, histfname, "RECOVERYHISTORY", 0, false);
        }
        else
                TLHistoryFilePath(path, targetTLI);
@@ -153,7 +153,7 @@ existsTimeLineHistory(TimeLineID probeTLI)
        if (InArchiveRecovery)
        {
                TLHistoryFileName(histfname, probeTLI);
-               RestoreArchivedFile(path, histfname, "RECOVERYHISTORY", 0);
+               RestoreArchivedFile(path, histfname, "RECOVERYHISTORY", 0, false);
        }
        else
                TLHistoryFilePath(path, probeTLI);
@@ -257,7 +257,7 @@ writeTimeLineHistory(TimeLineID newTLI, TimeLineID parentTLI,
        if (InArchiveRecovery)
        {
                TLHistoryFileName(histfname, parentTLI);
-               RestoreArchivedFile(path, histfname, "RECOVERYHISTORY", 0);
+               RestoreArchivedFile(path, histfname, "RECOVERYHISTORY", 0, false);
        }
        else
                TLHistoryFilePath(path, parentTLI);
index 1faf666f43c8bfbdce44c94b5804310fa4693f7f..09d4dffc75e2bb75445e75e2ff01dfdb31cd80f0 100644 (file)
@@ -2588,7 +2588,8 @@ XLogFileRead(XLogSegNo segno, int emode, TimeLineID tli,
 
                        restoredFromArchive = RestoreArchivedFile(path, xlogfname,
                                                                                                          "RECOVERYXLOG",
-                                                                                                         XLogSegSize);
+                                                                                                         XLogSegSize,
+                                                                                                         InRedo);
                        if (!restoredFromArchive)
                                return -1;
                        break;
@@ -9051,33 +9052,16 @@ GetXLogWriteRecPtr(void)
 }
 
 /*
- * Returns the redo pointer of the last restartpoint. This is the oldest
- * point in WAL that we still need, if we have to restart recovery. Returns
- * InvalidXLogRecPtr if we don't reliably know that point yet, that is,
- * before we have started WAL redo.
- *
- * This function only works in the startup process, and only while we are
- * in WAL redo. It's important to not return a value before redo has started,
- * to avoid deleting WAL files that we might still need, but there's no
- * fundamental reason why this couldn't return a valid value after redo has
- * finished, or in other processes. This is enough for the current usage,
- * however.
+ * 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.
  */
 void
 GetOldestRestartPoint(XLogRecPtr *oldrecptr, TimeLineID *oldtli)
 {
-       if (InRedo)
-       {
-               LWLockAcquire(ControlFileLock, LW_SHARED);
-               *oldrecptr = ControlFile->checkPointCopy.redo;
-               *oldtli = ControlFile->checkPointCopy.ThisTimeLineID;
-               LWLockRelease(ControlFileLock);
-       }
-       else
-       {
-               *oldrecptr = InvalidXLogRecPtr;
-               *oldtli = 0;
-       }
+       LWLockAcquire(ControlFileLock, LW_SHARED);
+       *oldrecptr = ControlFile->checkPointCopy.redo;
+       *oldtli = ControlFile->checkPointCopy.ThisTimeLineID;
+       LWLockRelease(ControlFileLock);
 }
 
 /*
index ce9dfaa9601aea39bc1e739241a025159d8122d1..9bd6b8e3a2f5d667ae26ef24724e99b909525cab 100644 (file)
  * For fixed-size files, the caller may pass the expected size as an
  * additional crosscheck on successful recovery.  If the file size is not
  * known, set expectedSize = 0.
+ *
+ * When 'cleanupEnabled' is false, refrain from deleting any old WAL segments
+ * in the archive. This is used when fetching the initial checkpoint record,
+ * when we are not yet sure how far back we need the WAL.
  */
 bool
 RestoreArchivedFile(char *path, const char *xlogfname,
-                                       const char *recovername, off_t expectedSize)
+                                       const char *recovername, off_t expectedSize,
+                                       bool cleanupEnabled)
 {
        char            xlogpath[MAXPGPATH];
        char            xlogRestoreCmd[MAXPGPATH];
@@ -113,9 +118,10 @@ RestoreArchivedFile(char *path, const char *xlogfname,
         * replication. All files earlier than this point can be deleted from the
         * archive, though there is no requirement to do so.
         *
-        * We initialise this with the filename of an InvalidXLogRecPtr, which
-        * will prevent the deletion of any WAL files from the archive because of
-        * the alphabetic sorting property of WAL filenames.
+        * If cleanup is not enabled, initialise this with the filename of
+        * InvalidXLogRecPtr, which will prevent the deletion of any WAL files
+        * from the archive because of the alphabetic sorting property of WAL
+        * filenames.
         *
         * Once we have successfully located the redo pointer of the checkpoint
         * from which we start recovery we never request a file prior to the redo
@@ -124,9 +130,9 @@ RestoreArchivedFile(char *path, const char *xlogfname,
         * flags to signify the point when we can begin deleting WAL files from
         * the archive.
         */
-       GetOldestRestartPoint(&restartRedoPtr, &restartTli);
-       if (!XLogRecPtrIsInvalid(restartRedoPtr))
+       if (cleanupEnabled)
        {
+               GetOldestRestartPoint(&restartRedoPtr, &restartTli);
                XLByteToSeg(restartRedoPtr, restartSegNo);
                XLogFileName(lastRestartPointFname, restartTli, restartSegNo);
                /* we shouldn't need anything earlier than last restart point */
index 2c66b2feb8afc470113e55b56b71a9237ad0816a..b70a62052c4d6cba5ca294d29e8bd3858d09fdb0 100644 (file)
@@ -243,7 +243,8 @@ extern char *recoveryRestoreCommand;
  * Prototypes for functions in xlogarchive.c
  */
 extern bool RestoreArchivedFile(char *path, const char *xlogfname,
-                                       const char *recovername, off_t expectedSize);
+                                       const char *recovername, off_t expectedSize,
+                                       bool cleanupEnabled);
 extern void ExecuteRecoveryCommand(char *command, char *commandName,
                                           bool failOnerror);
 extern void XLogArchiveNotify(const char *xlog);