From df7f50672829e241245e2cd1f22774bdcf127989 Mon Sep 17 00:00:00 2001 From: reshke Date: Mon, 20 Jul 2026 18:25:39 +0300 Subject: [PATCH v8 2/3] Add `primary_last_archived` column to pg_stat_wal_receiver view. Comes in-handy for monitoring shared archive feature. TAP tests for shared archive feature were extended to check for this column value. Bumps catversion. --- src/backend/catalog/system_views.sql | 1 + src/backend/replication/walreceiver.c | 25 +++++++++++++++-------- src/include/catalog/pg_proc.dat | 6 +++--- src/test/recovery/t/055_archive_shared.pl | 20 ++++++++++++++++++ src/test/regress/expected/rules.out | 3 ++- 5 files changed, 43 insertions(+), 12 deletions(-) diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql index 090281a03dd..5bd037aa59b 100644 --- a/src/backend/catalog/system_views.sql +++ b/src/backend/catalog/system_views.sql @@ -1025,6 +1025,7 @@ CREATE VIEW pg_stat_wal_receiver AS s.last_msg_receipt_time, s.latest_end_lsn, s.latest_end_time, + s.primary_last_archived, s.slot_name, s.sender_host, s.sender_port, diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c index abf449a9089..cce623f169f 100644 --- a/src/backend/replication/walreceiver.c +++ b/src/backend/replication/walreceiver.c @@ -1713,6 +1713,7 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS) int sender_port = 0; char slotname[NAMEDATALEN]; char conninfo[MAXCONNINFO]; + char primary_last_archived[MAX_XFN_CHARS + 1]; /* Take a lock to ensure value consistency */ SpinLockAcquire(&WalRcv->mutex); @@ -1740,6 +1741,10 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS) if (pid == 0 || !ready_to_display) PG_RETURN_NULL(); + SpinLockAcquire(&PgArch->lock); + strlcpy(primary_last_archived, PgArch->primary_last_archived, sizeof(primary_last_archived)); + SpinLockRelease(&PgArch->lock); + /* * Read "writtenUpto" without holding a spinlock. Note that it may not be * consistent with the other shared variables of the WAL receiver @@ -1801,22 +1806,26 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS) nulls[10] = true; else values[10] = TimestampTzGetDatum(latest_end_time); - if (*slotname == '\0') + if (*primary_last_archived == '\0') nulls[11] = true; else - values[11] = CStringGetTextDatum(slotname); - if (*sender_host == '\0') + values[11] = CStringGetTextDatum(primary_last_archived); + if (*slotname == '\0') nulls[12] = true; else - values[12] = CStringGetTextDatum(sender_host); - if (sender_port == 0) + values[12] = CStringGetTextDatum(slotname); + if (*sender_host == '\0') nulls[13] = true; else - values[13] = Int32GetDatum(sender_port); - if (*conninfo == '\0') + values[13] = CStringGetTextDatum(sender_host); + if (sender_port == 0) nulls[14] = true; else - values[14] = CStringGetTextDatum(conninfo); + values[14] = Int32GetDatum(sender_port); + if (*conninfo == '\0') + nulls[15] = true; + else + values[15] = CStringGetTextDatum(conninfo); } /* Returns the record as Datum */ diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index f8a021987b5..1974b430f84 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -5718,9 +5718,9 @@ { oid => '3317', descr => 'statistics: information about WAL receiver', proname => 'pg_stat_get_wal_receiver', proisstrict => 'f', provolatile => 's', proparallel => 'r', prorettype => 'record', proargtypes => '', - proallargtypes => '{int4,text,pg_lsn,int4,pg_lsn,pg_lsn,int4,timestamptz,timestamptz,pg_lsn,timestamptz,text,text,int4,text}', - proargmodes => '{o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}', - proargnames => '{pid,status,receive_start_lsn,receive_start_tli,written_lsn,flushed_lsn,received_tli,last_msg_send_time,last_msg_receipt_time,latest_end_lsn,latest_end_time,slot_name,sender_host,sender_port,conninfo}', + proallargtypes => '{int4,text,pg_lsn,int4,pg_lsn,pg_lsn,int4,timestamptz,timestamptz,pg_lsn,timestamptz,text,text,text,int4,text}', + proargmodes => '{o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}', + proargnames => '{pid,status,receive_start_lsn,receive_start_tli,written_lsn,flushed_lsn,received_tli,last_msg_send_time,last_msg_receipt_time,latest_end_lsn,latest_end_time,primary_last_archived,slot_name,sender_host,sender_port,conninfo}', prosrc => 'pg_stat_get_wal_receiver' }, { oid => '6514', descr => 'statistics: information about WAL recovery', proname => 'pg_stat_get_recovery', proisstrict => 'f', provolatile => 's', diff --git a/src/test/recovery/t/055_archive_shared.pl b/src/test/recovery/t/055_archive_shared.pl index 106065e0f68..1d1d6145b94 100644 --- a/src/test/recovery/t/055_archive_shared.pl +++ b/src/test/recovery/t/055_archive_shared.pl @@ -196,6 +196,9 @@ note("Standby has $done_count .done files"); ok(-f "$standby_archive_status/$primary_last_archived.done", "WAL segment $primary_last_archived done file exists in standby pg_wal/archive_status"); +is($primary_last_archived, $standby->safe_psql('postgres', + q{SELECT primary_last_archived from pg_stat_wal_receiver; }), "standby wal receiver stat view updated with primary last archived wal"); + ############################################################################### # Test 2: Cascading replication ############################################################################### @@ -220,6 +223,9 @@ my $cascading_archived_before = $primary->safe_psql('postgres', 'SELECT archived my $current_walfile = $primary->safe_psql('postgres', "SELECT pg_walfile_name(pg_current_wal_lsn());"); +$cascade_standby->safe_psql('postgres', + q{SELECT injection_points_attach('walreceiver-after-primary-last-archived', 'wait')}); + $primary->safe_psql( 'postgres', q{ CHECKPOINT; @@ -234,6 +240,15 @@ $primary->poll_query_until('postgres', "SELECT archived_count > $cascading_archived_before FROM pg_stat_archiver") or die "Timed out waiting for primary to archive segment in cascading test"; + +wait_for_injection_point($cascade_standby, 'walreceiver-after-primary-last-archived'); + +$cascade_standby->safe_psql( + 'postgres', qq[ +SELECT injection_points_detach('walreceiver-after-primary-last-archived'); +SELECT injection_points_wakeup('walreceiver-after-primary-last-archived'); +]); + # Wait for cascading standby to catch up $standby->wait_for_catchup($cascade_standby); @@ -257,4 +272,9 @@ ok( -f "$cascade_data/$walfile_done", ".done file exists on cascade replica for WAL segment $current_walfile" ); + +is($current_walfile, $cascade_standby->safe_psql('postgres', + q{SELECT primary_last_archived from pg_stat_wal_receiver; }), + "cascade standby wal receiver stat view updated with primary last archived wal"); + done_testing(); diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out index 6a3341356da..eae03d9c105 100644 --- a/src/test/regress/expected/rules.out +++ b/src/test/regress/expected/rules.out @@ -2444,11 +2444,12 @@ pg_stat_wal_receiver| SELECT pid, last_msg_receipt_time, latest_end_lsn, latest_end_time, + primary_last_archived, slot_name, sender_host, sender_port, conninfo - FROM pg_stat_get_wal_receiver() s(pid, status, receive_start_lsn, receive_start_tli, written_lsn, flushed_lsn, received_tli, last_msg_send_time, last_msg_receipt_time, latest_end_lsn, latest_end_time, slot_name, sender_host, sender_port, conninfo) + FROM pg_stat_get_wal_receiver() s(pid, status, receive_start_lsn, receive_start_tli, written_lsn, flushed_lsn, received_tli, last_msg_send_time, last_msg_receipt_time, latest_end_lsn, latest_end_time, primary_last_archived, slot_name, sender_host, sender_port, conninfo) WHERE (pid IS NOT NULL); pg_stat_xact_all_tables| SELECT c.oid AS relid, n.nspname AS schemaname, -- 2.50.1 (Apple Git-155)