Commit 52f8a59d authored by Robert Haas's avatar Robert Haas

Make pg_stop_backup's wait_for_archive flag work on standbys.

Previously, it had no effect.  Now, if archive_mode=always, it will
work, and if not, you'll get a warning.

Masahiko Sawada, Michael Paquier, and Robert Haas.  The patch as
submitted also changed the behavior so that we would write and remove
history files on standbys, but that seems like material for a separate
patch to me.

Discussion: http://postgr.es/m/CAD21AoC2Xw6M=ZJyejq_9d_iDkReC_=rpvQRw5QsyzKQdfYpkw@mail.gmail.com
parent eccead9e
...@@ -1012,10 +1012,15 @@ SELECT pg_start_backup('label', true); ...@@ -1012,10 +1012,15 @@ SELECT pg_start_backup('label', true);
<programlisting> <programlisting>
SELECT pg_stop_backup(); SELECT pg_stop_backup();
</programlisting> </programlisting>
This terminates the backup mode and performs an automatic switch to This function, when called on a primary, terminates the backup mode and
the next WAL segment. The reason for the switch is to arrange for performs an automatic switch to the next WAL segment. The reason for the
the last WAL segment file written during the backup interval to be switch is to arrange for the last WAL segment written during the backup
ready to archive. interval to be ready to archive. When called on a standby, this function
only terminates backup mode. A subsequent WAL segment switch will be
needed in order to ensure that all WAL files needed to restore the backup
can be archived; if the primary does not have sufficient write activity
to trigger one, <function>pg_switch_wal</function> should be executed on
the primary.
</para> </para>
</listitem> </listitem>
<listitem> <listitem>
......
...@@ -18597,7 +18597,12 @@ postgres=# select pg_start_backup('label_goes_here'); ...@@ -18597,7 +18597,12 @@ postgres=# select pg_start_backup('label_goes_here');
WAL to be archived. This behavior is only useful for backup WAL to be archived. This behavior is only useful for backup
software which independently monitors WAL archiving. Otherwise, WAL software which independently monitors WAL archiving. Otherwise, WAL
required to make the backup consistent might be missing and make the backup required to make the backup consistent might be missing and make the backup
useless. useless. When this parameter is set to true, <function>pg_stop_backup</>
will wait for WAL to be archived when archiving is enabled; on the standby,
this means that it will wait only when <varname>archive_mode = always</>.
If write activity on the primary is low, it may be useful to run
<function>pg_switch_wal</> on the primary in order to trigger
an immediate segment switch.
</para> </para>
<para> <para>
......
...@@ -10880,11 +10880,13 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p) ...@@ -10880,11 +10880,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 * backup. We have no way of checking if pg_control wasn't backed up last
* however. * however.
* *
* We don't force a switch to new WAL file and wait for all the required * We don't force a switch to new WAL file but it is still possible to
* files to be archived. This is okay if we use the backup to start the * wait for all the required files to be archived if waitforarchive is
* standby. But, if it's for an archive recovery, to ensure all the * true. This is okay if we use the backup to start a standby and fetch
* required files are available, a user should wait for them to be * the missing WAL using streaming replication. But in the case of an
* archived, or include them into the backup. * 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 * We return the current minimum recovery point as the backup end
* location. Note that it can be greater than the exact backup end * location. Note that it can be greater than the exact backup end
...@@ -10924,66 +10926,65 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p) ...@@ -10924,66 +10926,65 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
stoppoint = ControlFile->minRecoveryPoint; stoppoint = ControlFile->minRecoveryPoint;
stoptli = ControlFile->minRecoveryPointTLI; stoptli = ControlFile->minRecoveryPointTLI;
LWLockRelease(ControlFileLock); 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 * 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.
XLogBeginInsert(); */
XLogRegisterData((char *) (&startpoint), sizeof(startpoint)); RequestXLogSwitch(false);
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(false);
XLByteToPrevSeg(stoppoint, _logSegNo); XLByteToPrevSeg(stoppoint, _logSegNo);
XLogFileName(stopxlogfilename, ThisTimeLineID, _logSegNo); XLogFileName(stopxlogfilename, stoptli, _logSegNo);
/* Use the log timezone here, not the session timezone */ /* Use the log timezone here, not the session timezone */
stamp_time = (pg_time_t) time(NULL); stamp_time = (pg_time_t) time(NULL);
pg_strftime(strfbuf, sizeof(strfbuf), pg_strftime(strfbuf, sizeof(strfbuf),
"%Y-%m-%d %H:%M:%S %Z", "%Y-%m-%d %H:%M:%S %Z",
pg_localtime(&stamp_time, log_timezone)); pg_localtime(&stamp_time, log_timezone));
/* /*
* Write the backup history file * Write the backup history file
*/ */
XLByteToSeg(startpoint, _logSegNo); XLByteToSeg(startpoint, _logSegNo);
BackupHistoryFilePath(histfilepath, ThisTimeLineID, _logSegNo, BackupHistoryFilePath(histfilepath, stoptli, _logSegNo,
(uint32) (startpoint % XLogSegSize)); (uint32) (startpoint % XLogSegSize));
fp = AllocateFile(histfilepath, "w"); fp = AllocateFile(histfilepath, "w");
if (!fp) if (!fp)
ereport(ERROR, ereport(ERROR,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not create file \"%s\": %m", errmsg("could not create file \"%s\": %m",
histfilepath))); histfilepath)));
fprintf(fp, "START WAL LOCATION: %X/%X (file %s)\n", fprintf(fp, "START WAL LOCATION: %X/%X (file %s)\n",
(uint32) (startpoint >> 32), (uint32) startpoint, startxlogfilename); (uint32) (startpoint >> 32), (uint32) startpoint, startxlogfilename);
fprintf(fp, "STOP WAL LOCATION: %X/%X (file %s)\n", fprintf(fp, "STOP WAL LOCATION: %X/%X (file %s)\n",
(uint32) (stoppoint >> 32), (uint32) stoppoint, stopxlogfilename); (uint32) (stoppoint >> 32), (uint32) stoppoint, stopxlogfilename);
/* transfer remaining lines from label to history file */ /* transfer remaining lines from label to history file */
fprintf(fp, "%s", remaining); fprintf(fp, "%s", remaining);
fprintf(fp, "STOP TIME: %s\n", strfbuf); fprintf(fp, "STOP TIME: %s\n", strfbuf);
if (fflush(fp) || ferror(fp) || FreeFile(fp)) if (fflush(fp) || ferror(fp) || FreeFile(fp))
ereport(ERROR, ereport(ERROR,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not write file \"%s\": %m", errmsg("could not write file \"%s\": %m",
histfilepath))); histfilepath)));
/* /*
* Clean out any no-longer-needed history files. As a side effect, this * Clean out any no-longer-needed history files. As a side effect,
* will post a .ready file for the newly created history file, notifying * this will post a .ready file for the newly created history file,
* the archiver that history file may be archived immediately. * notifying the archiver that history file may be archived
*/ * immediately.
CleanupBackupHistory(); */
CleanupBackupHistory();
}
/* /*
* If archiving is enabled, wait for all the required WAL files to be * If archiving is enabled, wait for all the required WAL files to be
...@@ -11005,13 +11006,16 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p) ...@@ -11005,13 +11006,16 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
* or you can set statement_timeout. Also, some notices are issued to * or you can set statement_timeout. Also, some notices are issued to
* clue in anyone who might be doing this interactively. * 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); XLByteToPrevSeg(stoppoint, _logSegNo);
XLogFileName(lastxlogfilename, ThisTimeLineID, _logSegNo); XLogFileName(lastxlogfilename, stoptli, _logSegNo);
XLByteToSeg(startpoint, _logSegNo); XLByteToSeg(startpoint, _logSegNo);
BackupHistoryFileName(histfilename, ThisTimeLineID, _logSegNo, BackupHistoryFileName(histfilename, stoptli, _logSegNo,
(uint32) (startpoint % XLogSegSize)); (uint32) (startpoint % XLogSegSize));
seconds_before_warning = 60; seconds_before_warning = 60;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment