Age Owner TLA Line data Source code
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
587 akapila 54 CBC 174 : FileSetInit(FileSet *fileset)
55 : {
56 : static uint32 counter = 0;
57 :
58 174 : fileset->creator_pid = MyProcPid;
59 174 : fileset->number = counter;
60 174 : counter = (counter + 1) % INT_MAX;
61 :
62 : /* Capture the tablespace OIDs so that all backends agree on them. */
63 174 : PrepareTempTablespaces();
64 174 : fileset->ntablespaces =
65 174 : GetTempTablespaces(&fileset->tablespaces[0],
66 : lengthof(fileset->tablespaces));
67 174 : if (fileset->ntablespaces == 0)
68 : {
69 : /* If the GUC is empty, use current database's default tablespace */
70 174 : fileset->tablespaces[0] = MyDatabaseTableSpace;
71 174 : 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 : */
587 akapila 82 UBC 0 : for (i = 0; i < fileset->ntablespaces; i++)
83 : {
84 0 : if (fileset->tablespaces[i] == InvalidOid)
85 0 : fileset->tablespaces[i] = MyDatabaseTableSpace;
86 : }
87 : }
587 akapila 88 CBC 174 : }
89 :
90 : /*
91 : * Create a new file in the given set.
92 : */
93 : File
94 1439 : FileSetCreate(FileSet *fileset, const char *name)
95 : {
96 : char path[MAXPGPATH];
97 : File file;
98 :
99 1439 : FilePath(path, fileset, name);
100 1439 : file = PathNameCreateTemporaryFile(path, false);
101 :
102 : /* If we failed, see if we need to create the directory on demand. */
103 1439 : if (file <= 0)
104 : {
105 : char tempdirpath[MAXPGPATH];
106 : char filesetpath[MAXPGPATH];
107 171 : Oid tablespace = ChooseTablespace(fileset, name);
108 :
109 171 : TempTablespacePath(tempdirpath, tablespace);
110 171 : FileSetPath(filesetpath, fileset, tablespace);
111 171 : PathNameCreateTemporaryDir(tempdirpath, filesetpath);
112 171 : file = PathNameCreateTemporaryFile(path, true);
113 : }
114 :
115 1439 : return file;
116 : }
117 :
118 : /*
119 : * Open a file that was created with FileSetCreate() */
120 : File
121 4059 : FileSetOpen(FileSet *fileset, const char *name, int mode)
122 : {
123 : char path[MAXPGPATH];
124 : File file;
125 :
126 4059 : FilePath(path, fileset, name);
127 4059 : file = PathNameOpenTemporaryFile(path, mode);
128 :
129 4059 : 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 1828 : FileSetDelete(FileSet *fileset, const char *name,
139 : bool error_on_failure)
140 : {
141 : char path[MAXPGPATH];
142 :
143 1828 : FilePath(path, fileset, name);
144 :
145 1828 : return PathNameDeleteTemporaryFile(path, error_on_failure);
146 : }
147 :
148 : /*
149 : * Delete all files in the set.
150 : */
151 : void
152 198 : FileSetDeleteAll(FileSet *fileset)
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 396 : for (i = 0; i < fileset->ntablespaces; ++i)
163 : {
164 198 : FileSetPath(dirpath, fileset, fileset->tablespaces[i]);
165 198 : PathNameDeleteTemporaryDir(dirpath);
166 : }
167 198 : }
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 7695 : FileSetPath(char *path, FileSet *fileset, Oid tablespace)
175 : {
176 : char tempdirpath[MAXPGPATH];
177 :
178 7695 : TempTablespacePath(tempdirpath, tablespace);
179 7695 : snprintf(path, MAXPGPATH, "%s/%s%lu.%u.fileset",
180 : tempdirpath, PG_TEMP_FILE_PREFIX,
181 7695 : (unsigned long) fileset->creator_pid, fileset->number);
182 7695 : }
183 :
184 : /*
185 : * Sorting has to determine which tablespace a given temporary file belongs in.
186 : */
187 : static Oid
188 7497 : ChooseTablespace(const FileSet *fileset, const char *name)
189 : {
190 7497 : uint32 hash = hash_any((const unsigned char *) name, strlen(name));
191 :
192 7497 : 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 7326 : FilePath(char *path, FileSet *fileset, const char *name)
200 : {
201 : char dirpath[MAXPGPATH];
202 :
203 7326 : FileSetPath(dirpath, fileset, ChooseTablespace(fileset, name));
204 7326 : snprintf(path, MAXPGPATH, "%s/%s", dirpath, name);
205 7326 : }
|