From cdd7026e1d58cc5b3ae9816b3168cbad26cdc27b Mon Sep 17 00:00:00 2001 From: Sergey Levin Date: Sat, 4 Oct 2025 20:22:46 +0500 Subject: [PATCH] Migration of the pg_commit_ts directory --- src/bin/pg_upgrade/check.c | 24 +++++++ src/bin/pg_upgrade/controldata.c | 20 ++++++ src/bin/pg_upgrade/meson.build | 1 + src/bin/pg_upgrade/pg_upgrade.c | 29 +++++++- src/bin/pg_upgrade/pg_upgrade.h | 2 + .../pg_upgrade/t/007_transfer_commit_ts.pl | 67 +++++++++++++++++++ 6 files changed, 140 insertions(+), 3 deletions(-) create mode 100644 src/bin/pg_upgrade/t/007_transfer_commit_ts.pl diff --git a/src/bin/pg_upgrade/check.c b/src/bin/pg_upgrade/check.c index 1e17d64b3ec6..73c69236d4dc 100644 --- a/src/bin/pg_upgrade/check.c +++ b/src/bin/pg_upgrade/check.c @@ -32,6 +32,7 @@ static void check_new_cluster_replication_slots(void); static void check_new_cluster_subscription_configuration(void); static void check_old_cluster_for_valid_slots(void); static void check_old_cluster_subscription_state(void); +static void check_new_cluster_pg_commit_ts(void); /* * DataTypesUsageChecks - definitions of data type checks for the old cluster @@ -767,9 +768,32 @@ check_new_cluster(void) check_new_cluster_replication_slots(); check_new_cluster_subscription_configuration(); + + check_new_cluster_pg_commit_ts(); + } +void +check_new_cluster_pg_commit_ts(void) +{ + PGconn *conn; + PGresult *res; + bool track_commit_timestamp_on; + + prep_status("Checking for new cluster configuration for commit timestamp"); + conn = connectToServer(&new_cluster, "template1"); + res = executeQueryOrDie(conn, "SELECT setting FROM pg_settings " + "WHERE name = 'track_commit_timestamp'"); + track_commit_timestamp_on = strcmp(PQgetvalue(res, 0, 0), "on") == 0; + PQclear(res); + PQfinish(conn); + if (!track_commit_timestamp_on && + old_cluster.controldata.chkpnt_newstCommitTsxid > 0) + pg_fatal("\"track_commit_timestamp\" must be \"on\" but is set to \"off\""); + + check_ok(); +} void report_clusters_compatible(void) { diff --git a/src/bin/pg_upgrade/controldata.c b/src/bin/pg_upgrade/controldata.c index 90cef0864de7..594dc1c0a9fb 100644 --- a/src/bin/pg_upgrade/controldata.c +++ b/src/bin/pg_upgrade/controldata.c @@ -321,6 +321,26 @@ get_control_data(ClusterInfo *cluster) cluster->controldata.chkpnt_nxtmulti = str2uint(p); got_multi = true; } + else if ((p = strstr(bufin, "Latest checkpoint's oldestCommitTsXid:")) != NULL) + { + p = strchr(p, ':'); + + if (p == NULL || strlen(p) <= 1) + pg_fatal("%d: controldata retrieval problem", __LINE__); + + p++; /* remove ':' char */ + cluster->controldata.chkpnt_oldstCommitTsxid = str2uint(p); + } + else if ((p = strstr(bufin, "Latest checkpoint's newestCommitTsXid:")) != NULL) + { + p = strchr(p, ':'); + + if (p == NULL || strlen(p) <= 1) + pg_fatal("%d: controldata retrieval problem", __LINE__); + + p++; /* remove ':' char */ + cluster->controldata.chkpnt_newstCommitTsxid = str2uint(p); + } else if ((p = strstr(bufin, "Latest checkpoint's oldestXID:")) != NULL) { p = strchr(p, ':'); diff --git a/src/bin/pg_upgrade/meson.build b/src/bin/pg_upgrade/meson.build index ac992f0d14b1..030618152d06 100644 --- a/src/bin/pg_upgrade/meson.build +++ b/src/bin/pg_upgrade/meson.build @@ -47,6 +47,7 @@ tests += { 't/004_subscription.pl', 't/005_char_signedness.pl', 't/006_transfer_modes.pl', + 't/007_transfer_commit_ts.pl', ], 'test_kwargs': {'priority': 40}, # pg_upgrade tests are slow }, diff --git a/src/bin/pg_upgrade/pg_upgrade.c b/src/bin/pg_upgrade/pg_upgrade.c index 490e98fa26f2..3566a2a75bc8 100644 --- a/src/bin/pg_upgrade/pg_upgrade.c +++ b/src/bin/pg_upgrade/pg_upgrade.c @@ -772,6 +772,10 @@ copy_subdir_files(const char *old_subdir, const char *new_subdir) static void copy_xact_xlog_xid(void) { + bool is_copy_commit_ts; + uint32 oldest_xid, + newest_xid; + /* * Copy old commit logs to new data dir. pg_clog has been renamed to * pg_xact in post-10 clusters. @@ -781,6 +785,22 @@ copy_xact_xlog_xid(void) GET_MAJOR_VERSION(new_cluster.major_version) <= 906 ? "pg_clog" : "pg_xact"); + /* + * Copy old commit_timestamp data to new, if available. + */ + is_copy_commit_ts = + (old_cluster.controldata.chkpnt_oldstCommitTsxid > 0 && + old_cluster.controldata.chkpnt_newstCommitTsxid > 0); + + if (is_copy_commit_ts) + { + copy_subdir_files("pg_commit_ts", "pg_commit_ts"); + oldest_xid = old_cluster.controldata.chkpnt_oldstCommitTsxid; + newest_xid = old_cluster.controldata.chkpnt_newstCommitTsxid; + } + else + oldest_xid = newest_xid = old_cluster.controldata.chkpnt_nxtxid; + prep_status("Setting oldest XID for new cluster"); exec_prog(UTILITY_LOG_FILE, NULL, true, true, "\"%s/pg_resetwal\" -f -u %u \"%s\"", @@ -798,12 +818,15 @@ copy_xact_xlog_xid(void) "\"%s/pg_resetwal\" -f -e %u \"%s\"", new_cluster.bindir, old_cluster.controldata.chkpnt_nxtepoch, new_cluster.pgdata); - /* must reset commit timestamp limits also */ + + /* + * must reset commit timestamp limits also or copy from the old cluster + */ exec_prog(UTILITY_LOG_FILE, NULL, true, true, "\"%s/pg_resetwal\" -f -c %u,%u \"%s\"", new_cluster.bindir, - old_cluster.controldata.chkpnt_nxtxid, - old_cluster.controldata.chkpnt_nxtxid, + oldest_xid, + newest_xid, new_cluster.pgdata); check_ok(); diff --git a/src/bin/pg_upgrade/pg_upgrade.h b/src/bin/pg_upgrade/pg_upgrade.h index e86336f4be95..ccc391311a35 100644 --- a/src/bin/pg_upgrade/pg_upgrade.h +++ b/src/bin/pg_upgrade/pg_upgrade.h @@ -238,6 +238,8 @@ typedef struct uint32 chkpnt_nxtmxoff; uint32 chkpnt_oldstMulti; uint32 chkpnt_oldstxid; + uint32 chkpnt_oldstCommitTsxid; + uint32 chkpnt_newstCommitTsxid; uint32 align; uint32 blocksz; uint32 largesz; diff --git a/src/bin/pg_upgrade/t/007_transfer_commit_ts.pl b/src/bin/pg_upgrade/t/007_transfer_commit_ts.pl new file mode 100644 index 000000000000..e4ae1d951fae --- /dev/null +++ b/src/bin/pg_upgrade/t/007_transfer_commit_ts.pl @@ -0,0 +1,67 @@ +# Copyright (c) 2025, PostgreSQL Global Development Group + +# Tests for transfer pg_commit_ts directory. + +use strict; +use warnings FATAL => 'all'; + +use PostgreSQL::Test::Cluster; +use PostgreSQL::Test::Utils; +use Test::More; + +# 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; +my $resold = $old->safe_psql( + 'postgres', qq{ + create table a(a int); + select xid,timestamp from pg_last_committed_xact(); +}); + +my ($xid) = $resold =~ /\s*(\d+)\s*\|.*/; +$old->stop; + +# Initialize new cluster +my $new = PostgreSQL::Test::Cluster->new('new'); +$new->init; + +# Setup a common pg_upgrade command to be used by all the test cases +my @pg_upgrade_cmd = ( + 'pg_upgrade', '--no-sync', + '--old-datadir' => $old->data_dir, + '--new-datadir' => $new->data_dir, + '--old-bindir' => $old->config_data('--bindir'), + '--new-bindir' => $new->config_data('--bindir'), + '--socketdir' => $new->host, + '--old-port' => $old->port, + '--new-port' => $new->port, + $mode); + +# In a VPATH build, we'll be started in the source directory, but we want +# to run pg_upgrade in the build directory so that any files generated finish +# in it, like delete_old_cluster.{sh,bat}. +chdir ${PostgreSQL::Test::Utils::tmp_check}; + +command_checks_all( + [@pg_upgrade_cmd], 1, + [qr{"track_commit_timestamp" must be "on" but is set to "off"}], [], + 'run of pg_upgrade for mismatch parameter track_commit_timestamp'); + +$new->append_conf('postgresql.conf', 'track_commit_timestamp = on'); + +command_ok([@pg_upgrade_cmd], 'run of pg_upgrade ok'); + +$new->start; +my $resnew = $new->safe_psql( + 'postgres', qq{ + select $xid,pg_xact_commit_timestamp(${xid}::text::xid); +}); +$new->stop; +ok($resold eq $resnew, "timestamp transferred successfully"); + +done_testing();