Re: [PATCH] pg_upgrade: add --initdb option to create the new cluster automatically

From: Bohyun Lee <bohyun(dot)lee(at)databricks(dot)com>
To: Heikki Linnakangas <hlinnaka(at)iki(dot)fi>
Cc: Greg Sabino Mullane <htamfids(at)gmail(dot)com>, Daniel Gustafsson <daniel(at)yesql(dot)se>, pgsql-hackers(at)lists(dot)postgresql(dot)org
Subject: Re: [PATCH] pg_upgrade: add --initdb option to create the new cluster automatically
Date: 2026-10-07 17:44:43
Message-ID: CAMPh8MojTuNXGhL4tKyiKe2B4yNri8M61CAChEeHu=KciikHGA@mail.gmail.com
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

Hi Shihao and Heikki,

Thanks for testing and for the feedback.

*1. Meson coverage — Shihao #1*
> t/009_initdb_option.pl is not listed in
> src/bin/pg_upgrade/meson.build, so it never runs in a meson build.

Thanks, included t/009_initdb_option.pl in the Meson test list.

*2. Group access — Shihao #2*
> The group access setting from initdb -g is not copied from the old
> cluster.

The current patch now preserves the old cluster's group-access setting
by passing --allow-group-access to initdb when the old cluster allows
group access.

*3. Missing -B — Shihao #3 and Heikki*

Shihao Zhong wrote:

> resolve_new_bindir() is a nice cleanup, but the new callers pass
> os_info.progname. That is get_progname(argv[0]), so it has no directory
> in it. find_my_exec() then searches PATH instead of using argv[0].

Heikki Linnakangas wrote:

> Another little issue I noticed: Without the --new-bindir/-B option, it
> fails to find the binary:
>
> $ bin/pg_upgrade --check -d data -b bin -D data-new2 --initdb
> could not find a "pg_upgrade" to execute

The current patch now passes the original argv[0] to
resolve_new_bindir(). Without -B or PGBINNEW, the new binary directory
defaults to the directory containing pg_upgrade, matching the existing
behavior.

*4. Log location and cleanup — Shihao #4*
> The <pgdata>.initdb_log directory is never deleted. It stays after a
> successful run and after --check, and --retain has no effect on it.

The patch is updated so that it now writes --initdb logs under
./pg_upgrade_output.d
in the current working directory, using the normal cleanup and --retain
handling. Successful runs, including --check, remove their logs unless
--retain is given; failed runs keep them.
This avoids requiring write access to the new data directory's parent
just for logging. Logs stay outside the new data directory because
initdb requires it to be empty.

*5. Existing empty target — Shihao #5*
> A small note on the empty directory check. It stops initdb from
> running where there are files, but the cleanup still calls rmtree() on
> the directory itself. So a directory the operator made by hand is gone
> after a failed run.

The patch now leaves initialization-failure cleanup to initdb,
which preserves an operator-created directory. It removes the contents
of a pre-existing empty target or removes a directory it created, unless
--no-clean was requested. Initdb sets the directory permissions as
usual, and the original mode is not restored.
Once initialization succeeds, pg_upgrade leaves the new cluster in place
if any later pg_upgrade step fails, as it does for a manually
initialized cluster.

*6. --check --initdb — Shihao #6 and Heikki*

Shihao Zhong wrote:

> Two things about --check --initdb. I saw that v5 turned this into a
> dry run instead of blocking it. First, the live check problem Daniel
> reported for v2 is back. With the old cluster running, plain --check
> says "Clusters are compatible", while --check --initdb says "There seems
> to be a postmaster servicing the old cluster". Second, the dry run
> returns 0 for a cluster that cannot be upgraded. With a regproc column
> in the old cluster, --check --initdb returns 0 and the real run returns
> 1.

Heikki Linnakangas wrote:

> That's not good, that essentially means that --check doesn't work with
> the --initdb option. Some of the checks check that the new cluster is
> compatible with the old cluster, and assuming we run initdb correctly,
> there's no need to run those checks with --initdb. But we should still
> run all the checks we can on the old cluster.

The current patch now allows --check --initdb to check a running old
server without stopping it. The new server must use a different port.

Additionally, the patch now initializes the new cluster and runs the
compatibility checks on both clusters for --check --initdb, without
performing the upgrade. Unsupported regproc columns cause the check to
fail.

