Skip to content

Commit 105b2cb

Browse files
author
Amit Kapila
committed
Stabilize 035_standby_logical_decoding.pl.
Some tests try to invalidate logical slots on the standby server by running VACUUM on the primary. The problem is that xl_running_xacts was getting generated and replayed before the VACUUM command, leading to the advancement of the active slot's catalog_xmin. Due to this, active slots were not getting invalidated, leading to test failures. We fix it by skipping the generation of xl_running_xacts for the required tests with the help of injection points. As the required interface for injection points was not present in back branches, we fixed the failing tests in them by disallowing the slot to become active for the required cases (where rows_removed conflict could be generated). Author: Hayato Kuroda <kuroda.hayato@fujitsu.com> Reviewed-by: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Amit Kapila <amit.kapila16@gmail.com> Backpatch-through: 16, where it was introduced Discussion: https://postgr.es/m/Z6oQXc8LmiTLfwLA@ip-10-97-1-34.eu-west-3.compute.internal
1 parent 46b4ba5 commit 105b2cb

File tree

2 files changed

+54
-14
lines changed

2 files changed

+54
-14
lines changed

src/backend/storage/ipc/standby.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include "storage/sinvaladt.h"
3232
#include "storage/standby.h"
3333
#include "utils/hsearch.h"
34+
#include "utils/injection_point.h"
3435
#include "utils/ps_status.h"
3536
#include "utils/timeout.h"
3637
#include "utils/timestamp.h"
@@ -1287,6 +1288,17 @@ LogStandbySnapshot(void)
12871288

12881289
Assert(XLogStandbyInfoActive());
12891290

1291+
#ifdef USE_INJECTION_POINTS
1292+
if (IS_INJECTION_POINT_ATTACHED("skip-log-running-xacts"))
1293+
{
1294+
/*
1295+
* This record could move slot's xmin forward during decoding, leading
1296+
* to unpredictable results, so skip it when requested by the test.
1297+
*/
1298+
return GetInsertRecPtr();
1299+
}
1300+
#endif
1301+
12901302
/*
12911303
* Get details of any AccessExclusiveLocks being held at the moment.
12921304
*/

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

Lines changed: 42 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@
1010
use PostgreSQL::Test::Utils;
1111
use Test::More;
1212

13+
if ($ENV{enable_injection_points} ne 'yes')
14+
{
15+
plan skip_all => 'Injection points not supported by this build';
16+
}
17+
1318
my ($stdout, $stderr, $cascading_stdout, $cascading_stderr, $handle);
1419

1520
my $node_primary = PostgreSQL::Test::Cluster->new('primary');
@@ -241,16 +246,19 @@ sub check_for_invalidation
241246
# VACUUM command, $sql the sql to launch before triggering the vacuum and
242247
# $to_vac the relation to vacuum.
243248
#
244-
# Note that pg_current_snapshot() is used to get the horizon. It does
245-
# not generate a Transaction/COMMIT WAL record, decreasing the risk of
246-
# seeing a xl_running_xacts that would advance an active replication slot's
247-
# catalog_xmin. Advancing the active replication slot's catalog_xmin
248-
# would break some tests that expect the active slot to conflict with
249-
# the catalog xmin horizon.
249+
# Note that the injection_point avoids seeing a xl_running_xacts that could
250+
# advance an active replication slot's catalog_xmin. Advancing the active
251+
# replication slot's catalog_xmin would break some tests that expect the
252+
# active slot to conflict with the catalog xmin horizon.
250253
sub wait_until_vacuum_can_remove
251254
{
252255
my ($vac_option, $sql, $to_vac) = @_;
253256

257+
# Note that from this point the checkpointer and bgwriter will skip writing
258+
# xl_running_xacts record.
259+
$node_primary->safe_psql('testdb',
260+
"SELECT injection_points_attach('skip-log-running-xacts', 'error');");
261+
254262
# Get the current xid horizon,
255263
my $xid_horizon = $node_primary->safe_psql('testdb',
256264
qq[select pg_snapshot_xmin(pg_current_snapshot());]);
@@ -268,6 +276,12 @@ sub wait_until_vacuum_can_remove
268276
$node_primary->safe_psql(
269277
'testdb', qq[VACUUM $vac_option verbose $to_vac;
270278
INSERT INTO flush_wal DEFAULT VALUES;]);
279+
280+
$node_primary->wait_for_replay_catchup($node_standby);
281+
282+
# Resume generating the xl_running_xacts record
283+
$node_primary->safe_psql('testdb',
284+
"SELECT injection_points_detach('skip-log-running-xacts');");
271285
}
272286

