From c86f467d18aa58e18fd85b560b46d8de014e6017 Mon Sep 17 00:00:00 2001
From: Bruce Momjian <bruce@momjian.us>
Date: Tue, 20 Jul 2010 18:14:16 +0000
Subject: [PATCH] Properly replay CREATE TABLESPACE during crash recovery by
 deleting directory/symlink before creation.

Report from Tom Lane.

Backpatch to 9.0.
---
 src/backend/commands/dbcommands.c |  3 ++-
 src/backend/commands/tablespace.c | 31 ++++++++++++++++++++++++++++++-
 2 files changed, 32 insertions(+), 2 deletions(-)

diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c
index 4b7131b7097..e629b9ab248 100644
--- a/src/backend/commands/dbcommands.c
+++ b/src/backend/commands/dbcommands.c
@@ -13,7 +13,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.235 2010/02/26 02:00:38 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.236 2010/07/20 18:14:16 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1908,6 +1908,7 @@ dbase_redo(XLogRecPtr lsn, XLogRecord *record)
 		if (stat(dst_path, &st) == 0 && S_ISDIR(st.st_mode))
 		{
 			if (!rmtree(dst_path, true))
+				/* If this failed, copydir() below is going to error. */
 				ereport(WARNING,
 						(errmsg("some useless files may be left behind in old database directory \"%s\"",
 								dst_path)));
diff --git a/src/backend/commands/tablespace.c b/src/backend/commands/tablespace.c
index 2e0ae340fb1..519824f3281 100644
--- a/src/backend/commands/tablespace.c
+++ b/src/backend/commands/tablespace.c
@@ -40,7 +40,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/tablespace.c,v 1.77 2010/07/18 04:47:46 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/tablespace.c,v 1.78 2010/07/20 18:14:16 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -562,6 +562,25 @@ create_tablespace_directories(const char *location, const Oid tablespaceoid)
 						 location)));
 	}
 
+	if (InRecovery)
+	{
+		struct stat st;
+
+		/*
+		 * Our theory for replaying a CREATE is to forcibly drop the target
+		 * subdirectory if present, and then recreate it. This may be
+		 * more work than needed, but it is simple to implement.
+		 */
+		if (stat(location_with_version_dir, &st) == 0 && S_ISDIR(st.st_mode))
+		{
+			if (!rmtree(location_with_version_dir, true))
+				/* If this failed, mkdir() below is going to error. */
+				ereport(WARNING,
+						(errmsg("some useless files may be left behind in old database directory \"%s\"",
+								location_with_version_dir)));
+		}
+	}
+
 	/*
 	 * The creation of the version directory prevents more than one tablespace
 	 * in a single location.
@@ -580,6 +599,16 @@ create_tablespace_directories(const char *location, const Oid tablespaceoid)
 							location_with_version_dir)));
 	}
 
+	/* Remove old symlink in recovery, in case it points to the wrong place */
+	if (InRecovery)
+	{
+		if (unlink(linkloc) < 0 && errno != ENOENT)
+			ereport(ERROR,
+					(errcode_for_file_access(),
+					 errmsg("could not remove symbolic link \"%s\": %m",
+							linkloc)));
+	}
+	
 	/*
 	 * Create the symlink under PGDATA
 	 */
-- 
GitLab