--check --initdb retains the initialized new cluster whether the
compatibility
checks succeed or fail. After a successful check, rerun pg_upgrade against
that
cluster without --check, --initdb, or --initdb-options.

*7. -O and extra initdb options — Heikki*
> But why forbid using -O with --initdb? I
> would imagine that the -O options are passed to the postmaster the same
> way with or without --initdb.

Right, the patch now allows -O with --initdb and passes it only to the
new postmaster, using the existing server-option handling.

*8. Source-server startup description — Heikki*
> Hmm, how's that different from how it works without --initdb? pg_upgrade
> needs to launch the old cluster anyway to perform the compatibility
> checks, right?

Yes. With --initdb, the old cluster's encoding and locale are read
before initializing the new cluster. The current implementation now omits
this
startup detail from the option documentation since the Notes already
describe
temporary server starts.

*9. Passing extra options to initdb — Heikki*
> Is there a way to pass extra options to initdb? Or do you require the
> user to run initdb first or change the settings afterwards, if they want
> some additional settings?

The current patch now provides --initdb-options to pass additional
arguments to initdb, for example:

pg_upgrade --initdb \
--initdb-options='-c huge_pages=off --waldir=/wal/new' ...

It requires --initdb and it can be repeated, preserving upstream initdb
option
ordering.
Settings passed with initdb -c apply during initialization and remain in
postgresql.conf. Options that conflict with pg_upgrade's managed settings
are
rejected, while other option values and paths are validated by initdb.

Github repo: https://github.com/LeeBohyun/postgres/tree/pg_upgrade_initdb

Best,
Bohyun

On Mon, Oct 5, 2026 at 2:49 PM Heikki Linnakangas <hlinnaka(at)iki(dot)fi> wrote:

> On 17/07/2026 15:10, Bohyun Lee wrote:
> > -O: dropped support with --initdb entirely, as you originally suggested.
> > The partial "-c only" forwarding still broke on quoted values with
> > spaces. pg_upgrade now rejects -O + --initdb during option parsing, with
> > a test and a doc note.
>
> > @@ -244,6 +249,17 @@ parseCommandLine(int argc, char *argv[])
> > if (optind < argc)
> > pg_fatal("too many command-line arguments (first is
> \"%s\")", argv[optind]);
> >
> > + /*
> > + * -O passes options to the new cluster's postmaster, but with
> --initdb
> > + * the new cluster is created by initdb, which accepts a
> different option
> > + * set. Rather than guess which -O options initdb also
> understands, reject
> > + * the combination and let the user create the cluster manually
> (without
> > + * --initdb) if they need postmaster-only options.
> > + */
> > + if (new_cluster.pgopts && user_opts.initdb_new_cluster)
> > + pg_fatal("options %s and %s cannot be used together",
> > + "-O/--new-options", "--initdb");
> > +
> > if (!user_opts.sync_method)
> > user_opts.sync_method = pg_strdup("fsync");
> >
>
> That doesn't sound right. There's indeed no reason think that initdb
> would accept the same options as postmaster, so it doesn't make sense to
> pass the -O options to initdb. But why forbid using -O with --initdb? I
> would imagine that the -O options are passed to the postmaster the same
> way with or without --initdb.
>
> Is there a way to pass extra options to initdb? Or do you require the
> user to run initdb first or change the settings afterwards, if they want
> some additional settings?
>
> > + <para>
> > + To discover the old cluster's encoding and locale,
> > + <option>--initdb</option> briefly starts the old server in
> > + binary-upgrade mode (which disables autovacuum) and stops it
> again
> > + before creating the new cluster. If a compatibility check
> fails after
> > + the new cluster has been created, its data directory is removed
> > + automatically, so the upgrade can be retried without manual
> cleanup.
> > + </para>
>
> Hmm, how's that different from how it works without --initdb? pg_upgrade
> needs to launch the old cluster anyway to perform the compatibility
> checks, right?
>
> - Heikki
>
>

Attachment Content-Type Size
v7-0001-pg_upgrade-initdb-doc.patch application/octet-stream 2.1 KB
v7-0002-pg_upgrade-initdb.patch application/octet-stream 52.6 KB

In response to

Browse pgsql-hackers by date

  From Date Subject
Next Message Alexandre Felipe 2026-10-07 17:52:18 Re: LWLock granular partition lock memory layout
Previous Message Peter Eisentraut 2026-10-07 17:41:13 Re: fix more casting away of qualifiers