Re: pg_upgrade and logical replication

From: Peter Smith <smithpb2250(at)gmail(dot)com>
To: Julien Rouhaud <rjuju123(at)gmail(dot)com>
Cc: "Hayato Kuroda (Fujitsu)" <kuroda(dot)hayato(at)fujitsu(dot)com>, PostgreSQL Hackers <pgsql-hackers(at)lists(dot)postgresql(dot)org>, Amit Kapila <amit(dot)kapila16(at)gmail(dot)com>
Subject: Re: pg_upgrade and logical replication
Date: 2023-04-13 02:42:05
Message-ID: CAHut+PuThBY=MSYHRgUa6iv6tyCmnqU78itZ+f4rMM2b124vqQ@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

Here are some review comments for patch v4-0001 (not the test code)

(There are some overlaps here with what Kuroda-san already posted
yesterday because we were looking at the same patch code. Also, a few
of my comments might become moot points if refactoring will be done
according to Kuroda-san's "general" questions).

======
Commit message

1.
To fix this problem, this patch teaches pg_dump in binary upgrade mode to emit
additional commands to be able to restore the content of pg_subscription_rel,
and addition LSN parameter in the subscription creation to restore the
underlying replication origin remote LSN. The LSN parameter is only accepted
in CREATE SUBSCRIPTION in binary upgrade mode.

~

SUGGESTION
To fix this problem, this patch teaches pg_dump in binary upgrade mode
to emit additional ALTER SUBSCRIPTION commands to facilitate restoring
the content of pg_subscription_rel, and provides an additional LSN
parameter for CREATE SUBSCRIPTION to restore the underlying
replication origin remote LSN. The new ALTER SUBSCRIPTION syntax and
new LSN parameter are not exposed to the user -- they are only
accepted in binary upgrade mode.

======
src/sgml/ref/pgupgrade.sgml

2.
+ <varlistentry>
+ <term><option>--preserve-subscription-state</option></term>
+ <listitem>
+ <para>
+ Fully preserve the logical subscription state if any. That includes
+ the underlying replication origin with their remote LSN and the list of
+ relations in each subscription so that replication can be simply
+ resumed if the subscriptions are reactived.
+ If that option isn't used, it is up to the user to reactivate the
+ subscriptions in a suitable way; see the subscription part in <xref
+ linkend="pg-dump-notes"/> for more information.
+ If this option is used and any of the subscription on the old cluster
+ has an unknown <varname>remote_lsn</varname> (0/0), or has any relation
+ in a state different from <literal>r</literal> (ready), the
+ <application>pg_upgrade</application> run will error.
+ </para>
+ </listitem>
+ </varlistentry>

~

2a.
"If that option isn't used" --> "If this option isn't used"

~

2b.
The link renders strangely. It just says:

See the subscription part in the [section called "Notes"] for more information.

Maybe the link part can be rewritten so that it renders more nicely,
and also makes mention of pg_dump.

~

2c.
Maybe it is more readable to have the "isn't used" and "is used" parts
as separate paragraphs?

~

2d.
Typo /reactived/reactivated/ ??

======
src/backend/commands/subscriptioncmds.c

3.
+#define SUBOPT_RELID 0x00008000
+#define SUBOPT_STATE 0x00010000

Maybe 'SUBOPT_RELSTATE' is a better name for this per-relation state option?

~~~

4. SubOpts

+ Oid relid;
+ char state;
} SubOpts;

(similar to #3)

Maybe 'relstate' is a better name for this per-relation state?

~~~

5. parse_subscription_options

+ else if (IsSet(supported_opts, SUBOPT_STATE) &&
+ strcmp(defel->defname, "state") == 0)
+ {

(similar to #3)

Maybe called this option "relstate".

~

6.
+ if (strlen(state_str) != 1)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("invalid relation state used")));

IIUC this is syntax not supposed to be reachable by user input. Maybe
there is some merit in making the errors similar looking to the normal
options, but OTOH it could also be misleading.

This might as well just be: Assert(strlen(state_str) == 1 &&
*state_str == SUBREL_STATE_READY);
or even simply: Assert(IsBinaryUpgrade);

~~~

7. CreateSubscription

+ if(IsBinaryUpgrade)
+ supported_opts |= SUBOPT_LSN;
parse_subscription_options(pstate, stmt->options, supported_opts, &opts);

7a.
Missing whitespace after the "if".

~

7b.
I wonder if this was deserving of a comment something like "The LSN
option is for internal use only"...

~~~

8. CreateSubscription

+ originid = replorigin_create(originname);
+
+ if (IsBinaryUpgrade && IsSet(opts.lsn, SUBOPT_LSN))
+ replorigin_advance(originid, opts.lsn, InvalidXLogRecPtr,
+ false /* backward */ ,
+ false /* WAL log */ );

I think the 'IsBinaryUpgrade' check is redundant here because
SUBOPT_LSN is not possible to be set unless that is true anyhow.

~~~

9. AlterSubscription

+ AddSubscriptionRelState(subid, opts.relid, opts.state,
+ opts.lsn);

This line wrapping of AddSubscriptionRelState seems unnecessary.

======
src/bin/pg_dump/pg_backup.h

10.
+
+ bool preserve_subscriptions;
} DumpOptions;

