Re: Handle infinite recursion in logical replication setup

From: Peter Smith <smithpb2250(at)gmail(dot)com>
To: vignesh C <vignesh21(at)gmail(dot)com>
Cc: Amit Kapila <amit(dot)kapila16(at)gmail(dot)com>, Ashutosh Bapat <ashutosh(dot)bapat(dot)oss(at)gmail(dot)com>, "kuroda(dot)hayato(at)fujitsu(dot)com" <kuroda(dot)hayato(at)fujitsu(dot)com>, PostgreSQL Hackers <pgsql-hackers(at)lists(dot)postgresql(dot)org>
Subject: Re: Handle infinite recursion in logical replication setup
Date: 2022-06-15 06:39:29
Message-ID: CAHut+PuLVdLKsDFQazox7pw_i-8wkmZq_xRneM3f=WTt=ORYrg@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

Here are some review comments for patch v20-0002

======

1. General comment

Something subtle but significant changed since I last reviewed v18*.
Now the describe.c is changed so that the catalog will never display a
NULL origin column; it would always be "any". But now I am not sure if
it is a good idea to still allow the NULL in this catalog column while
at the same time you are pretending it is not there. I felt it might
be less confusing, and would simplify the code (e.g. remove quite a
few null checks) to have just used a single concept of the default -
e.g. Just assign the default as "any" everywhere. The column would be
defined as NOT NULL. Most of the following review comments are related
to this point.

======

2. doc/src/sgml/catalogs.sgml

+ <para>
+ Possible origin values are <literal>local</literal>,
+ <literal>any</literal>, or <literal>NULL</literal> if none is specified.
+ If <literal>local</literal>, the subscription will request the
+ publisher to only send changes that originated locally. If
+ <literal>any</literal> (or <literal>NULL</literal>), the publisher sends
+ any changes regardless of their origin.
+ </para></entry>

Is NULL still possible? Perhaps it would be better if it was not and
the default "any" was always written instead.

======

3. src/backend/catalog/pg_subscription.c

+ if (!isnull)
+ sub->origin = TextDatumGetCString(datum);
+ else
+ sub->origin = NULL;
+

Maybe better to either disallow NULL in the first place or assign the
"any" here instead of NULL.

======

4. src/backend/commands/subscriptioncmds.c - parse_subscription_options

