Multiple Repositories

A key feature of the v2.33 pgBackrest release is support for multiple repositories. This lets you define different behavior for different backup repositories. As an example, you could have a local repository for fast restore that had short retention period (to save space) paired with a remote repository which is larger for cold storage.

This feature introduces a new --repo option which can be used to set the repository the command should apply to. All repo*- options are indexed to enable configuring multiple repositories.

In this section, we will set up a demo cluster (using EDB Postgres Advanced Server version 13 on CentOS 7) to demonstrate how this new feature impacts each pgBackRest command.

Configuration

It must be noted that in this demo, we will set up two local repositories on our database host. For production purposes, it is recommended to store each repository on separate storage, and configure at least one remote repository.

[global]
# repository details
repo1-path=/var/lib/edb/as13/backups/repo1
repo1-retention-full=1
repo2-path=/var/lib/edb/as13/backups/repo2
repo2-retention-full=1

# general options
process-max=2
log-level-console=info
log-level-file=debug
start-fast=y
delta=y

[demo]
pg1-path=/var/lib/edb/as13/data
pg1-user=enterprisedb
pg1-port=5444

For safety reasons, the --repo option can't be defined in the configuration file or a warning will be triggered: WARN: configuration file contains command-line only option 'repo'. If there is more than one repository configured and the --repo option is not specified for a command, the repository with the highest priority order (e.g. repo1 then repo2) will be chosen by default.

The --repo option is not required when only repo1 is configured to maintain backward compatibility. However, when a single repository is configured, it is recommended to use repo1 in the configuration.

Initialization

Stanza Create Command

The stanza-create command will automatically operate on all configured repositories:

$ pgbackrest --stanza=demo stanza-create
P00   INFO: stanza-create for stanza 'demo' on repo1
P00   INFO: stanza-create for stanza 'demo' on repo2

Check Command

The check command will trigger a new WAL segment to be archived and try to push it to all defined repositories:

$ pgbackrest --stanza=demo check
P00   INFO: check repo1 configuration (primary)
P00   INFO: check repo2 configuration (primary)
P00   INFO: check repo1 archive for WAL (primary)
P00   INFO: WAL segment ... successfully archived to '...' on repo1
P00   INFO: check repo2 archive for WAL (primary)
P00   INFO: WAL segment ... successfully archived to '...' on repo2

Archive Push Command

The archive-push command will always archive WALs in all configured repositories. Backups will need to be scheduled individually for each repository. In most cases, this is desirable since backup types and retention could vary per repository.

The archive_command can still be defined as usual:

$ psql -d postgres -c "show archive_command;"
             archive_command              
------------------------------------------
 pgbackrest --stanza=demo archive-push %p
(1 row)

Here is a DEBUG extract of the PostgreSQL logs showing the archive-push activity:

