From e19ab85f17cc74bfa8df57d249b85a83fd859ac7 Mon Sep 17 00:00:00 2001 From: Nikolay Samokhvalov Date: Wed, 4 Jun 2025 11:37:43 -0700 Subject: [PATCH] [PATCH] Add --system-identifier option to pg_resetwal This patch adds a new --system-identifier option to pg_resetwal that allows users to change the database cluster's system identifier. This feature is useful in recovery scenarios where a restored cluster needs to be made distinct from the original. The system identifier change makes the cluster incompatible with existing backups, standby servers, and replication setups, so the feature includes appropriate safety checks and user warnings. --- doc/src/sgml/ref/pg_resetwal.sgml | 23 +++++++++++++++++++++++ src/bin/pg_resetwal/pg_resetwal.c | 25 +++++++++++++++++++++++++ src/bin/pg_resetwal/t/001_basic.pl | 29 +++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+) diff --git a/doc/src/sgml/ref/pg_resetwal.sgml b/doc/src/sgml/ref/pg_resetwal.sgml index 2c019c2aac6..7ee1c2a08b2 100644 --- a/doc/src/sgml/ref/pg_resetwal.sgml +++ b/doc/src/sgml/ref/pg_resetwal.sgml @@ -356,6 +356,29 @@ PostgreSQL documentation + + + + + Manually set the database system identifier. + + + + This option should only be used in recovery scenarios where you need + to make a restored cluster distinct from the original, or when cloning + a cluster for testing purposes. The value must be a positive 64-bit + integer and cannot be zero. + + + + + Changing the system identifier will break compatibility with existing + backups and standby servers. Use this option with extreme caution. + + + + + diff --git a/src/bin/pg_resetwal/pg_resetwal.c b/src/bin/pg_resetwal/pg_resetwal.c index e876f35f38e..995f4b166b9 100644 --- a/src/bin/pg_resetwal/pg_resetwal.c +++ b/src/bin/pg_resetwal/pg_resetwal.c @@ -76,6 +76,7 @@ static XLogSegNo minXlogSegNo = 0; static int WalSegSz; static int set_wal_segsize; static int set_char_signedness = -1; +static uint64 set_sysid = 0; static void CheckDataVersion(void); static bool read_controlfile(void); @@ -105,6 +106,7 @@ main(int argc, char *argv[]) {"next-oid", required_argument, NULL, 'o'}, {"multixact-offset", required_argument, NULL, 'O'}, {"oldest-transaction-id", required_argument, NULL, 'u'}, + {"system-identifier", required_argument, NULL, 3}, {"next-transaction-id", required_argument, NULL, 'x'}, {"wal-segsize", required_argument, NULL, 1}, {"char-signedness", required_argument, NULL, 2}, @@ -321,6 +323,19 @@ main(int argc, char *argv[]) break; } + case 3: + errno = 0; + set_sysid = strtou64(optarg, &endptr, 0); + if (endptr == optarg || *endptr != '\0' || errno != 0) + { + pg_log_error("invalid argument for option %s", "--system-identifier"); + pg_log_error_hint("Try \"%s --help\" for more information.", progname); + exit(1); + } + if (set_sysid == 0) + pg_fatal("system identifier must not be 0"); + break; + default: /* getopt_long already emitted a complaint */ pg_log_error_hint("Try \"%s --help\" for more information.", progname); @@ -478,6 +493,9 @@ main(int argc, char *argv[]) if (set_char_signedness != -1) ControlFile.default_char_signedness = (set_char_signedness == 1); + if (set_sysid != 0) + ControlFile.system_identifier = set_sysid; + if (minXlogSegNo > newXlogSegNo) newXlogSegNo = minXlogSegNo; @@ -875,6 +893,12 @@ PrintNewControlValues(void) printf(_("Bytes per WAL segment: %u\n"), ControlFile.xlog_seg_size); } + + if (set_sysid != 0) + { + printf(_("System identifier: " UINT64_FORMAT "\n"), + ControlFile.system_identifier); + } } @@ -1212,6 +1236,7 @@ usage(void) printf(_(" -O, --multixact-offset=OFFSET set next multitransaction offset\n")); printf(_(" -u, --oldest-transaction-id=XID set oldest transaction ID\n")); printf(_(" -x, --next-transaction-id=XID set next transaction ID\n")); + printf(_(" --system-identifier=SYSID set system identifier\n")); printf(_(" --char-signedness=OPTION set char signedness to \"signed\" or \"unsigned\"\n")); printf(_(" --wal-segsize=SIZE size of WAL segments, in megabytes\n")); diff --git a/src/bin/pg_resetwal/t/001_basic.pl b/src/bin/pg_resetwal/t/001_basic.pl index d6bbbd0ceda..c740759882c 100644 --- a/src/bin/pg_resetwal/t/001_basic.pl +++ b/src/bin/pg_resetwal/t/001_basic.pl @@ -179,6 +179,35 @@ command_fails_like( qr/error: invalid argument for option --char-signedness/, 'fails with incorrect --char-signedness option'); +# --system-identifier +command_fails_like( + [ 'pg_resetwal', '--system-identifier' => 'foo', $node->data_dir ], + qr/error: invalid argument for option --system-identifier/, + 'fails with incorrect --system-identifier option'); +command_fails_like( + [ 'pg_resetwal', '--system-identifier' => '0', $node->data_dir ], + qr/system identifier must not be 0/, + 'fails with zero system identifier'); + +# Test actual system identifier change with force flag +$node->stop; +my $new_sysid = '9876543210987654321'; +command_ok( + [ 'pg_resetwal', '-f', '--system-identifier' => $new_sysid, $node->data_dir ], + 'pg_resetwal --system-identifier with force flag succeeds'); + +# Verify the change was applied by checking pg_control +$node->start; +my $controldata_output = $node->safe_psql('postgres', + "SELECT system_identifier FROM pg_control_system()"); +is($controldata_output, $new_sysid, 'system identifier was changed correctly'); + +# Test that the server works normally after system identifier change +is($node->safe_psql("postgres", "SELECT 1;"), + 1, 'server running and working after system identifier change'); + +$node->stop; + # run with control override options my $out = (run_command([ 'pg_resetwal', '--dry-run', $node->data_dir ]))[0]; -- 2.39.5 (Apple Git-154)