LCOV - differential code coverage report
Current view: top level - src/bin/pg_basebackup - bbstreamer_inject.c (source / functions) Coverage Total Hit UBC CBC
Current: Differential Code Coverage HEAD vs 15 Lines: 82.7 % 75 62 13 62
Current Date: 2023-04-08 15:15:32 Functions: 100.0 % 5 5 5
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           TLA  Line data    Source code
       1                 : /*-------------------------------------------------------------------------
       2                 :  *
       3                 :  * bbstreamer_inject.c
       4                 :  *
       5                 :  * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
       6                 :  *
       7                 :  * IDENTIFICATION
       8                 :  *        src/bin/pg_basebackup/bbstreamer_inject.c
       9                 :  *-------------------------------------------------------------------------
      10                 :  */
      11                 : 
      12                 : #include "postgres_fe.h"
      13                 : 
      14                 : #include "bbstreamer.h"
      15                 : #include "common/file_perm.h"
      16                 : #include "common/logging.h"
      17                 : 
      18                 : typedef struct bbstreamer_recovery_injector
      19                 : {
      20                 :     bbstreamer  base;
      21                 :     bool        skip_file;
      22                 :     bool        is_recovery_guc_supported;
      23                 :     bool        is_postgresql_auto_conf;
      24                 :     bool        found_postgresql_auto_conf;
      25                 :     PQExpBuffer recoveryconfcontents;
      26                 :     bbstreamer_member member;
      27                 : } bbstreamer_recovery_injector;
      28                 : 
      29                 : static void bbstreamer_recovery_injector_content(bbstreamer *streamer,
      30                 :                                                  bbstreamer_member *member,
      31                 :                                                  const char *data, int len,
      32                 :                                                  bbstreamer_archive_context context);
      33                 : static void bbstreamer_recovery_injector_finalize(bbstreamer *streamer);
      34                 : static void bbstreamer_recovery_injector_free(bbstreamer *streamer);
      35                 : 
      36                 : const bbstreamer_ops bbstreamer_recovery_injector_ops = {
      37                 :     .content = bbstreamer_recovery_injector_content,
      38                 :     .finalize = bbstreamer_recovery_injector_finalize,
      39                 :     .free = bbstreamer_recovery_injector_free
      40                 : };
      41                 : 
      42                 : /*
      43                 :  * Create a bbstreamer that can edit recoverydata into an archive stream.
      44                 :  *
      45                 :  * The input should be a series of typed chunks (not BBSTREAMER_UNKNOWN) as
      46                 :  * per the conventions described in bbstreamer.h; the chunks forwarded to
      47                 :  * the next bbstreamer will be similarly typed, but the
      48                 :  * BBSTREAMER_MEMBER_HEADER chunks may be zero-length in cases where we've
      49                 :  * edited the archive stream.
      50                 :  *
      51                 :  * Our goal is to do one of the following three things with the content passed
      52                 :  * via recoveryconfcontents: (1) if is_recovery_guc_supported is false, then
      53                 :  * put the content into recovery.conf, replacing any existing archive member
      54                 :  * by that name; (2) if is_recovery_guc_supported is true and
      55                 :  * postgresql.auto.conf exists in the archive, then append the content
      56                 :  * provided to the existing file; and (3) if is_recovery_guc_supported is
      57                 :  * true but postgresql.auto.conf does not exist in the archive, then create
      58                 :  * it with the specified content.
      59                 :  *
      60                 :  * In addition, if is_recovery_guc_supported is true, then we create a
      61                 :  * zero-length standby.signal file, dropping any file with that name from
      62                 :  * the archive.
      63                 :  */
      64                 : extern bbstreamer *
      65 CBC           2 : bbstreamer_recovery_injector_new(bbstreamer *next,
      66                 :                                  bool is_recovery_guc_supported,
      67                 :                                  PQExpBuffer recoveryconfcontents)
      68                 : {
      69                 :     bbstreamer_recovery_injector *streamer;
      70                 : 
      71               2 :     streamer = palloc0(sizeof(bbstreamer_recovery_injector));
      72               2 :     *((const bbstreamer_ops **) &streamer->base.bbs_ops) =
      73                 :         &bbstreamer_recovery_injector_ops;
      74               2 :     streamer->base.bbs_next = next;
      75               2 :     streamer->is_recovery_guc_supported = is_recovery_guc_supported;
      76               2 :     streamer->recoveryconfcontents = recoveryconfcontents;
      77                 : 
      78               2 :     return &streamer->base;
      79                 : }
      80                 : 
      81                 : /*
      82                 :  * Handle each chunk of tar content while injecting recovery configuration.
      83                 :  */
      84                 : static void
      85            6340 : bbstreamer_recovery_injector_content(bbstreamer *streamer,
      86                 :                                      bbstreamer_member *member,
      87                 :                                      const char *data, int len,
      88                 :                                      bbstreamer_archive_context context)
      89                 : {
      90                 :     bbstreamer_recovery_injector *mystreamer;
      91                 : 
      92            6340 :     mystreamer = (bbstreamer_recovery_injector *) streamer;
      93            6340 :     Assert(member != NULL || context == BBSTREAMER_ARCHIVE_TRAILER);
      94                 : 
      95            6340 :     switch (context)
      96                 :     {
      97            1986 :         case BBSTREAMER_MEMBER_HEADER:
      98                 :             /* Must copy provided data so we have the option to modify it. */
      99            1986 :             memcpy(&mystreamer->member, member, sizeof(bbstreamer_member));
     100                 : 
     101                 :             /*
     102                 :              * On v12+, skip standby.signal and edit postgresql.auto.conf; on
     103                 :              * older versions, skip recovery.conf.
     104                 :              */
     105            1986 :             if (mystreamer->is_recovery_guc_supported)
     106                 :             {
     107            1986 :                 mystreamer->skip_file =
     108            1986 :                     (strcmp(member->pathname, "standby.signal") == 0);
     109            1986 :                 mystreamer->is_postgresql_auto_conf =
     110            1986 :                     (strcmp(member->pathname, "postgresql.auto.conf") == 0);
     111            1986 :                 if (mystreamer->is_postgresql_auto_conf)
     112                 :                 {
     113                 :                     /* Remember we saw it so we don't add it again. */
     114               2 :                     mystreamer->found_postgresql_auto_conf = true;
     115                 : 
     116                 :                     /* Increment length by data to be injected. */
     117               2 :                     mystreamer->member.size +=
     118               2 :                         mystreamer->recoveryconfcontents->len;
     119                 : 
     120                 :                     /*
     121                 :                      * Zap data and len because the archive header is no
     122                 :                      * longer valid; some subsequent bbstreamer must
     123                 :                      * regenerate it if it's necessary.
     124                 :                      */
     125               2 :                     data = NULL;
     126               2 :                     len = 0;
     127                 :                 }
     128                 :             }
     129                 :             else
     130 UBC           0 :                 mystreamer->skip_file =
     131               0 :                     (strcmp(member->pathname, "recovery.conf") == 0);
     132                 : 
     133                 :             /* Do not forward if the file is to be skipped. */
     134 CBC        1986 :             if (mystreamer->skip_file)
     135 UBC           0 :                 return;
     136 CBC        1986 :             break;
     137                 : 
     138            2366 :         case BBSTREAMER_MEMBER_CONTENTS:
     139                 :             /* Do not forward if the file is to be skipped. */
     140            2366 :             if (mystreamer->skip_file)
     141 UBC           0 :                 return;
     142 CBC        2366 :             break;
     143                 : 
     144            1986 :         case BBSTREAMER_MEMBER_TRAILER:
     145                 :             /* Do not forward it the file is to be skipped. */
     146            1986 :             if (mystreamer->skip_file)
     147 UBC           0 :                 return;
     148                 : 
     149                 :             /* Append provided content to whatever we already sent. */
     150 CBC        1986 :             if (mystreamer->is_postgresql_auto_conf)
     151               2 :                 bbstreamer_content(mystreamer->base.bbs_next, member,
     152               2 :                                    mystreamer->recoveryconfcontents->data,
     153               2 :                                    mystreamer->recoveryconfcontents->len,
     154                 :                                    BBSTREAMER_MEMBER_CONTENTS);
     155            1986 :             break;
     156                 : 
     157               2 :         case BBSTREAMER_ARCHIVE_TRAILER:
     158               2 :             if (mystreamer->is_recovery_guc_supported)
     159                 :             {
     160                 :                 /*
     161                 :                  * If we didn't already find (and thus modify)
     162                 :                  * postgresql.auto.conf, inject it as an additional archive
     163                 :                  * member now.
     164                 :                  */
     165               2 :                 if (!mystreamer->found_postgresql_auto_conf)
     166 UBC           0 :                     bbstreamer_inject_file(mystreamer->base.bbs_next,
     167                 :                                            "postgresql.auto.conf",
     168               0 :                                            mystreamer->recoveryconfcontents->data,
     169               0 :                                            mystreamer->recoveryconfcontents->len);
     170                 : 
     171                 :                 /* Inject empty standby.signal file. */
     172 CBC           2 :                 bbstreamer_inject_file(mystreamer->base.bbs_next,
     173                 :                                        "standby.signal", "", 0);
     174                 :             }
     175                 :             else
     176                 :             {
     177                 :                 /* Inject recovery.conf file with specified contents. */
     178 UBC           0 :                 bbstreamer_inject_file(mystreamer->base.bbs_next,
     179                 :                                        "recovery.conf",
     180               0 :                                        mystreamer->recoveryconfcontents->data,
     181               0 :                                        mystreamer->recoveryconfcontents->len);
     182                 :             }
     183                 : 
     184                 :             /* Nothing to do here. */
     185 CBC           2 :             break;
     186                 : 
     187 UBC           0 :         default:
     188                 :             /* Shouldn't happen. */
     189               0 :             pg_fatal("unexpected state while injecting recovery settings");
     190                 :     }
     191                 : 
     192 CBC        6340 :     bbstreamer_content(mystreamer->base.bbs_next, &mystreamer->member,
     193                 :                        data, len, context);
     194                 : }
     195                 : 
     196                 : /*
     197                 :  * End-of-stream processing for this bbstreamer.
     198                 :  */
     199                 : static void
     200               2 : bbstreamer_recovery_injector_finalize(bbstreamer *streamer)
     201                 : {
     202               2 :     bbstreamer_finalize(streamer->bbs_next);
     203               2 : }
     204                 : 
     205                 : /*
     206                 :  * Free memory associated with this bbstreamer.
     207                 :  */
     208                 : static void
     209               2 : bbstreamer_recovery_injector_free(bbstreamer *streamer)
     210                 : {
     211               2 :     bbstreamer_free(streamer->bbs_next);
     212               2 :     pfree(streamer);
     213               2 : }
     214                 : 
     215                 : /*
     216                 :  * Inject a member into the archive with specified contents.
     217                 :  */
     218                 : void
     219               2 : bbstreamer_inject_file(bbstreamer *streamer, char *pathname, char *data,
     220                 :                        int len)
     221                 : {
     222                 :     bbstreamer_member member;
     223                 : 
     224               2 :     strlcpy(member.pathname, pathname, MAXPGPATH);
     225               2 :     member.size = len;
     226               2 :     member.mode = pg_file_create_mode;
     227               2 :     member.is_directory = false;
     228               2 :     member.is_link = false;
     229               2 :     member.linktarget[0] = '\0';
     230                 : 
     231                 :     /*
     232                 :      * There seems to be no principled argument for these values, but they are
     233                 :      * what PostgreSQL has historically used.
     234                 :      */
     235               2 :     member.uid = 04000;
     236               2 :     member.gid = 02000;
     237                 : 
     238                 :     /*
     239                 :      * We don't know here how to generate valid member headers and trailers
     240                 :      * for the archiving format in use, so if those are needed, some successor
     241                 :      * bbstreamer will have to generate them using the data from 'member'.
     242                 :      */
     243               2 :     bbstreamer_content(streamer, &member, NULL, 0,
     244                 :                        BBSTREAMER_MEMBER_HEADER);
     245               2 :     bbstreamer_content(streamer, &member, data, len,
     246                 :                        BBSTREAMER_MEMBER_CONTENTS);
     247               2 :     bbstreamer_content(streamer, &member, NULL, 0,
     248                 :                        BBSTREAMER_MEMBER_TRAILER);
     249               2 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a