...
P00  DEBUG:     storage/storage::storageNewWrite: => {
	type: posix, name: {"/var/lib/edb/as13/backups/repo1/archive/demo/13-1/0000000100000000/
							000000010000000000000005-be9a61a800934879842fa647b0d50385f44e0228.gz"}, 
	modeFile: 0640, modePath: 0750, createPath: true, syncFile: true, syncPath: true, atomic: true}
...
P00  DEBUG:     storage/storage::storageNewWrite: => {
	type: posix, name: {"/var/lib/edb/as13/backups/repo2/archive/demo/13-1/0000000100000000/
							000000010000000000000005-be9a61a800934879842fa647b0d50385f44e0228.gz"}, 
	modeFile: 0640, modePath: 0750, createPath: true, syncFile: true, syncPath: true, atomic: true}
...
P00   INFO: pushed WAL file '000000010000000000000005' to the archive

The archive-push command will try to push the WAL archive to all reachable repositories. The idea is to archive to as many repositories as possible even if we still need to throw an error to PostgreSQL to prevent it from removing the WAL file.

P00   INFO: archive-push command begin: [pg_wal/000000010000000000000006] ...
...
P00   INFO: archive-push command begin: [pg_wal/000000010000000000000007] ...
ERROR: [104]: archive-push command encountered error(s):
       repo2: [PathOpenError] unable to list file info for path '...': [13] Permission denied
P00   INFO: archive-push command end: aborted with exception [104]
DETAIL:  The failed archive command was: pgbackrest --stanza=demo archive-push pg_wal/000000010000000000000007
WARNING:  archiving write-ahead log file "000000010000000000000007" failed too many times, will try again later

The PostgreSQL archiver process should then report an error:

$ ps -o pid,cmd fx |grep archiver
 4440  \_ postgres: archiver failed on 000000010000000000000007

The next WAL segments should not then be archived:

$ psql -d postgres -c "SELECT pg_create_restore_point('generate some activity'); SELECT pg_switch_wal();"
 pg_switch_wal 
---------------
 0/80001C8
(1 row)

$ ls as13/data/pg_wal/archive_status/ |grep ".ready"
000000010000000000000007.ready
000000010000000000000008.ready

This becomes very handy by adding archive-async=y to the configuration in order to use asynchronous archiving processes within pgBackRest itself. Even if PostgreSQL archiver process is still stuck, the archives will reach the working repositories:

$ $ ls /var/lib/edb/as13/backups/repo1/archive/demo/13-1/0000000100000000/
000000010000000000000005-be9a61a800934879842fa647b0d50385f44e0228.gz
000000010000000000000006-7108296955e1208c93447dcfc5712ce59af97907.gz
000000010000000000000007-f1b6fcdd23e96a19a7a89dc92613674c2316aa49.gz
000000010000000000000008-791c44d39ef772d58e51d64c8e3589231d3916a4.gz
000000010000000000000009-47241214eb3fd5e693eed778caa7b304a778ecc2.gz

$ ls /var/lib/edb/as13/backups/repo2/archive/demo/13-1/0000000100000000/
000000010000000000000005-be9a61a800934879842fa647b0d50385f44e0228.gz
000000010000000000000006-7108296955e1208c93447dcfc5712ce59af97907.gz

Let us unblock the archiver process (and remove asynchronous archiving) before going further:

$ $ ps -o pid,cmd fx |grep archiver
 4440  \_ postgres: archiver last was 00000001000000000000000

Backups

Backup Command

Let us take a few backups:

$ pgbackrest backup --stanza=demo --type=full
P00   INFO: backup command begin ...
P00   INFO: repo option not specified, defaulting to repo1
P00   INFO: execute non-exclusive pg_start_backup(): backup begins after the requested immediate checkpoint completes
P00   INFO: backup start archive = 00000001000000000000000C, lsn = 0/C000060
P00   INFO: full backup size = 50.4MB
P00   INFO: execute non-exclusive pg_stop_backup() and wait for all WAL segments to archive
P00   INFO: backup stop archive = 00000001000000000000000C, lsn = 0/C000138
P00   INFO: check archive for segment(s) 00000001000000000000000C:00000001000000000000000C
P00   INFO: new backup label = 20210419-142212F
P00   INFO: backup command end: completed successfully

$ pgbackrest backup --stanza=demo --type=full --repo=2
P00   INFO: backup command begin ...
P00   INFO: execute non-exclusive pg_start_backup(): backup begins after the requested immediate checkpoint completes
P00   INFO: backup start archive = 00000001000000000000000E, lsn = 0/E000028
P00   INFO: full backup size = 50.5MB
P00   INFO: execute non-exclusive pg_stop_backup() and wait for all WAL segments to archive
P00   INFO: backup stop archive = 00000001000000000000000E, lsn = 0/E000138
P00   INFO: check archive for segment(s) 00000001000000000000000E:00000001000000000000000E
P00   INFO: new backup label = 20210419-142414F
P00   INFO: backup command end: completed successfully

$ pgbackrest backup --stanza=demo --type=incr --repo=1
P00   INFO: backup command begin ...
P00   INFO: last backup label = 20210419-142212F, version = ...
P00   INFO: execute non-exclusive pg_start_backup(): backup begins after the requested immediate checkpoint completes
P00   INFO: backup start archive = 000000010000000000000010, lsn = 0/10000028
P00   INFO: incr backup size = 50.5MB
P00   INFO: execute non-exclusive pg_stop_backup() and wait for all WAL segments to archive
P00   INFO: backup stop archive = 000000010000000000000010, lsn = 0/10000100
P00   INFO: check archive for segment(s) 000000010000000000000010:000000010000000000000010
P00   INFO: new backup label = 20210419-142212F_20210419-142502I
P00   INFO: backup command end: completed successfully

$ pgbackrest backup --stanza=demo --type=incr --repo=2
P00   INFO: backup command begin ...
P00   INFO: last backup label = 20210419-142414F, version = ...
P00   INFO: execute non-exclusive pg_start_backup(): backup begins after the requested immediate checkpoint completes
P00   INFO: backup start archive = 000000010000000000000012, lsn = 0/12000028
P00   INFO: incr backup size = 50.6MB
P00   INFO: execute non-exclusive pg_stop_backup() and wait for all WAL segments to archive
P00   INFO: backup stop archive = 000000010000000000000012, lsn = 0/12000100
P00   INFO: check archive for segment(s) 000000010000000000000012:000000010000000000000012
P00   INFO: new backup label = 20210419-142414F_20210419-142556I
P00   INFO: backup command end: completed successfully

Here, we alternated full and incr backups in each repository.

Info Command

$ pgbackrest info --stanza=demo
stanza: demo
    status: ok
    cipher: none

    db (current)
        wal archive min/max (13): 000000010000000000000002/000000010000000000000012

        full backup: 20210419-142212F
            timestamp start/stop: 2021-04-19 14:22:12 / 2021-04-19 14:22:26
            wal start/stop: 00000001000000000000000C / 00000001000000000000000C
            database size: 50.4MB, database backup size: 50.4MB
            repo1: backup set size: 8MB, backup size: 8MB

        full backup: 20210419-142414F
            timestamp start/stop: 2021-04-19 14:24:14 / 2021-04-19 14:24:26
            wal start/stop: 00000001000000000000000E / 00000001000000000000000E
            database size: 50.5MB, database backup size: 50.5MB
            repo2: backup set size: 8MB, backup size: 8MB

        incr backup: 20210419-142212F_20210419-142502I
            timestamp start/stop: 2021-04-19 14:25:02 / 2021-04-19 14:25:04
            wal start/stop: 000000010000000000000010 / 000000010000000000000010
            database size: 50.5MB, database backup size: 613.4KB
            repo1: backup set size: 8MB, backup size: 26.3KB
            backup reference list: 20210419-142212F

        incr backup: 20210419-142414F_20210419-142556I
            timestamp start/stop: 2021-04-19 14:25:56 / 2021-04-19 14:25:57
            wal start/stop: 000000010000000000000012 / 000000010000000000000012
            database size: 50.6MB, database backup size: 661.5KB
            repo2: backup set size: 8MB, backup size: 28KB
            backup reference list: 20210419-142414F

The default order will sort backups by dates mixing the repositories. It might be confusing to find the backups depending on each other.

We can then split this view per repository:

$ pgbackrest info --stanza=demo --repo=1
stanza: demo
    status: ok
    cipher: none

    db (current)
        wal archive min/max (13): 00000001000000000000000C/000000010000000000000012

        full backup: 20210419-142212F
            timestamp start/stop: 2021-04-19 14:22:12 / 2021-04-19 14:22:26
            wal start/stop: 00000001000000000000000C / 00000001000000000000000C
            database size: 50.4MB, database backup size: 50.4MB
            repo1: backup set size: 8MB, backup size: 8MB

        incr backup: 20210419-142212F_20210419-142502I
            timestamp start/stop: 2021-04-19 14:25:02 / 2021-04-19 14:25:04
            wal start/stop: 000000010000000000000010 / 000000010000000000000010
            database size: 50.5MB, database backup size: 613.4KB
            repo1: backup set size: 8MB, backup size: 26.3KB
            backup reference list: 20210419-142212F

$ pgbackrest info --stanza=demo --repo=2
stanza: demo
    status: ok
    cipher: none

    db (current)
        wal archive min/max (13): 00000001000000000000000E/000000010000000000000012

        full backup: 20210419-142414F
            timestamp start/stop: 2021-04-19 14:24:14 / 2021-04-19 14:24:26
            wal start/stop: 00000001000000000000000E / 00000001000000000000000E
            database size: 50.5MB, database backup size: 50.5MB
            repo2: backup set size: 8MB, backup size: 8MB

        incr backup: 20210419-142414F_20210419-142556I
            timestamp start/stop: 2021-04-19 14:25:56 / 2021-04-19 14:25:57
            wal start/stop: 000000010000000000000012 / 000000010000000000000012
            database size: 50.6MB, database backup size: 661.5KB
            repo2: backup set size: 8MB, backup size: 28KB
            backup reference list: 20210419-142414F

The 'wal archive min/max' shows the minimum and maximum WAL currently stored in the archive and, in the case of multiple repositories, will be reported across all repositories unless the --repo option is set. There may be gaps due to archive retention policies or other reasons.

Let us break the first repository by removing its content:

$ pgbackrest --stanza=demo stanza-delete --repo=1 --force
P00   INFO: stanza-delete command end: completed successfully

$ pgbackrest --stanza=demo stanza-create
P00   INFO: stanza-create for stanza 'demo' on repo1
P00   INFO: stanza-create for stanza 'demo' on repo2
P00   INFO: stanza 'demo' already exists on repo2 and is valid
P00   INFO: stanza-create command end: completed successfully

If multiple repositories are configured, then a status of mixed indicates that the stanza is not in a healthy state for one or more of the repositories. In this case, the state of the stanza will be detailed in additional lines per repository.

$ pgbackrest info --stanza=demo
stanza: demo
    status: mixed
        repo1: error (no valid backups)
        repo2: ok
    cipher: none

    db (current)
        wal archive min/max (13): 00000001000000000000000E/000000010000000000000012

        full backup: 20210419-142414F
            timestamp start/stop: 2021-04-19 14:24:14 / 2021-04-19 14:24:26
            wal start/stop: 00000001000000000000000E / 00000001000000000000000E
            database size: 50.5MB, database backup size: 50.5MB
            repo2: backup set size: 8MB, backup size: 8MB

        incr backup: 20210419-142414F_20210419-142556I
            timestamp start/stop: 2021-04-19 14:25:56 / 2021-04-19 14:25:57
            wal start/stop: 000000010000000000000012 / 000000010000000000000012
            database size: 50.6MB, database backup size: 661.5KB
            repo2: backup set size: 8MB, backup size: 28KB
            backup reference list: 20210419-142414F

This state can be resolved by taking a new backup:

$ pgbackrest backup --stanza=demo --type=full --repo=1
P00   INFO: backup command begin ...
P00   INFO: execute non-exclusive pg_start_backup(): backup begins after the requested immediate checkpoint completes
P00   INFO: backup start archive = 000000010000000000000014, lsn = 0/14000028
P00   INFO: full backup size = 50.6MB
P00   INFO: execute non-exclusive pg_stop_backup() and wait for all WAL segments to archive
P00   INFO: backup stop archive = 000000010000000000000014, lsn = 0/14000138
P00   INFO: check archive for segment(s) 000000010000000000000014:000000010000000000000014
P00   INFO: new backup label = 20210419-143400F
P00   INFO: backup command end: completed successfully

Restore

Let us initiate a situation with some data, backups and restore point:

$ createdb test
$ psql -d test -c "CREATE TABLE t1(id int);"
CREATE TABLE
$ psql -d test -c "INSERT INTO t1 VALUES (1);"
INSERT 0 1

$ pgbackrest backup --stanza=demo --type=full --repo=1
P00   INFO: backup command begin ...
P00   INFO: execute non-exclusive pg_start_backup(): backup begins after the requested immediate checkpoint completes
P00   INFO: backup start archive = 000000010000000000000016, lsn = 0/16000028
P00   INFO: full backup size = 63.0MB
P00   INFO: execute non-exclusive pg_stop_backup() and wait for all WAL segments to archive
P00   INFO: backup stop archive = 000000010000000000000016, lsn = 0/16000138
P00   INFO: check archive for segment(s) 000000010000000000000016:000000010000000000000016
P00   INFO: new backup label = 20210419-143643F
P00   INFO: backup command end: completed successfully
P00   INFO: expire command begin ...
P00   INFO: repo1: expire full backup 20210419-143400F
P00   INFO: repo1: remove expired backup 20210419-143400F
P00   INFO: expire command end: completed successfully

$ psql -d test -c "INSERT INTO t1 VALUES (2);"
INSERT 0 1
$ pgbackrest backup --stanza=demo --type=full --repo=2
P00   INFO: backup command begin ...
P00   INFO: execute non-exclusive pg_start_backup(): backup begins after the requested immediate checkpoint completes
P00   INFO: backup start archive = 000000010000000000000018, lsn = 0/18000028
P00   INFO: full backup size = 63MB
P00   INFO: execute non-exclusive pg_stop_backup() and wait for all WAL segments to archive
P00   INFO: backup stop archive = 000000010000000000000018, lsn = 0/18000138
P00   INFO: check archive for segment(s) 000000010000000000000018:000000010000000000000018
P00   INFO: new backup label = 20210419-143749F
P00   INFO: backup command end: completed successfully
P00   INFO: expire command begin ...
P00   INFO: repo2: expire full backup set 20210419-142414F, 20210419-142414F_20210419-142556I
P00   INFO: repo2: remove expired backup 20210419-142414F_20210419-142556I
P00   INFO: repo2: remove expired backup 20210419-142414F
P00   INFO: expire command end: completed successfully

$ psql -d postgres -c "select pg_create_restore_point('RP1');"
 pg_create_restore_point 
-------------------------
 0/190000C8
(1 row)

$ psql -d postgres -Atc "select current_timestamp,current_setting('datestyle'),txid_current();"
19-APR-21 14:38:55.313716 +00:00|Redwood, SHOW_TIME|1183

$ psql -d test -c "INSERT INTO t1 VALUES (3); SELECT pg_switch_wal();"
 pg_switch_wal 
---------------
 0/19000238
(1 row)

$ pgbackrest info --stanza=demo
stanza: demo
    status: ok
    cipher: none

    db (current)
        wal archive min/max (13): 000000010000000000000016/000000010000000000000019

        full backup: 20210419-143643F
            timestamp start/stop: 2021-04-19 14:36:43 / 2021-04-19 14:37:01
            wal start/stop: 000000010000000000000016 / 000000010000000000000016
            database size: 63.0MB, database backup size: 63.0MB
            repo1: backup set size: 10MB, backup size: 10MB

        full backup: 20210419-143749F
            timestamp start/stop: 2021-04-19 14:37:49 / 2021-04-19 14:38:03
            wal start/stop: 000000010000000000000018 / 000000010000000000000018
            database size: 63MB, database backup size: 63MB
            repo2: backup set size: 10MB, backup size: 10MB

As you can see in the example above, the backup command automatically triggered the expire command on the repository when we created a backup. Since this command is operating on one repository only, it would not expire anything in the other repositories until the backup or expire command is run for that repository.

Since the default retention policy is based on a number of backups, it is expected that only new backups are affecting the backups and archives to expire.

Restore Command

The restore command automatically defaults to selecting the latest backup from the first repository where backups exist. The order in which the repositories are checked is dictated by order of the repositories as configured in the pgbackrest.conf (e.g. repo1 will be checked before repo2). To restore from from a specific repository, the --repo option can be used.

PITR can be performed by specifying --type=time and specifying the target time with --target. If a backup is not specified via the --set option, then the configured repositories will be checked for a backup that contains the requested time. If no backup can be found, the latest backup from the first repository containing backups will be used.

$ mkdir /tmp/restored_data
$ pgbackrest restore --stanza=demo --target="RP1" --type=name --no-delta --pg1-path=/tmp/restored_data
P00   INFO: repo1: restore backup set 20210419-143643F

$ rm -rf /tmp/restored_data/*
$ pgbackrest restore --stanza=demo --target="2021-04-19 14:38:55.313716+00:00" --type=time --no-delta --pg1-path=/tmp/restored_data
HINT: time format must be YYYY-MM-DD HH:MM:SS with optional msec and optional timezone (+/- HH or HHMM or HH:MM) 
	- if timezone is omitted, local time is assumed (for UTC use +00)
P00   INFO: repo1: restore backup set 20210419-143643F

$ rm -rf /tmp/restored_data/* 
$ pgbackrest restore --stanza=demo --target="RP1" --type=name --no-delta --pg1-path=/tmp/restored_data --repo=2
P00   INFO: repo2: restore backup set 20210419-143749F

Even if the backup in repo2 is newer, the first found match is preserved. Let's take a new backup in repo1 to check if pgBackRest will auto-select the backup in repo2:

$ pgbackrest backup --stanza=demo --type=full --repo=1
P00   INFO: backup command begin ...
P00   INFO: execute non-exclusive pg_start_backup(): backup begins after the requested immediate checkpoint completes
P00   INFO: backup start archive = 00000001000000000000001B, lsn = 0/1B000028
P00   INFO: full backup size = 63MB
P00   INFO: execute non-exclusive pg_stop_backup() and wait for all WAL segments to archive
P00   INFO: backup stop archive = 00000001000000000000001B, lsn = 0/1B000138
P00   INFO: check archive for segment(s) 00000001000000000000001B:00000001000000000000001B
P00   INFO: new backup label = 20210419-144656F
P00   INFO: backup command end: completed successfully
P00   INFO: expire command begin ...
P00   INFO: repo1: expire full backup 20210419-143643F
P00   INFO: repo1: remove expired backup 20210419-143643F
P00   INFO: expire command end: completed successfully

$ pgbackrest info --stanza=demo
stanza: demo
    status: ok
    cipher: none

    db (current)
        wal archive min/max (13): 000000010000000000000018/00000001000000000000001B

        full backup: 20210419-143749F
            timestamp start/stop: 2021-04-19 14:37:49 / 2021-04-19 14:38:03
            wal start/stop: 000000010000000000000018 / 000000010000000000000018
            database size: 63MB, database backup size: 63MB
            repo2: backup set size: 10MB, backup size: 10MB

        full backup: 20210419-144656F
            timestamp start/stop: 2021-04-19 14:46:56 / 2021-04-19 14:47:10
            wal start/stop: 00000001000000000000001B / 00000001000000000000001B
            database size: 63MB, database backup size: 63MB
            repo1: backup set size: 10MB, backup size: 10MB

$ rm -rf /tmp/restored_data/*
$ pgbackrest restore --stanza=demo --target="2021-04-19 14:38:55.313716+00:00" --type=time --no-delta --pg1-path=/tmp/restored_data
P00   INFO: repo2: restore backup set 20210419-143749F

The recovery process may be complex and tricky depending on the target, and therefore, the info command can really be helpful to determine the repository to restore from.

Archive Get Command

When multiple repositories are configured, WAL will be fetched from the repositories in priority order (e.g. repo1, repo2, etc.). In general it is better if faster storage has higher priority. The command can operate on a single repository by specifying it with the --repo option.

root# systemctl stop edb-as-13.service
$ mv /var/lib/edb/as13/data /var/lib/edb/as13/data.orig
$ mkdir -m 700 /var/lib/edb/as13/data

$ pgbackrest restore --stanza=demo --target="2021-04-19 14:38:55.313716+00:00" --type=time --no-delta --target-action=promote
P00   INFO: restore command begin ...
P00   INFO: write updated /var/lib/edb/as13/data/postgresql.auto.conf
P00   INFO: restore global/pg_control (performed last to ensure aborted restores cannot be started)
P00   INFO: restore command end: completed successfully

$ cat /var/lib/edb/as13/data/postgresql.auto.conf|grep restore_command
restore_command = 'pgbackrest --stanza=demo archive-get %f "%p"'

root# systemctl start edb-as-13.service
$ cat /var/lib/edb/as13/data/log/edb-2021-04-19_145147.log
...
LOG:  starting point-in-time recovery to 2021-04-19 14:38:55.313716+00
P00   INFO: found 000000010000000000000018 in the repo2: 13-1 archive
P00   INFO: found 000000010000000000000019 in the repo2: 13-1 archive
LOG:  recovery stopping before commit of transaction 1183, time 2021-04-19 14:38:55.314118+00
LOG:  redo done at 0/19000100
P00   INFO: unable to find 00000002.history in the archive
LOG:  selected new timeline ID: 2
LOG:  archive recovery complete
P00   INFO: pushed WAL file '00000002.history' to the archive

$ ls /var/lib/edb/as13/backups/repo*/archive/demo/13-1/00000002.history 
/var/lib/edb/as13/backups/repo1/archive/demo/13-1/00000002.history
/var/lib/edb/as13/backups/repo2/archive/demo/13-1/00000002.history

PostgreSQL found the WALs needed for recovery in our repo2, picked a new timeline and pushed the history file to the repositories.

Whenever a new timeline is created, PostgreSQL creates a timeline history file that shows which timeline it branched off from and when. These history files are necessary to allow the system to pick the right WAL segment files when recovering from a backup that contains multiple timelines.

root# systemctl stop edb-as-13.service
$ rm -rf /var/lib/edb/as13/data/*
$ rm -rf /var/lib/edb/as13/backups/repo1/archive/demo/13-1/00000002.history
$ pgbackrest restore --stanza=demo --target="2021-04-19 14:38:55.313716+00:00" --type=time --target-timeline=current --no-delta --target-action=promote
P00   INFO: restore command begin ...
P00   INFO: repo2: restore backup set 20210419-143749F
P00   INFO: write updated /var/lib/edb/as13/data/postgresql.auto.conf
P00   INFO: restore global/pg_control (performed last to ensure aborted restores cannot be started)
P00   INFO: restore command end: completed successfully

root# systemctl start edb-as-13.service
$ cat /var/lib/edb/as13/data/log/edb-2021-04-19_145721.log
P00   INFO: found 00000002.history in the repo2: 13-1 archive
P00   INFO: unable to find 00000003.history in the archive
LOG:  selected new timeline ID: 3
P00   INFO: pushed WAL file '00000003.history' to the archive

As shown above, since the history file is stored within the same repository as the restored backup set, PostgreSQL is able to pick a new and accurate timeline.

Let us now retry after moving the history file to repo1.

root# systemctl stop edb-as-13.service
$ rm -rf /var/lib/edb/as13/data/*
$ mv /var/lib/edb/as13/backups/repo2/archive/demo/13-1/00000002.history /var/lib/edb/as13/backups/repo1/archive/demo/13-1/00000002.history
$ pgbackrest restore --stanza=demo --target="2021-04-19 14:38:55.313716+00:00" --type=time --target-timeline=current --no-delta --target-action=promote
root# systemctl start edb-as-13.service
$ cat /var/lib/edb/as13/data/log/edb-2021-04-19_150037.log
P00   INFO: found 00000002.history in the repo1: 13-1 archive
P00   INFO: found 00000003.history in the repo1: 13-1 archive
P00   INFO: unable to find 00000004.history in the archive
LOG:  selected new timeline ID: 4
P00   INFO: pushed WAL file '00000004.history' to the archive

As we can see, both 00000002.history and 00000003.history have been found in repo1 so PostgreSQL could pick the next timeline correctly, even if the restored backup set came from repo2.

When using multiple repositories, the archive-get command will tolerate gaps in one repository (due to lack of disk space e.g.) mainly because it will still be able to find the missing files in the other repository.


Could this page be better? Report a problem or suggest an addition!