Coverage Report

Created: 2026-08-14 06:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/postgres/src/backend/storage/file/fileset.c
Line
Count
Source
1
/*-------------------------------------------------------------------------
2
 *
3
 * fileset.c
4
 *    Management of named temporary files.
5
 *
6
 * Portions Copyright (c) 1996-2026, 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
52
FileSetInit(FileSet *fileset)
53
0
{
54
0
  static uint32 counter = 0;
55
56
0
  fileset->creator_pid = MyProcPid;
57
0
  fileset->number = counter;
58
0
  counter = (counter + 1) % INT_MAX;
59
60
  /* Capture the tablespace OIDs so that all backends agree on them. */
61
0
  PrepareTempTablespaces();
62
0
  fileset->ntablespaces =
63
0
    GetTempTablespaces(&fileset->tablespaces[0],
64
0
               lengthof(fileset->tablespaces));
65
0
  if (fileset->ntablespaces == 0)
66
0
  {
67
    /* If the GUC is empty, use current database's default tablespace */
68
0
    fileset->tablespaces[0] = MyDatabaseTableSpace;
69
0
    fileset->ntablespaces = 1;
70
0
  }
71
0
  else
72
0
  {
73
0
    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
     */
80
0
    for (i = 0; i < fileset->ntablespaces; i++)
81
0
    {
82
0
      if (fileset->tablespaces[i] == InvalidOid)
83
0
        fileset->tablespaces[i] = MyDatabaseTableSpace;
84
0
    }
85
0
  }
86
0
}
87
88
/*
89
 * Create a new file in the given set.
90
 */
91
File
92
FileSetCreate(FileSet *fileset, const char *name)
93
0
{
94
0
  char    path[MAXPGPATH];
95
0
  File    file;
96
97
0
  FilePath(path, fileset, name);
98
0
  file = PathNameCreateTemporaryFile(path, false);
99
100
  /* If we failed, see if we need to create the directory on demand. */
101
0
  if (file <= 0)
102
0
  {
103
0
    char    tempdirpath[MAXPGPATH];
104
0
    char    filesetpath[MAXPGPATH];
105
0
    Oid     tablespace = ChooseTablespace(fileset, name);
106
107
0
    TempTablespacePath(tempdirpath, tablespace);
108
0
    FileSetPath(filesetpath, fileset, tablespace);
109
0
    PathNameCreateTemporaryDir(tempdirpath, filesetpath);
110
0
    file = PathNameCreateTemporaryFile(path, true);
111
0
  }
112
113
0
  return file;
114
0
}
115
116
/*
117
 * Open a file that was created with FileSetCreate()
118
 */
119
File
120
FileSetOpen(FileSet *fileset, const char *name, int mode)
121
0
{
122
0
  char    path[MAXPGPATH];
123
0
  File    file;
124
125
0
  FilePath(path, fileset, name);
126
0
  file = PathNameOpenTemporaryFile(path, mode);
127
128
0
  return file;
129
0
}
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
FileSetDelete(FileSet *fileset, const char *name,
138
        bool error_on_failure)
139
0
{
140
0
  char    path[MAXPGPATH];
141
142
0
  FilePath(path, fileset, name);
143
144
0
  return PathNameDeleteTemporaryFile(path, error_on_failure);
145
0
}
146
147
/*
148
 * Delete all files in the set.
149
 */
150
void
151
FileSetDeleteAll(FileSet *fileset)
152
0
{
153
0
  char    dirpath[MAXPGPATH];
154
0
  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
0
  for (i = 0; i < fileset->ntablespaces; ++i)
162
0
  {
163
0
    FileSetPath(dirpath, fileset, fileset->tablespaces[i]);
164
0
    PathNameDeleteTemporaryDir(dirpath);
165
0
  }
166
0
}
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
FileSetPath(char *path, FileSet *fileset, Oid tablespace)
174
0
{
175
0
  char    tempdirpath[MAXPGPATH];
176
177
0
  TempTablespacePath(tempdirpath, tablespace);
178
0
  snprintf(path, MAXPGPATH, "%s/%s%lu.%u.fileset",
179
0
       tempdirpath, PG_TEMP_FILE_PREFIX,
180
0
       (unsigned long) fileset->creator_pid, fileset->number);
181
0
}
182
183
/*
184
 * Sorting has to determine which tablespace a given temporary file belongs in.
185
 */
186
static Oid
187
ChooseTablespace(const FileSet *fileset, const char *name)
188
0
{
189
0
  uint32    hash = hash_bytes((const unsigned char *) name, strlen(name));
190
191
0
  return fileset->tablespaces[hash % fileset->ntablespaces];
192
0
}
193
194
/*
195
 * Compute the full path of a file in a FileSet.
196
 */
197
static void
198
FilePath(char *path, FileSet *fileset, const char *name)
199
0
{
200
0
  char    dirpath[MAXPGPATH];
201
202
0
  FileSetPath(dirpath, fileset, ChooseTablespace(fileset, name));
203
0
  snprintf(path, MAXPGPATH, "%s/%s", dirpath, name);
204
0
}