]> granicus.if.org Git - postgresql/commitdiff
Fix (re-)starting from a basebackup taken off a standby after a failure.
authorAndres Freund <andres@anarazel.de>
Thu, 18 Dec 2014 07:35:27 +0000 (08:35 +0100)
committerAndres Freund <andres@anarazel.de>
Thu, 18 Dec 2014 07:47:33 +0000 (08:47 +0100)
When starting up from a basebackup taken off a standby extra logic has
to be applied to compute the point where the data directory is
consistent. Normal base backups use a WAL record for that purpose, but
that isn't possible on a standby.

That logic had a error check ensuring that the cluster's control file
indicates being in recovery. Unfortunately that check was too strict,
disregarding the fact that the control file could also indicate that
the cluster was shut down while in recovery.

That's possible when the a cluster starting from a basebackup is shut
down before the backup label has been removed. When everything goes
well that's a short window, but when either restore_command or
primary_conninfo isn't configured correctly the window can get much
wider. That's because inbetween reading and unlinking the label we
restore the last checkpoint from WAL which can need additional WAL.

To fix simply also allow starting when the control file indicates
"shutdown in recovery". There's nicer fixes imaginable, but they'd be
more invasive.

Backpatch to 9.2 where support for taking basebackups from standbys
was added.

src/backend/access/transam/xlog.c

index 3005aa706d4f5ef64a43e9e5fe0aaede287c1352..5ae297a77b4d0c2999cbd1fcbcd43c73923e11ad 100644 (file)
@@ -6633,11 +6633,17 @@ StartupXLOG(void)
                /*
                 * Set backupStartPoint if we're starting recovery from a base backup.
                 *
-                * Set backupEndPoint and use minRecoveryPoint as the backup end
+                * Also set backupEndPoint and use minRecoveryPoint as the backup end
                 * location if we're starting recovery from a base backup which was
-                * taken from the standby. In this case, the database system status in
-                * pg_control must indicate DB_IN_ARCHIVE_RECOVERY. If not, which
-                * means that backup is corrupted, so we cancel recovery.
+                * taken from a standby. In this case, the database system status in
+                * pg_control must indicate that the database was already in
+                * recovery. Usually that will be DB_IN_ARCHIVE_RECOVERY but also can
+                * be DB_SHUTDOWNED_IN_RECOVERY if recovery previously was interrupted
+                * before reaching this point; e.g. because restore_command or
+                * primary_conninfo were faulty.
+                *
+                * Any other state indicates that the backup somehow became corrupted
+                * and we can't sensibly continue with recovery.
                 */
                if (haveBackupLabel)
                {
@@ -6646,7 +6652,8 @@ StartupXLOG(void)
 
                        if (backupFromStandby)
                        {
-                               if (dbstate_at_startup != DB_IN_ARCHIVE_RECOVERY)
+                               if (dbstate_at_startup != DB_IN_ARCHIVE_RECOVERY &&
+                                       dbstate_at_startup != DB_SHUTDOWNED_IN_RECOVERY)
                                        ereport(FATAL,
                                                        (errmsg("backup_label contains data inconsistent with control file"),
                                                         errhint("This means that the backup is corrupted and you will "