Skip to content

Commit 007693f

Browse files
author
Amit Kapila
committed
Track conflict_reason in pg_replication_slots.
This changes the existing 'conflicting' field to 'conflict_reason' in pg_replication_slots. This new field indicates the reason for the logical slot's conflict with recovery. It is always NULL for physical slots, as well as for logical slots which are not invalidated. The non-NULL values indicate that the slot is marked as invalidated. Possible values are: wal_removed = required WAL has been removed. rows_removed = required rows have been removed. wal_level_insufficient = the primary doesn't have a wal_level sufficient to perform logical decoding. The existing users of 'conflicting' column can get the same answer by using 'conflict_reason' IS NOT NULL. Author: Shveta Malik Reviewed-by: Amit Kapila, Bertrand Drouvot, Michael Paquier Discussion: https://postgr.es/m/[email protected]
1 parent 29275b1 commit 007693f

File tree

8 files changed

+90
-49
lines changed

8 files changed

+90
-49
lines changed

‎doc/src/sgml/system-views.sgml

+26-3
Original file line numberDiff line numberDiff line change
@@ -2525,11 +2525,34 @@ SELECT * FROM pg_locks pl LEFT JOIN pg_prepared_xacts ppx
25252525

25262526
<row>
25272527
<entry role="catalog_table_entry"><para role="column_definition">
2528-
<structfield>conflicting</structfield> <type>bool</type>
2528+
<structfield>conflict_reason</structfield> <type>text</type>
25292529
</para>
25302530
<para>
2531-
True if this logical slot conflicted with recovery (and so is now
2532-
invalidated). Always NULL for physical slots.
2531+
The reason for the logical slot's conflict with recovery. It is always
2532+
NULL for physical slots, as well as for logical slots which are not
2533+
invalidated. The non-NULL values indicate that the slot is marked
2534+
as invalidated. Possible values are:
2535+
<itemizedlist spacing="compact">
2536+
<listitem>
2537+
<para>
2538+
<literal>wal_removed</literal> means that the required WAL has been
2539+
removed.
2540+
</para>
2541+
</listitem>
2542+
<listitem>
2543+
<para>
2544+
<literal>rows_removed</literal> means that the required rows have
2545+
been removed.
2546+
</para>
2547+
</listitem>
2548+
<listitem>
2549+
<para>
2550+
<literal>wal_level_insufficient</literal> means that the
2551+
primary doesn't have a <xref linkend="guc-wal-level"/> sufficient to
2552+
perform logical decoding.
2553+
</para>
2554+
</listitem>
2555+
</itemizedlist>
25332556
</para></entry>
25342557
</row>
25352558
</tbody>

‎src/backend/catalog/system_views.sql

+1-1
Original file line numberDiff line numberDiff line change
@@ -1023,7 +1023,7 @@ CREATE VIEW pg_replication_slots AS
10231023
L.wal_status,
10241024
L.safe_wal_size,
10251025
L.two_phase,
1026-
L.conflicting
1026+
L.conflict_reason
10271027
FROM pg_get_replication_slots() AS L
10281028
LEFT JOIN pg_database D ON (L.datoid = D.oid);
10291029

‎src/backend/replication/slotfuncs.c

+18-4
Original file line numberDiff line numberDiff line change
@@ -406,10 +406,24 @@ pg_get_replication_slots(PG_FUNCTION_ARGS)
406406
nulls[i++] = true;
407407
else
408408
{
409-
if (slot_contents.data.invalidated != RS_INVAL_NONE)
410-
values[i++] = BoolGetDatum(true);
411-
else
412-
values[i++] = BoolGetDatum(false);
409+
switch (slot_contents.data.invalidated)
410+
{
411+
case RS_INVAL_NONE:
412+
nulls[i++] = true;
413+
break;
414+
415+
case RS_INVAL_WAL_REMOVED:
416+
values[i++] = CStringGetTextDatum("wal_removed");
417+
break;
418+
419+
case RS_INVAL_HORIZON:
420+
values[i++] = CStringGetTextDatum("rows_removed");
421+
break;
422+
423+
case RS_INVAL_WAL_LEVEL:
424+
values[i++] = CStringGetTextDatum("wal_level_insufficient");
425+
break;
426+
}
413427
}
414428