@@ -137,6 +139,8 @@ parse_subscription_options(ParseState *pstate,
List *stmt_options,
opts->twophase = false;
if (IsSet(supported_opts, SUBOPT_DISABLE_ON_ERR))
opts->disableonerr = false;
+ if (IsSet(supported_opts, SUBOPT_ORIGIN))
+ opts->origin = NULL;

If opt->origin was assigned to "any" then other code would be simplified.

~~~

5. src/backend/commands/subscriptioncmds.c - CreateSubscription

@@ -607,6 +626,11 @@ CreateSubscription(ParseState *pstate,
CreateSubscriptionStmt *stmt,
LOGICALREP_TWOPHASE_STATE_PENDING :
LOGICALREP_TWOPHASE_STATE_DISABLED);
values[Anum_pg_subscription_subdisableonerr - 1] =
BoolGetDatum(opts.disableonerr);
+ if (opts.origin)
+ values[Anum_pg_subscription_suborigin - 1] =
+ CStringGetTextDatum(opts.origin);
+ else
+ values[Anum_pg_subscription_suborigin - 1] =
CStringGetTextDatum(LOGICALREP_ORIGIN_ANY);

If NULL was not possible then this would just be one line:
values[Anum_pg_subscription_suborigin - 1] = CStringGetTextDatum(opts.origin);

======

6. src/backend/replication/logical/worker.c

@@ -276,6 +276,10 @@ static TransactionId stream_xid = InvalidTransactionId;
static XLogRecPtr skip_xact_finish_lsn = InvalidXLogRecPtr;
#define is_skipping_changes()
(unlikely(!XLogRecPtrIsInvalid(skip_xact_finish_lsn)))

+/* Macro for comparing string fields that might be NULL */
+#define equalstr(a, b) \
+ (((a) != NULL && (b) != NULL) ? (strcmp((a), (b)) == 0) : (a) == (b))
+

If the NULL was not allowed in the first place then I think this macro
would just become redundant.

7. src/backend/replication/logical/worker.c - ApplyWorkerMain

@@ -3741,6 +3746,11 @@ ApplyWorkerMain(Datum main_arg)
options.proto.logical.streaming = MySubscription->stream;
options.proto.logical.twophase = false;

+ if (MySubscription->origin)
+ options.proto.logical.origin = pstrdup(MySubscription->origin);
+ else
+ options.proto.logical.origin = NULL;
+

Can't the if/else be avoided if you always assigned the "any" default
in the first place?

======

8. src/backend/replication/pgoutput/pgoutput.c - parse_output_parameters

@@ -287,11 +289,13 @@ parse_output_parameters(List *options, PGOutputData *data)
bool messages_option_given = false;
bool streaming_given = false;
bool two_phase_option_given = false;
+ bool origin_option_given = false;

data->binary = false;
data->streaming = false;
data->messages = false;
data->two_phase = false;
+ data->origin = NULL;

Consider assigning default "any" here instead of NULL.

======

9. src/bin/pg_dump/pg_dump.c - getSubscriptions

+ /* FIXME: 150000 should be changed to 160000 later for PG16. */
+ if (fout->remoteVersion >= 150000)
+ appendPQExpBufferStr(query, " s.suborigin\n");
+ else
+ appendPQExpBufferStr(query, " NULL AS suborigin\n");
+

Maybe say: 'any' AS suborigin?

~~~

10. src/bin/pg_dump/pg_dump.c - getSubscriptions

@@ -4517,6 +4525,11 @@ getSubscriptions(Archive *fout)
subinfo[i].subdisableonerr =
pg_strdup(PQgetvalue(res, i, i_subdisableonerr));

+ if (PQgetisnull(res, i, i_suborigin))
+ subinfo[i].suborigin = NULL;
+ else
+ subinfo[i].suborigin = pg_strdup(PQgetvalue(res, i, i_suborigin));
+

If you disallow the NULL in the first place this condition maybe is no
longer needed.

~~~

11. src/bin/pg_dump/pg_dump.c - dumpSubscription

@@ -4589,6 +4602,9 @@ dumpSubscription(Archive *fout, const
SubscriptionInfo *subinfo)
if (strcmp(subinfo->subdisableonerr, "t") == 0)
appendPQExpBufferStr(query, ", disable_on_error = true");

+ if (subinfo->suborigin)
+ appendPQExpBuffer(query, ", origin = %s", subinfo->suborigin);
+

If NULL cannot happen then maybe this test is also redundant.

======

12. src/bin/pg_dump/t/002_pg_dump.pl

AFAICT there is a test for no origin (default), and a test for
explicit origin = local, but there is no test case for the explicit
origin = any.

======

13. src/include/catalog/pg_subscription.h

@@ -31,6 +31,9 @@
#define LOGICALREP_TWOPHASE_STATE_PENDING 'p'
#define LOGICALREP_TWOPHASE_STATE_ENABLED 'e'

+#define LOGICALREP_ORIGIN_LOCAL "local"
+#define LOGICALREP_ORIGIN_ANY "any"
+

I thought there should be a comment above these new constants.

~~~

14. src/include/catalog/pg_subscription.h

@@ -87,6 +90,9 @@ CATALOG(pg_subscription,6100,SubscriptionRelationId)
BKI_SHARED_RELATION BKI_ROW

/* List of publications subscribed to */
text subpublications[1] BKI_FORCE_NOT_NULL;
+
+ /* Only publish data originating from the specified origin */
+ text suborigin;
#endif
} FormData_pg_subscription;

Perhaps it would be better if this new column was also forced to be NOT NULL.

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

In response to

Responses

Browse pgsql-hackers by date

  From Date Subject
Next Message Peter Smith 2022-06-15 06:41:21 Re: Handle infinite recursion in logical replication setup
Previous Message XueJing Zhao 2022-06-15 06:03:59 Reply: Remove useless param for create_groupingsets_path