aboutsummaryrefslogtreecommitdiff
path: root/src/backend/storage/file/fd.c
diff options
context:
space:
mode:
authorRobert Haas <rhaas@postgresql.org>2010-08-13 20:10:54 +0000
committerRobert Haas <rhaas@postgresql.org>2010-08-13 20:10:54 +0000
commitdebcec7dc31a992703911a9953e299c8d730c778 (patch)
treedad0d10ec39eafe0cc254c17e36eb82ec822cdac /src/backend/storage/file/fd.c
parent3f9479ef3fdf49fc22088be5268fa536cf5d4efd (diff)
downloadpostgresql-debcec7dc31a992703911a9953e299c8d730c778.tar.gz
postgresql-debcec7dc31a992703911a9953e299c8d730c778.zip
Include the backend ID in the relpath of temporary relations.
This allows us to reliably remove all leftover temporary relation files on cluster startup without reference to system catalogs or WAL; therefore, we no longer include temporary relations in XLOG_XACT_COMMIT and XLOG_XACT_ABORT WAL records. Since these changes require including a backend ID in each SharedInvalSmgrMsg, the size of the SharedInvalidationMessage.id field has been reduced from two bytes to one, and the maximum number of connections has been reduced from INT_MAX / 4 to 2^23-1. It would be possible to remove these restrictions by increasing the size of SharedInvalidationMessage by 4 bytes, but right now that doesn't seem like a good trade-off. Review by Jaime Casanova and Tom Lane.
Diffstat (limited to 'src/backend/storage/file/fd.c')
-rw-r--r--src/backend/storage/file/fd.c136
1 files changed, 133 insertions, 3 deletions
diff --git a/src/backend/storage/file/fd.c b/src/backend/storage/file/fd.c
index 91bf4af8e4d..18d6de1dec7 100644
--- a/src/backend/storage/file/fd.c
+++ b/src/backend/storage/file/fd.c
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/storage/file/fd.c,v 1.157 2010/07/06 22:55:26 rhaas Exp $
+ * $PostgreSQL: pgsql/src/backend/storage/file/fd.c,v 1.158 2010/08/13 20:10:52 rhaas Exp $
*
* NOTES:
*
@@ -249,6 +249,9 @@ static File OpenTemporaryFileInTablespace(Oid tblspcOid, bool rejectError);
static void AtProcExit_Files(int code, Datum arg);
static void CleanupTempFiles(bool isProcExit);
static void RemovePgTempFilesInDir(const char *tmpdirname);
+static void RemovePgTempRelationFiles(const char *tsdirname);
+static void RemovePgTempRelationFilesInDbspace(const char *dbspacedirname);
+static bool looks_like_temp_rel_name(const char *name);
/*
@@ -1824,10 +1827,12 @@ CleanupTempFiles(bool isProcExit)
/*
- * Remove temporary files left over from a prior postmaster session
+ * Remove temporary and temporary relation files left over from a prior
+ * postmaster session
*
* This should be called during postmaster startup. It will forcibly
- * remove any leftover files created by OpenTemporaryFile.
+ * remove any leftover files created by OpenTemporaryFile and any leftover
+ * temporary relation files created by mdcreate.
*
* NOTE: we could, but don't, call this during a post-backend-crash restart
* cycle. The argument for not doing it is that someone might want to examine
@@ -1847,6 +1852,7 @@ RemovePgTempFiles(void)
*/
snprintf(temp_path, sizeof(temp_path), "base/%s", PG_TEMP_FILES_DIR);
RemovePgTempFilesInDir(temp_path);
+ RemovePgTempRelationFiles("base");
/*
* Cycle through temp directories for all non-default tablespaces.
@@ -1862,6 +1868,10 @@ RemovePgTempFiles(void)
snprintf(temp_path, sizeof(temp_path), "pg_tblspc/%s/%s/%s",
spc_de->d_name, TABLESPACE_VERSION_DIRECTORY, PG_TEMP_FILES_DIR);
RemovePgTempFilesInDir(temp_path);
+
+ snprintf(temp_path, sizeof(temp_path), "pg_tblspc/%s/%s",
+ spc_de->d_name, TABLESPACE_VERSION_DIRECTORY);
+ RemovePgTempRelationFiles(temp_path);
}
FreeDir(spc_dir);
@@ -1915,3 +1925,123 @@ RemovePgTempFilesInDir(const char *tmpdirname)
FreeDir(temp_dir);
}
+
+/* Process one tablespace directory, look for per-DB subdirectories */
+static void
+RemovePgTempRelationFiles(const char *tsdirname)
+{
+ DIR *ts_dir;
+ struct dirent *de;
+ char dbspace_path[MAXPGPATH];
+
+ ts_dir = AllocateDir(tsdirname);
+ if (ts_dir == NULL)
+ {
+ /* anything except ENOENT is fishy */
+ if (errno != ENOENT)
+ elog(LOG,
+ "could not open tablespace directory \"%s\": %m",
+ tsdirname);
+ return;
+ }
+
+ while ((de = ReadDir(ts_dir, tsdirname)) != NULL)
+ {
+ int i = 0;
+
+ /*
+ * We're only interested in the per-database directories, which have
+ * numeric names. Note that this code will also (properly) ignore "."
+ * and "..".
+ */
+ while (isdigit((unsigned char) de->d_name[i]))
+ ++i;
+ if (de->d_name[i] != '\0' || i == 0)
+ continue;
+
+ snprintf(dbspace_path, sizeof(dbspace_path), "%s/%s",
+ tsdirname, de->d_name);
+ RemovePgTempRelationFilesInDbspace(dbspace_path);
+ }
+
+ FreeDir(ts_dir);
+}
+
+/* Process one per-dbspace directory for RemovePgTempRelationFiles */
+static void
+RemovePgTempRelationFilesInDbspace(const char *dbspacedirname)
+{
+ DIR *dbspace_dir;
+ struct dirent *de;
+ char rm_path[MAXPGPATH];
+
+ dbspace_dir = AllocateDir(dbspacedirname);
+ if (dbspace_dir == NULL)
+ {
+ /* we just saw this directory, so it really ought to be there */
+ elog(LOG,
+ "could not open dbspace directory \"%s\": %m",
+ dbspacedirname);
+ return;
+ }
+
+ while ((de = ReadDir(dbspace_dir, dbspacedirname)) != NULL)
+ {
+ if (!looks_like_temp_rel_name(de->d_name))
+ continue;
+
+ snprintf(rm_path, sizeof(rm_path), "%s/%s",
+ dbspacedirname, de->d_name);
+
+ unlink(rm_path); /* note we ignore any error */
+ }
+
+ FreeDir(dbspace_dir);
+}
+
+/* t<digits>_<digits>, or t<digits>_<digits>_<forkname> */
+static bool
+looks_like_temp_rel_name(const char *name)
+{
+ int pos;
+ int savepos;
+
+ /* Must start with "t". */
+ if (name[0] != 't')
+ return false;
+
+ /* Followed by a non-empty string of digits and then an underscore. */
+ for (pos = 1; isdigit((unsigned char) name[pos]); ++pos)
+ ;
+ if (pos == 1 || name[pos] != '_')
+ return false;
+
+ /* Followed by another nonempty string of digits. */
+ for (savepos = ++pos; isdigit((unsigned char) name[pos]); ++pos)
+ ;
+ if (savepos == pos)
+ return false;
+
+ /* We might have _forkname or .segment or both. */
+ if (name[pos] == '_')
+ {
+ int forkchar = forkname_chars(&name[pos+1]);
+ if (forkchar <= 0)
+ return false;
+ pos += forkchar + 1;
+ }
+ if (name[pos] == '.')
+ {
+ int segchar;
+ for (segchar = 1; isdigit((unsigned char) name[pos+segchar]); ++segchar)
+ ;
+ if (segchar <= 1)
+ return false;
+ pos += segchar;
+ }
+
+ /* Now we should be at the end. */
+ if (name[pos] != '\0')
+ return false;
+ return true;
+}