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-2024, 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
958 akapila@postgresql.o 52 :CBC 180 : FileSetInit(FileSet *fileset)
53 : : {
54 : : static uint32 counter = 0;
55 : :
56 : 180 : fileset->creator_pid = MyProcPid;
57 : 180 : fileset->number = counter;
58 : 180 : counter = (counter + 1) % INT_MAX;
59 : :
60 : : /* Capture the tablespace OIDs so that all backends agree on them. */
61 : 180 : PrepareTempTablespaces();
62 : 180 : fileset->ntablespaces =
63 : 180 : GetTempTablespaces(&fileset->tablespaces[0],
64 : : lengthof(fileset->tablespaces));
65 [ + - ]: 180 : if (fileset->ntablespaces == 0)
66 : : {
67 : : /* If the GUC is empty, use current database's default tablespace */
68 : 180 : fileset->tablespaces[0] = MyDatabaseTableSpace;
69 : 180 : 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 : : */
958 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 : : }
958 akapila@postgresql.o 86 :CBC 180 : }
87 : :
88 : : /*
89 : : * Create a new file in the given set.
90 : : */
91 : : File
92 : 1872 : FileSetCreate(FileSet *fileset, const char *name)
93 : : {
94 : : char path[MAXPGPATH];
95 : : File file;
96 : :
97 : 1872 : FilePath(path, fileset, name);
98 : 1872 : file = PathNameCreateTemporaryFile(path, false);
99 : :
100 : : /* If we failed, see if we need to create the directory on demand. */
101 [ + + ]: 1871 : if (file <= 0)
102 : : {
103 : : char tempdirpath[MAXPGPATH];
104 : : char filesetpath[MAXPGPATH];
105 : 172 : Oid tablespace = ChooseTablespace(fileset, name);
106 : :
107 : 172 : TempTablespacePath(tempdirpath, tablespace);
108 : 172 : FileSetPath(filesetpath, fileset, tablespace);
109 : 172 : PathNameCreateTemporaryDir(tempdirpath, filesetpath);
110 : 172 : file = PathNameCreateTemporaryFile(path, true);
111 : : }
112 : :
113 : 1871 : return file;
114 : : }
115 : :
116 : : /*
117 : : * Open a file that was created with FileSetCreate() */
118 : : File
119 : 4975 : FileSetOpen(FileSet *fileset, const char *name, int mode)
120 : : {
121 : : char path[MAXPGPATH];
122 : : File file;
123 : :
124 : 4975 : FilePath(path, fileset, name);
125 : 4975 : file = PathNameOpenTemporaryFile(path, mode);
126 : :
127 : 4975 : return file;
128 : : }
129 : :
130 : : /*
131 : : * Delete a file that was created with FileSetCreate().
132 : : *
133 : : * Return true if the file existed, false if didn't.
134 : : */
135 : : bool
136 : 2295 : FileSetDelete(FileSet *fileset, const char *name,
137 : : bool error_on_failure)
138 : : {
139 : : char path[MAXPGPATH];
140 : :
141 : 2295 : FilePath(path, fileset, name);
142 : :
143 : 2295 : return PathNameDeleteTemporaryFile(path, error_on_failure);
144 : : }
145 : :
146 : : /*
147 : : * Delete all files in the set.
148 : : */
149 : : void
150 : 203 : FileSetDeleteAll(FileSet *fileset)
151 : : {
152 : : char dirpath[MAXPGPATH];
153 : : int i;
154 : :
155 : : /*
156 : : * Delete the directory we created in each tablespace. Doesn't fail
157 : : * because we use this in error cleanup paths, but can generate LOG
158 : : * message on IO error.
159 : : */
160 [ + + ]: 406 : for (i = 0; i < fileset->ntablespaces; ++i)
161 : : {
162 : 203 : FileSetPath(dirpath, fileset, fileset->tablespaces[i]);
163 : 203 : PathNameDeleteTemporaryDir(dirpath);
164 : : }
165 : 203 : }
166 : :
167 : : /*
168 : : * Build the path for the directory holding the files backing a FileSet in a
169 : : * given tablespace.
170 : : */
171 : : static void
172 : 9517 : FileSetPath(char *path, FileSet *fileset, Oid tablespace)
173 : : {
174 : : char tempdirpath[MAXPGPATH];
175 : :
176 : 9517 : TempTablespacePath(tempdirpath, tablespace);
177 : 9517 : snprintf(path, MAXPGPATH, "%s/%s%lu.%u.fileset",
178 : : tempdirpath, PG_TEMP_FILE_PREFIX,
179 : 9517 : (unsigned long) fileset->creator_pid, fileset->number);
180 : 9517 : }
181 : :
182 : : /*
183 : : * Sorting has to determine which tablespace a given temporary file belongs in.
184 : : */
185 : : static Oid
186 : 9314 : ChooseTablespace(const FileSet *fileset, const char *name)
187 : : {
188 : 9314 : uint32 hash = hash_any((const unsigned char *) name, strlen(name));
189 : :
190 : 9314 : return fileset->tablespaces[hash % fileset->ntablespaces];
191 : : }
192 : :
193 : : /*
194 : : * Compute the full path of a file in a FileSet.
195 : : */
196 : : static void
197 : 9142 : FilePath(char *path, FileSet *fileset, const char *name)
198 : : {
199 : : char dirpath[MAXPGPATH];
200 : :
201 : 9142 : FileSetPath(dirpath, fileset, ChooseTablespace(fileset, name));
202 : 9142 : snprintf(path, MAXPGPATH, "%s/%s", dirpath, name);
203 : 9142 : }
|