PostgreSQL Source Code  git master
fileset.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * fileset.c
4  * Management of named temporary files.
5  *
6  * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  * IDENTIFICATION
10  * src/backend/storage/file/fileset.c
11  *
12  * FileSets provide a temporary namespace (think directory) so that files can
13  * be discovered by name.
14  *
15  * FileSets can be used by backends when the temporary files need to be
16  * opened/closed multiple times and the underlying files need to survive across
17  * transactions.
18  *
19  *-------------------------------------------------------------------------
20  */
21 
22 #include "postgres.h"
23 
24 #include <limits.h>
25 
26 #include "catalog/pg_tablespace.h"
27 #include "commands/tablespace.h"
28 #include "common/hashfn.h"
29 #include "miscadmin.h"
30 #include "storage/ipc.h"
31 #include "storage/fileset.h"
32 #include "utils/builtins.h"
33 
34 static void FileSetPath(char *path, FileSet *fileset, Oid tablespace);
35 static void FilePath(char *path, FileSet *fileset, const char *name);
36 static Oid ChooseTablespace(const FileSet *fileset, const char *name);
37 
38 /*
39  * Initialize a space for temporary files. This API can be used by shared
40  * fileset as well as if the temporary files are used only by single backend
41  * but the files need to be opened and closed multiple times and also the
42  * underlying files need to survive across transactions.
43  *
44  * The callers are expected to explicitly remove such files by using
45  * FileSetDelete/FileSetDeleteAll.
46  *
47  * Files will be distributed over the tablespaces configured in
48  * temp_tablespaces.
49  *
50  * Under the covers the set is one or more directories which will eventually
51  * be deleted.
52  */
53 void
55 {
56  static uint32 counter = 0;
57 
58  fileset->creator_pid = MyProcPid;
59  fileset->number = counter;
60  counter = (counter + 1) % INT_MAX;
61 
62  /* Capture the tablespace OIDs so that all backends agree on them. */
64  fileset->ntablespaces =
65  GetTempTablespaces(&fileset->tablespaces[0],
66  lengthof(fileset->tablespaces));
67  if (fileset->ntablespaces == 0)
68  {
69  /* If the GUC is empty, use current database's default tablespace */
70  fileset->tablespaces[0] = MyDatabaseTableSpace;
71  fileset->ntablespaces = 1;
72  }
73  else
74  {
75  int i;
76 
77  /*
78  * An entry of InvalidOid means use the default tablespace for the
79  * current database. Replace that now, to be sure that all users of
80  * the FileSet agree on what to do.
81  */
82  for (i = 0; i < fileset->ntablespaces; i++)
83  {
84  if (fileset->tablespaces[i] == InvalidOid)
86  }
87  }
88 }
89 
90 /*
91  * Create a new file in the given set.
92  */
93 File
94 FileSetCreate(FileSet *fileset, const char *name)
95 {
96  char path[MAXPGPATH];
97  File file;
98 
99  FilePath(path, fileset, name);
100  file = PathNameCreateTemporaryFile(path, false);
101 
102  /* If we failed, see if we need to create the directory on demand. */
103  if (file <= 0)
104  {
105  char tempdirpath[MAXPGPATH];
106  char filesetpath[MAXPGPATH];
107  Oid tablespace = ChooseTablespace(fileset, name);
108 
109  TempTablespacePath(tempdirpath, tablespace);
110  FileSetPath(filesetpath, fileset, tablespace);
111  PathNameCreateTemporaryDir(tempdirpath, filesetpath);
112  file = PathNameCreateTemporaryFile(path, true);
113  }
114 
115  return file;
116 }
117 
118 /*
119  * Open a file that was created with FileSetCreate() */
120 File
121 FileSetOpen(FileSet *fileset, const char *name, int mode)
122 {
123  char path[MAXPGPATH];
124  File file;
125 
126  FilePath(path, fileset, name);
127  file = PathNameOpenTemporaryFile(path, mode);
128 
129  return file;
130 }
131 
132 /*
133  * Delete a file that was created with FileSetCreate().
134  *
135  * Return true if the file existed, false if didn't.
136  */
137 bool
138 FileSetDelete(FileSet *fileset, const char *name,
139  bool error_on_failure)
140 {
141  char path[MAXPGPATH];
142 
143  FilePath(path, fileset, name);
144 
145  return PathNameDeleteTemporaryFile(path, error_on_failure);
146 }
147 
148 /*
149  * Delete all files in the set.
150  */
151 void
153 {
154  char dirpath[MAXPGPATH];
155  int i;
156 
157  /*
158  * Delete the directory we created in each tablespace. Doesn't fail
159  * because we use this in error cleanup paths, but can generate LOG
160  * message on IO error.
161  */
162  for (i = 0; i < fileset->ntablespaces; ++i)
163  {
164  FileSetPath(dirpath, fileset, fileset->tablespaces[i]);
166  }
167 }
168 
169 /*
170  * Build the path for the directory holding the files backing a FileSet in a
171  * given tablespace.
172  */
173 static void
174 FileSetPath(char *path, FileSet *fileset, Oid tablespace)
175 {
176  char tempdirpath[MAXPGPATH];
177 
178  TempTablespacePath(tempdirpath, tablespace);
179  snprintf(path, MAXPGPATH, "%s/%s%lu.%u.fileset",
180  tempdirpath, PG_TEMP_FILE_PREFIX,
181  (unsigned long) fileset->creator_pid, fileset->number);
182 }
183 
184 /*
185  * Sorting has to determine which tablespace a given temporary file belongs in.
186  */
187 static Oid
188 ChooseTablespace(const FileSet *fileset, const char *name)
189 {
190  uint32 hash = hash_any((const unsigned char *) name, strlen(name));
191 
192  return fileset->tablespaces[hash % fileset->ntablespaces];
193 }
194 
195 /*
196  * Compute the full path of a file in a FileSet.
197  */
198 static void
199 FilePath(char *path, FileSet *fileset, const char *name)
200 {
201  char dirpath[MAXPGPATH];
202 
203  FileSetPath(dirpath, fileset, ChooseTablespace(fileset, name));
204  snprintf(path, MAXPGPATH, "%s/%s", dirpath, name);
205 }
void PrepareTempTablespaces(void)
Definition: tablespace.c:1337
unsigned int uint32
Definition: c.h:490
#define lengthof(array)
Definition: c.h:772
const char * name
Definition: encode.c:571
int GetTempTablespaces(Oid *tableSpaces, int numSpaces)
Definition: fd.c:2990
File PathNameOpenTemporaryFile(const char *path, int mode)
Definition: fd.c:1812
File PathNameCreateTemporaryFile(const char *path, bool error_on_failure)
Definition: fd.c:1772
void PathNameDeleteTemporaryDir(const char *dirname)
Definition: fd.c:1602
bool PathNameDeleteTemporaryFile(const char *path, bool error_on_failure)
Definition: fd.c:1843
void PathNameCreateTemporaryDir(const char *basedir, const char *directory)
Definition: fd.c:1571
void TempTablespacePath(char *path, Oid tablespace)
Definition: fd.c:1690
int File
Definition: fd.h:55
File FileSetOpen(FileSet *fileset, const char *name, int mode)
Definition: fileset.c:121
bool FileSetDelete(FileSet *fileset, const char *name, bool error_on_failure)
Definition: fileset.c:138
static void FilePath(char *path, FileSet *fileset, const char *name)
Definition: fileset.c:199
void FileSetInit(FileSet *fileset)
Definition: fileset.c:54
void FileSetDeleteAll(FileSet *fileset)
Definition: fileset.c:152
static void FileSetPath(char *path, FileSet *fileset, Oid tablespace)
Definition: fileset.c:174
static Oid ChooseTablespace(const FileSet *fileset, const char *name)
Definition: fileset.c:188
File FileSetCreate(FileSet *fileset, const char *name)
Definition: fileset.c:94
int MyProcPid
Definition: globals.c:44
Oid MyDatabaseTableSpace
Definition: globals.c:91
static Datum hash_any(const unsigned char *k, int keylen)
Definition: hashfn.h:31
int i
Definition: isn.c:73
static PgChecksumMode mode
Definition: pg_checksums.c:65
#define PG_TEMP_FILE_PREFIX
Definition: pg_checksums.c:63
#define MAXPGPATH
char * tablespace
Definition: pgbench.c:226
#define snprintf
Definition: port.h:238
#define InvalidOid
Definition: postgres_ext.h:36
unsigned int Oid
Definition: postgres_ext.h:31
static unsigned hash(unsigned *uv, int n)
Definition: rege_dfa.c:715
Oid tablespaces[8]
Definition: fileset.h:27
pid_t creator_pid
Definition: fileset.h:24
uint32 number
Definition: fileset.h:25
int ntablespaces
Definition: fileset.h:26