415429
Assert(i == PG_GET_REPLICATION_SLOTS_COLS);

‎src/bin/pg_upgrade/info.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -667,13 +667,13 @@ get_old_cluster_logical_slot_infos(DbInfo *dbinfo, bool live_check)
667667
* removed.
668668
*/
669669
res = executeQueryOrDie(conn, "SELECT slot_name, plugin, two_phase, "
670-
"%s as caught_up, conflicting as invalid "
670+
"%s as caught_up, conflict_reason IS NOT NULL as invalid "
671671
"FROM pg_catalog.pg_replication_slots "
672672
"WHERE slot_type = 'logical' AND "
673673
"database = current_database() AND "
674674
"temporary IS FALSE;",
675675
live_check ? "FALSE" :
676-
"(CASE WHEN conflicting THEN FALSE "
676+
"(CASE WHEN conflict_reason IS NOT NULL THEN FALSE "
677677
"ELSE (SELECT pg_catalog.binary_upgrade_logical_slot_has_caught_up(slot_name)) "
678678
"END)");
679679

‎src/include/catalog/catversion.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,6 @@
5757
*/
5858

5959
/* yyyymmddN */
60-
#define CATALOG_VERSION_NO 202401021
60+
#define CATALOG_VERSION_NO 202401041
6161

6262
#endif

‎src/include/catalog/pg_proc.dat

+2-2
Original file line numberDiff line numberDiff line change
@@ -11115,9 +11115,9 @@
1111511115
proname => 'pg_get_replication_slots', prorows => '10', proisstrict => 'f',
1111611116
proretset => 't', provolatile => 's', prorettype => 'record',
1111711117
proargtypes => '',
11118-
proallargtypes => '{name,name,text,oid,bool,bool,int4,xid,xid,pg_lsn,pg_lsn,text,int8,bool,bool}',
11118+
proallargtypes => '{name,name,text,oid,bool,bool,int4,xid,xid,pg_lsn,pg_lsn,text,int8,bool,text}',
1111911119
proargmodes => '{o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}',
11120-
proargnames => '{slot_name,plugin,slot_type,datoid,temporary,active,active_pid,xmin,catalog_xmin,restart_lsn,confirmed_flush_lsn,wal_status,safe_wal_size,two_phase,conflicting}',
11120+
proargnames => '{slot_name,plugin,slot_type,datoid,temporary,active,active_pid,xmin,catalog_xmin,restart_lsn,confirmed_flush_lsn,wal_status,safe_wal_size,two_phase,conflict_reason}',
1112111121
prosrc => 'pg_get_replication_slots' },
1112211122
{ oid => '3786', descr => 'set up a logical replication slot',
1112311123
proname => 'pg_create_logical_replication_slot', provolatile => 'v',

‎src/test/recovery/t/035_standby_logical_decoding.pl

+38-34
Original file line numberDiff line numberDiff line change
@@ -168,27 +168,25 @@ sub change_hot_standby_feedback_and_wait_for_xmins
168168
}
169169
}
170170

