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/file_utils.h"
29 #include "common/hashfn.h"
30 #include "miscadmin.h"
31 #include "storage/ipc.h"
32 #include "storage/fileset.h"
33 #include "utils/builtins.h"
34 
35 static void FileSetPath(char *path, FileSet *fileset, Oid tablespace);
36 static void FilePath(char *path, FileSet *fileset, const char *name);
37 static Oid ChooseTablespace(const FileSet *fileset, const char *name);
38 
39 /*
40  * Initialize a space for temporary files. This API can be used by shared
41  * fileset as well as if the temporary files are used only by single backend
42  * but the files need to be opened and closed multiple times and also the
43  * underlying files need to survive across transactions.
44  *
45  * The callers are expected to explicitly remove such files by using
46  * FileSetDelete/FileSetDeleteAll.
47  *
48  * Files will be distributed over the tablespaces configured in
49  * temp_tablespaces.
50  *
51  * Under the covers the set is one or more directories which will eventually
52  * be deleted.
53  */
54 void
56 {
57  static uint32 counter = 0;
58 
59  fileset->creator_pid = MyProcPid;
60  fileset->number = counter;
61  counter = (counter + 1) % INT_MAX;
62 
63  /* Capture the tablespace OIDs so that all backends agree on them. */
65  fileset->ntablespaces =
66  GetTempTablespaces(&fileset->tablespaces[0],
67  lengthof(fileset->tablespaces));
68  if (fileset->ntablespaces == 0)
69  {
70  /* If the GUC is empty, use current database's default tablespace */
71  fileset->tablespaces[0] = MyDatabaseTableSpace;
72  fileset->ntablespaces = 1;
73  }
74  else
75  {
76  int i;
77 
78  /*
79  * An entry of InvalidOid means use the default tablespace for the
80  * current database. Replace that now, to be sure that all users of
81  * the FileSet agree on what to do.
82  */
83  for (i = 0; i < fileset->ntablespaces; i++)
84  {
85  if (fileset->tablespaces[i] == InvalidOid)
87  }
88  }
89 }
90 
91 /*
92  * Create a new file in the given set.
93  */
94 File
95 FileSetCreate(FileSet *fileset, const char *name)
96 {
97  char path[MAXPGPATH];
98  File file;
99 
100  FilePath(path, fileset, name);
101  file = PathNameCreateTemporaryFile(path, false);
102 
103  /* If we failed, see if we need to create the directory on demand. */
104  if (file <= 0)
105  {
106  char tempdirpath[MAXPGPATH];
107  char filesetpath[MAXPGPATH];
108  Oid tablespace = ChooseTablespace(fileset, name);
109 
110  TempTablespacePath(tempdirpath, tablespace);
111  FileSetPath(filesetpath, fileset, tablespace);
112  PathNameCreateTemporaryDir(tempdirpath, filesetpath);
113  file = PathNameCreateTemporaryFile(path, true);
114  }
115 
116  return file;
117 }
118 
119 /*
120  * Open a file that was created with FileSetCreate() */
121 File
122 FileSetOpen(FileSet *fileset, const char *name, int mode)
123 {
124  char path[MAXPGPATH];
125  File file;
126 
127  FilePath(path, fileset, name);
128  file = PathNameOpenTemporaryFile(path, mode);
129 
130  return file;
131 }
132 
133 /*
134  * Delete a file that was created with FileSetCreate().
135  *
136  * Return true if the file existed, false if didn't.
137  */
138 bool
139 FileSetDelete(FileSet *fileset, const char *name,
140  bool error_on_failure)
141 {
142  char path[MAXPGPATH];
143 
144  FilePath(path, fileset, name);
145 
146  return PathNameDeleteTemporaryFile(path, error_on_failure);
147 }
148 
149 /*
150  * Delete all files in the set.
151  */
152 void
154 {
155  char dirpath[MAXPGPATH];
156  int i;
157 
158  /*
159  * Delete the directory we created in each tablespace. Doesn't fail
160  * because we use this in error cleanup paths, but can generate LOG
161  * message on IO error.
162  */
163  for (i = 0; i < fileset->ntablespaces; ++i)
164  {
165  FileSetPath(dirpath, fileset, fileset->tablespaces[i]);
167  }
168 }
169 
170 /*
171  * Build the path for the directory holding the files backing a FileSet in a
172  * given tablespace.
173  */
174 static void
175 FileSetPath(char *path, FileSet *fileset, Oid tablespace)
176 {
177  char tempdirpath[MAXPGPATH];
178 
179  TempTablespacePath(tempdirpath, tablespace);
180  snprintf(path, MAXPGPATH, "%s/%s%lu.%u.fileset",
181  tempdirpath, PG_TEMP_FILE_PREFIX,
182  (unsigned long) fileset->creator_pid, fileset->number);
183 }
184 
185 /*
186  * Sorting has to determine which tablespace a given temporary file belongs in.
187  */
188 static Oid
189 ChooseTablespace(const FileSet *fileset, const char *name)
190 {
191  uint32 hash = hash_any((const unsigned char *) name, strlen(name));
192 
193  return fileset->tablespaces[hash % fileset->ntablespaces];
194 }
195 
196 /*
197  * Compute the full path of a file in a FileSet.
198  */
199 static void
200 FilePath(char *path, FileSet *fileset, const char *name)
201 {
202  char dirpath[MAXPGPATH];
203 
204  FileSetPath(dirpath, fileset, ChooseTablespace(fileset, name));
205  snprintf(path, MAXPGPATH, "%s/%s", dirpath, name);
206 }
void PrepareTempTablespaces(void)
Definition: tablespace.c:1337
unsigned int uint32
Definition: c.h:495
#define lengthof(array)
Definition: c.h:777
int GetTempTablespaces(Oid *tableSpaces, int numSpaces)
Definition: fd.c:3063
File PathNameOpenTemporaryFile(const char *path, int mode)
Definition: fd.c:1878
File PathNameCreateTemporaryFile(const char *path, bool error_on_failure)
Definition: fd.c:1838
void PathNameDeleteTemporaryDir(const char *dirname)
Definition: fd.c:1668
bool PathNameDeleteTemporaryFile(const char *path, bool error_on_failure)
Definition: fd.c:1909
void PathNameCreateTemporaryDir(const char *basedir, const char *directory)
Definition: fd.c:1637
void TempTablespacePath(char *path, Oid tablespace)
Definition: fd.c:1756
int File
Definition: fd.h:49
#define PG_TEMP_FILE_PREFIX
Definition: file_utils.h:58
File FileSetOpen(FileSet *fileset, const char *name, int mode)
Definition: fileset.c:122
bool FileSetDelete(FileSet *fileset, const char *name, bool error_on_failure)
Definition: fileset.c:139
static void FilePath(char *path, FileSet *fileset, const char *name)
Definition: fileset.c:200
void FileSetInit(FileSet *fileset)
Definition: fileset.c:55
void FileSetDeleteAll(FileSet *fileset)
Definition: fileset.c:153
static void FileSetPath(char *path, FileSet *fileset, Oid tablespace)
Definition: fileset.c:175
static Oid ChooseTablespace(const FileSet *fileset, const char *name)
Definition: fileset.c:189
File FileSetCreate(FileSet *fileset, const char *name)
Definition: fileset.c:95
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:56
#define MAXPGPATH
char * tablespace
Definition: pgbench.c:216
#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
const char * name