From f0eb3e5e580f0ac95cb451f931dac4352cb9adba Mon Sep 17 00:00:00 2001
From: Heikki Linnakangas <heikki.linnakangas@iki.fi>
Date: Fri, 9 May 2008 14:27:47 +0000
Subject: [PATCH] Fix incorrect archive truncation point calculation in the %r
 recovery_command parameter. This fixes bug 4137 reported by Wojciech
 Strzalka, where a WAL file is deleted too early when starting the recovery of
 a warm standby server.

Also add a sanity check in pg_standby so that it will refuse to delete anything
earlier than the file being restored, and improve the debug message in case
nothing is deleted.

Simon Riggs. Backpatch to 8.3, which is where %r was introduced.
---
 contrib/pg_standby/pg_standby.c   | 15 ++++++++++++-
 src/backend/access/transam/xlog.c | 36 +++++++++++++++++++++++++------
 2 files changed, 44 insertions(+), 7 deletions(-)

diff --git a/contrib/pg_standby/pg_standby.c b/contrib/pg_standby/pg_standby.c
index 41b3500dd11..9879348cc1b 100644
--- a/contrib/pg_standby/pg_standby.c
+++ b/contrib/pg_standby/pg_standby.c
@@ -297,6 +297,15 @@ SetWALFileNameForCleanup(void)
 
 	if (restartWALFileName)
 	{
+		/*
+		 * Don't do cleanup if the restartWALFileName provided
+		 * is later than the xlog file requested. This is an error
+		 * and we must not remove these files from archive.
+		 * This shouldn't happen, but better safe than sorry.
+		 */
+		if (strcmp(restartWALFileName, nextWALFileName) > 0)
+			return false;
+
 		strcpy(exclusiveCleanupFileName, restartWALFileName);
 		return true;
 	}
@@ -584,7 +593,11 @@ main(int argc, char **argv)
 		fprintf(stderr, "\nMax wait interval	: %d %s",
 				maxwaittime, (maxwaittime > 0 ? "seconds" : "forever"));
 		fprintf(stderr, "\nCommand for restore	: %s", restoreCommand);
-		fprintf(stderr, "\nKeep archive history	: %s and later", exclusiveCleanupFileName);
+		fprintf(stderr, "\nKeep archive history	: ");
+		if (need_cleanup)
+			fprintf(stderr, "%s and later", exclusiveCleanupFileName);
+		else
+			fprintf(stderr, "No cleanup required");
 		fflush(stderr);
 	}
 
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index df1549f97d9..f0b86fdc714 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.300 2008/04/24 14:23:43 mha Exp $
+ * $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.301 2008/05/09 14:27:47 heikki Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -2483,6 +2483,35 @@ RestoreArchivedFile(char *path, const char *xlogfname,
 							xlogpath)));
 	}
 
+	/*
+	 * Calculate the archive file cutoff point for use during log shipping
+	 * 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. 
+	 *
+	 * 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
+	 * pointer of the last restartpoint. When redo begins we know that we
+	 * have successfully located it, so there is no need for additional
+	 * status flags to signify the point when we can begin deleting WAL files
+	 * from the archive. 
+	 */
+	if (InRedo)
+	{
+		XLByteToSeg(ControlFile->checkPointCopy.redo,
+					restartLog, restartSeg);
+		XLogFileName(lastRestartPointFname,
+					 ControlFile->checkPointCopy.ThisTimeLineID,
+					 restartLog, restartSeg);
+		/* we shouldn't need anything earlier than last restart point */
+		Assert(strcmp(lastRestartPointFname, xlogfname) < 0);
+	}
+	else
+		XLogFileName(lastRestartPointFname, 0, 0, 0);
+
 	/*
 	 * construct the command to be executed
 	 */
@@ -2512,11 +2541,6 @@ RestoreArchivedFile(char *path, const char *xlogfname,
 				case 'r':
 					/* %r: filename of last restartpoint */
 					sp++;
-					XLByteToSeg(ControlFile->checkPointCopy.redo,
-								restartLog, restartSeg);
-					XLogFileName(lastRestartPointFname,
-								 ControlFile->checkPointCopy.ThisTimeLineID,
-								 restartLog, restartSeg);
 					StrNCpy(dp, lastRestartPointFname, endp - dp);
 					dp += strlen(dp);
 					break;
-- 
GitLab