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

Generated by: LCOV version 1.13