summaryrefslogtreecommitdiffstats
path: root/src/test/modules/commit_ts/t/004_restart.pl
blob: 39ca25a06bf0126414a14c0e9a8ec6a7f033e869 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
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;