273287
########################
@@ -285,6 +299,14 @@ sub wait_until_vacuum_can_remove
285299
$node_primary->dump_info;
286300
$node_primary->start;
287301

302+
# Check if the extension injection_points is available, as it may be
303+
# possible that this script is run with installcheck, where the module
304+
# would not be installed by default.
305+
if (!$node_primary->check_extension('injection_points'))
306+
{
307+
plan skip_all => 'Extension injection_points not installed';
308+
}
309+
288310
$node_primary->psql('postgres', q[CREATE DATABASE testdb]);
289311

290312
$node_primary->safe_psql('testdb',
@@ -528,6 +550,9 @@ sub wait_until_vacuum_can_remove
528550
$node_subscriber->safe_psql('postgres', "DROP SUBSCRIPTION tap_sub");
529551
$node_subscriber->stop;
530552

553+
# Create the injection_points extension
554+
$node_primary->safe_psql('testdb', 'CREATE EXTENSION injection_points;');
555+
531556
##################################################
532557
# Recovery conflict: Invalidate conflicting slots, including in-use slots
533558
# Scenario 1: hot_standby_feedback off and vacuum FULL
@@ -557,8 +582,6 @@ sub wait_until_vacuum_can_remove
557582
'full', 'CREATE TABLE conflict_test(x integer, y text);
558583
DROP TABLE conflict_test;', 'pg_class');
559584

560-
$node_primary->wait_for_replay_catchup($node_standby);
561-
562585
# Check invalidation in the logfile and in pg_stat_database_conflicts
563586
check_for_invalidation('vacuum_full_', 1, 'with vacuum FULL on pg_class');
564587

@@ -665,8 +688,6 @@ sub wait_until_vacuum_can_remove
665688
'', 'CREATE TABLE conflict_test(x integer, y text);
666689
DROP TABLE conflict_test;', 'pg_class');
667690

668-
$node_primary->wait_for_replay_catchup($node_standby);
669-
670691
# Check invalidation in the logfile and in pg_stat_database_conflicts
671692
check_for_invalidation('row_removal_', $logstart, 'with vacuum on pg_class');
672693

@@ -699,8 +720,6 @@ sub wait_until_vacuum_can_remove
699720
'', 'CREATE ROLE create_trash;
700721
DROP ROLE create_trash;', 'pg_authid');
701722

702-
$node_primary->wait_for_replay_catchup($node_standby);
703-
704723
# Check invalidation in the logfile and in pg_stat_database_conflicts
705724
check_for_invalidation('shared_row_removal_', $logstart,
706725
'with vacuum on pg_authid');
@@ -733,8 +752,6 @@ sub wait_until_vacuum_can_remove
733752
INSERT INTO conflict_test(x,y) SELECT s, s::text FROM generate_series(1,4) s;
734753
UPDATE conflict_test set x=1, y=1;', 'conflict_test');
735754

736-
$node_primary->wait_for_replay_catchup($node_standby);
737-
738755
# message should not be issued
739756
ok( !$node_standby->log_contains(
740757
"invalidating obsolete slot \"no_conflict_inactiveslot\"", $logstart),
@@ -782,6 +799,13 @@ sub wait_until_vacuum_can_remove
782799
reactive_slots_change_hfs_and_wait_for_xmins('no_conflict_', 'pruning_', 0,
783800
0);
784801

802+
# Injection_point avoids seeing a xl_running_xacts. This is required because if
803+
# it is generated between the last two updates, then the catalog_xmin of the
804+
# active slot could be updated, and hence, the conflict won't occur. See
805+
# comments atop wait_until_vacuum_can_remove.
806+
$node_primary->safe_psql('testdb',
807+
"SELECT injection_points_attach('skip-log-running-xacts', 'error');");
808+
785809
# This should trigger the conflict
786810
$node_primary->safe_psql('testdb',
787811
qq[CREATE TABLE prun(id integer, s char(2000)) WITH (fillfactor = 75, user_catalog_table = true);]
@@ -794,6 +818,10 @@ sub wait_until_vacuum_can_remove
794818

795819
$node_primary->wait_for_replay_catchup($node_standby);
796820

821+
# Resume generating the xl_running_xacts record
822+
$node_primary->safe_psql('testdb',
823+
"SELECT injection_points_detach('skip-log-running-xacts');");
824+
797825
# Check invalidation in the logfile and in pg_stat_database_conflicts
798826
check_for_invalidation('pruning_', $logstart, 'with on-access pruning');
799827

0 commit comments

Comments
 (0)