PostgreSQL Timelines and History File – Master Guide

“TIMELINES ARE THE DIVERGENT POINTS”

Let’s assume you did a point in time recovery after a wrong transaction, PostgreSQL branches to a new timeline and continue with the operations.

But what happens after you perform a point in time recovery, realized you made a mistake again?

That’s where recovery_target_timeline comes into picture.

In this post we are going to understand everything about recovery_target_timeline and timelines in PostgreSQL in general.

PostgreSQL Timeline

Everytime you do a transaction in PostgreSQL the information is recorded in a wal file under $DATADIR/wal location.

The first file that is created is

000000010000000000000001

and when it is filled the next wal will be created with the name 000000010000000000000002 and so on.(It is a HEX notation and more information is beyond the scope of this post)

Here, the first eight digits represent PostgreSQL timeline.

In our example, the database cluster is in timeline 1.

After every point in time recovery, the timeline id will be increased by 1 and a new file called NewTimelineID.history is created.

recovery_target_timeline is a parameter which helps us to take our cluster to any timeline in the history provided a valid base backup and all the archivelogs in place.

Lets consider below example.,

I have initialized and started a new cluster with the below command

Then I created a table and inserted a record into it

My record is somewhere in my wal 000000010000000000000001

After few switches, I have taken a full backup when my wal at 000000010000000000000005

Then I made a few switches and when my wal is at 000000010000000000000008

I inserted a new record.

Then I made few switches and my current archived wal location is something like this

At this point of time, I have done a point in time recovery to some point in 000000010000000000000007 wal, before second insert.

so I gave recovery target lsn as ‘0/07000060’ in postgresql.conf file.

After successful point in time recovery, the PostgreSQL branched to a new timeline.

At the end of recovery the following things will happen

  • End of recovery means the point where the the database opens up for writing
  • New timeline is chosen
  • A timeline history file is written
  • The partial last WAL file on the previous timeline is copied with the new timeline’s ID
  • A checkpoint record is written on the new timeline

alert log says,

after executing pg_wal_replay_resume(), the postgresql changed to timeline 2 and the same information is recorded in archivelog location.

Here, the PostgreSQL has branched to a new timeline at walfile 7 and started creating new walfiles with timeline id 2.

The 00000002.history file confirms that the PostgreSQL has branched to new timeline.

The history file is a small text file that read

Here

1<parentTLI>    0/70000D8 <switchpoint>     after LSN 0/7000060<reason>

parentTLI                  ID of the parent timeline
switchpoint                XLogRecPtr of the WAL location where the switch happened
reason                       human-readable explanation of why the timeline was changed

Now, I inserted one record at 00000002000000000000000A (0/A000060)

and another record at 00000002000000000000000D (0/D000000)

At this point of time I realized that I did a mistake at 00000002000000000000000D and has to rollback to 00000002000000000000000C of timeline 2.

This can be achieved by setting below parameters in postgresql.conf file

After setting up above parameters, I started the cluster and the alert log says

When I selected the table,

The history file will is recorded with below details

Here

timeline 1 branched at 0/70000D8

timeline 2 branched at 0/C0000D8

and current timeline is going to be 3.

Active data guard in PostgreSQL:

Let us consider there is an active streaming replication in place (streaming replication configuration is not the part of this post)

The left hand side demonstrates primary and right hand side indicates that standby is in sync with primary.

During the cutover, the wal files diverged at wal file 16

Here, from 16 onwards, both primary and standby started creating its own wal files.

I inserted few records in same table in both machines and have done few log switches.

Here, which indicates that I used my standby as an active data guard.

At this point of time, I have done with my testing, now I wanted to make my secondary machine as a standby for primary again.

How can I do that ?

Using divergent timeline,  just rewind the standby cluster and set up replication again(create recovery.conf file).

  • Stop standby cluster.
  • use pg_rewind to revert the changes made after divergent.

pg_rewind –target-pgdata=/u02/pgsql/16 –source-server=”port=5432 user=postgres host=192.168.1.128″

  • Create a recovery.conf file and place it in standby machine

  • start the standby cluster

pg_ctl start -D /u02/pgsql/16

alert log says,

  • Check if the recovery is getting continued from where it was stopped during divergent.

Records inserted after divergent are gone and my standby has started receiving data from primary.

How to resolve requested starting point XX on timeline x is not in this server’s history?

Let us conclude the timeline discussion with a final simulation.

From above output, it is confirmed that my standby started receiving data.

Here, I made divergence again and inserted a record

8 | simulate but in the history of the requested timeline

in old primary, at the same time inserted a record

‘8’,’simulate new record after divergent’

in new primary.

Ensured that both had different checkpoints after divergence.

Now when I tried to make old primary as standby to current primary by adding a recovery.conf file, I got below error when starting the cluster.

FATAL: could not start WAL streaming: ERROR: requested starting point 0/1D000000 on timeline 2 is not in this server’s history

DETAIL: This server’s history forked from timeline 2 at 0/1C0004C8.

The error is because, after divergence when I tried to make old primary as standby I need to ensure that all the changes made in old primary has to be reverted.

this can be achived with pg_rewind.

so I did pg_rewind and started my old primary cluster.

pg_rewind –target-pgdata=/u02/pgsql/15 –source-server=”port=5433 user=postgres host=192.168.1.128″

The database started with alert log

Words from postgreshelp

Thank you for giving your valuable time to read the above information. I hope the content served your purpose in reaching out the blog.
Suggestions for improvement of the blog are highly appreciable. Please contact us for any information/suggestion/feedback.

If you want to be updated with all our articles

please follow us on Facebook Twitter
Please subscribe to our newsletter.

Leave a Reply