From c86f467d18aa58e18fd85b560b46d8de014e6017 Mon Sep 17 00:00:00 2001 From: Bruce Momjian 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 4b7131b709..e629b9ab24 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 2e0ae340fb..519824f328 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 */ -- 2.11.0