From 207a44d8baa210a1b6baa07db8867a226200edc4 Mon Sep 17 00:00:00 2001 From: Andres Freund Date: Mon, 21 Feb 2022 16:42:16 -0800 Subject: [PATCH v3 2/4] Fix old-fd issues using global barriers everywhere. Commit 4eb21763 (and later improvement XXX) introduce a way to force every backend to closed all relation files, to fix a long-standing Windows-only problems. This commit extends that behavior to all operating systems, to handle a totaly different class of problem: the reuse of relfilenodes in scenarios that have no other kind of cache invalidation to prevent file descriptor mix-ups. In all releases, the problem could happen when you moved a database to another tablespace and then back again. In 15, since commit aa010514, it could happen when using CREATE DATABASE with a user-supplied OID, particularly as part of pg_upgrade. Author: Andres Freund Discussion: https://postgr.es/m/20220209220004.kb3dgtn2x2k2gtdm%40alap3.anarazel.de --- src/backend/commands/dbcommands.c | 6 ------ src/backend/commands/tablespace.c | 11 ++++------- src/include/pg_config_manual.h | 11 ----------- 3 files changed, 4 insertions(+), 24 deletions(-) diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c index 1bbecfeddf..1171d2b91a 100644 --- a/src/backend/commands/dbcommands.c +++ b/src/backend/commands/dbcommands.c @@ -1683,10 +1683,8 @@ dropdb(const char *dbname, bool missing_ok, bool force) */ RequestCheckpoint(CHECKPOINT_IMMEDIATE | CHECKPOINT_FORCE | CHECKPOINT_WAIT); -#if defined(USE_BARRIER_SMGRRELEASE) /* Close all smgr fds in all backends. */ WaitForProcSignalBarrier(EmitProcSignalBarrier(PROCSIGNAL_BARRIER_SMGRRELEASE)); -#endif /* * Remove all tablespace subdirs belonging to the database. @@ -1936,10 +1934,8 @@ movedb(const char *dbname, const char *tblspcname) RequestCheckpoint(CHECKPOINT_IMMEDIATE | CHECKPOINT_FORCE | CHECKPOINT_WAIT | CHECKPOINT_FLUSH_ALL); -#if defined(USE_BARRIER_SMGRRELEASE) /* Close all smgr fds in all backends. */ WaitForProcSignalBarrier(EmitProcSignalBarrier(PROCSIGNAL_BARRIER_SMGRRELEASE)); -#endif /* * Now drop all buffers holding data of the target database; they should @@ -3098,10 +3094,8 @@ dbase_redo(XLogReaderState *record) /* Clean out the xlog relcache too */ XLogDropDatabase(xlrec->db_id); -#if defined(USE_BARRIER_SMGRRELEASE) /* Close all sgmr fds in all backends. */ WaitForProcSignalBarrier(EmitProcSignalBarrier(PROCSIGNAL_BARRIER_SMGRRELEASE)); -#endif for (i = 0; i < xlrec->ntablespaces; i++) { diff --git a/src/backend/commands/tablespace.c b/src/backend/commands/tablespace.c index 40514ab550..822d65287e 100644 --- a/src/backend/commands/tablespace.c +++ b/src/backend/commands/tablespace.c @@ -548,11 +548,10 @@ DropTableSpace(DropTableSpaceStmt *stmt) * use a global barrier to ask all backends to close all files, and * wait until they're finished. */ -#if defined(USE_BARRIER_SMGRRELEASE) LWLockRelease(TablespaceCreateLock); WaitForProcSignalBarrier(EmitProcSignalBarrier(PROCSIGNAL_BARRIER_SMGRRELEASE)); LWLockAcquire(TablespaceCreateLock, LW_EXCLUSIVE); -#endif + /* And now try again. */ if (!destroy_tablespace_directories(tablespaceoid, false)) { @@ -1574,6 +1573,9 @@ tblspc_redo(XLogReaderState *record) { xl_tblspc_drop_rec *xlrec = (xl_tblspc_drop_rec *) XLogRecGetData(record); + /* Close all smgr fds in all backends. */ + WaitForProcSignalBarrier(EmitProcSignalBarrier(PROCSIGNAL_BARRIER_SMGRRELEASE)); + /* * If we issued a WAL record for a drop tablespace it implies that * there were no files in it at all when the DROP was done. That means @@ -1591,11 +1593,6 @@ tblspc_redo(XLogReaderState *record) */ if (!destroy_tablespace_directories(xlrec->ts_id, true)) { -#if defined(USE_BARRIER_SMGRRELEASE) - /* Close all smgr fds in all backends. */ - WaitForProcSignalBarrier(EmitProcSignalBarrier(PROCSIGNAL_BARRIER_SMGRRELEASE)); -#endif - ResolveRecoveryConflictWithTablespace(xlrec->ts_id); /* diff --git a/src/include/pg_config_manual.h b/src/include/pg_config_manual.h index 84ce5a4a5d..8d2e3e3a57 100644 --- a/src/include/pg_config_manual.h +++ b/src/include/pg_config_manual.h @@ -152,17 +152,6 @@ #define EXEC_BACKEND #endif -/* - * If USE_BARRIER_SMGRRELEASE is defined, certain code paths that unlink - * directories will ask other backends to close all smgr file descriptors. - * This is enabled on Windows, because otherwise unlinked but still open files - * can prevent rmdir(containing_directory) from succeeding. On other - * platforms, it can be defined to exercise those code paths. - */ -#if defined(WIN32) -#define USE_BARRIER_SMGRRELEASE -#endif - /* * Define this if your operating system supports link() */ -- 2.35.1