Yes, the pg_commit_ts directory is not transferred by pg_upgrade.
Basically, you can get the exact same result by manually copying the
pg_commit_ts directory and running pg_resetwal.  And this patch does it
automatically.

In other words, the patch provides the stated functionality, but
consider running pgindet.

I'm not sure whether there were any reasons not to make this move from
the beginning.  The authors' opinions are needed here.

And one more thing.  In my perspective, having some tests is always a
good idea, even if they are not meant to be committed. After briefly
examining the patch, I developed this basic test. This is not finalized
in any manner, but it is simply an idea.

-- 
Best regards,
Maxim Orlov.
# Copyright (c) 2025, PostgreSQL Global Development Group

# Tests for handling the default char signedness during upgrade.

use strict;
use warnings FATAL => 'all';

use PostgreSQL::Test::Cluster;
use PostgreSQL::Test::Utils;
use Test::More;

sub command_output
{
        my ($cmd) = @_;
        my ($stdout, $stderr);

        print("# Running: " . join(" ", @{$cmd}) . "\n");

        my $result = IPC::Run::run $cmd, '>', \$stdout, '2>', \$stderr;
        ok($result, "@$cmd exit code 0");
        is($stderr, '', "@$cmd no stderr");

        return $stdout;
}

# Can be changed to test the other modes
my $mode = $ENV{PG_TEST_PG_UPGRADE_MODE} || '--copy';

# Initialize old cluster
my $old = PostgreSQL::Test::Cluster->new('old');
$old->init;
$old->append_conf('postgresql.conf', 'track_commit_timestamp = on');
$old->start;
$old->command_ok([ 'pgbench', '-i', '-s', '1' ], 'init pgbench');
$old->command_ok([ 'pgbench', '-t', '100', '-j', '2' ], 'pgbench it');
$old->stop;

# Initialize new cluster
my $new = PostgreSQL::Test::Cluster->new('new');
$new->init;
$new->append_conf('postgresql.conf', 'track_commit_timestamp = on');

command_ok(
        [
                'pg_upgrade', '--no-sync',
                '-d', $old->data_dir,
                '-D', $new->data_dir,
                '-b', $old->config_data('--bindir'),
                '-B', $new->config_data('--bindir'),
                '-s', $new->host,
                '-p', $old->port,
                '-P', $new->port,
                $mode
        ],
        'run of pg_upgrade');

$new->start;
$new->command_ok([ 'pgbench', '-t', '10' ], 'pgbench it');
$new->stop;

sub xact_commit_ts
{
        my ($node) = @_;
        my ($oldest, $newest);
        my $out = command_output([ 'pg_controldata', '-D', $node->data_dir ]);

        if ($out =~ /oldestCommitTsXid:(\d+)/) {
                $oldest = $1;
        }
        if ($out =~ /newestCommitTsXid:(\d+)/) {
                $newest= $1;
        }

        for my $line (grep { /\S/ } split /\n/, $out) {
                if ($line =~ /Latest checkpoint's NextXID:/) {
                        print $line . "\n";
                }
                if ($line =~ /Latest checkpoint's oldestXID:/) {
                        print $line . "\n";
                }
                if ($line =~ /Latest checkpoint's oldestCommitTsXid/) {
                        print $line . "\n";
                }
                if ($line =~ /Latest checkpoint's newestCommitTsXid:/) {
                        print $line . "\n";
                }
        }

        $node->start;
        my $res = $node->safe_psql('postgres', "
        WITH xids AS (
                SELECT v::text::xid AS x
                FROM generate_series($oldest, $newest) v
        )
        SELECT x, pg_xact_commit_timestamp(x::text::xid)
        FROM xids;
        ");
        $node->stop;

        return grep { /\S/ } split /\n/, $res;
}

my @a = xact_commit_ts($old);
my @b = xact_commit_ts($new);
my %h1 = map { $_ => 1 } @a;
my %h2 = map { $_ => 1 } @b;

#
# All timestamps from the old cluster should appear in the new one.
#
my $count = 0;
print "Commit timestamp only in old cluster:\n";
for my $line (@a) {
        unless ($h2{$line}) {
                print "$line\n";
                $count = $count + 1;
        }
}
ok($count == 0, "all the timestamp transferred successfully");

#
# The new cluster should contain timestamps created during the pg_upgrade and
# some more created by the pgbench.
#
print "\nCommit timestamp only in new cluster:\n";
for my $line (@b) {
        print "$line\n" unless $h1{$line};
}

done_testing();

Reply via email to