Skip to content

Commit 964aa44

Browse files
michaelpqCommitfest Bot
authored andcommitted
Add regression test for 2PC visibility check on standby
This adds some test coverage for a defect fixed in 2e57790, where the only reliable test back then was to use a hardcoded sleep(). This test relies on an injection point that is persisted across a node restart, so as it is possible to cause the checkpointer to wait when configuring the shared memory state of shared_preload_libraries at a very early startup stage. Reverting 2e57790 causes the test to fail, and it passes on HEAD.
1 parent 674819c commit 964aa44

File tree

2 files changed

+63
-0
lines changed

2 files changed

+63
-0
lines changed

src/backend/replication/syncrep.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@
8484
#include "storage/proc.h"
8585
#include "tcop/tcopprot.h"
8686
#include "utils/guc_hooks.h"
87+
#include "utils/injection_point.h"
8788
#include "utils/ps_status.h"
8889

8990
/* User-settable parameters for sync rep */
@@ -968,6 +969,8 @@ SyncRepUpdateSyncStandbysDefined(void)
968969
if (sync_standbys_defined !=
969970
((WalSndCtl->sync_standbys_status & SYNC_STANDBY_DEFINED) != 0))
970971
{
972+
INJECTION_POINT("checkpointer-syncrep-update", NULL);
973+
971974
LWLockAcquire(SyncRepLock, LW_EXCLUSIVE);
972975

973976
/*

src/test/recovery/t/009_twophase.pl

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,27 @@ sub configure_and_reload
5151
));
5252
$node_paris->start;
5353

54+
# Check if the extension injection_points is available, as it may be
55+
# possible that this script is run with installcheck, where the module
56+
# would not be installed by default.
57+
my $injection_points_supported =
58+
$node_london->check_extension('injection_points');
59+
if ($injection_points_supported != 0)
60+
{
61+
$node_london->safe_psql('postgres', 'CREATE EXTENSION injection_points;');
62+
63+
# Set shared_preload_libraries, to allow the injection points to persist
64+
# across restarts.
65+
$node_london->append_conf(
66+
'postgresql.conf', qq(
67+
shared_preload_libraries = 'injection_points'
68+
));
69+
$node_paris->append_conf(
70+
'postgresql.conf', qq(
71+
shared_preload_libraries = 'injection_points'
72+
));
73+
}
74+
5475
# Switch to synchronous replication in both directions
5576
configure_and_reload($node_london, "synchronous_standby_names = 'paris'");
5677
configure_and_reload($node_paris, "synchronous_standby_names = 'london'");
@@ -327,6 +348,23 @@ sub configure_and_reload
327348
INSERT INTO t_009_tbl_standby_mvcc VALUES (2, 'issued to ${cur_primary_name}');
328349
PREPARE TRANSACTION 'xact_009_standby_mvcc';
329350
");
351+
352+
# Attach an injection point to wait in the checkpointer when configuring
353+
# the shared memory state data related to synchronous_standby_names, then
354+
# persist the attached point to disk so as the follow-up restart will be able
355+
# to wait at the early stages of the checkpointer startup sequence.
356+
#
357+
# Note that as the checkpointer has already applied the
358+
# synchronous_standby_names configuration, this has no effect until the
359+
# next startup of the primary.
360+
if ($injection_points_supported != 0)
361+
{
362+
$cur_primary->psql('postgres',
363+
"SELECT injection_points_attach('checkpointer-syncrep-update', 'wait')"
364+
);
365+
$cur_primary->psql('postgres', "SELECT injection_points_flush()");
366+
}
367+
330368
$cur_primary->stop;
331369
$cur_standby->restart;
332370

@@ -341,6 +379,16 @@ sub configure_and_reload
341379

342380
# Commit the transaction in primary
343381
$cur_primary->start;
382+
383+
# Make sure that the checkpointer is waiting before setting up the data of
384+
# synchronous_standby_names in shared memory. We want the checkpointer to be
385+
# stuck and make sure that the next COMMIT PREPARED is detected correctly on
386+
# the standby when remote_apply is set on the primary.
387+
if ($injection_points_supported != 0)
388+
{
389+
$cur_primary->wait_for_event('checkpointer',
390+
'checkpointer-syncrep-update');
391+
}
344392
$cur_primary->psql(
345393
'postgres', "
346394
SET synchronous_commit='remote_apply'; -- To ensure the standby is caught up
@@ -361,6 +409,18 @@ sub configure_and_reload
361409
"Committed prepared transaction is visible to new snapshot in standby");
362410
$standby_session->quit;
363411

412+
# Remove the injection point, the checkpointer now applies the configuration
413+
# related to synchronous_standby_names in shared memory.
414+
if ($injection_points_supported != 0)
415+
{
416+
$cur_primary->psql('postgres',
417+
"SELECT injection_points_wakeup('checkpointer-syncrep-update')");
418+
$cur_primary->psql('postgres',
419+
"SELECT injection_points_detach('checkpointer-syncrep-update')");
420+
}
421+
422+
$cur_standby->restart;
423+
364424
###############################################################################
365425
# Check for a lock conflict between prepared transaction with DDL inside and
366426
# replay of XLOG_STANDBY_LOCK wal record.

0 commit comments

Comments
 (0)