171-
# Check conflicting status in pg_replication_slots.
172-
sub check_slots_conflicting_status
171+
# Check conflict_reason in pg_replication_slots.
172+
sub check_slots_conflict_reason
173173
{
174-
my ($conflicting) = @_;
174+
my ($slot_prefix, $reason) = @_;
175175

176-
if ($conflicting)
177-
{
178-
$res = $node_standby->safe_psql(
179-
'postgres', qq(
180-
select bool_and(conflicting) from pg_replication_slots;));
176+
my $active_slot = $slot_prefix . 'activeslot';
177+
my $inactive_slot = $slot_prefix . 'inactiveslot';
181178

182-
is($res, 't', "Logical slots are reported as conflicting");
183-
}
184-
else
185-
{
186-
$res = $node_standby->safe_psql(
187-
'postgres', qq(
188-
select bool_or(conflicting) from pg_replication_slots;));
179+
$res = $node_standby->safe_psql(
180+
'postgres', qq(
181+
select conflict_reason from pg_replication_slots where slot_name = '$active_slot';));
189182

190-
is($res, 'f', "Logical slots are reported as non conflicting");
191-
}
183+
is($res, "$reason", "$active_slot conflict_reason is $reason");
184+
185+
$res = $node_standby->safe_psql(
186+
'postgres', qq(
187+
select conflict_reason from pg_replication_slots where slot_name = '$inactive_slot';));
188+
189+
is($res, "$reason", "$inactive_slot conflict_reason is $reason");
192190
}
193191

194192
# Drop the slots, re-create them, change hot_standby_feedback,
@@ -260,13 +258,13 @@ sub check_for_invalidation
260258
qq[SELECT * FROM pg_create_physical_replication_slot('$primary_slotname');]
261259
);
262260

263-
# Check conflicting is NULL for physical slot
261+
# Check conflict_reason is NULL for physical slot
264262
$res = $node_primary->safe_psql(
265263
'postgres', qq[
266-
SELECT conflicting is null FROM pg_replication_slots where slot_name = '$primary_slotname';]
264+
SELECT conflict_reason is null FROM pg_replication_slots where slot_name = '$primary_slotname';]
267265
);
268266

269-
is($res, 't', "Physical slot reports conflicting as NULL");
267+
is($res, 't', "Physical slot reports conflict_reason as NULL");
270268

271269
my $backup_name = 'b1';
272270
$node_primary->backup($backup_name);
@@ -483,8 +481,8 @@ sub check_for_invalidation
483481
# Check invalidation in the logfile and in pg_stat_database_conflicts
484482
check_for_invalidation('vacuum_full_', 1, 'with vacuum FULL on pg_class');
485483

486-
# Verify slots are reported as conflicting in pg_replication_slots
487-
check_slots_conflicting_status(1);
484+
# Verify conflict_reason is 'rows_removed' in pg_replication_slots
485+
check_slots_conflict_reason('vacuum_full_', 'rows_removed');
488486

489487
$handle =
490488
make_slot_active($node_standby, 'vacuum_full_', 0, \$stdout, \$stderr);
@@ -502,16 +500,16 @@ sub check_for_invalidation
502500
##################################################
503501
$node_standby->restart;
504502

505-
# Verify slots are reported as conflicting in pg_replication_slots
506-
check_slots_conflicting_status(1);
503+
# Verify conflict_reason is retained across a restart.
504+
check_slots_conflict_reason('vacuum_full_', 'rows_removed');
507505

508506
##################################################
509507
# Verify that invalidated logical slots do not lead to retaining WAL.
510508
##################################################
511509

512510
# Get the restart_lsn from an invalidated slot
513511
my $restart_lsn = $node_standby->safe_psql('postgres',
514-
"SELECT restart_lsn from pg_replication_slots WHERE slot_name = 'vacuum_full_activeslot' and conflicting is true;"
512+
"SELECT restart_lsn from pg_replication_slots WHERE slot_name = 'vacuum_full_activeslot' and conflict_reason is not null;"
515513
);
516514

517515
chomp($restart_lsn);
@@ -565,8 +563,8 @@ sub check_for_invalidation
565563
# Check invalidation in the logfile and in pg_stat_database_conflicts
566564
check_for_invalidation('row_removal_', $logstart, 'with vacuum on pg_class');
567565

568-
# Verify slots are reported as conflicting in pg_replication_slots
569-
check_slots_conflicting_status(1);
566+
# Verify conflict_reason is 'rows_removed' in pg_replication_slots
567+
check_slots_conflict_reason('row_removal_', 'rows_removed');
570568

