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 da...@pgmasters.net
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 (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers