Skip to content
This documentation is sourced from a third-party project and is not maintained by pgEdge.

Point-in-Time Recovery

Restore a Backup in Quick Start performed default recovery, which is to play all the way to the end of the WAL stream. In the case of a hardware failure this is usually the best choice but for data corruption scenarios (whether machine or human in origin) Point-in-Time Recovery (PITR) is often more appropriate.

Point-in-Time Recovery (PITR) allows the WAL to be played from a backup to a specified lsn, time, transaction id, or recovery point. For common recovery scenarios time-based recovery is arguably the most useful. A typical recovery scenario is to restore a table that was accidentally dropped or data that was accidentally deleted. Recovering a dropped table is more dramatic so that's the example given here but deleted data would be recovered in exactly the same way.

Create a table with very important data

psql -c "begin;
                             create table important_table (message text);
                             insert into important_table values ('Important Data');
                             commit;
                             select * from important_table;"

It is important to represent the time as reckoned by PostgreSQL and to include timezone offsets. This reduces the possibility of unintended timezone conversions and an unexpected recovery result.

Get the time from

psql -Atc "select current_timestamp"

Now that the time has been recorded the table is dropped. In practice finding the exact time that the table was dropped is a lot harder than in this example. It may not be possible to find the exact time, but some forensic work should be able to get you close.

Drop the important table

psql -c "begin;
                                  drop table important_table;
                                  commit;
                                  select * from important_table;"

If the wrong backup is selected for restore then recovery to the required time target will fail. To demonstrate this a new incremental backup is performed where important_table does not exist.

Perform an incremental backup

pgbackrest --stanza=demo --type=incr backup
pgbackrest info

It will not be possible to recover the lost table from this backup since PostgreSQL can only play forward, not backward.

Attempt recovery from an incorrect backup

pg_ctlcluster 17 demo stop
pgbackrest --stanza=demo --delta
                     --set=<backup-last> --target-timeline=current
                     --type=time "--target=<time-recovery-timestamp>" --target-action=promote restore
pg_ctlcluster 17 demo start
pg_ctlcluster 17 demo start
cat /var/log/postgresql/postgresql-17-demo.log
pg_ctlcluster 17 demo start
psql -c "select * from important_table"

Looking at the log output it's not obvious that recovery failed to restore the table. The key is to look for the presence of the "recovery stopping before..." and "last completed transaction..." log messages. If they are not present then the recovery to the specified point-in-time was not successful.

Examine the log output to discover the recovery was not successful

cat /var/log/postgresql/postgresql-17-demo.log

A reliable method is to allow pgBackRest to automatically select a backup capable of recovery to the time target, i.e. a backup that ended before the specified time.

Note

pgBackRest cannot automatically select a backup when the restore type is xid or name.

Restore the demo cluster to

pg_ctlcluster 17 demo stop
pgbackrest --stanza=demo --delta
                    --type=time "--target=<time-recovery-timestamp>"
                    --target-action=promote restore
cat /var/lib/postgresql/17/demo/postgresql.auto.conf

pgBackRest has generated the recovery settings in postgresql.auto.conf so PostgreSQL can be started immediately. %f is how PostgreSQL specifies the WAL segment it needs and %p is the location where it should be copied. Once PostgreSQL has finished recovery the table will exist again and can be queried.

Start and check that the important table exists

pg_ctlcluster 17 demo start
psql -c "select * from important_table"

The PostgreSQL log also contains valuable information. It will indicate the time and transaction where the recovery stopped and also give the time of the last transaction to be applied.

Examine the log output

cat /var/log/postgresql/postgresql-17-demo.log