=== Applying patches on top of PostgreSQL commit ID 49b82522f13fa5f756687f5609f687877fc970ff === /etc/rc.d/jail: WARNING: Per-jail configuration via jail_* variables is obsolete. Please consider migrating to /etc/jail.conf. Sun Mar 30 20:16:23 UTC 2025 On branch cf/5568 nothing to commit, working tree clean === using 'git am' to apply patch ./PG16-v2-0001-Stabilize-035_standby_logical_decoding.pl-by-usin.patch === Applying: Stabilize 035_standby_logical_decoding.pl by using the injection_points. Using index info to reconstruct a base tree... M src/test/recovery/t/035_standby_logical_decoding.pl Falling back to patching base and 3-way merge... Auto-merging src/test/recovery/t/035_standby_logical_decoding.pl CONFLICT (content): Merge conflict in src/test/recovery/t/035_standby_logical_decoding.pl error: Failed to merge in the changes. hint: Use 'git am --show-current-patch=diff' to see the failed patch Patch failed at 0001 Stabilize 035_standby_logical_decoding.pl by using the injection_points. When you have resolved this problem, run "git am --continue". If you prefer to skip this patch, run "git am --skip" instead. To restore the original branch and stop patching, run "git am --abort". Unstaged changes after reset: M src/test/recovery/t/035_standby_logical_decoding.pl === using patch(1) to apply patch ./PG16-v2-0001-Stabilize-035_standby_logical_decoding.pl-by-usin.patch === patch: unrecognized option `--no-backup-if-mismatch' usage: patch [-bCcEeflNnRstuv] [-B backup-prefix] [-D symbol] [-d directory] [-F max-fuzz] [-i patchfile] [-o out-file] [-p strip-count] [-r rej-name] [-V t | nil | never | none] [-x number] [-z backup-ext] [--posix] [origfile [patchfile]] patch safe_psql( - 'postgres', qq( - select bool_and(conflicting) from pg_replication_slots;)); + my $active_slot = $slot_prefix . 'activeslot'; + my $inactive_slot = $slot_prefix . 'inactiveslot'; - is($res, 't', "Logical slots are reported as conflicting"); - } - else - { - $res = $node_standby->safe_psql( - 'postgres', qq( - select bool_or(conflicting) from pg_replication_slots;)); + $res = $node_standby->safe_psql( + 'postgres', qq( + select invalidation_reason from pg_replication_slots where slot_name = '$active_slot' and conflicting;) + ); - is($res, 'f', "Logical slots are reported as non conflicting"); - } + is($res, "$reason", "$active_slot reason for conflict is $reason"); + + $res = $node_standby->safe_psql( + 'postgres', qq( + select invalidation_reason from pg_replication_slots where slot_name = '$inactive_slot' and conflicting;) + ); + + is($res, "$reason", "$inactive_slot reason for conflict is $reason"); } - # Drop the slots, re-create them, change hot_standby_feedback, - # check xmin and catalog_xmin values, make slot active and reset stat. + # Create slots, change hot_standby_feedback, check xmin and catalog_xmin + # values, make slot active and reset stat. sub reactive_slots_change_hfs_and_wait_for_xmins { - my ($previous_slot_prefix, $slot_prefix, $hsf, $invalidated) = @_; - - # drop the logical slots - drop_logical_slots($previous_slot_prefix); + my ($slot_prefix, $hsf, $invalidated, $needs_active_slot) = @_; # create the logical slots - create_logical_slots($node_standby, $slot_prefix); + create_logical_slots($node_standby, $slot_prefix, $needs_active_slot); change_hot_standby_feedback_and_wait_for_xmins($hsf, $invalidated); @@@ -531,27 -541,16 +538,29 @@@ $node_subscriber->stop ################################################## # Recovery conflict: Invalidate conflicting slots, including in-use slots # Scenario 1: hot_standby_feedback off and vacuum FULL +# +# In passing, ensure that replication slot stats are not removed when the +# active slot is invalidated, and check that an error occurs when +# attempting to alter the invalid slot. ################################################## + # drop the logical slots used by previous tests + drop_logical_slots('behaves_ok_', 1); + # One way to produce recovery conflict is to create/drop a relation and # launch a vacuum full on pg_class with hot_standby_feedback turned off on # the standby. - reactive_slots_change_hfs_and_wait_for_xmins('behaves_ok_', 'vacuum_full_', - 0, 1); + reactive_slots_change_hfs_and_wait_for_xmins('vacuum_full_', 0, 1, 0); +# Ensure that replication slot stats are not empty before triggering the +# conflict. +$node_primary->safe_psql('testdb', + qq[INSERT INTO decoding_test(x,y) SELECT 100,'100';]); + +$node_standby->poll_query_until('testdb', + qq[SELECT total_txns > 0 FROM pg_stat_replication_slots WHERE slot_name = 'vacuum_full_activeslot'] +) or die "replication slot stats of vacuum_full_activeslot not updated"; + # This should trigger the conflict wait_until_vacuum_can_remove( 'full', 'CREATE TABLE conflict_test(x integer, y text); @@@ -560,37 -559,11 +569,40 @@@ $node_primary->wait_for_replay_catchup($node_standby); # Check invalidation in the logfile and in pg_stat_database_conflicts - check_for_invalidation('vacuum_full_', 1, 'with vacuum FULL on pg_class'); + check_for_invalidation('vacuum_full_', 1, 'with vacuum FULL on pg_class', 0); -# Verify slots are reported as conflicting in pg_replication_slots -check_slots_conflicting_status(1); +# Verify reason for conflict is 'rows_removed' in pg_replication_slots +check_slots_conflict_reason('vacuum_full_', 'rows_removed'); +# Attempting to alter an invalidated slot should result in an error +($result, $stdout, $stderr) = $node_standby->psql( + 'postgres', + qq[ALTER_REPLICATION_SLOT vacuum_full_inactiveslot (failover);], + replication => 'database'); +ok( $stderr =~ + /ERROR: can no longer access replication slot "vacuum_full_inactiveslot"/ + && $stderr =~ + /DETAIL: This replication slot has been invalidated due to "rows_removed"./, + "invalidated slot cannot be altered"); + +# Ensure that replication slot stats are not removed after invalidation. +is( $node_standby->safe_psql( + 'testdb', + qq[SELECT total_txns > 0 FROM pg_stat_replication_slots WHERE slot_name = 'vacuum_full_activeslot'] + ), + 't', + 'replication slot stats not removed after invalidation'); + ++<<<<<<< ours +$handle = + make_slot_active($node_standby, 'vacuum_full_', 0, \$stdout, \$stderr); + +# We are not able to read from the slot as it has been invalidated +check_pg_recvlogical_stderr($handle, + "can no longer access replication slot \"vacuum_full_activeslot\""); + ++======= ++>>>>>>> theirs # Turn hot_standby_feedback back on change_hot_standby_feedback_and_wait_for_xmins(1, 1); @@@ -607,10 -580,8 +619,15 @@@ check_slots_conflict_reason('vacuum_ful ################################################## # Get the restart_lsn from an invalidated slot ++<<<<<<< ours +my $restart_lsn = $node_standby->safe_psql( + 'postgres', + "SELECT restart_lsn FROM pg_replication_slots + WHERE slot_name = 'vacuum_full_activeslot' AND conflicting;" ++======= + my $restart_lsn = $node_standby->safe_psql('postgres', + "SELECT restart_lsn from pg_replication_slots WHERE slot_name = 'vacuum_full_inactiveslot' and conflicting is true;" ++>>>>>>> theirs ); chomp($restart_lsn); @@@ -659,18 -635,11 +678,21 @@@ wait_until_vacuum_can_remove $node_primary->wait_for_replay_catchup($node_standby); # Check invalidation in the logfile and in pg_stat_database_conflicts - check_for_invalidation('row_removal_', $logstart, 'with vacuum on pg_class'); + check_for_invalidation('row_removal_', $logstart, 'with vacuum on pg_class', 0); -# Verify slots are reported as conflicting in pg_replication_slots -check_slots_conflicting_status(1); +# Verify reason for conflict is 'rows_removed' in pg_replication_slots +check_slots_conflict_reason('row_removal_', 'rows_removed'); + ++<<<<<<< ours +$handle = + make_slot_active($node_standby, 'row_removal_', 0, \$stdout, \$stderr); + +# We are not able to read from the slot as it has been invalidated +check_pg_recvlogical_stderr($handle, + "can no longer access replication slot \"row_removal_activeslot\""); ++======= ++>>>>>>> theirs ################################################## # Recovery conflict: Same as Scenario 2 but on a shared catalog table # Scenario 3: conflict due to row removal with hot_standby_feedback off. @@@ -694,19 -665,11 +718,22 @@@ $node_primary->wait_for_replay_catchup( # Check invalidation in the logfile and in pg_stat_database_conflicts check_for_invalidation('shared_row_removal_', $logstart, - 'with vacuum on pg_authid'); + 'with vacuum on pg_authid', 0); -# Verify slots are reported as conflicting in pg_replication_slots -check_slots_conflicting_status(1); +# Verify reason for conflict is 'rows_removed' in pg_replication_slots +check_slots_conflict_reason('shared_row_removal_', 'rows_removed'); + ++<<<<<<< ours +$handle = make_slot_active($node_standby, 'shared_row_removal_', 0, \$stdout, + \$stderr); +# We are not able to read from the slot as it has been invalidated +check_pg_recvlogical_stderr($handle, + "can no longer access replication slot \"shared_row_removal_activeslot\"" +); + ++======= ++>>>>>>> theirs ################################################## # Recovery conflict: Same as Scenario 2 but on a non catalog table # Scenario 4: No conflict expected. @@@ -786,17 -747,13 +817,20 @@@ $node_primary->safe_psql('testdb', qq[U $node_primary->wait_for_replay_catchup($node_standby); # Check invalidation in the logfile and in pg_stat_database_conflicts - check_for_invalidation('pruning_', $logstart, 'with on-access pruning'); + check_for_invalidation('pruning_', $logstart, 'with on-access pruning', 0); -# Verify slots are reported as conflicting in pg_replication_slots -check_slots_conflicting_status(1); +# Verify reason for conflict is 'rows_removed' in pg_replication_slots +check_slots_conflict_reason('pruning_', 'rows_removed'); $handle = make_slot_active($node_standby, 'pruning_', 0, \$stdout, \$stderr); ++<<<<<<< ours +# We are not able to read from the slot as it has been invalidated +check_pg_recvlogical_stderr($handle, + "can no longer access replication slot \"pruning_activeslot\""); + ++======= ++>>>>>>> theirs # Turn hot_standby_feedback back on change_hot_standby_feedback_and_wait_for_xmins(1, 1); @@@ -830,10 -787,10 +864,10 @@@ $node_primary->restart $node_primary->wait_for_replay_catchup($node_standby); # Check invalidation in the logfile and in pg_stat_database_conflicts - check_for_invalidation('wal_level_', $logstart, 'due to wal_level'); + check_for_invalidation('wal_level_', $logstart, 'due to wal_level', 1); -# Verify slots are reported as conflicting in pg_replication_slots -check_slots_conflicting_status(1); +# Verify reason for conflict is 'wal_level_insufficient' in pg_replication_slots +check_slots_conflict_reason('wal_level_', 'wal_level_insufficient'); $handle = make_slot_active($node_standby, 'wal_level_', 0, \$stdout, \$stderr);