]> granicus.if.org Git - postgresql/commitdiff
Fix compatibility of pg_basebackup -R with 11 and older versions
authorMichael Paquier <michael@paquier.xyz>
Fri, 8 Mar 2019 01:14:03 +0000 (10:14 +0900)
committerMichael Paquier <michael@paquier.xyz>
Fri, 8 Mar 2019 01:17:23 +0000 (10:17 +0900)
When 2dedf4d9 has integrated recovery.conf into postgresql.conf, it also
changed pg_basebackup -R in the way recovery configuration is
generated.  However this implementation forgot the fact that
pg_basebackup needs to keep compatibility with older server versions as
well.

Reported-by: Devrim Gündüz
Author: Sergei Kornilov, Michael Paquier
Discussion: https://postgr.es/m/3458f7cd12d74acd90180a671c8d5a081d60e162.camel@gunduz.org

src/bin/pg_basebackup/pg_basebackup.c

index 3d2d4cd0b9428a74868aa6d8650582bddeeff4b2..916371232bfaafaf3d89f1088c67b9664ffaa278 100644 (file)
@@ -66,6 +66,11 @@ typedef struct TablespaceList
  */
 #define MINIMUM_VERSION_FOR_TEMP_SLOTS 100000
 
+/*
+ * recovery.conf is integrated into postgresql.conf from version 12.
+ */
+#define MINIMUM_VERSION_FOR_RECOVERY_GUC 120000
+
 /*
  * Different ways to include WAL
  */
@@ -974,6 +979,7 @@ ReceiveTarFile(PGconn *conn, PGresult *res, int rownum)
        bool            basetablespace = PQgetisnull(res, rownum, 0);
        bool            in_tarhdr = true;
        bool            skip_file = false;
+       bool            is_recovery_guc_supported = true;
        bool            is_postgresql_auto_conf = false;
        bool            found_postgresql_auto_conf = false;
        int                     file_padding_len = 0;
@@ -984,6 +990,10 @@ ReceiveTarFile(PGconn *conn, PGresult *res, int rownum)
        gzFile          ztarfile = NULL;
 #endif
 
