pg_autoctl show timeline
pg_autoctl show timeline - Show the timeline history known to the monitor for a group, and each node’s position against it
Synopsis
This command prints the group’s known timeline history and each node’s current position against it, as computed by the monitor:
usage: pg_autoctl show timeline [ --pgdata ] --formation --group
--pgdata path to data directory
--monitor pg_auto_failover Monitor Postgres URL
--formation formation to query, defaults to 'default'
--group group to query formation, defaults to 0
Description
Every node periodically publishes its own known timeline history (each
timeline it has ever been on, its parent timeline, and the LSN at which it
switched) to the monitor. pg_autoctl show timeline prints two tables
built from that data:
A timeline history table: every
(tli, parent tli, switchpoint LSN)triple known to the group, one row per timeline, in ascending order.A per-node status table: each node’s currently reported timeline and LSN, and whether that timeline is on the group’s reference lineage — the accepted timeline if one has been pinned with pg_autoctl accept timeline, otherwise the highest reported timeline that nothing else in the group disagrees with. A node not on the reference lineage is flagged
FORK: diverges from the reference timeline, pg_rewind required.
See Timeline Forks for the failure scenario this detects, and the
Report_LSN section of Failover State Machine for how the
election uses this same ancestry information to exclude a diverged
candidate.
Important
Auto-detection only has something to compare against when at least two nodes disagree. In a two-node formation — or whenever every surviving node happens to already be on the same diverged branch — a fork can read as clean, because it’s the only lineage anyone is reporting. Use pg_autoctl accept timeline to pin the correct lineage explicitly when you know, from other evidence, that auto-detection got it wrong.
Options
- --pgdata
Location of the Postgres node being managed locally. Defaults to the environment variable
PGDATA. Use--monitorto connect to a monitor from anywhere, rather than the monitor URI used by a local Postgres node managed withpg_autoctl.- --monitor
Postgres URI used to connect to the monitor. Must use the
autoctl_nodeusername and target thepg_auto_failoverdatabase name. It is possible to show the Postgres URI from the monitor node using the command pg_autoctl show uri.Defaults to the value of the environment variable
PG_AUTOCTL_MONITOR.- --formation
Show the timeline history for the given formation. Defaults to the
defaultformation.- --group
Show the timeline history for the given group in the given formation. Defaults to group
0.
Environment
PGDATA
Postgres directory location. Can be used instead of the
--pgdataoption.
PG_AUTOCTL_MONITOR
Postgres URI to connect to the monitor node, can be used instead of the
--monitoroption.
XDG_CONFIG_HOME
The pg_autoctl command stores its configuration files in the standard place XDG_CONFIG_HOME. See the XDG Base Directory Specification.
XDG_DATA_HOME
The pg_autoctl command stores its internal states files in the standard place XDG_DATA_HOME, which defaults to
~/.local/share. See the XDG Base Directory Specification.
Examples
In this two-node example, node2 was network-partitioned, promoted
directly at the Postgres level (bypassing pg_autoctl), and given a few
local-only writes — a genuine fork onto timeline 2. Unpinned, node2’s
fork reads as clean: it’s the only lineage being reported, and nothing
disagrees with it (the two-node limitation described above):
$ pg_autoctl show timeline --formation default
TLI | Parent TLI | Switchpoint LSN
---------+------------+----------------
1 | 0 | 0/0
2 | 1 | 0/3000130
Name | NodeId | TLI | LSN | Status
---------------------+--------+------+-------------+-----------------------------------------
node1 | 1 | 1 | 0/3000130 | ok, on accepted lineage
node2 | 2 | 2 | 0/3016330 | ok, on accepted lineage
After confirming, from other evidence (here, knowing which node was
manually promoted), that timeline 1 is the real lineage, pin it with
pg_autoctl accept timeline. node2 is now unambiguously flagged:
$ pg_autoctl accept timeline --tli 1 --formation default \
--reason "node2 self-promoted out of band during a network partition"
Timeline 1 accepted as ground truth for formation "default" group 0. The election will now only consider nodes on that lineage; other nodes need pg_rewind before rejoining.
$ pg_autoctl show timeline --formation default
TLI | Parent TLI | Switchpoint LSN
---------+------------+----------------
1 | 0 | 0/0
2 | 1 | 0/3000130
Name | NodeId | TLI | LSN | Status
---------------------+--------+------+-------------+-----------------------------------------
node1 | 1 | 1 | 0/30599B8 | ok, on accepted lineage
node2 | 2 | 2 | 0/3016330 | FORK: diverges from the reference timeline, pg_rewind required
One or more nodes have diverged from the reference timeline (see FORK above).
See `pg_autoctl accept timeline --help` to resolve.
No resync needs to be forced: the monitor re-checks every currently-secondary
node’s ancestry against the freshly-pinned lineage right away, so node2
is pushed to catchingup — and rewound onto timeline 1 with pg_rewind
— within about a second of the accept timeline command above. It rejoins
on the accepted lineage, and the fork clears on its own — no maintenance
cycle, no further operator action, and no need to run an “accept” or
“resolve” command a second time:
$ pg_autoctl show timeline --formation default
TLI | Parent TLI | Switchpoint LSN
---------+------------+----------------
1 | 0 | 0/0
2 | 1 | 0/3000130
Name | NodeId | TLI | LSN | Status
---------------------+--------+------+-------------+-----------------------------------------
node1 | 1 | 1 | 0/70000F8 | ok, on accepted lineage
node2 | 2 | 1 | 0/70000F8 | ok, on accepted lineage
See Resolving a detected timeline fork for the full walkthrough, including how to drive the resync.
More nodes doesn’t fix the blind spot by itself
It’s tempting to assume that a third node closes the gap above — surely,
with a sibling around to disagree, auto-detection catches the fork? A
normal three-node formation’s show timeline looks like this:
$ pg_autoctl show timeline --formation default
TLI | Parent TLI | Switchpoint LSN
---------+------------+----------------
1 | 0 | 0/0
Name | NodeId | TLI | LSN | Status
---------------------+--------+------+-------------+-----------------------------------------
node1 | 1 | 1 | 0/5000060 | ok, on accepted lineage
node2 | 2 | 1 | 0/5000060 | ok, on accepted lineage
node3 | 3 | 1 | 0/5000060 | ok, on accepted lineage
The application keeps writing to the primary the whole time below — a
fork developing on one standby elsewhere in the formation is not a reason
for the main system to pause traffic, and an example where node1/node2
sit idle while only node3 does anything would be misleading about what
this actually looks like in production. Fork node3 the same way as
before (network-partition it, promote it directly at the Postgres level,
give it a couple of local-only writes) while node1 keeps taking
ordinary application writes and replicating them to node2 throughout.
Unpinned, this still reads as clean:
$ pg_autoctl show timeline --formation default
TLI | Parent TLI | Switchpoint LSN
---------+------------+----------------
1 | 0 | 0/0
2 | 1 | 0/5016BC0
Name | NodeId | TLI | LSN | Status
---------------------+--------+------+-------------+-----------------------------------------
node1 | 1 | 1 | 0/5042910 | ok, on accepted lineage
node2 | 2 | 1 | 0/5042910 | ok, on accepted lineage
node3 | 3 | 2 | 0/502D758 | ok, on accepted lineage
Notice node1/node2 are well ahead of node3 in LSN, on their own
unbroken timeline 1 — that’s the application’s own ordinary traffic having
kept flowing the entire time, completely unrelated to node3’s fork. The
auto-detection heuristic (no operator pin) is “the reference lineage is
whichever branch contains the highest reported timeline” — and it only
excludes a candidate when a genuinely competing branch is reported by
someone else: two nodes each diverging from the same point onto two
different timelines. node1 and node2 aren’t competing with
node3 here, they’re simply on a different, ongoing timeline, and
timeline 1 really is node3’s own recorded parent. Structurally that’s
indistinguishable from node3 having been legitimately promoted past two
ordinary, honestly lagging standbys. A third node only helps when it
also reports a divergent history from the same switchpoint; a sibling
that just keeps working on its own lineage doesn’t contest anything.
pg_autoctl accept timeline is still the way out, exactly as in the two-node case. The application’s writes to node1 don’t stop for this either:
$ pg_autoctl accept timeline --tli 1 --formation default --reason "node3 self-promoted out of band during a network partition"
Timeline 1 accepted as ground truth for formation "default" group 0. The election will now only consider nodes on that lineage; other nodes need pg_rewind before rejoining.
$ pg_autoctl show timeline --formation default
TLI | Parent TLI | Switchpoint LSN
---------+------------+----------------
1 | 0 | 0/0
2 | 1 | 0/5016BC0
Name | NodeId | TLI | LSN | Status
---------------------+--------+------+-------------+-----------------------------------------
node1 | 1 | 1 | 0/509CE00 | ok, on accepted lineage
node2 | 2 | 1 | 0/509CE00 | ok, on accepted lineage
node3 | 3 | 2 | 0/502D758 | FORK: diverges from the reference timeline, pg_rewind required
One or more nodes have diverged from the reference timeline (see FORK above).
See `pg_autoctl accept timeline --help` to resolve.
Same as before, no resync needs to be forced — the pin alone is enough, and node3 is caught and rewound within about a second, no maintenance cycle involved. Every row the application wrote to node1 in the meantime — 200 rows, none of them lost or delayed by node3’s fork — is there once node3 rejoins:
$ pg_autoctl show timeline --formation default
TLI | Parent TLI | Switchpoint LSN
---------+------------+----------------
1 | 0 | 0/0
2 | 1 | 0/5016BC0
Name | NodeId | TLI | LSN | Status
---------------------+--------+------+-------------+-----------------------------------------
node1 | 1 | 1 | 0/7000060 | ok, on accepted lineage
node2 | 2 | 1 | 0/7000060 | ok, on accepted lineage
node3 | 3 | 1 | 0/7000060 | ok, on accepted lineage
See tests/tap/specs/timeline_fork_3node_auto_detect.pgaf for the
automated version of this exact scenario.