Expose waitforarchive option through pg_stop_backup()
authorStephen Frost <sfrost@snowman.net>
Thu, 23 Mar 2017 03:44:58 +0000 (23:44 -0400)
committerStephen Frost <sfrost@snowman.net>
Thu, 23 Mar 2017 03:44:58 +0000 (23:44 -0400)
Internally, we have supported the option to either wait for all of the
WAL associated with a backup to be archived, or to return immediately.
This option is useful to users of pg_stop_backup() as well, when they
are reading the stop backup record position and checking that the WAL
they need has been archived independently.

This patch adds an additional, optional, argument to pg_stop_backup()
which allows the user to indicate if they wish to wait for the WAL to be
archived or not.  The default matches current behavior, which is to
wait.

Author: David Steele, with some minor changes, doc updates by me.
Reviewed by: Takayuki Tsunakawa, Fujii Masao
Discussion: https://postgr.es/m/758e3fd1-45b4-5e28-75cd-e9e7f93a4c02@pgmasters.net

doc/src/sgml/backup.sgml
doc/src/sgml/func.sgml
src/backend/access/transam/xlog.c
src/backend/access/transam/xlogfuncs.c
src/backend/catalog/system_views.sql
src/include/catalog/catversion.h
src/include/catalog/pg_proc.h

index 2d67521775c06141bff90bf12538479923654d7c..8cf63e478a0e4d308cc86d2c932041f514cc999a 100644 (file)
@@ -887,7 +887,7 @@ SELECT pg_start_backup('label', false, false);
     <para>
      In the same connection as before, issue the command:
 <programlisting>
-SELECT * FROM pg_stop_backup(false);
+SELECT * FROM pg_stop_backup(false, true);
 </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
@@ -924,6 +924,17 @@ SELECT * FROM pg_stop_backup(false);
      <function>pg_stop_backup</> terminates because of this your backup
      may not be valid.
     </para>
+    <para>
+     If the backup process monitors and ensures that all WAL segment files
+     required for the backup are successfully archived then the second
+     parameter (which defaults to true) can be set to false to have
+     <function>pg_stop_backup</> return as soon as the stop backup record is
+     written to the WAL.  By default, <function>pg_stop_backup</> will wait
+     until all WAL has been archived, which can take some time.  This option
+     must be used with caution: if WAL archiving is not monitored correctly
+     then the backup might not include all of the WAL files and will
+     therefore be incomplete and not able to be restored.
+    </para>
    </listitem>
   </orderedlist>
     </para>
index 9408a255dc6b15183cc561687318a444b99a197b..4dc30caccb63d422fcbdc7c8dc1fb33904ebd1c6 100644 (file)
@@ -18355,7 +18355,7 @@ SELECT set_config('log_statement_stats', 'off', false);
       </row>
       <row>
        <entry>
-        <literal><function>pg_stop_backup(<parameter>exclusive</> <type>boolean</>)</function></literal>
+        <literal><function>pg_stop_backup(<parameter>exclusive</> <type>boolean</> <optional>, <parameter>wait_for_archive</> <type>boolean</> </optional>)</function></literal>
         </entry>
        <entry><type>setof record</type></entry>
        <entry>Finish performing exclusive or non-exclusive on-line backup (restricted to superusers by default, but other users can be granted EXECUTE to run the function)</entry>
@@ -18439,7 +18439,13 @@ 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).  There is an optional second
+    parameter of type boolean.  If false, the <function>pg_stop_backup</>
+    will return immediately after the backup is completed without waiting for
+    WAL to be archived.  This behavior is only useful for backup
+    software which independently monitors WAL archiving. Otherwise, WAL
+    required to make the backup consistent might be missing and make the backup
+    useless.
    </para>
 
    <para>
index ff4cf3a810b6c8cc9fd982a11338147f2f8ff883..3924738a336d2ad6a4f31a62182ebc54e0e081e4 100644 (file)
@@ -10944,7 +10944,8 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
     *
     * We wait forever, since archive_command is supposed to work and we
     * assume the admin wanted his backup to work completely. If you don't
-    * wish to wait, you can set statement_timeout.  Also, some notices are
+    * wish to wait, then either waitforarchive should be passed in as false,
+    * or you can set statement_timeout.  Also, some notices are
     * issued to clue in anyone who might be doing this interactively.
     */
    if (waitforarchive && XLogArchivingActive())
index 96aa15e9cc3d72cc4843b5b944b9235aa80bc71d..5073aaca84f60064b280d0dcd04a6227c180d99f 100644 (file)
@@ -175,6 +175,13 @@ pg_stop_backup(PG_FUNCTION_ARGS)
  * the backup label and tablespace map files as text fields in as part of the
  * resultset.
  *
+ * The first parameter (variable 'exclusive') allows the user to tell us if
+ * this is an exclusive or a non-exclusive backup.
+ *
+ * The second paramter (variable 'waitforarchive'), which is optional,
+ * allows the user to choose if they want to wait for the WAL to be archived
+ * or if we should just return as soon as the WAL record is written.
+ *
  * Permission checking for this function is managed through the normal
  * GRANT system.
  */
