Currently pg_stop_backup() will wait for all WAL to be archived before
returning. If there is a problem with the archive command or a large
backlog it may not return for a very long time (if ever). Backup
software is faced with the choice of cancelling the query and hoping the
stop backup record was written or waiting indefinitely.
The purpose of this patch is to make waiting for archive optional, with
the default being the current behavior, i.e., to wait for all WAL to be
archived. This functionality is already used internally by
pg_basebackup, so the only real change is to expose it through the
pg_stop_backup() function.
I wasn't sure where, if anywhere, to put tests (the underlying
functionality is tested in the pg_basebackup TAP tests). test/recovery
and bin/pg_basebackup did not seem like appropriate places and the
pg_regress tests are not capable enough. It seems like a new
test/backup suite would be a good idea but I wanted to get some feedback
before proceeding in that direction.
I also marked the pg_stop_* functions as parallel restricted, the same
as pg_start_backup(). Previously they were parallel safe which I don't
believe is accurate for the non-exclusive version at the very least,
since it is tied to a particular backend.
The patch applies cleanly on 30df93f but will be broken (and easily
fixed) by any cat version bump in later commits.
--
-David
[email protected]
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 9c53e42..680a0dc 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -18044,7 +18044,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>
@@ -18128,7 +18128,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>
diff --git a/src/backend/access/transam/xlogfuncs.c
b/src/backend/access/transam/xlogfuncs.c
index 27c0c56..d8fdacf 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -190,6 +190,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 +233,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 +251,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);
diff --git a/src/backend/catalog/system_views.sql
b/src/backend/catalog/system_views.sql
index 38be9cf..c2ca2b8 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -984,6 +984,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'
+ 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)
@@ -1084,7 +1090,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;
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index 9e8c1c2..df47eea 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -53,6 +53,6 @@
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 201702231
+#define CATALOG_VERSION_NO 201702271
#endif
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index a4cc86d..68735c3 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -3141,9 +3141,9 @@ DATA(insert OID = 2096 ( pg_terminate_backend
PGNSP PGUID 12 1 0 0 0 f f f f t
DESCR("terminate a server process");
DATA(insert OID = 2172 ( pg_start_backup PGNSP PGUID 12 1 0 0 0
f f f f t f v r 3 0 3220 "25 16 16" _null_ _null_ _null_ _null_ _null_
pg_start_backup _null_ _null_ _null_ ));
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 s 0 0 3220 "" _null_ _null_ _null_ _null_ _null_
pg_stop_backup _null_ _null_ _null_ ));
+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 s 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");
--
Sent via pgsql-hackers mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers