diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c index 48e478a4ecb..0ec274d887e 100644 --- a/src/backend/access/transam/twophase.c +++ b/src/backend/access/transam/twophase.c @@ -1539,7 +1539,10 @@ FinishPreparedTransaction(const char *gid, bool isCommit) if (gxact->ondisk) buf = ReadTwoPhaseFile(fxid, false); else + { + INJECTION_POINT("wait-checkpointer-deals", NULL); XlogReadTwoPhaseData(gxact->prepare_start_lsn, &buf, NULL); + } /* diff --git a/src/test/modules/Makefile b/src/test/modules/Makefile index 71a2e65ad70..79e0630c9af 100644 --- a/src/test/modules/Makefile +++ b/src/test/modules/Makefile @@ -54,6 +54,7 @@ SUBDIRS = \ test_shm_mq \ test_slru \ test_tidstore \ + test_two_phase \ test_wait_lsn \ unsafe_tests \ worker_spi \ diff --git a/src/test/modules/test_two_phase/Makefile b/src/test/modules/test_two_phase/Makefile new file mode 100644 index 00000000000..f2757b4e9a0 --- /dev/null +++ b/src/test/modules/test_two_phase/Makefile @@ -0,0 +1,17 @@ +# src/test/modules/test_two_phase/Makefile + +TAP_TESTS = 1 + +EXTRA_INSTALL=src/test/modules/injection_points +export enable_injection_points + +ifdef USE_PGXS +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +subdir = src/test/modules/test_two_phase +top_builddir = ../../../.. +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif diff --git a/src/test/modules/test_two_phase/t/001_checkpoint.pl b/src/test/modules/test_two_phase/t/001_checkpoint.pl new file mode 100644 index 00000000000..741c8f8e154 --- /dev/null +++ b/src/test/modules/test_two_phase/t/001_checkpoint.pl @@ -0,0 +1,64 @@ +# Simple tests for the reproducing race between prepared transaction commit and checkpointer. + +use strict; +use warnings FATAL => 'all'; +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 $node_primary = PostgreSQL::Test::Cluster->new('primary'); +$node_primary->init(allows_streaming => 1); +$node_primary->append_conf('postgresql.conf', qq( + max_prepared_transactions = 10 + checkpoint_timeout = 1d + log_min_messages = debug2 +)); + +$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->safe_psql('postgres', qq{ CREATE EXTENSION injection_points }); + +# Create table that we will experiment with +$node_primary->safe_psql('postgres', qq{ CREATE TABLE test_tab (id INT); }); + +$node_primary->safe_psql('postgres', + "SELECT injection_points_attach('wait-checkpointer-deals', 'wait');" +); + +my $psql = $node_primary->background_psql('postgres', on_error_stop => 1); + +$psql->query_until( + qr/start/, q{ + \echo start + BEGIN; + INSERT INTO test_tab VALUES(1); + PREPARE TRANSACTION 'test_transaction'; + COMMIT PREPARED 'test_transaction'; +}); + +$node_primary->wait_for_event('client backend', 'wait-checkpointer-deals'); + +$node_primary->safe_psql('postgres',"CHECKPOINT;"); + +$node_primary->safe_psql('postgres', + "SELECT injection_points_wakeup('wait-checkpointer-deals');" +); + +sleep(5); + +# expect coredump here +$psql->quit; +$node_primary->stop; +done_testing();