Maybe name this field "preserve_subscription_state" for consistency
with the option name.

======
src/bin/pg_dump/pg_dump.c

11. dumpSubscription

if (subinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+ {
+ for (i = 0; i < subinfo->nrels; i++)
+ {
+ appendPQExpBuffer(query, "\nALTER SUBSCRIPTION %s ADD TABLE "
+ "(relid = %u, state = '%c'",
+ qsubname,
+ subinfo->subrels[i].srrelid,
+ subinfo->subrels[i].srsubstate);
+
+ if (subinfo->subrels[i].srsublsn[0] != '\0')
+ appendPQExpBuffer(query, ", LSN = '%s'",
+ subinfo->subrels[i].srsublsn);
+
+ appendPQExpBufferStr(query, ");");
+ }
+

Maybe I misunderstood something -- Shouldn't this new ALTER
SUBSCRIPTION TABLE cmd only be happening when the option
dopt->preserve_subscriptions is true?

======
src/bin/pg_dump/pg_dump.h

12. SubRelInfo

+/*
+ * The SubRelInfo struct is used to represent subscription relation.
+ */
+typedef struct _SubRelInfo
+{
+ Oid srrelid;
+ char srsubstate;
+ char *srsublsn;
+} SubRelInfo;
+

12a.
"represent subscription relation" --> "represent a subscription relation"

~

12b.
Should include the indent file typdefs.list in the patch, and add this
new typedef to it.

======
src/bin/pg_upgrade/check.c

13. check_for_subscription_state

+/*
+ * check_for_subscription_state()
+ *
+ * Verify that all subscriptions have a valid remote_lsn and doesn't contain
+ * any table in a state different than ready.
+ */
+static void
+check_for_subscription_state(ClusterInfo *cluster)

SUGGESTION
Verify that all subscriptions have a valid remote_lsn and do not
contain any tables with srsubstate other than READY ('r').

~~~

14.
+ /* No subscription before pg10. */
+ if (GET_MAJOR_VERSION(cluster->major_version < 1000))
+ return;

14a.
The existing checking code seems slightly different to this because
the other check_XXX calls are guarded by the GET_MAJOR_VERSION before
being called.

~

14b.
Furthermore, I was confused about the combination when the < PG10 and
user_opts.preserve_subscriptions is true. Since this is just a return
(not an error) won't the subsequent pg_dump still attempt to use that
option (--preserve-subscriptions) even though we already know it
cannot work?

Would it be better to give an ERROR saying -preserve-subscriptions is
incompatible with the old PG version?

~~~

15.

+ pg_log(PG_WARNING,
+ "\nWARNING: %d subscription have invalid remote_lsn",
+ nb);

15a.
"have invalid" --> "has invalid"

~

15b.
I guess it would be more useful if the message can include the names
of the failing subscription and/or the relation that was in the wrong
state. Maybe that means moving all this checking logic into the
pg_dump code?

======
src/bin/pg_upgrade/option.c

16. parseCommandLine

user_opts.transfer_mode = TRANSFER_MODE_COPY;
+ user_opts.preserve_subscriptions = false;

This initial assignment is not needed because user_opts is static.

======
src/bin/pg_upgrade/pg_upgrade.h

17.
char *socketdir; /* directory to use for Unix sockets */
+ bool preserve_subscriptions; /* fully transfer subscription state */
} UserOpts;

Maybe name this field 'preserve_subscription_state' to match the option.

------
Kind Regards,
Peter Smith.
Fujitsu Australia

In response to

Responses

Browse pgsql-hackers by date

  From Date Subject
Next Message Yurii Rashkovskii 2023-04-13 02:45:09 Re: [PATCH] Allow Postgres to pick an unused port to listen
Previous Message Richard Guo 2023-04-13 02:39:03 Re: Unexpected (wrong?) result querying boolean partitioned table with NULL partition