]> granicus.if.org Git - postgresql/commitdiff
Fix crash restart bug introduced in 8356753c212.
authorAndres Freund <andres@anarazel.de>
Sun, 17 Sep 2017 08:00:39 +0000 (01:00 -0700)
committerAndres Freund <andres@anarazel.de>
Tue, 19 Sep 2017 00:25:49 +0000 (17:25 -0700)
The bug was caused by not re-reading the control file during crash
recovery restarts, which lead to an attempt to pfree() shared memory
contents. The fix is to re-read the control file, which seems good
anyway.

It's unclear as of this moment, whether we want to keep the
refactoring introduced in the commit referenced above, or come up with
an alternative approach. But fixing the bug in the mean time seems
like a good idea regardless.

A followup commit will introduce regression test coverage for crash
restarts.

Reported-By: Tom Lane
Discussion: https://postgr.es/m/14134.1505572349@sss.pgh.pa.us

src/backend/access/transam/xlog.c
src/backend/postmaster/postmaster.c
src/backend/tcop/postgres.c
src/include/access/xlog.h

index b8f648927a21c18d8eb8c8cf88087cefc4813c6b..96ebf32a58a5b0ae1ec169bd817b9075eabd80a1 100644 (file)
@@ -4802,15 +4802,19 @@ check_wal_buffers(int *newval, void **extra, GucSource source)
 /*
  * Read the control file, set respective GUCs.
  *
- * This is to be called during startup, unless in bootstrap mode, where no
- * control file yet exists.  As there's no shared memory yet (its sizing can
- * depend on the contents of the control file!), first store data in local
- * memory. XLOGShemInit() will then copy it to shared memory later.
+ * This is to be called during startup, including a crash recovery cycle,
+ * unless in bootstrap mode, where no control file yet exists.  As there's no
+ * usable shared memory yet (its sizing can depend on the contents of the
+ * control file!), first store the contents in local memory. XLOGShemInit()
+ * will then copy it to shared memory later.
+ *
+ * reset just controls whether previous contents are to be expected (in the
+ * reset case, there's a dangling pointer into old shared memory), or not.
  */
 void
-LocalProcessControlFile(void)
+LocalProcessControlFile(bool reset)
 {
-       Assert(ControlFile == NULL);
+       Assert(reset || ControlFile == NULL);
        ControlFile = palloc(sizeof(ControlFileData));
        ReadControlFile();
 }
@@ -4884,20 +4888,13 @@ XLOGShmemInit(void)
        }
 #endif
 
-       /*
-        * Already have read control file locally, unless in bootstrap mode. Move
-        * local version into shared memory.
-        */
+
+       XLogCtl = (XLogCtlData *)
+               ShmemInitStruct("XLOG Ctl", XLOGShmemSize(), &foundXLog);
+
        localControlFile = ControlFile;
        ControlFile = (ControlFileData *)
                ShmemInitStruct("Control File", sizeof(ControlFileData), &foundCFile);
-       if (localControlFile)
-       {
-               memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
-               pfree(localControlFile);
-       }
-       XLogCtl = (XLogCtlData *)
-               ShmemInitStruct("XLOG Ctl", XLOGShmemSize(), &foundXLog);
 
        if (foundCFile || foundXLog)
        {
@@ -4908,10 +4905,23 @@ XLOGShmemInit(void)
                WALInsertLocks = XLogCtl->Insert.WALInsertLocks;
                LWLockRegisterTranche(LWTRANCHE_WAL_INSERT,
                                                          "wal_insert");
+
+               if (localControlFile)
+                       pfree(localControlFile);
                return;
        }
        memset(XLogCtl, 0, sizeof(XLogCtlData));
 
+       /*
+        * Already have read control file locally, unless in bootstrap mode. Move
+        * contents into shared memory.
+        */
+       if (localControlFile)
+       {
+               memcpy(ControlFile, localControlFile, sizeof(ControlFileData));
+               pfree(localControlFile);
+       }
+
        /*
         * Since XLogCtlData contains XLogRecPtr fields, its sizeof should be a
         * multiple of the alignment for same, so no extra alignment padding is
index e4f8f597c6060cddc7cf6aa656937910e279d607..160b555294f153a62752a39eb5784cf81d5f2855 100644 (file)
@@ -951,7 +951,7 @@ PostmasterMain(int argc, char *argv[])
        CreateDataDirLockFile(true);
 
        /* read control file (error checking and contains config) */
-       LocalProcessControlFile();
+       LocalProcessControlFile(false);
 
        /*
         * Initialize SSL library, if specified.
@@ -3829,6 +3829,10 @@ PostmasterStateMachine(void)
                ResetBackgroundWorkerCrashTimes();
 
                shmem_exit(1);
+
+               /* re-read control file into local memory */
+               LocalProcessControlFile(true);
+
                reset_shared(PostPortNumber);
 
                StartupPID = StartupDataBase();
@@ -4808,8 +4812,11 @@ SubPostmasterMain(int argc, char *argv[])
        /* Read in remaining GUC variables */
        read_nondefault_variables();
 
-       /* (re-)read control file (contains config) */
-       LocalProcessControlFile();
+       /*
+        * (re-)read control file, as it contains config. The postmaster will
+        * already have read this, but this process doesn't know about that.
+        */
+       LocalProcessControlFile(false);
 
        /*
         * Reload any libraries that were preloaded by the postmaster.  Since we
index 46b662266b56085355567769c68657935e7ece5a..dfd52b3c87eb0b2bfcf0f5e2a31538d1b4d47d63 100644 (file)
@@ -3718,7 +3718,7 @@ PostgresMain(int argc, char *argv[],
                CreateDataDirLockFile(false);
 
                /* read control file (error checking and contains config ) */
-               LocalProcessControlFile();
+               LocalProcessControlFile(false);
 
                /* Initialize MaxBackends (if under postmaster, was done already) */
                InitializeMaxBackends();
index e0635ab4e68a4146d0ebad4bf86ff01dba60a6d7..7213af0e813e554ce3e4d92f445130f0f8738929 100644 (file)
@@ -261,7 +261,7 @@ extern XLogRecPtr GetFakeLSNForUnloggedRel(void);
 extern Size XLOGShmemSize(void);
 extern void XLOGShmemInit(void);
 extern void BootStrapXLOG(void);
-extern void LocalProcessControlFile(void);
+extern void LocalProcessControlFile(bool reset);
 extern void StartupXLOG(void);
 extern void ShutdownXLOG(int code, Datum arg);
 extern void InitXLOGAccess(void);