LCOV - code coverage report
Current view: top level - src/backend/storage/file - fileset.c (source / functions) Hit Total Coverage
Test: PostgreSQL 19devel Lines: 45 48 93.8 %
Date: 2025-12-12 10:19:18 Functions: 8 8 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.16