aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/storage/ipc/standby.c12
-rw-r--r--src/test/recovery/t/035_standby_logical_decoding.pl56
2 files changed, 54 insertions, 14 deletions
diff --git a/src/backend/storage/ipc/standby.c b/src/backend/storage/ipc/standby.c
index 5acb4508f85..7fa8d9247e0 100644
--- a/src/backend/storage/ipc/standby.c
+++ b/src/backend/storage/ipc/standby.c
@@ -31,6 +31,7 @@
#include "storage/sinvaladt.h"
#include "storage/standby.h"
#include "utils/hsearch.h"
+#include "utils/injection_point.h"
#include "utils/ps_status.h"
#include "utils/timeout.h"
#include "utils/timestamp.h"
@@ -1287,6 +1288,17 @@ LogStandbySnapshot(void)
Assert(XLogStandbyInfoActive());
+#ifdef USE_INJECTION_POINTS
+ if (IS_INJECTION_POINT_ATTACHED("skip-log-running-xacts"))
+ {
+ /*
+ * This record could move slot's xmin forward during decoding, leading
+ * to unpredictable results, so skip it when requested by the test.
+ */
+ return GetInsertRecPtr();
+ }
+#endif
+
/*
* Get details of any AccessExclusiveLocks being held at the moment.
*/
diff --git a/src/test/recovery/t/035_standby_logical_decoding.pl b/src/test/recovery/t/035_standby_logical_decoding.pl
index ee066626af7..b85a4a4eda6 100644
--- a/src/test/recovery/t/035_standby_logical_decoding.pl
+++ b/src/test/recovery/t/035_standby_logical_decoding.pl
@@ -10,6 +10,11 @@ use PostgreSQL::Test::Cluster;
use PostgreSQL::Test::Utils;
use Test::More;
+if ($ENV{enable_injection_points} ne 'yes')
+{
+ plan skip_all => 'Injection points not supported by this build';
+}
+
my ($stdout, $stderr, $cascading_stdout, $cascading_stderr, $handle);
my $node_primary = PostgreSQL::Test::Cluster->new('primary');
@@ -241,16 +246,19 @@ sub check_for_invalidation
# VACUUM command, $sql the sql to launch before triggering the vacuum and
# $to_vac the relation to vacuum.
#
-# Note that pg_current_snapshot() is used to get the horizon. It does
-# not generate a Transaction/COMMIT WAL record, decreasing the risk of
-# seeing a xl_running_xacts that would advance an active replication slot's
-# catalog_xmin. Advancing the active replication slot's catalog_xmin
-# would break some tests that expect the active slot to conflict with
-# the catalog xmin horizon.
+# Note that the injection_point avoids seeing a xl_running_xacts that could
+# advance an active replication slot's catalog_xmin. Advancing the active
+# replication slot's catalog_xmin would break some tests that expect the
+# active slot to conflict with the catalog xmin horizon.
sub wait_until_vacuum_can_remove
{
my ($vac_option, $sql, $to_vac) = @_;
+ # Note that from this point the checkpointer and bgwriter will skip writing
+ # xl_running_xacts record.
+ $node_primary->safe_psql('testdb',
+ "SELECT injection_points_attach('skip-log-running-xacts', 'error');");
+
# Get the current xid horizon,
my $xid_horizon = $node_primary->safe_psql('testdb',
qq[select pg_snapshot_xmin(pg_current_snapshot());]);
@@ -268,6 +276,12 @@ sub wait_until_vacuum_can_remove
$node_primary->safe_psql(
'testdb', qq[VACUUM $vac_option verbose $to_vac;
INSERT INTO flush_wal DEFAULT VALUES;]);
+
+ $node_primary->wait_for_replay_catchup($node_standby);
+
+ # Resume generating the xl_running_xacts record
+ $node_primary->safe_psql('testdb',
+ "SELECT injection_points_detach('skip-log-running-xacts');");
}
########################
@@ -285,6 +299,14 @@ autovacuum = off
$node_primary->dump_info;
$node_primary->start;
+# Check if the extension injection_points is available, as it may be
+# possible that this script is run with installcheck, where the module
+# would not be installed by default.
+if (!$node_primary->check_extension('injection_points'))
+{
+ plan skip_all => 'Extension injection_points not installed';
+}
+
$node_primary->psql('postgres', q[CREATE DATABASE testdb]);
$node_primary->safe_psql('testdb',
@@ -528,6 +550,9 @@ is($result, qq(10), 'check replicated inserts after subscription on standby');
$node_subscriber->safe_psql('postgres', "DROP SUBSCRIPTION tap_sub");
$node_subscriber->stop;
+# Create the injection_points extension
+$node_primary->safe_psql('testdb', 'CREATE EXTENSION injection_points;');
+
##################################################
# Recovery conflict: Invalidate conflicting slots, including in-use slots
# Scenario 1: hot_standby_feedback off and vacuum FULL
@@ -557,8 +582,6 @@ wait_until_vacuum_can_remove(
'full', 'CREATE TABLE conflict_test(x integer, y text);
DROP TABLE conflict_test;', 'pg_class');
-$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');
@@ -665,8 +688,6 @@ wait_until_vacuum_can_remove(
'', 'CREATE TABLE conflict_test(x integer, y text);
DROP TABLE conflict_test;', 'pg_class');
-$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');
@@ -699,8 +720,6 @@ wait_until_vacuum_can_remove(
'', 'CREATE ROLE create_trash;
DROP ROLE create_trash;', 'pg_authid');
-$node_primary->wait_for_replay_catchup($node_standby);
-
# Check invalidation in the logfile and in pg_stat_database_conflicts
check_for_invalidation('shared_row_removal_', $logstart,
'with vacuum on pg_authid');
@@ -733,8 +752,6 @@ wait_until_vacuum_can_remove(
INSERT INTO conflict_test(x,y) SELECT s, s::text FROM generate_series(1,4) s;
UPDATE conflict_test set x=1, y=1;', 'conflict_test');
-$node_primary->wait_for_replay_catchup($node_standby);
-
# message should not be issued
ok( !$node_standby->log_contains(
"invalidating obsolete slot \"no_conflict_inactiveslot\"", $logstart),
@@ -782,6 +799,13 @@ $logstart = -s $node_standby->logfile;
reactive_slots_change_hfs_and_wait_for_xmins('no_conflict_', 'pruning_', 0,
0);
+# Injection_point avoids seeing a xl_running_xacts. This is required because if
+# it is generated between the last two updates, then the catalog_xmin of the
+# active slot could be updated, and hence, the conflict won't occur. See
+# comments atop wait_until_vacuum_can_remove.
+$node_primary->safe_psql('testdb',
+ "SELECT injection_points_attach('skip-log-running-xacts', 'error');");
+
# This should trigger the conflict
$node_primary->safe_psql('testdb',
qq[CREATE TABLE prun(id integer, s char(2000)) WITH (fillfactor = 75, user_catalog_table = true);]
@@ -794,6 +818,10 @@ $node_primary->safe_psql('testdb', qq[UPDATE prun SET s = 'E';]);
$node_primary->wait_for_replay_catchup($node_standby);
+# Resume generating the xl_running_xacts record
+$node_primary->safe_psql('testdb',
+ "SELECT injection_points_detach('skip-log-running-xacts');");
+
# Check invalidation in the logfile and in pg_stat_database_conflicts
check_for_invalidation('pruning_', $logstart, 'with on-access pruning');