From 650221d14c1c34023aa66b1c22398eeae00dbcb8 Mon Sep 17 00:00:00 2001 From: Paul Guo Date: Tue, 30 Apr 2019 13:30:49 +0800 Subject: [PATCH v2] skip copydir() if either src directory or dst directory is missing due to re-redoing create database but the tablespace is dropped. --- src/backend/access/rmgrdesc/dbasedesc.c | 14 ++++++---- src/backend/commands/dbcommands.c | 35 ++++++++++++++++++++++++- src/backend/commands/tablespace.c | 28 +------------------- 3 files changed, 44 insertions(+), 33 deletions(-) diff --git a/src/backend/access/rmgrdesc/dbasedesc.c b/src/backend/access/rmgrdesc/dbasedesc.c index c7d60ce10d..35092ffb0e 100644 --- a/src/backend/access/rmgrdesc/dbasedesc.c +++ b/src/backend/access/rmgrdesc/dbasedesc.c @@ -23,21 +23,25 @@ dbase_desc(StringInfo buf, XLogReaderState *record) { char *rec = XLogRecGetData(record); uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK; + char *dbpath1, *dbpath2; if (info == XLOG_DBASE_CREATE) { xl_dbase_create_rec *xlrec = (xl_dbase_create_rec *) rec; - appendStringInfo(buf, "copy dir %u/%u to %u/%u", - xlrec->src_tablespace_id, xlrec->src_db_id, - xlrec->tablespace_id, xlrec->db_id); + dbpath1 = GetDatabasePath(xlrec->src_db_id, xlrec->src_tablespace_id); + dbpath2 = GetDatabasePath(xlrec->db_id, xlrec->tablespace_id); + appendStringInfo(buf, "copy dir %s to %s", dbpath1, dbpath2); + pfree(dbpath2); + pfree(dbpath1); } else if (info == XLOG_DBASE_DROP) { xl_dbase_drop_rec *xlrec = (xl_dbase_drop_rec *) rec; - appendStringInfo(buf, "dir %u/%u", - xlrec->tablespace_id, xlrec->db_id); + dbpath1 = GetDatabasePath(xlrec->db_id, xlrec->tablespace_id); + appendStringInfo(buf, "dir %s", dbpath1); + pfree(dbpath1); } } diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c index 9707afabd9..b7943529be 100644 --- a/src/backend/commands/dbcommands.c +++ b/src/backend/commands/dbcommands.c @@ -45,6 +45,7 @@ #include "commands/defrem.h" #include "commands/seclabel.h" #include "commands/tablespace.h" +#include "common/file_perm.h" #include "mb/pg_wchar.h" #include "miscadmin.h" #include "pgstat.h" @@ -2089,7 +2090,9 @@ dbase_redo(XLogReaderState *record) xl_dbase_create_rec *xlrec = (xl_dbase_create_rec *) XLogRecGetData(record); char *src_path; char *dst_path; + char *parent_path; struct stat st; + bool do_copydir = true; src_path = GetDatabasePath(xlrec->src_db_id, xlrec->src_tablespace_id); dst_path = GetDatabasePath(xlrec->db_id, xlrec->tablespace_id); @@ -2107,6 +2110,35 @@ dbase_redo(XLogReaderState *record) (errmsg("some useless files may be left behind in old database directory \"%s\"", dst_path))); } + else + { + /* + * It is possible that the tablespace was later dropped, but we are + * re-redoing database create before that. In that case, + * the directory are missing, we simply skip the copydir step. + */ + parent_path = pstrdup(dst_path); + get_parent_directory(parent_path); + if (!(stat(parent_path, &st) == 0 && S_ISDIR(st.st_mode))) + { + do_copydir = false; + ereport(WARNING, + (errmsg("directory \"%s\" for copydir() does not exists." + "It is possibly expected. Skip copydir().", + parent_path))); + } + pfree(parent_path); + } + + /* src directory is possibly missing also. See previous comment. */ + if (!(stat(src_path, &st) == 0 && S_ISDIR(st.st_mode))) + { + do_copydir = false; + ereport(WARNING, + (errmsg("source directory \"%s\" for copydir() does not exists." + "It is possibly expected. Skip copydir().", + src_path))); + } /* * Force dirty buffers out to disk, to ensure source database is @@ -2119,7 +2151,8 @@ dbase_redo(XLogReaderState *record) * * We don't need to copy subdirectories */ - copydir(src_path, dst_path, false); + if (do_copydir) + copydir(src_path, dst_path, false); } else if (info == XLOG_DBASE_DROP) { diff --git a/src/backend/commands/tablespace.c b/src/backend/commands/tablespace.c index 8ec963f1cf..798c4586b8 100644 --- a/src/backend/commands/tablespace.c +++ b/src/backend/commands/tablespace.c @@ -154,8 +154,6 @@ TablespaceCreateDbspace(Oid spcNode, Oid dbNode, bool isRedo) /* Directory creation failed? */ if (MakePGDirectory(dir) < 0) { - char *parentdir; - /* Failure other than not exists or not in WAL replay? */ if (errno != ENOENT || !isRedo) ereport(ERROR, @@ -168,32 +166,8 @@ TablespaceCreateDbspace(Oid spcNode, Oid dbNode, bool isRedo) * continue by creating simple parent directories rather * than a symlink. */ - - /* create two parents up if not exist */ - parentdir = pstrdup(dir); - get_parent_directory(parentdir); - get_parent_directory(parentdir); - /* Can't create parent and it doesn't already exist? */ - if (MakePGDirectory(parentdir) < 0 && errno != EEXIST) - ereport(ERROR, - (errcode_for_file_access(), - errmsg("could not create directory \"%s\": %m", - parentdir))); - pfree(parentdir); - - /* create one parent up if not exist */ - parentdir = pstrdup(dir); - get_parent_directory(parentdir); - /* Can't create parent and it doesn't already exist? */ - if (MakePGDirectory(parentdir) < 0 && errno != EEXIST) - ereport(ERROR, - (errcode_for_file_access(), - errmsg("could not create directory \"%s\": %m", - parentdir))); - pfree(parentdir); - /* Create database directory */ - if (MakePGDirectory(dir) < 0) + if (pg_mkdir_p(dir, pg_dir_create_mode) < 0) ereport(ERROR, (errcode_for_file_access(), errmsg("could not create directory \"%s\": %m", -- 2.17.2