Preserve commit timestamps across clean restart

An oversight in setting the boundaries of known commit timestamps during
startup caused old commit timestamps to become inaccessible after a
server restart.

Author and reporter: Julien Rouhaud
Review, test code: Craig Ringer
This commit is contained in:
Alvaro Herrera 2016-10-24 09:27:24 -03:00
parent 7d80417d3d
commit 00f15338b2
2 changed files with 139 additions and 0 deletions

View File

@ -844,6 +844,8 @@ SetCommitTsLimit(TransactionId oldestXact, TransactionId newestXact)
else
{
Assert(ShmemVariableCache->newestCommitTsXid == InvalidTransactionId);
ShmemVariableCache->oldestCommitTsXid = oldestXact;
ShmemVariableCache->newestCommitTsXid = newestXact;
}
LWLockRelease(CommitTsLock);
}

View File

@ -0,0 +1,137 @@
# Testing of commit timestamps preservation across clean 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', qq(
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, 3, 'getting ts of BootstrapTransactionId reports error');
like(
$stderr,
qr/cannot retrieve commit timestamp for transaction/,
'expected error from BootstrapTransactionId');
($ret, $stdout, $stderr) =
$node_master->psql('postgres', qq[SELECT pg_xact_commit_timestamp('2');]);
is($ret, 3, 'getting ts of FrozenTransactionId reports error');
like(
$stderr,
qr/cannot retrieve commit timestamp for transaction/,
'expected error from FrozenTransactionId');
# 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 txid_current();
COMMIT;
]);
my $before_restart_ts = $node_master->safe_psql('postgres',
qq[SELECT pg_xact_commit_timestamp('$xid');]);
ok($before_restart_ts != '' && $before_restart_ts != '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', qq(
track_commit_timestamp = off
));
$node_master->stop('fast');
$node_master->start;
($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 txid_current();
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', qq(
track_commit_timestamp = on
));
$node_master->stop('fast');
$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;