pg_stop_backup_on_standby_v6_96.patch
application/octet-stream
Filename: pg_stop_backup_on_standby_v6_96.patch
Type: application/octet-stream
Part: 0
Patch
Format: unified
Series: patch v6
| File | + | − |
|---|---|---|
| doc/src/sgml/backup.sgml | 6 | 4 |
| doc/src/sgml/func.sgml | 10 | 1 |
| src/backend/access/transam/xlog.c | 38 | 38 |
| src/backend/access/transam/xlogfuncs.c | 2 | 1 |
diff --git a/doc/src/sgml/backup.sgml b/doc/src/sgml/backup.sgml
index 03c0dbf1cd..882d255829 100644
--- a/doc/src/sgml/backup.sgml
+++ b/doc/src/sgml/backup.sgml
@@ -1001,10 +1001,12 @@ SELECT pg_start_backup('label', true);
<programlisting>
SELECT pg_stop_backup();
</programlisting>
- This terminates the backup mode and performs an automatic switch to
- the next WAL segment. The reason for the switch is to arrange for
- the last WAL segment file written during the backup interval to be
- ready to archive.
+ When called on a primary it terminates the backup mode and performs
+ an automatic switch to the next WAL segment. The reason for the switch
+ is to arrange for the last WAL segment written during the backup
+ interval to be ready to archive. When called on a standby the WAL
+ segment switch must be performed manually on the primary if it does
+ not happen with normal write activity.
</para>
</listitem>
<listitem>
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 12bbc391e0..681d6465e3 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -18041,7 +18041,16 @@ postgres=# select pg_start_backup('label_goes_here');
<function>pg_start_backup</>. In a non-exclusive backup, the contents of
the <filename>backup_label</> and <filename>tablespace_map</> are returned
in the result of the function, and should be written to files in the
- backup (and not in the data directory).
+ backup (and not in the data directory).
+ If the backup is taken from a standby, <function>pg_stop_backup</> waits for
+ WAL to be archived when <varname>archive_mode</> = <literal>always</>.
+ Enforcing manually a WAL segment switch to happen with for example
+ <function>pg_switch_wal</> may be necessary if the primary has low activity
+ to allow the backup to complete. Using <varname>statement_timeout</> to
+ limit the amount of time to wait will control the wait time, though all the
+ WAL segments necessary to recover into a consistent state using the backup
+ taken may not be archived at the time <function>pg_stop_backup</> returns
+ its status to the caller.
</para>
<para>
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 68109e2541..6285b96771 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -10030,10 +10030,9 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
/*
* During recovery, since we don't use the end-of-backup WAL
- * record and don't write the backup history file, the
- * starting WAL location doesn't need to be unique. This means
- * that two base backups started at the same time might use
- * the same checkpoint as starting locations.
+ * record, the starting WAL location doesn't need to be unique.
+ * This means that two base backups started at the same time
+ * might use the same checkpoint as starting locations.
*/
gotUniqueStartpoint = true;
}
@@ -10550,11 +10549,13 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
* backup. We have no way of checking if pg_control wasn't backed up last
* however.
*
- * We don't force a switch to new WAL file and wait for all the required
- * files to be archived. This is okay if we use the backup to start the
- * standby. But, if it's for an archive recovery, to ensure all the
- * required files are available, a user should wait for them to be
- * archived, or include them into the backup.
+ * We don't force a switch to new WAL file but it is still possible to
+ * wait for all the required files to be archived if waitforarchive is
+ * true. This is okay if we use the backup to start a standby and fetch
+ * the missing WAL using streaming replication. But in the case of an
+ * archive recovery, a user should set waitforarchive to true and wait
+ * for them to be archived to ensure that all the required files are
+ * available.
*
* We return the current minimum recovery point as the backup end
* location. Note that it can be greater than the exact backup end
@@ -10562,10 +10563,7 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
* pg_control. This is harmless for current uses.
*
* XXX currently a backup history file is for informational and debug
- * purposes only. It's not essential for an online backup. Furthermore,
- * even if it's created, it will not be archived during recovery because
- * an archiver is not invoked. So it doesn't seem worthwhile to write a
- * backup history file during recovery.
+ * purposes only. It's not essential for an online backup.
*/
if (backup_started_in_recovery)
{
@@ -10594,28 +10592,26 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
stoppoint = ControlFile->minRecoveryPoint;
stoptli = ControlFile->minRecoveryPointTLI;
LWLockRelease(ControlFileLock);
-
- if (stoptli_p)
- *stoptli_p = stoptli;
- return stoppoint;
}
+ else
+ {
+ /*
+ * Write the backup-end xlog record
+ */
+ XLogBeginInsert();
+ XLogRegisterData((char *) (&startpoint), sizeof(startpoint));
+ stoppoint = XLogInsert(RM_XLOG_ID, XLOG_BACKUP_END);
+ stoptli = ThisTimeLineID;
- /*
- * Write the backup-end xlog record
- */
- XLogBeginInsert();
- XLogRegisterData((char *) (&startpoint), sizeof(startpoint));
- stoppoint = XLogInsert(RM_XLOG_ID, XLOG_BACKUP_END);
- stoptli = ThisTimeLineID;
-
- /*
- * Force a switch to a new xlog segment file, so that the backup is valid
- * as soon as archiver moves out the current segment file.
- */
- RequestXLogSwitch();
+ /*
+ * Force a switch to a new xlog segment file, so that the backup is valid
+ * as soon as archiver moves out the current segment file.
+ */
+ RequestXLogSwitch();
+ }
XLByteToPrevSeg(stoppoint, _logSegNo);
- XLogFileName(stopxlogfilename, ThisTimeLineID, _logSegNo);
+ XLogFileName(stopxlogfilename, stoptli, _logSegNo);
/* Use the log timezone here, not the session timezone */
stamp_time = (pg_time_t) time(NULL);
@@ -10627,7 +10623,7 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
* Write the backup history file
*/
XLByteToSeg(startpoint, _logSegNo);
- BackupHistoryFilePath(histfilepath, ThisTimeLineID, _logSegNo,
+ BackupHistoryFilePath(histfilepath, stoptli, _logSegNo,
(uint32) (startpoint % XLogSegSize));
fp = AllocateFile(histfilepath, "w");
if (!fp)
@@ -10674,13 +10670,16 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
* wish to wait, you can set statement_timeout. Also, some notices are
* issued to clue in anyone who might be doing this interactively.
*/
- if (waitforarchive && XLogArchivingActive())
+
+ if (waitforarchive &&
+ ((!backup_started_in_recovery && XLogArchivingActive()) ||
+ (backup_started_in_recovery && XLogArchivingAlways())))
{
XLByteToPrevSeg(stoppoint, _logSegNo);
- XLogFileName(lastxlogfilename, ThisTimeLineID, _logSegNo);
+ XLogFileName(lastxlogfilename, stoptli, _logSegNo);
XLByteToSeg(startpoint, _logSegNo);
- BackupHistoryFileName(histfilename, ThisTimeLineID, _logSegNo,
+ BackupHistoryFileName(histfilename, stoptli, _logSegNo,
(uint32) (startpoint % XLogSegSize));
seconds_before_warning = 60;
@@ -10706,9 +10705,10 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
ereport(WARNING,
(errmsg("pg_stop_backup still waiting for all required WAL segments to be archived (%d seconds elapsed)",
waits),
- errhint("Check that your archive_command is executing properly. "
- "pg_stop_backup can be canceled safely, "
- "but the database backup will not be usable without all the WAL segments.")));
+ errhint("Either archive_command is failing or not enough WAL has been "
+ "generated to require a segment switch. Run pg_switch_wal() to "
+ "request a WAL switch and monitor your logs to check that your "
+ "archive_command is executing properly.")));
}
}
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index 9e07ad7e8a..0d90119178 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -286,7 +286,8 @@ pg_switch_xlog(PG_FUNCTION_ARGS)
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("recovery is in progress"),
- errhint("WAL control functions cannot be executed during recovery.")));
+ errhint("WAL control functions cannot be executed during recovery; "
+ "they should be executed on the primary instead")));
switchpoint = RequestXLogSwitch();