diff options
Diffstat (limited to 'src/test/modules/commit_ts/t')
-rw-r--r-- | src/test/modules/commit_ts/t/001_base.pl | 33 | ||||
-rw-r--r-- | src/test/modules/commit_ts/t/002_standby.pl | 63 | ||||
-rw-r--r-- | src/test/modules/commit_ts/t/003_standby_2.pl | 64 | ||||
-rw-r--r-- | src/test/modules/commit_ts/t/004_restart.pl | 149 |
4 files changed, 309 insertions, 0 deletions
diff --git a/src/test/modules/commit_ts/t/001_base.pl b/src/test/modules/commit_ts/t/001_base.pl new file mode 100644 index 0000000..f8d5d84 --- /dev/null +++ b/src/test/modules/commit_ts/t/001_base.pl @@ -0,0 +1,33 @@ +# Single-node test: value can be set, and is still present after recovery + +use strict; +use warnings; + +use TestLib; +use Test::More tests => 2; +use PostgresNode; + +my $node = get_new_node('foxtrot'); +$node->init; +$node->append_conf('postgresql.conf', 'track_commit_timestamp = on'); +$node->start; + +# Create a table, compare "now()" to the commit TS of its xmin +$node->safe_psql('postgres', + 'create table t as select now from (select now(), pg_sleep(1)) f'); +my $true = $node->safe_psql('postgres', + 'select t.now - ts.* < \'1s\' from t, pg_class c, pg_xact_commit_timestamp(c.xmin) ts where relname = \'t\'' +); +is($true, 't', 'commit TS is set'); +my $ts = $node->safe_psql('postgres', + 'select ts.* from pg_class, pg_xact_commit_timestamp(xmin) ts where relname = \'t\'' +); + +# Verify that we read the same TS after crash recovery +$node->stop('immediate'); +$node->start; + +my $recovered_ts = $node->safe_psql('postgres', + 'select ts.* from pg_class, pg_xact_commit_timestamp(xmin) ts where relname = \'t\'' +); +is($recovered_ts, $ts, 'commit TS remains after crash recovery'); diff --git a/src/test/modules/commit_ts/t/002_standby.pl b/src/test/modules/commit_ts/t/002_standby.pl new file mode 100644 index 0000000..f376b59 --- /dev/null +++ b/src/test/modules/commit_ts/t/002_standby.pl @@ -0,0 +1,63 @@ +# Test simple scenario involving a standby + +use strict; +use warnings; + +use TestLib; +use Test::More tests => 4; +use PostgresNode; + +my $bkplabel = 'backup'; +my $master = get_new_node('master'); +$master->init(allows_streaming => 1); + +$master->append_conf( + 'postgresql.conf', qq{ + track_commit_timestamp = on + max_wal_senders = 5 + }); +$master->start; +$master->backup($bkplabel); + +my $standby = get_new_node('standby'); +$standby->init_from_backup($master, $bkplabel, has_streaming => 1); +$standby->start; + +for my $i (1 .. 10) +{ + $master->safe_psql('postgres', "create table t$i()"); +} +my $master_ts = $master->safe_psql('postgres', + qq{SELECT ts.* FROM pg_class, pg_xact_commit_timestamp(xmin) AS ts WHERE relname = 't10'} +); +my $master_lsn = + $master->safe_psql('postgres', 'select pg_current_wal_lsn()'); +$standby->poll_query_until('postgres', + qq{SELECT '$master_lsn'::pg_lsn <= pg_last_wal_replay_lsn()}) + or die "standby never caught up"; + +my $standby_ts = $standby->safe_psql('postgres', + qq{select ts.* from pg_class, pg_xact_commit_timestamp(xmin) ts where relname = 't10'} +); +is($master_ts, $standby_ts, "standby gives same value as master"); + +$master->append_conf('postgresql.conf', 'track_commit_timestamp = off'); +$master->restart; +$master->safe_psql('postgres', 'checkpoint'); +$master_lsn = $master->safe_psql('postgres', 'select pg_current_wal_lsn()'); +$standby->poll_query_until('postgres', + qq{SELECT '$master_lsn'::pg_lsn <= pg_last_wal_replay_lsn()}) + or die "standby never caught up"; +$standby->safe_psql('postgres', 'checkpoint'); + +# This one should raise an error now +my ($ret, $standby_ts_stdout, $standby_ts_stderr) = $standby->psql('postgres', + 'select ts.* from pg_class, pg_xact_commit_timestamp(xmin) ts where relname = \'t10\'' +); +is($ret, 3, 'standby errors when master turned feature off'); +is($standby_ts_stdout, '', + "standby gives no value when master turned feature off"); +like( + $standby_ts_stderr, + qr/could not get commit timestamp data/, + 'expected error when master turned feature off'); diff --git a/src/test/modules/commit_ts/t/003_standby_2.pl b/src/test/modules/commit_ts/t/003_standby_2.pl new file mode 100644 index 0000000..9165d50 --- /dev/null +++ b/src/test/modules/commit_ts/t/003_standby_2.pl @@ -0,0 +1,64 @@ +# Test master/standby scenario where the track_commit_timestamp GUC is +# repeatedly toggled on and off. +use strict; +use warnings; + +use TestLib; +use Test::More tests => 4; +use PostgresNode; + +my $bkplabel = 'backup'; +my $master = get_new_node('master'); +$master->init(allows_streaming => 1); +$master->append_conf( + 'postgresql.conf', qq{ + track_commit_timestamp = on + max_wal_senders = 5 + }); +$master->start; +$master->backup($bkplabel); + +my $standby = get_new_node('standby'); +$standby->init_from_backup($master, $bkplabel, has_streaming => 1); +$standby->start; + +for my $i (1 .. 10) +{ + $master->safe_psql('postgres', "create table t$i()"); +} +$master->append_conf('postgresql.conf', 'track_commit_timestamp = off'); +$master->restart; +$master->safe_psql('postgres', 'checkpoint'); +my $master_lsn = + $master->safe_psql('postgres', 'select pg_current_wal_lsn()'); +$standby->poll_query_until('postgres', + qq{SELECT '$master_lsn'::pg_lsn <= pg_last_wal_replay_lsn()}) + or die "standby never caught up"; + +$standby->safe_psql('postgres', 'checkpoint'); +$standby->restart; + +my ($psql_ret, $standby_ts_stdout, $standby_ts_stderr) = $standby->psql( + 'postgres', + qq{SELECT ts.* FROM pg_class, pg_xact_commit_timestamp(xmin) AS ts WHERE relname = 't10'} +); +is($psql_ret, 3, 'expect error when getting commit timestamp after restart'); +is($standby_ts_stdout, '', "standby does not return a value after restart"); +like( + $standby_ts_stderr, + qr/could not get commit timestamp data/, + 'expected err msg after restart'); + +$master->append_conf('postgresql.conf', 'track_commit_timestamp = on'); +$master->restart; +$master->append_conf('postgresql.conf', 'track_commit_timestamp = off'); +$master->restart; + +system_or_bail('pg_ctl', '-D', $standby->data_dir, 'promote'); + +$standby->safe_psql('postgres', "create table t11()"); +my $standby_ts = $standby->safe_psql('postgres', + qq{SELECT ts.* FROM pg_class, pg_xact_commit_timestamp(xmin) AS ts WHERE relname = 't11'} +); +isnt($standby_ts, '', + "standby gives valid value ($standby_ts) after promotion"); diff --git a/src/test/modules/commit_ts/t/004_restart.pl b/src/test/modules/commit_ts/t/004_restart.pl new file mode 100644 index 0000000..39ca25a --- /dev/null +++ b/src/test/modules/commit_ts/t/004_restart.pl @@ -0,0 +1,149 @@ +# Testing of commit timestamps preservation across restarts +use strict; +use warnings; +use PostgresNode; +use TestLib; +use Test::More tests => 16; + +my $node_master = get_new_node('master'); +$node_master->init(allows_streaming => 1); +$node_master->append_conf('postgresql.conf', 'track_commit_timestamp = on'); +$node_master->start; + +my ($ret, $stdout, $stderr); + +($ret, $stdout, $stderr) = + $node_master->psql('postgres', qq[SELECT pg_xact_commit_timestamp('0');]); +is($ret, 3, 'getting ts of InvalidTransactionId reports error'); +like( + $stderr, + qr/cannot retrieve commit timestamp for transaction/, + 'expected error from InvalidTransactionId'); + +($ret, $stdout, $stderr) = + $node_master->psql('postgres', qq[SELECT pg_xact_commit_timestamp('1');]); +is($ret, 0, 'getting ts of BootstrapTransactionId succeeds'); +is($stdout, '', 'timestamp of BootstrapTransactionId is null'); + +($ret, $stdout, $stderr) = + $node_master->psql('postgres', qq[SELECT pg_xact_commit_timestamp('2');]); +is($ret, 0, 'getting ts of FrozenTransactionId succeeds'); +is($stdout, '', 'timestamp of FrozenTransactionId is null'); + +# Since FirstNormalTransactionId will've occurred during initdb, long before we +# enabled commit timestamps, it'll be null since we have no cts data for it but +# cts are enabled. +is( $node_master->safe_psql( + 'postgres', qq[SELECT pg_xact_commit_timestamp('3');]), + '', + 'committs for FirstNormalTransactionId is null'); + +$node_master->safe_psql('postgres', + qq[CREATE TABLE committs_test(x integer, y timestamp with time zone);]); + +my $xid = $node_master->safe_psql( + 'postgres', qq[ + BEGIN; + INSERT INTO committs_test(x, y) VALUES (1, current_timestamp); + SELECT pg_current_xact_id()::xid; + COMMIT; +]); + +my $before_restart_ts = $node_master->safe_psql('postgres', + qq[SELECT pg_xact_commit_timestamp('$xid');]); +ok($before_restart_ts ne '' && $before_restart_ts ne 'null', + 'commit timestamp recorded'); + +$node_master->stop('immediate'); +$node_master->start; + +my $after_crash_ts = $node_master->safe_psql('postgres', + qq[SELECT pg_xact_commit_timestamp('$xid');]); +is($after_crash_ts, $before_restart_ts, + 'timestamps before and after crash are equal'); + +$node_master->stop('fast'); +$node_master->start; + +my $after_restart_ts = $node_master->safe_psql('postgres', + qq[SELECT pg_xact_commit_timestamp('$xid');]); +is($after_restart_ts, $before_restart_ts, + 'timestamps before and after restart are equal'); + +# Now disable commit timestamps +$node_master->append_conf('postgresql.conf', 'track_commit_timestamp = off'); +$node_master->stop('fast'); + +# Start the server, which generates a XLOG_PARAMETER_CHANGE record where +# the parameter change is registered. +$node_master->start; + +# Now restart again the server so as no XLOG_PARAMETER_CHANGE record are +# replayed with the follow-up immediate shutdown. +$node_master->restart; + +# Move commit timestamps across page boundaries. Things should still +# be able to work across restarts with those transactions committed while +# track_commit_timestamp is disabled. +$node_master->safe_psql( + 'postgres', + qq(CREATE PROCEDURE consume_xid(cnt int) +AS \$\$ +DECLARE + i int; + BEGIN + FOR i in 1..cnt LOOP + EXECUTE 'SELECT pg_current_xact_id()'; + COMMIT; + END LOOP; + END; +\$\$ +LANGUAGE plpgsql; +)); +$node_master->safe_psql('postgres', 'CALL consume_xid(2000)'); + +($ret, $stdout, $stderr) = $node_master->psql('postgres', + qq[SELECT pg_xact_commit_timestamp('$xid');]); +is($ret, 3, 'no commit timestamp from enable tx when cts disabled'); +like( + $stderr, + qr/could not get commit timestamp data/, + 'expected error from enabled tx when committs disabled'); + +# Do a tx while cts disabled +my $xid_disabled = $node_master->safe_psql( + 'postgres', qq[ + BEGIN; + INSERT INTO committs_test(x, y) VALUES (2, current_timestamp); + SELECT pg_current_xact_id(); + COMMIT; +]); + +# Should be inaccessible +($ret, $stdout, $stderr) = $node_master->psql('postgres', + qq[SELECT pg_xact_commit_timestamp('$xid_disabled');]); +is($ret, 3, 'no commit timestamp when disabled'); +like( + $stderr, + qr/could not get commit timestamp data/, + 'expected error from disabled tx when committs disabled'); + +# Re-enable, restart and ensure we can still get the old timestamps +$node_master->append_conf('postgresql.conf', 'track_commit_timestamp = on'); + +# An immediate shutdown is used here. At next startup recovery will +# replay transactions which committed when track_commit_timestamp was +# disabled, and the facility should be able to work properly. +$node_master->stop('immediate'); +$node_master->start; + +my $after_enable_ts = $node_master->safe_psql('postgres', + qq[SELECT pg_xact_commit_timestamp('$xid');]); +is($after_enable_ts, '', 'timestamp of enabled tx null after re-enable'); + +my $after_enable_disabled_ts = $node_master->safe_psql('postgres', + qq[SELECT pg_xact_commit_timestamp('$xid_disabled');]); +is($after_enable_disabled_ts, '', + 'timestamp of disabled tx null after re-enable'); + +$node_master->stop; |