+       /* recovery.conf is integrated into postgresql.conf in 12 and newer */
+       if (PQserverVersion(conn) < MINIMUM_VERSION_FOR_RECOVERY_GUC)
+               is_recovery_guc_supported = false;
+
        if (basetablespace)
        {
                /*
@@ -1130,11 +1140,20 @@ ReceiveTarFile(PGconn *conn, PGresult *res, int rownum)
                        {
                                char            header[512];
 
-                               if (!found_postgresql_auto_conf)
+                               /*
+                                * If postgresql.auto.conf has not been found in the streamed
+                                * data, add recovery configuration to postgresql.auto.conf if
+                                * recovery parameters are GUCs.  If the instance connected to
+                                * is older than 12, create recovery.conf with this data
+                                * otherwise.
+                                */
+                               if (!found_postgresql_auto_conf || !is_recovery_guc_supported)
                                {
                                        int                     padding;
 
-                                       tarCreateHeader(header, "postgresql.auto.conf", NULL,
+                                       tarCreateHeader(header,
+                                                                       is_recovery_guc_supported ? "postgresql.auto.conf" : "recovery.conf",
+                                                                       NULL,
                                                                        recoveryconfcontents->len,
                                                                        pg_file_create_mode, 04000, 02000,
                                                                        time(NULL));
@@ -1142,18 +1161,26 @@ ReceiveTarFile(PGconn *conn, PGresult *res, int rownum)
                                        padding = ((recoveryconfcontents->len + 511) & ~511) - recoveryconfcontents->len;
 
                                        WRITE_TAR_DATA(header, sizeof(header));
-                                       WRITE_TAR_DATA(recoveryconfcontents->data, recoveryconfcontents->len);
+                                       WRITE_TAR_DATA(recoveryconfcontents->data,
+                                                                  recoveryconfcontents->len);
                                        if (padding)
                                                WRITE_TAR_DATA(zerobuf, padding);
                                }
 
-                               tarCreateHeader(header, "standby.signal", NULL,
-                                                               0,      /* zero-length file */
-                                                               pg_file_create_mode, 04000, 02000,
-                                                               time(NULL));
+                               /*
+                                * standby.signal is supported only if recovery parameters are
+                                * GUCs.
+                                */
+                               if (is_recovery_guc_supported)
+                               {
+                                       tarCreateHeader(header, "standby.signal", NULL,
+                                                                       0,      /* zero-length file */
+                                                                       pg_file_create_mode, 04000, 02000,
+                                                                       time(NULL));
 
-                               WRITE_TAR_DATA(header, sizeof(header));
-                               WRITE_TAR_DATA(zerobuf, 511);
+                                       WRITE_TAR_DATA(header, sizeof(header));
+                                       WRITE_TAR_DATA(zerobuf, 511);
+                               }
                        }
 
                        /* 2 * 512 bytes empty data at end of file */
@@ -1252,16 +1279,24 @@ ReceiveTarFile(PGconn *conn, PGresult *res, int rownum)
                                                 * We have the complete header structure in tarhdr,
                                                 * look at the file metadata: we may want append
                                                 * recovery info into postgresql.auto.conf and skip
-                                                * standby.signal file.  In both cases we must
-                                                * calculate tar padding
+                                                * standby.signal file if recovery parameters are
+                                                * integrated as GUCs, and recovery.conf otherwise. In
+                                                * both cases we must calculate tar padding.
                                                 */
-                                               skip_file = (strcmp(&tarhdr[0], "standby.signal") == 0);
-                                               is_postgresql_auto_conf = (strcmp(&tarhdr[0], "postgresql.auto.conf") == 0);
+                                               if (is_recovery_guc_supported)
+                                               {
+                                                       skip_file = (strcmp(&tarhdr[0], "standby.signal") == 0);
+                                                       is_postgresql_auto_conf = (strcmp(&tarhdr[0], "postgresql.auto.conf") == 0);
+                                               }
+                                               else
+                                                       skip_file = (strcmp(&tarhdr[0], "recovery.conf") == 0);
 
                                                filesz = read_tar_number(&tarhdr[124], 12);
                                                file_padding_len = ((filesz + 511) & ~511) - filesz;
 
-                                               if (is_postgresql_auto_conf && writerecoveryconf)
+                                               if (is_recovery_guc_supported &&
+                                                       is_postgresql_auto_conf &&
+                                                       writerecoveryconf)
                                                {
                                                        /* replace tar header */
                                                        char            header[512];
@@ -1313,7 +1348,9 @@ ReceiveTarFile(PGconn *conn, PGresult *res, int rownum)
                                                pos += bytes2write;
                                                filesz -= bytes2write;
                                        }
-                                       else if (is_postgresql_auto_conf && writerecoveryconf)
+                                       else if (is_recovery_guc_supported &&
+                                                        is_postgresql_auto_conf &&
+                                                        writerecoveryconf)
                                        {
                                                /* append recovery config to postgresql.auto.conf */
                                                int                     padding;
@@ -1690,6 +1727,13 @@ GenerateRecoveryConf(PGconn *conn)
                exit(1);
        }
 
+       /*
+        * In PostgreSQL 12 and newer versions, standby_mode is gone, replaced by
+        * standby.signal to trigger a standby state at recovery.
+        */
+       if (PQserverVersion(conn) < MINIMUM_VERSION_FOR_RECOVERY_GUC)
+               appendPQExpBufferStr(recoveryconfcontents, "standby_mode = 'on'\n");
+
        connOptions = PQconninfo(conn);
        if (connOptions == NULL)
        {
@@ -1756,21 +1800,29 @@ GenerateRecoveryConf(PGconn *conn)
 
 /*
  * Write the configuration file into the directory specified in basedir,
- * with the contents already collected in memory.
- * Then write the signal file into the basedir also.
+ * with the contents already collected in memory appended.  Then write
+ * the signal file into the basedir.  If the server does not support
+ * recovery parameters as GUCs, the signal file is not necessary, and
+ * configuration is written to recovery.conf.
  */
 static void
 WriteRecoveryConf(void)
 {
        char            filename[MAXPGPATH];
        FILE       *cf;
+       bool            is_recovery_guc_supported = true;
 
-       snprintf(filename, MAXPGPATH, "%s/%s", basedir, "postgresql.auto.conf");
+       if (PQserverVersion(conn) < MINIMUM_VERSION_FOR_RECOVERY_GUC)
+               is_recovery_guc_supported = false;
 
-       cf = fopen(filename, "a");
+       snprintf(filename, MAXPGPATH, "%s/%s", basedir,
+                        is_recovery_guc_supported ? "postgresql.auto.conf" : "recovery.conf");
+
+       cf = fopen(filename, is_recovery_guc_supported ? "a" : "w");
        if (cf == NULL)
        {
-               fprintf(stderr, _("%s: could not open file \"%s\": %s\n"), progname, filename, strerror(errno));
+               fprintf(stderr, _("%s: could not open file \"%s\": %s\n"),
+                               progname, filename, strerror(errno));
                exit(1);
        }
 
@@ -1784,15 +1836,18 @@ WriteRecoveryConf(void)
 
        fclose(cf);
 
-       snprintf(filename, MAXPGPATH, "%s/%s", basedir, "standby.signal");
-       cf = fopen(filename, "w");
-       if (cf == NULL)
+       if (is_recovery_guc_supported)
        {
-               fprintf(stderr, _("%s: could not create file \"%s\": %s\n"), progname, filename, strerror(errno));
-               exit(1);
-       }
+               snprintf(filename, MAXPGPATH, "%s/%s", basedir, "standby.signal");
+               cf = fopen(filename, "w");
+               if (cf == NULL)
+               {
+                       fprintf(stderr, _("%s: could not create file \"%s\": %s\n"), progname, filename, strerror(errno));
+                       exit(1);
+               }
 
-       fclose(cf);
+               fclose(cf);
+       }
 }