LCOV - code coverage report
Current view: top level - src/bin/pg_dump - pg_backup_directory.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 0.0 % 310 0
Test Date: 2026-01-26 10:56:24 Functions: 0.0 % 27 0
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*-------------------------------------------------------------------------
       2              :  *
       3              :  * pg_backup_directory.c
       4              :  *
       5              :  *      A directory format dump is a directory, which contains a "toc.dat" file
       6              :  *      for the TOC, and a separate file for each data entry, named "<oid>.dat".
       7              :  *      Large objects are stored in separate files named "blob_<oid>.dat",
       8              :  *      and there's a plain-text TOC file for each BLOBS TOC entry named
       9              :  *      "blobs_<dumpID>.toc" (or just "blobs.toc" in archive versions before 16).
      10              :  *
      11              :  *      If compression is used, each data file is individually compressed and the
      12              :  *      ".gz" suffix is added to the filenames. The TOC files are never
      13              :  *      compressed by pg_dump, however they are accepted with the .gz suffix too,
      14              :  *      in case the user has manually compressed them with 'gzip'.
      15              :  *
      16              :  *      NOTE: This format is identical to the files written in the tar file in
      17              :  *      the 'tar' format, except that we don't write the restore.sql file (TODO),
      18              :  *      and the tar format doesn't support compression. Please keep the formats in
      19              :  *      sync.
      20              :  *
      21              :  *
      22              :  *      Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
      23              :  *      Portions Copyright (c) 1994, Regents of the University of California
      24              :  *      Portions Copyright (c) 2000, Philip Warner
      25              :  *
      26              :  *      Rights are granted to use this software in any way so long
      27              :  *      as this notice is not removed.
      28              :  *
      29              :  *      The author is not responsible for loss or damages that may
      30              :  *      result from its use.
      31              :  *
      32              :  * IDENTIFICATION
      33              :  *              src/bin/pg_dump/pg_backup_directory.c
      34              :  *
      35              :  *-------------------------------------------------------------------------
      36              :  */
      37              : #include "postgres_fe.h"
      38              : 
      39              : #include <dirent.h>
      40              : #include <sys/stat.h>
      41              : 
      42              : #include "common/file_utils.h"
      43              : #include "compress_io.h"
      44              : #include "dumputils.h"
      45              : #include "parallel.h"
      46              : #include "pg_backup_utils.h"
      47              : 
      48              : typedef struct
      49              : {
      50              :         /*
      51              :          * Our archive location. This is basically what the user specified as his
      52              :          * backup file but of course here it is a directory.
      53              :          */
      54              :         char       *directory;
      55              : 
      56              :         CompressFileHandle *dataFH; /* currently open data file */
      57              :         CompressFileHandle *LOsTocFH;   /* file handle for blobs_NNN.toc */
      58              :         ParallelState *pstate;          /* for parallel backup / restore */
      59              : } lclContext;
      60              : 
      61              : typedef struct
      62              : {
      63              :         char       *filename;           /* filename excluding the directory (basename) */
      64              : } lclTocEntry;
      65              : 
      66              : /* prototypes for private functions */
      67              : static void _ArchiveEntry(ArchiveHandle *AH, TocEntry *te);
      68              : static void _StartData(ArchiveHandle *AH, TocEntry *te);
      69              : static void _EndData(ArchiveHandle *AH, TocEntry *te);
      70              : static void _WriteData(ArchiveHandle *AH, const void *data, size_t dLen);
      71              : static int      _WriteByte(ArchiveHandle *AH, const int i);
      72              : static int      _ReadByte(ArchiveHandle *AH);
      73              : static void _WriteBuf(ArchiveHandle *AH, const void *buf, size_t len);
      74              : static void _ReadBuf(ArchiveHandle *AH, void *buf, size_t len);
      75              : static void _CloseArchive(ArchiveHandle *AH);
      76              : static void _ReopenArchive(ArchiveHandle *AH);
      77              : static void _PrintTocData(ArchiveHandle *AH, TocEntry *te);
      78              : 
      79              : static void _WriteExtraToc(ArchiveHandle *AH, TocEntry *te);
      80              : static void _ReadExtraToc(ArchiveHandle *AH, TocEntry *te);
      81              : static void _PrintExtraToc(ArchiveHandle *AH, TocEntry *te);
      82              : 
      83              : static void _StartLOs(ArchiveHandle *AH, TocEntry *te);
      84              : static void _StartLO(ArchiveHandle *AH, TocEntry *te, Oid oid);
      85              : static void _EndLO(ArchiveHandle *AH, TocEntry *te, Oid oid);
      86              : static void _EndLOs(ArchiveHandle *AH, TocEntry *te);
      87              : static void _LoadLOs(ArchiveHandle *AH, TocEntry *te);
      88              : 
      89              : static void _PrepParallelRestore(ArchiveHandle *AH);
      90              : static void _Clone(ArchiveHandle *AH);
      91              : static void _DeClone(ArchiveHandle *AH);
      92              : 
      93              : static int      _WorkerJobRestoreDirectory(ArchiveHandle *AH, TocEntry *te);
      94              : static int      _WorkerJobDumpDirectory(ArchiveHandle *AH, TocEntry *te);
      95              : 
      96              : static void setFilePath(ArchiveHandle *AH, char *buf,
      97              :                                                 const char *relativeFilename);
      98              : 
      99              : /*
     100              :  *      Init routine required by ALL formats. This is a global routine
     101              :  *      and should be declared in pg_backup_archiver.h
     102              :  *
     103              :  *      Its task is to create any extra archive context (using AH->formatData),
     104              :  *      and to initialize the supported function pointers.
     105              :  *
     106              :  *      It should also prepare whatever its input source is for reading/writing,
     107              :  *      and in the case of a read mode connection, it should load the Header & TOC.
     108              :  */
     109              : void
     110            0 : InitArchiveFmt_Directory(ArchiveHandle *AH)
     111              : {
     112            0 :         lclContext *ctx;
     113              : 
     114              :         /* Assuming static functions, this can be copied for each format. */
     115            0 :         AH->ArchiveEntryPtr = _ArchiveEntry;
     116            0 :         AH->StartDataPtr = _StartData;
     117            0 :         AH->WriteDataPtr = _WriteData;
     118            0 :         AH->EndDataPtr = _EndData;
     119            0 :         AH->WriteBytePtr = _WriteByte;
     120            0 :         AH->ReadBytePtr = _ReadByte;
     121            0 :         AH->WriteBufPtr = _WriteBuf;
     122            0 :         AH->ReadBufPtr = _ReadBuf;
     123            0 :         AH->ClosePtr = _CloseArchive;
     124            0 :         AH->ReopenPtr = _ReopenArchive;
     125            0 :         AH->PrintTocDataPtr = _PrintTocData;
     126            0 :         AH->ReadExtraTocPtr = _ReadExtraToc;
     127            0 :         AH->WriteExtraTocPtr = _WriteExtraToc;
     128            0 :         AH->PrintExtraTocPtr = _PrintExtraToc;
     129              : 
     130            0 :         AH->StartLOsPtr = _StartLOs;
     131            0 :         AH->StartLOPtr = _StartLO;
     132            0 :         AH->EndLOPtr = _EndLO;
     133            0 :         AH->EndLOsPtr = _EndLOs;
     134              : 
     135            0 :         AH->PrepParallelRestorePtr = _PrepParallelRestore;
     136            0 :         AH->ClonePtr = _Clone;
     137            0 :         AH->DeClonePtr = _DeClone;
     138              : 
     139            0 :         AH->WorkerJobRestorePtr = _WorkerJobRestoreDirectory;
     140            0 :         AH->WorkerJobDumpPtr = _WorkerJobDumpDirectory;
     141              : 
     142              :         /* Set up our private context */
     143            0 :         ctx = (lclContext *) pg_malloc0(sizeof(lclContext));
     144            0 :         AH->formatData = ctx;
     145              : 
     146            0 :         ctx->dataFH = NULL;
     147            0 :         ctx->LOsTocFH = NULL;
     148              : 
     149              :         /*
     150              :          * Now open the TOC file
     151              :          */
     152              : 
     153            0 :         if (!AH->fSpec || strcmp(AH->fSpec, "") == 0)
     154            0 :                 pg_fatal("no output directory specified");
     155              : 
     156            0 :         ctx->directory = AH->fSpec;
     157              : 
     158            0 :         if (AH->mode == archModeWrite)
     159              :         {
     160              :                 /* we accept an empty existing directory */
     161            0 :                 create_or_open_dir(ctx->directory);
     162            0 :         }
     163              :         else
     164              :         {                                                       /* Read Mode */
     165            0 :                 char            fname[MAXPGPATH];
     166            0 :                 CompressFileHandle *tocFH;
     167              : 
     168            0 :                 setFilePath(AH, fname, "toc.dat");
     169              : 
     170            0 :                 tocFH = InitDiscoverCompressFileHandle(fname, PG_BINARY_R);
     171            0 :                 if (tocFH == NULL)
     172            0 :                         pg_fatal("could not open input file \"%s\": %m", fname);
     173              : 
     174            0 :                 ctx->dataFH = tocFH;
     175              : 
     176              :                 /*
     177              :                  * The TOC of a directory format dump shares the format code of the
     178              :                  * tar format.
     179              :                  */
     180            0 :                 AH->format = archTar;
     181            0 :                 ReadHead(AH);
     182            0 :                 AH->format = archDirectory;
     183            0 :                 ReadToc(AH);
     184              : 
     185              :                 /* Nothing else in the file, so close it again... */
     186            0 :                 if (!EndCompressFileHandle(tocFH))
     187            0 :                         pg_fatal("could not close TOC file: %m");
     188            0 :                 ctx->dataFH = NULL;
     189            0 :         }
     190            0 : }
     191              : 
     192              : /*
     193              :  * Called by the Archiver when the dumper creates a new TOC entry.
     194              :  *
     195              :  * We determine the filename for this entry.
     196              : */
     197              : static void
     198            0 : _ArchiveEntry(ArchiveHandle *AH, TocEntry *te)
     199              : {
     200            0 :         lclTocEntry *tctx;
     201            0 :         char            fn[MAXPGPATH];
     202              : 
     203            0 :         tctx = (lclTocEntry *) pg_malloc0(sizeof(lclTocEntry));
     204            0 :         if (strcmp(te->desc, "BLOBS") == 0)
     205              :         {
     206            0 :                 snprintf(fn, MAXPGPATH, "blobs_%d.toc", te->dumpId);
     207            0 :                 tctx->filename = pg_strdup(fn);
     208            0 :         }
     209            0 :         else if (te->dataDumper)
     210              :         {
     211            0 :                 snprintf(fn, MAXPGPATH, "%d.dat", te->dumpId);
     212            0 :                 tctx->filename = pg_strdup(fn);
     213            0 :         }
     214              :         else
     215            0 :                 tctx->filename = NULL;
     216              : 
     217            0 :         te->formatData = tctx;
     218            0 : }
     219              : 
     220              : /*
     221              :  * Called by the Archiver to save any extra format-related TOC entry
     222              :  * data.
     223              :  *
     224              :  * Use the Archiver routines to write data - they are non-endian, and
     225              :  * maintain other important file information.
     226              :  */
     227              : static void
     228            0 : _WriteExtraToc(ArchiveHandle *AH, TocEntry *te)
     229              : {
     230            0 :         lclTocEntry *tctx = (lclTocEntry *) te->formatData;
     231              : 
     232              :         /*
     233              :          * A dumpable object has set tctx->filename, any other object has not.
     234              :          * (see _ArchiveEntry).
     235              :          */
     236            0 :         if (tctx->filename)
     237            0 :                 WriteStr(AH, tctx->filename);
     238              :         else
     239            0 :                 WriteStr(AH, "");
     240            0 : }
     241              : 
     242              : /*
     243              :  * Called by the Archiver to read any extra format-related TOC data.
     244              :  *
     245              :  * Needs to match the order defined in _WriteExtraToc, and should also
     246              :  * use the Archiver input routines.
     247              :  */
     248              : static void
     249            0 : _ReadExtraToc(ArchiveHandle *AH, TocEntry *te)
     250              : {
     251            0 :         lclTocEntry *tctx = (lclTocEntry *) te->formatData;
     252              : 
     253            0 :         if (tctx == NULL)
     254              :         {
     255            0 :                 tctx = (lclTocEntry *) pg_malloc0(sizeof(lclTocEntry));
     256            0 :                 te->formatData = tctx;
     257            0 :         }
     258              : 
     259            0 :         tctx->filename = ReadStr(AH);
     260            0 :         if (strlen(tctx->filename) == 0)
     261              :         {
     262            0 :                 free(tctx->filename);
     263            0 :                 tctx->filename = NULL;
     264            0 :         }
     265            0 : }
     266              : 
     267              : /*
     268              :  * Called by the Archiver when restoring an archive to output a comment
     269              :  * that includes useful information about the TOC entry.
     270              :  */
     271              : static void
     272            0 : _PrintExtraToc(ArchiveHandle *AH, TocEntry *te)
     273              : {
     274            0 :         lclTocEntry *tctx = (lclTocEntry *) te->formatData;
     275              : 
     276            0 :         if (AH->public.verbose && tctx->filename)
     277            0 :                 ahprintf(AH, "-- File: %s\n", tctx->filename);
     278            0 : }
     279              : 
     280              : /*
     281              :  * Called by the archiver when saving TABLE DATA (not schema). This routine
     282              :  * should save whatever format-specific information is needed to read
     283              :  * the archive back.
     284              :  *
     285              :  * It is called just prior to the dumper's 'DataDumper' routine being called.
     286              :  *
     287              :  * We create the data file for writing.
     288              :  */
     289              : static void
     290            0 : _StartData(ArchiveHandle *AH, TocEntry *te)
     291              : {
     292            0 :         lclTocEntry *tctx = (lclTocEntry *) te->formatData;
     293            0 :         lclContext *ctx = (lclContext *) AH->formatData;
     294            0 :         char            fname[MAXPGPATH];
     295              : 
     296            0 :         setFilePath(AH, fname, tctx->filename);
     297              : 
     298            0 :         ctx->dataFH = InitCompressFileHandle(AH->compression_spec);
     299              : 
     300            0 :         if (!ctx->dataFH->open_write_func(fname, PG_BINARY_W, ctx->dataFH))
     301            0 :                 pg_fatal("could not open output file \"%s\": %m", fname);
     302            0 : }
     303              : 
     304              : /*
     305              :  * Called by archiver when dumper calls WriteData. This routine is
     306              :  * called for both LO and table data; it is the responsibility of
     307              :  * the format to manage each kind of data using StartLO/StartData.
     308              :  *
     309              :  * It should only be called from within a DataDumper routine.
     310              :  *
     311              :  * We write the data to the open data file.
     312              :  */
     313              : static void
     314            0 : _WriteData(ArchiveHandle *AH, const void *data, size_t dLen)
     315              : {
     316            0 :         lclContext *ctx = (lclContext *) AH->formatData;
     317            0 :         CompressFileHandle *CFH = ctx->dataFH;
     318              : 
     319            0 :         if (dLen <= 0)
     320            0 :                 return;
     321            0 :         CFH->write_func(data, dLen, CFH);
     322            0 : }
     323              : 
     324              : /*
     325              :  * Called by the archiver when a dumper's 'DataDumper' routine has
     326              :  * finished.
     327              :  *
     328              :  * We close the data file.
     329              :  */
     330              : static void
     331            0 : _EndData(ArchiveHandle *AH, TocEntry *te)
     332              : {
     333            0 :         lclContext *ctx = (lclContext *) AH->formatData;
     334              : 
     335              :         /* Close the file */
     336            0 :         if (!EndCompressFileHandle(ctx->dataFH))
     337            0 :                 pg_fatal("could not close data file: %m");
     338              : 
     339            0 :         ctx->dataFH = NULL;
     340            0 : }
     341              : 
     342              : /*
     343              :  * Print data for a given file (can be a LO as well)
     344              :  */
     345              : static void
     346            0 : _PrintFileData(ArchiveHandle *AH, char *filename)
     347              : {
     348            0 :         size_t          cnt;
     349            0 :         char       *buf;
     350            0 :         size_t          buflen;
     351            0 :         CompressFileHandle *CFH;
     352              : 
     353            0 :         if (!filename)
     354            0 :                 return;
     355              : 
     356            0 :         CFH = InitDiscoverCompressFileHandle(filename, PG_BINARY_R);
     357            0 :         if (!CFH)
     358            0 :                 pg_fatal("could not open input file \"%s\": %m", filename);
     359              : 
     360            0 :         buflen = DEFAULT_IO_BUFFER_SIZE;
     361            0 :         buf = pg_malloc(buflen);
     362              : 
     363            0 :         while ((cnt = CFH->read_func(buf, buflen, CFH)) > 0)
     364              :         {
     365            0 :                 ahwrite(buf, 1, cnt, AH);
     366              :         }
     367              : 
     368            0 :         free(buf);
     369            0 :         if (!EndCompressFileHandle(CFH))
     370            0 :                 pg_fatal("could not close data file \"%s\": %m", filename);
     371            0 : }
     372              : 
     373              : /*
     374              :  * Print data for a given TOC entry
     375              : */
     376              : static void
     377            0 : _PrintTocData(ArchiveHandle *AH, TocEntry *te)
     378              : {
     379            0 :         lclTocEntry *tctx = (lclTocEntry *) te->formatData;
     380              : 
     381            0 :         if (!tctx->filename)
     382            0 :                 return;
     383              : 
     384            0 :         if (strcmp(te->desc, "BLOBS") == 0)
     385            0 :                 _LoadLOs(AH, te);
     386              :         else
     387              :         {
     388            0 :                 char            fname[MAXPGPATH];
     389              : 
     390            0 :                 setFilePath(AH, fname, tctx->filename);
     391            0 :                 _PrintFileData(AH, fname);
     392            0 :         }
     393            0 : }
     394              : 
     395              : static void
     396            0 : _LoadLOs(ArchiveHandle *AH, TocEntry *te)
     397              : {
     398            0 :         Oid                     oid;
     399            0 :         lclContext *ctx = (lclContext *) AH->formatData;
     400            0 :         lclTocEntry *tctx = (lclTocEntry *) te->formatData;
     401            0 :         CompressFileHandle *CFH;
     402            0 :         char            tocfname[MAXPGPATH];
     403            0 :         char            line[MAXPGPATH];
     404              : 
     405            0 :         StartRestoreLOs(AH);
     406              : 
     407              :         /*
     408              :          * Note: before archive v16, there was always only one BLOBS TOC entry,
     409              :          * now there can be multiple.  Furthermore, although the actual filename
     410              :          * was always "blobs.toc" before v16, the value of tctx->filename did not
     411              :          * match that before commit 548e50976 fixed it.  For simplicity we assume
     412              :          * it must be "blobs.toc" in all archives before v16.
     413              :          */
     414            0 :         if (AH->version < K_VERS_1_16)
     415            0 :                 setFilePath(AH, tocfname, "blobs.toc");
     416              :         else
     417            0 :                 setFilePath(AH, tocfname, tctx->filename);
     418              : 
     419            0 :         CFH = ctx->LOsTocFH = InitDiscoverCompressFileHandle(tocfname, PG_BINARY_R);
     420              : 
     421            0 :         if (ctx->LOsTocFH == NULL)
     422            0 :                 pg_fatal("could not open large object TOC file \"%s\" for input: %m",
     423              :                                  tocfname);
     424              : 
     425              :         /* Read the LOs TOC file line-by-line, and process each LO */
     426            0 :         while ((CFH->gets_func(line, MAXPGPATH, CFH)) != NULL)
     427              :         {
     428            0 :                 char            lofname[MAXPGPATH + 1];
     429            0 :                 char            path[MAXPGPATH];
     430              : 
     431              :                 /* Can't overflow because line and lofname are the same length */
     432            0 :                 if (sscanf(line, "%u %" CppAsString2(MAXPGPATH) "s\n", &oid, lofname) != 2)
     433            0 :                         pg_fatal("invalid line in large object TOC file \"%s\": \"%s\"",
     434              :                                          tocfname, line);
     435              : 
     436            0 :                 StartRestoreLO(AH, oid, AH->public.ropt->dropSchema);
     437            0 :                 snprintf(path, MAXPGPATH, "%s/%s", ctx->directory, lofname);
     438            0 :                 _PrintFileData(AH, path);
     439            0 :                 EndRestoreLO(AH, oid);
     440            0 :         }
     441            0 :         if (!CFH->eof_func(CFH))
     442            0 :                 pg_fatal("error reading large object TOC file \"%s\"",
     443              :                                  tocfname);
     444              : 
     445            0 :         if (!EndCompressFileHandle(ctx->LOsTocFH))
     446            0 :                 pg_fatal("could not close large object TOC file \"%s\": %m",
     447              :                                  tocfname);
     448              : 
     449            0 :         ctx->LOsTocFH = NULL;
     450              : 
     451            0 :         EndRestoreLOs(AH);
     452            0 : }
     453              : 
     454              : 
     455              : /*
     456              :  * Write a byte of data to the archive.
     457              :  * Called by the archiver to do integer & byte output to the archive.
     458              :  * These routines are only used to read & write the headers & TOC.
     459              :  */
     460              : static int
     461            0 : _WriteByte(ArchiveHandle *AH, const int i)
     462              : {
     463            0 :         unsigned char c = (unsigned char) i;
     464            0 :         lclContext *ctx = (lclContext *) AH->formatData;
     465            0 :         CompressFileHandle *CFH = ctx->dataFH;
     466              : 
     467            0 :         CFH->write_func(&c, 1, CFH);
     468            0 :         return 1;
     469            0 : }
     470              : 
     471              : /*
     472              :  * Read a byte of data from the archive.
     473              :  * Called by the archiver to read bytes & integers from the archive.
     474              :  * These routines are only used to read & write headers & TOC.
     475              :  * EOF should be treated as a fatal error.
     476              :  */
     477              : static int
     478            0 : _ReadByte(ArchiveHandle *AH)
     479              : {
     480            0 :         lclContext *ctx = (lclContext *) AH->formatData;
     481            0 :         CompressFileHandle *CFH = ctx->dataFH;
     482              : 
     483            0 :         return CFH->getc_func(CFH);
     484            0 : }
     485              : 
     486              : /*
     487              :  * Write a buffer of data to the archive.
     488              :  * Called by the archiver to write a block of bytes to the TOC or a data file.
     489              :  */
     490              : static void
     491            0 : _WriteBuf(ArchiveHandle *AH, const void *buf, size_t len)
     492              : {
     493            0 :         lclContext *ctx = (lclContext *) AH->formatData;
     494            0 :         CompressFileHandle *CFH = ctx->dataFH;
     495              : 
     496            0 :         CFH->write_func(buf, len, CFH);
     497            0 : }
     498              : 
     499              : /*
     500              :  * Read a block of bytes from the archive.
     501              :  *
     502              :  * Called by the archiver to read a block of bytes from the archive
     503              :  */
     504              : static void
     505            0 : _ReadBuf(ArchiveHandle *AH, void *buf, size_t len)
     506              : {
     507            0 :         lclContext *ctx = (lclContext *) AH->formatData;
     508            0 :         CompressFileHandle *CFH = ctx->dataFH;
     509              : 
     510              :         /*
     511              :          * We do not expect a short read, so fail if we get one.  The read_func
     512              :          * already dealt with any outright I/O error.
     513              :          */
     514            0 :         if (CFH->read_func(buf, len, CFH) != len)
     515            0 :                 pg_fatal("could not read from input file: end of file");
     516            0 : }
     517              : 
     518              : /*
     519              :  * Close the archive.
     520              :  *
     521              :  * When writing the archive, this is the routine that actually starts
     522              :  * the process of saving it to files. No data should be written prior
     523              :  * to this point, since the user could sort the TOC after creating it.
     524              :  *
     525              :  * If an archive is to be written, this routine must call:
     526              :  *              WriteHead                       to save the archive header
     527              :  *              WriteToc                        to save the TOC entries
     528              :  *              WriteDataChunks         to save all data & LOs.
     529              :  */
     530              : static void
     531            0 : _CloseArchive(ArchiveHandle *AH)
     532              : {
     533            0 :         lclContext *ctx = (lclContext *) AH->formatData;
     534              : 
     535            0 :         if (AH->mode == archModeWrite)
     536              :         {
     537            0 :                 CompressFileHandle *tocFH;
     538            0 :                 pg_compress_specification compression_spec = {0};
     539            0 :                 char            fname[MAXPGPATH];
     540              : 
     541            0 :                 setFilePath(AH, fname, "toc.dat");
     542              : 
     543              :                 /* this will actually fork the processes for a parallel backup */
     544            0 :                 ctx->pstate = ParallelBackupStart(AH);
     545              : 
     546              :                 /* The TOC is always created uncompressed */
     547            0 :                 compression_spec.algorithm = PG_COMPRESSION_NONE;
     548            0 :                 tocFH = InitCompressFileHandle(compression_spec);
     549            0 :                 if (!tocFH->open_write_func(fname, PG_BINARY_W, tocFH))
     550            0 :                         pg_fatal("could not open output file \"%s\": %m", fname);
     551            0 :                 ctx->dataFH = tocFH;
     552              : 
     553              :                 /*
     554              :                  * Write 'tar' in the format field of the toc.dat file. The directory
     555              :                  * is compatible with 'tar', so there's no point having a different
     556              :                  * format code for it.
     557              :                  */
     558            0 :                 AH->format = archTar;
     559            0 :                 WriteHead(AH);
     560            0 :                 AH->format = archDirectory;
     561            0 :                 WriteToc(AH);
     562            0 :                 if (!EndCompressFileHandle(tocFH))
     563            0 :                         pg_fatal("could not close TOC file: %m");
     564            0 :                 WriteDataChunks(AH, ctx->pstate);
     565              : 
     566            0 :                 ParallelBackupEnd(AH, ctx->pstate);
     567              : 
     568              :                 /*
     569              :                  * In directory mode, there is no need to sync all the entries
     570              :                  * individually. Just recurse once through all the files generated.
     571              :                  */
     572            0 :                 if (AH->dosync)
     573            0 :                         sync_dir_recurse(ctx->directory, AH->sync_method);
     574            0 :         }
     575            0 :         AH->FH = NULL;
     576            0 : }
     577              : 
     578              : /*
     579              :  * Reopen the archive's file handle.
     580              :  */
     581              : static void
     582            0 : _ReopenArchive(ArchiveHandle *AH)
     583              : {
     584              :         /*
     585              :          * Our TOC is in memory, our data files are opened by each child anyway as
     586              :          * they are separate. We support reopening the archive by just doing
     587              :          * nothing.
     588              :          */
     589            0 : }
     590              : 
     591              : /*
     592              :  * LO support
     593              :  */
     594              : 
     595              : /*
     596              :  * Called by the archiver when starting to save BLOB DATA (not schema).
     597              :  * It is called just prior to the dumper's DataDumper routine.
     598              :  *
     599              :  * We open the large object TOC file here, so that we can append a line to
     600              :  * it for each LO.
     601              :  */
     602              : static void
     603            0 : _StartLOs(ArchiveHandle *AH, TocEntry *te)
     604              : {
     605            0 :         lclContext *ctx = (lclContext *) AH->formatData;
     606            0 :         lclTocEntry *tctx = (lclTocEntry *) te->formatData;
     607            0 :         pg_compress_specification compression_spec = {0};
     608            0 :         char            fname[MAXPGPATH];
     609              : 
     610            0 :         setFilePath(AH, fname, tctx->filename);
     611              : 
     612              :         /* The LO TOC file is never compressed */
     613            0 :         compression_spec.algorithm = PG_COMPRESSION_NONE;
     614            0 :         ctx->LOsTocFH = InitCompressFileHandle(compression_spec);
     615            0 :         if (!ctx->LOsTocFH->open_write_func(fname, "ab", ctx->LOsTocFH))
     616            0 :                 pg_fatal("could not open output file \"%s\": %m", fname);
     617            0 : }
     618              : 
     619              : /*
     620              :  * Called by the archiver when we're about to start dumping a LO.
     621              :  *
     622              :  * We create a file to write the LO to.
     623              :  */
     624              : static void
     625            0 : _StartLO(ArchiveHandle *AH, TocEntry *te, Oid oid)
     626              : {
     627            0 :         lclContext *ctx = (lclContext *) AH->formatData;
     628            0 :         char            fname[MAXPGPATH];
     629              : 
     630            0 :         snprintf(fname, MAXPGPATH, "%s/blob_%u.dat", ctx->directory, oid);
     631              : 
     632            0 :         ctx->dataFH = InitCompressFileHandle(AH->compression_spec);
     633            0 :         if (!ctx->dataFH->open_write_func(fname, PG_BINARY_W, ctx->dataFH))
     634            0 :                 pg_fatal("could not open output file \"%s\": %m", fname);
     635            0 : }
     636              : 
     637              : /*
     638              :  * Called by the archiver when the dumper is finished writing a LO.
     639              :  *
     640              :  * We close the LO file and write an entry to the LO TOC file for it.
     641              :  */
     642              : static void
     643            0 : _EndLO(ArchiveHandle *AH, TocEntry *te, Oid oid)
     644              : {
     645            0 :         lclContext *ctx = (lclContext *) AH->formatData;
     646            0 :         CompressFileHandle *CFH = ctx->LOsTocFH;
     647            0 :         char            buf[50];
     648            0 :         int                     len;
     649              : 
     650              :         /* Close the BLOB data file itself */
     651            0 :         if (!EndCompressFileHandle(ctx->dataFH))
     652            0 :                 pg_fatal("could not close LO data file: %m");
     653            0 :         ctx->dataFH = NULL;
     654              : 
     655              :         /* register the LO in blobs_NNN.toc */
     656            0 :         len = snprintf(buf, sizeof(buf), "%u blob_%u.dat\n", oid, oid);
     657            0 :         CFH->write_func(buf, len, CFH);
     658            0 : }
     659              : 
     660              : /*
     661              :  * Called by the archiver when finishing saving BLOB DATA.
     662              :  *
     663              :  * We close the LOs TOC file.
     664              :  */
     665              : static void
     666            0 : _EndLOs(ArchiveHandle *AH, TocEntry *te)
     667              : {
     668            0 :         lclContext *ctx = (lclContext *) AH->formatData;
     669              : 
     670            0 :         if (!EndCompressFileHandle(ctx->LOsTocFH))
     671            0 :                 pg_fatal("could not close LOs TOC file: %m");
     672            0 :         ctx->LOsTocFH = NULL;
     673            0 : }
     674              : 
     675              : /*
     676              :  * Gets a relative file name and prepends the output directory, writing the
     677              :  * result to buf. The caller needs to make sure that buf is MAXPGPATH bytes
     678              :  * big. Can't use a static char[MAXPGPATH] inside the function because we run
     679              :  * multithreaded on Windows.
     680              :  */
     681              : static void
     682            0 : setFilePath(ArchiveHandle *AH, char *buf, const char *relativeFilename)
     683              : {
     684            0 :         lclContext *ctx = (lclContext *) AH->formatData;
     685            0 :         char       *dname;
     686              : 
     687            0 :         dname = ctx->directory;
     688              : 
     689            0 :         if (strlen(dname) + 1 + strlen(relativeFilename) + 1 > MAXPGPATH)
     690            0 :                 pg_fatal("file name too long: \"%s\"", dname);
     691              : 
     692            0 :         strcpy(buf, dname);
     693            0 :         strcat(buf, "/");
     694            0 :         strcat(buf, relativeFilename);
     695            0 : }
     696              : 
     697              : /*
     698              :  * Prepare for parallel restore.
     699              :  *
     700              :  * The main thing that needs to happen here is to fill in TABLE DATA and BLOBS
     701              :  * TOC entries' dataLength fields with appropriate values to guide the
     702              :  * ordering of restore jobs.  The source of said data is format-dependent,
     703              :  * as is the exact meaning of the values.
     704              :  *
     705              :  * A format module might also choose to do other setup here.
     706              :  */
     707              : static void
     708            0 : _PrepParallelRestore(ArchiveHandle *AH)
     709              : {
     710            0 :         TocEntry   *te;
     711              : 
     712            0 :         for (te = AH->toc->next; te != AH->toc; te = te->next)
     713              :         {
     714            0 :                 lclTocEntry *tctx = (lclTocEntry *) te->formatData;
     715            0 :                 char            fname[MAXPGPATH];
     716            0 :                 struct stat st;
     717              : 
     718              :                 /*
     719              :                  * A dumpable object has set tctx->filename, any other object has not.
     720              :                  * (see _ArchiveEntry).
     721              :                  */
     722            0 :                 if (tctx->filename == NULL)
     723            0 :                         continue;
     724              : 
     725              :                 /* We may ignore items not due to be restored */
     726            0 :                 if ((te->reqs & (REQ_DATA | REQ_STATS)) == 0)
     727            0 :                         continue;
     728              : 
     729              :                 /*
     730              :                  * Stat the file and, if successful, put its size in dataLength.  When
     731              :                  * using compression, the physical file size might not be a very good
     732              :                  * guide to the amount of work involved in restoring the file, but we
     733              :                  * only need an approximate indicator of that.
     734              :                  */
     735            0 :                 setFilePath(AH, fname, tctx->filename);
     736              : 
     737            0 :                 if (stat(fname, &st) == 0)
     738            0 :                         te->dataLength = st.st_size;
     739            0 :                 else if (AH->compression_spec.algorithm != PG_COMPRESSION_NONE)
     740              :                 {
     741            0 :                         if (AH->compression_spec.algorithm == PG_COMPRESSION_GZIP)
     742            0 :                                 strlcat(fname, ".gz", sizeof(fname));
     743            0 :                         else if (AH->compression_spec.algorithm == PG_COMPRESSION_LZ4)
     744            0 :                                 strlcat(fname, ".lz4", sizeof(fname));
     745            0 :                         else if (AH->compression_spec.algorithm == PG_COMPRESSION_ZSTD)
     746            0 :                                 strlcat(fname, ".zst", sizeof(fname));
     747              : 
     748            0 :                         if (stat(fname, &st) == 0)
     749            0 :                                 te->dataLength = st.st_size;
     750            0 :                 }
     751              : 
     752              :                 /*
     753              :                  * If this is a BLOBS entry, what we stat'd was blobs_NNN.toc, which
     754              :                  * most likely is a lot smaller than the actual blob data.  We don't
     755              :                  * have a cheap way to estimate how much smaller, but fortunately it
     756              :                  * doesn't matter too much as long as we get the LOs processed
     757              :                  * reasonably early.  Arbitrarily scale up by a factor of 1K.
     758              :                  */
     759            0 :                 if (strcmp(te->desc, "BLOBS") == 0)
     760            0 :                         te->dataLength *= 1024;
     761            0 :         }
     762            0 : }
     763              : 
     764              : /*
     765              :  * Clone format-specific fields during parallel restoration.
     766              :  */
     767              : static void
     768            0 : _Clone(ArchiveHandle *AH)
     769              : {
     770            0 :         lclContext *ctx = (lclContext *) AH->formatData;
     771              : 
     772            0 :         AH->formatData = (lclContext *) pg_malloc(sizeof(lclContext));
     773            0 :         memcpy(AH->formatData, ctx, sizeof(lclContext));
     774            0 :         ctx = (lclContext *) AH->formatData;
     775              : 
     776              :         /*
     777              :          * TOC-entry-local state isn't an issue because any one TOC entry is
     778              :          * touched by just one worker child.
     779              :          */
     780              : 
     781              :         /*
     782              :          * We also don't copy the ParallelState pointer (pstate), only the leader
     783              :          * process ever writes to it.
     784              :          */
     785            0 : }
     786              : 
     787              : static void
     788            0 : _DeClone(ArchiveHandle *AH)
     789              : {
     790            0 :         lclContext *ctx = (lclContext *) AH->formatData;
     791              : 
     792            0 :         free(ctx);
     793            0 : }
     794              : 
     795              : /*
     796              :  * This function is executed in the child of a parallel backup for a
     797              :  * directory-format archive and dumps the actual data for one TOC entry.
     798              :  */
     799              : static int
     800            0 : _WorkerJobDumpDirectory(ArchiveHandle *AH, TocEntry *te)
     801              : {
     802              :         /*
     803              :          * This function returns void. We either fail and die horribly or
     804              :          * succeed... A failure will be detected by the parent when the child dies
     805              :          * unexpectedly.
     806              :          */
     807            0 :         WriteDataChunksForTocEntry(AH, te);
     808              : 
     809            0 :         return 0;
     810              : }
     811              : 
     812              : /*
     813              :  * This function is executed in the child of a parallel restore from a
     814              :  * directory-format archive and restores the actual data for one TOC entry.
     815              :  */
     816              : static int
     817            0 : _WorkerJobRestoreDirectory(ArchiveHandle *AH, TocEntry *te)
     818              : {
     819            0 :         return parallel_restore(AH, te);
     820              : }
        

Generated by: LCOV version 2.3.2-1