| From: | shveta malik <shveta(dot)malik(at)gmail(dot)com> |
|---|---|
| To: | Shlok Kyal <shlok(dot)kyal(dot)oss(at)gmail(dot)com> |
| Cc: | Ajin Cherian <itsajin(at)gmail(dot)com>, Zsolt Parragi <zsolt(dot)parragi(at)percona(dot)com>, pgsql-hackers(at)lists(dot)postgresql(dot)org, shveta malik <shveta(dot)malik(at)gmail(dot)com> |
| Subject: | Re: [PATCH] Preserve replication origin OIDs in pg_upgrade |
| Date: | 2026-07-08 04:01:59 |
| Message-ID: | CAJpy0uAsgc5--4dCut2mmQd+Yxe-jfVQR=AY38dzeEe0+yaH4g@mail.gmail.com |
| Views: | Whole Thread | Raw Message | Download mbox | Resend email |
| Thread: | |
| Lists: | pgsql-hackers |
On Mon, Jul 6, 2026 at 12:10 PM Shlok Kyal <shlok(dot)kyal(dot)oss(at)gmail(dot)com> wrote:
>
> > All the above changes are updated in patch v10.
> >
> I noticed that we can create user defined replication origin even if the
> total count of replication origins exceeds the max_active_replication_origins
> Example:
> postgres=# show max_active_replication_origins;
> max_active_replication_origins
> --------------------------------
> 1
>
> postgres=# select * from pg_replication_origin;
> roident | roname
> ---------+----------
> 1 | pg_16387
>
> postgres=# SELECT pg_replication_origin_create('origin1');
> pg_replication_origin_create
> ------------------------------
> 2
>
> postgres=# select * from pg_replication_origin;
> roident | roname
> ---------+----------
> 1 | pg_16387
> 2 | origin1
>
> postgres=# select * from pg_replication_origin_status;
> local_id | external_id | remote_lsn | local_lsn
> ----------+-------------+------------+------------
> 1 | pg_16387 | 0/00000000 | 0/00000000
>
> The documentation for max_active_replication_origins says:
> ```
> Specifies how many replication origins (see
> <xref linkend="replication-origins"/>) can be tracked simultaneously,
> effectively limiting how many logical replication subscriptions can
> be created on the server. Setting it to a lower value than the current
> number of tracked replication origins (reflected in
> <link linkend="view-pg-replication-origin-status">pg_replication_origin_status</link>)
> will prevent the server from starting. It defaults to 10. This parameter
> can only be set at server start.
> ```
> Since the user-created replication origin above is not
> actively tracked in pg_replication_origin_status, no error is reported.
>
> But with this patch, during pg_upgrade we are checking the
> 'max_active_replication_origins' against 'old_cluster.nrepl_origins'
> + if (old_cluster.nrepl_origins > max_active_replication_origins)
> pg_fatal("\"max_active_replication_origins\" (%d) must be greater
> than or equal to the number of "
> - "subscriptions (%d) in the old cluster",
> - max_active_replication_origins, old_cluster.nsubs);
> + "replication origins (%d) in the old cluster",
> + max_active_replication_origins, old_cluster.nrepl_origins);
>
> Since old_cluster.nrepl_origins counts all replication origins, including
> user-created ones that may not be tracked, should this check instead compare
> max_active_replication_origins with 'the number of rows in
> pg_replication_origin_status in old cluster' (i.e., the number of
> tracked replication origins)?
>
Thanks Shlok for exploring this scenario.
I had a look at it. Please find my analysis.
I was under the assumption that subscription creation (which
internally creates a replication origin) would fail if
max_active_replication_origins was exceeded. However, that is not the
case. See the following experiment:
postgres=# show max_active_replication_origins;
max_active_replication_origins
--------------------------------
2
Al these commands succeed:
postgres=# create subscription sub1 ...
postgres=# create subscription sub2 ..
postgres=# SELECT pg_replication_origin_create('user_origin1');
postgres=# SELECT pg_replication_origin_create('user_origin2');
postgres=# SELECT pg_replication_origin_create('user_origin3');
postgres=# SELECT pg_replication_origin_create('user_origin4');
postgres=# create subscription sub3 ..
postgres=# create subscription sub4...
postgres=# select * from pg_replication_origin_status;
local_id | external_id | remote_lsn | local_lsn
----------+-------------+------------+------------
1 | pg_16384 | 0/00000000 | 0/00000000
2 | pg_16385 | 0/00000000 | 0/00000000
(2 rows)
postgres=# select * from pg_replication_origin;
roident | roname
---------+--------------
1 | pg_16384
2 | pg_16385
3 | user_origin1
4 | user_origin2
5 | user_origin3
6 | user_origin4
7 | pg_16387
8 | pg_16388
(8 rows)
As shown above, sub3 and sub4 are created successfully, but their
replication origins are not tracked because there are no free active
replication origin slots. The apply workers for these subscriptions
also fail to start:
LOG: logical replication apply worker for subscription "sub3" has started
ERROR: could not find free replication state slot for replication
origin with ID 7
HINT: Increase "max_active_replication_origins" and try again.
LOG: background worker "logical replication apply worker" (PID
277193) exited with exit code 1
This means that if we implement the check suggested by Shlok:
Although pg_upgrade would succeed, it could leave some subscriptions
on the new cluster in non-functional state. I agree that this
situation (non-functional subscriptions) is also possible on the old
cluster. However, this would also deviate from the previous
implementation, where check_new_cluster_subscription_configuration()
compared old_cluster.nsubs against 'max_active_replication_origins' on
the new cluster, rather than comparing the number of entries in
pg_replication_origin_status.
For this reason, my inclination is to revert to the previous
implementation, where we compare old_cluster.nsubs with
max_active_replication_origins. But I'd like to hear what others think
before we make this change.
thanks
Shveta
| From | Date | Subject | |
|---|---|---|---|
| Next Message | shveta malik | 2026-07-08 04:07:51 | Re: [PATCH] Preserve replication origin OIDs in pg_upgrade |
| Previous Message | Ashutosh Bapat | 2026-07-08 03:28:27 | Re: Restructured Shared Buffer Hash Table |