1
0
mirror of https://github.com/postgres/postgres.git synced 2025-04-20 00:42:27 +03:00
postgres/src/test/modules/commit_ts/t/004_restart.pl
Andrew Dunstan 201a76183e
Unify PostgresNode's new() and get_new_node() methods
There is only one constructor now for PostgresNode, with the idiomatic
name 'new'. The method is not exported by the class, and must be called
as "PostgresNode->new('name',[args])". All the TAP tests that use
PostgresNode are modified accordingly. Third party scripts will need
adjusting, which is a fairly mechanical process (I just used a sed
script).
2021-07-29 05:58:08 -04:00

153 lines
5.0 KiB
Perl

# Copyright (c) 2021, PostgreSQL Global Development Group
# Testing of commit timestamps preservation across restarts
use strict;
use warnings;
use PostgresNode;
use TestLib;
use Test::More tests => 16;
my $node_primary = PostgresNode->new('primary');
$node_primary->init(allows_streaming => 1);
$node_primary->append_conf('postgresql.conf', 'track_commit_timestamp = on');
$node_primary->start;
my ($ret, $stdout, $stderr);
($ret, $stdout, $stderr) =
$node_primary->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_primary->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_primary->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_primary->safe_psql(
'postgres', qq[SELECT pg_xact_commit_timestamp('3');]),
'',
'committs for FirstNormalTransactionId is null');
$node_primary->safe_psql('postgres',
qq[CREATE TABLE committs_test(x integer, y timestamp with time zone);]);
my $xid = $node_primary->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_primary->safe_psql('postgres',
qq[SELECT pg_xact_commit_timestamp('$xid');]);
ok($before_restart_ts ne '' && $before_restart_ts ne 'null',
'commit timestamp recorded');
$node_primary->stop('immediate');
$node_primary->start;
my $after_crash_ts = $node_primary->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_primary->stop('fast');
$node_primary->start;
my $after_restart_ts = $node_primary->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_primary->append_conf('postgresql.conf', 'track_commit_timestamp = off');
$node_primary->stop('fast');
# Start the server, which generates a XLOG_PARAMETER_CHANGE record where
# the parameter change is registered.
$node_primary->start;
# Now restart again the server so as no XLOG_PARAMETER_CHANGE record are
# replayed with the follow-up immediate shutdown.
$node_primary->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_primary->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_primary->safe_psql('postgres', 'CALL consume_xid(2000)');
($ret, $stdout, $stderr) = $node_primary->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_primary->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_primary->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_primary->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_primary->stop('immediate');
$node_primary->start;
my $after_enable_ts = $node_primary->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_primary->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_primary->stop;