@@ -190,6 +197,7 @@ pg_stop_backup_v2(PG_FUNCTION_ARGS)
    bool        nulls[3];
 
    bool        exclusive = PG_GETARG_BOOL(0);
+   bool        waitforarchive = PG_GETARG_BOOL(1);
    XLogRecPtr  stoppoint;
 
    /* check to see if caller supports us returning a tuplestore */
@@ -232,7 +240,7 @@ pg_stop_backup_v2(PG_FUNCTION_ARGS)
         * Stop the exclusive backup, and since we're in an exclusive backup
         * return NULL for both backup_label and tablespace_map.
         */
-       stoppoint = do_pg_stop_backup(NULL, true, NULL);
+       stoppoint = do_pg_stop_backup(NULL, waitforarchive, NULL);
        exclusive_backup_running = false;
 
        nulls[1] = true;
@@ -250,7 +258,7 @@ pg_stop_backup_v2(PG_FUNCTION_ARGS)
         * Stop the non-exclusive backup. Return a copy of the backup label
         * and tablespace map so they can be written to disk by the caller.
         */
-       stoppoint = do_pg_stop_backup(label_file->data, true, NULL);
+       stoppoint = do_pg_stop_backup(label_file->data, waitforarchive, NULL);
        nonexclusive_backup_running = false;
        cancel_before_shmem_exit(nonexclusive_base_backup_cleanup, (Datum) 0);
 
index b6552da4b03eaf531cf68ea1e8f7b605a4ba3c87..c2b0bedc1d680ecf59f7aa417164e96b61550cba 100644 (file)
@@ -988,6 +988,12 @@ CREATE OR REPLACE FUNCTION
   RETURNS pg_lsn STRICT VOLATILE LANGUAGE internal AS 'pg_start_backup'
   PARALLEL RESTRICTED;
 
+CREATE OR REPLACE FUNCTION pg_stop_backup (
+        exclusive boolean, wait_for_archive boolean DEFAULT true,
+        OUT lsn pg_lsn, OUT labelfile text, OUT spcmapfile text)
+  RETURNS SETOF record STRICT VOLATILE LANGUAGE internal as 'pg_stop_backup_v2'
+  PARALLEL RESTRICTED;
+
 -- legacy definition for compatibility with 9.3
 CREATE OR REPLACE FUNCTION
   json_populate_record(base anyelement, from_json json, use_json_as_text boolean DEFAULT false)
@@ -1088,7 +1094,7 @@ AS 'jsonb_insert';
 -- available to superuser / cluster owner, if they choose.
 REVOKE EXECUTE ON FUNCTION pg_start_backup(text, boolean, boolean) FROM public;
 REVOKE EXECUTE ON FUNCTION pg_stop_backup() FROM public;
-REVOKE EXECUTE ON FUNCTION pg_stop_backup(boolean) FROM public;
+REVOKE EXECUTE ON FUNCTION pg_stop_backup(boolean, boolean) FROM public;
 REVOKE EXECUTE ON FUNCTION pg_create_restore_point(text) FROM public;
 REVOKE EXECUTE ON FUNCTION pg_switch_wal() FROM public;
 REVOKE EXECUTE ON FUNCTION pg_wal_replay_pause() FROM public;
index b4f1b9a6c2aa788e35d4634beefd3b65087286ef..315f155b6453bb928c4394e4ac2214189d352685 100644 (file)
@@ -53,6 +53,6 @@
  */
 
 /*                         yyyymmddN */
-#define CATALOG_VERSION_NO 201703161
+#define CATALOG_VERSION_NO 201703221
 
 #endif
index 836d6ff0b2069f95f5e51f421ef4480da4741473..22635655f5670a30bd762e70095baa4f062fc7c9 100644 (file)
@@ -3172,7 +3172,7 @@ DATA(insert OID = 2172 ( pg_start_backup      PGNSP PGUID 12 1 0 0 0 f f f f t f v r
 DESCR("prepare for taking an online backup");
 DATA(insert OID = 2173 ( pg_stop_backup            PGNSP PGUID 12 1 0 0 0 f f f f t f v r 0 0 3220 "" _null_ _null_ _null_ _null_ _null_ pg_stop_backup _null_ _null_ _null_ ));
 DESCR("finish taking an online backup");
-DATA(insert OID = 2739 ( pg_stop_backup            PGNSP PGUID 12 1 1 0 0 f f f f t t v r 1 0 2249 "16" "{16,3220,25,25}" "{i,o,o,o}" "{exclusive,lsn,labelfile,spcmapfile}" _null_ _null_ pg_stop_backup_v2 _null_ _null_ _null_ ));
+DATA(insert OID = 2739 ( pg_stop_backup            PGNSP PGUID 12 1 1 0 0 f f f f t t v r 2 0 2249 "16 16" "{16,16,3220,25,25}" "{i,i,o,o,o}" "{exclusive,wait_for_archive,lsn,labelfile,spcmapfile}" _null_ _null_ pg_stop_backup_v2 _null_ _null_ _null_ ));
 DESCR("finish taking an online backup");
 DATA(insert OID = 3813 ( pg_is_in_backup       PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 16 "" _null_ _null_ _null_ _null_ _null_ pg_is_in_backup _null_ _null_ _null_ ));
 DESCR("true if server is in online backup");