571569
$handle =
572570
make_slot_active($node_standby, 'row_removal_', 0, \$stdout, \$stderr);
@@ -604,8 +602,8 @@ sub check_for_invalidation
604602
check_for_invalidation('shared_row_removal_', $logstart,
605603
'with vacuum on pg_authid');
606604

607-
# Verify slots are reported as conflicting in pg_replication_slots
608-
check_slots_conflicting_status(1);
605+
# Verify conflict_reason is 'rows_removed' in pg_replication_slots
606+
check_slots_conflict_reason('shared_row_removal_', 'rows_removed');
609607

610608
$handle = make_slot_active($node_standby, 'shared_row_removal_', 0, \$stdout,
611609
\$stderr);
@@ -657,7 +655,13 @@ sub check_for_invalidation
657655
) or die "Timed out waiting confl_active_logicalslot to be updated";
658656

659657
# Verify slots are reported as non conflicting in pg_replication_slots
660-
check_slots_conflicting_status(0);
658+
is( $node_standby->safe_psql(
659+
'postgres',
660+
q[select bool_or(conflicting) from
661+
(select conflict_reason is not NULL as conflicting
662+
from pg_replication_slots WHERE slot_type = 'logical')]),
663+
'f',
664+
'Logical slots are reported as non conflicting');
661665

662666
# Turn hot_standby_feedback back on
663667
change_hot_standby_feedback_and_wait_for_xmins(1, 0);
@@ -693,8 +697,8 @@ sub check_for_invalidation
693697
# Check invalidation in the logfile and in pg_stat_database_conflicts
694698
check_for_invalidation('pruning_', $logstart, 'with on-access pruning');
695699

696-
# Verify slots are reported as conflicting in pg_replication_slots
697-
check_slots_conflicting_status(1);
700+
# Verify conflict_reason is 'rows_removed' in pg_replication_slots
701+
check_slots_conflict_reason('pruning_', 'rows_removed');
698702

699703
$handle = make_slot_active($node_standby, 'pruning_', 0, \$stdout, \$stderr);
700704

@@ -737,8 +741,8 @@ sub check_for_invalidation
737741
# Check invalidation in the logfile and in pg_stat_database_conflicts
738742
check_for_invalidation('wal_level_', $logstart, 'due to wal_level');
739743

740-
# Verify slots are reported as conflicting in pg_replication_slots
741-
check_slots_conflicting_status(1);
744+
# Verify conflict_reason is 'wal_level_insufficient' in pg_replication_slots
745+
check_slots_conflict_reason('wal_level_', 'wal_level_insufficient');
742746

743747
$handle =
744748
make_slot_active($node_standby, 'wal_level_', 0, \$stdout, \$stderr);

‎src/test/regress/expected/rules.out

+2-2
Original file line numberDiff line numberDiff line change
@@ -1473,8 +1473,8 @@ pg_replication_slots| SELECT l.slot_name,
14731473
l.wal_status,
14741474
l.safe_wal_size,
14751475
l.two_phase,
1476-
l.conflicting
1477-
FROM (pg_get_replication_slots() l(slot_name, plugin, slot_type, datoid, temporary, active, active_pid, xmin, catalog_xmin, restart_lsn, confirmed_flush_lsn, wal_status, safe_wal_size, two_phase, conflicting)
1476+
l.conflict_reason
1477+
FROM (pg_get_replication_slots() l(slot_name, plugin, slot_type, datoid, temporary, active, active_pid, xmin, catalog_xmin, restart_lsn, confirmed_flush_lsn, wal_status, safe_wal_size, two_phase, conflict_reason)
14781478
LEFT JOIN pg_database d ON ((l.datoid = d.oid)));
14791479
pg_roles| SELECT pg_authid.rolname,
14801480
pg_authid.rolsuper,

0 commit comments

Comments
 (0)