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