Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1wV4M6-001f6e-2p for pgsql-hackers@arkaria.postgresql.org; Thu, 04 Jun 2026 09:27:15 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1wV4M5-005rob-2Q for pgsql-hackers@arkaria.postgresql.org; Thu, 04 Jun 2026 09:27:13 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1wV4M5-005roT-1R for pgsql-hackers@lists.postgresql.org; Thu, 04 Jun 2026 09:27:13 +0000 Received: from mail-dl1-x122b.google.com ([2607:f8b0:4864:20::122b]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.98.2) (envelope-from ) id 1wV4M3-00000001DFW-23QR for pgsql-hackers@postgresql.org; Thu, 04 Jun 2026 09:27:13 +0000 Received: by mail-dl1-x122b.google.com with SMTP id a92af1059eb24-137335bc3caso579695c88.0 for ; Thu, 04 Jun 2026 02:27:10 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1780565229; cv=none; d=google.com; s=arc-20240605; b=fgyXhqJ8XpcPxE+r8YmUvYZOjChqx4A03M6bB9PmY0IwXY+hukM7CPsV1E7k6Kgm/d hsz+Lynx2xgwIpEeWD3hh0MLoj0w31eeS0/6fgiZ3SPXqUXCay/3ANlzY8gf+srm7FRO m5nEktftmLWFq2rRZ3O/+g96BPe8RWemRWb+cbrJJVwkcEuO3zbYfLi4OrqUh8IVS2if XVBDErnNPcUgvGKeFFJ/yWiJuNKvq7IB3J4ENbuoca1/TmpK5gI5bGj+iTKmsTb2obvO WJbf00ehV2KMA/6b2RQd0Wa5LLiEMr0WFngdXekRHFCW7SQIgU5kF6M0VNVP/8oRs4hn TUhg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:dkim-signature; bh=QM59xpkFgjvTNYZAEkL+tEBLa9etUB7wfD4y9Cghk8M=; fh=1YUHEAdsubhcnXqgBAgCIpzah4FPFgTdCw9ewl8RUAA=; b=adTl181hr8I26ovxDZy7OusLbgmwDOzm/CPa9OfCFH9Uq8e4eBX+HYi7opHU2h2Uiy Z1Qk13sSrK+IxNVInFPGK3ME2Z1uL/9whgmT9xMxCaw29wbZ8hhydOQdYq55J06+FG3b XQSs1gxcEYQyT9Ov8Im8t6H3NhVn892d7DlsW1Y6ev2oD9XRaDMHtov0pDY8tyrYsIcS EQ1x31IETBe6qJPAG/L05zIwJRFCRY+UU1wQHVfq6SkLniHPF6uatMe72wu6thKPk0e/ Y+9hdseWVweNE8yeW5ntiuqAal6kaeoVHS4SH0LUd1cfCp3VHo2YIfuL1KXrwrgKi6hc YitQ==; darn=postgresql.org ARC-Authentication-Results: i=1; mx.google.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1780565229; x=1781170029; darn=postgresql.org; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:from:to:cc:subject:date :message-id:reply-to; bh=QM59xpkFgjvTNYZAEkL+tEBLa9etUB7wfD4y9Cghk8M=; b=jGbQr87yVCh2NTUBfMSDteU52EWZYq17A25xF2nWymExLMAvNpv7FDDg3dTda7t6aG QMU2UgCkeyVPM4pjA3POp0kUfchq7IQ2TyXB2DIwLBQSy6TMZI3gclBHtOBPrStPeEWN YyH/5K1VNtgs3nOXzI5ykW1yQlDgyVs7i3TwO8z6Bcn+J6GIOyHUnOay8Fu7EiQxzXbD 0P4hfkUCNuIJMgy3SOBCxt7slqEQ0ePonbfLKFW+a3Wy/0+ZRtQpDd5V7GwKOPD2n/XB HU6EL10Q50i5prKyMTfcEd81jxdV748WihPlHVwMSaIZiYnB9/0WjUrWuq+fC1t69ijL aA0Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1780565229; x=1781170029; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=QM59xpkFgjvTNYZAEkL+tEBLa9etUB7wfD4y9Cghk8M=; b=l2Xzb3xNqxS53iM5ENmyAcYc+zJ5yhcMZyuJadoqTY5wcJ4Mju5N/NyuQKDrU2668p UiAzlqvK6keGavxvUJWsiFfwNkNgBU3ljHqXBtK4Hozpahy9o9jq0qapM1BJiw46ThIl FVy3Mq53F2xVe6zDpnInn/WIrFznpAsJ/aGBlYQpyYot/jI+f+iIQtd4Hdm9k4B7N+lh mMpHXjLeaf2FeGl9LcZCHUZktHfBDQIFtgmUzncbwm0ASt1IpQX141brcHhF2tMJm68q FERl9x+HuLyQ3y/QL/gWAhzMvdmlVN9011G0Xl8PMGdIM8R8TJSMnoSS/4ytueBb4x/V ZRKg== X-Forwarded-Encrypted: i=1; AFNElJ+cIMo5DajdUFMYkJkV2oKSTx/2aNrgksS8uTXrwTTg0wKi3ANB7ZUNgzs+uSSvmikt9dQipL8za8I32Och@postgresql.org X-Gm-Message-State: AOJu0Yw7qhRBw4c2DJhqbZuLrOkh4HQi8qwU9+tjAZqJPg501JQbcu/J 3VOFqjPpByWC+YH6uRo+vAnzslUyvOnMQsuIgth/D0XyrjxlxBwNSIhv0i/Q3oZFcyjBu3vjKJi Qnc8YLXNkJWiH3VUGDmCbIbRp2NTbB4o= X-Gm-Gg: Acq92OEgtB8Utu9Xf3YH7T5iIFfyu6Gauu5rnn4ESSPgijZ6RV8JZ1QrF4Sf/UZWwr8 +wL/MjgOwVXtQ9rxmHdwJQf116+pjEqX54UcmdsdCrDvq0eKxtPAyY2KKuhae7lF2zpiJFCf7+8 w4L5y/sEtw3J6JivmcKaIhEzaIL+1hCm4rBGnmuJnd8D8vfU4+0NH8sO3aUth7aL/DP0vdF3TdQ l3pPOTJAEHJk8a6u4BokuplewzGhkIx+mU1+sqIbpQSPht6UtIl7PQUjzjYq6TXp82XF0osCXfR T5hZ6fNHxKt2EpRS64h9L/pZVMMTp5nrx7vqMaWfNo/gd4vX X-Received: by 2002:a05:7022:6b89:b0:137:ea15:d1cc with SMTP id a92af1059eb24-137f6c25e33mr2966538c88.42.1780565228814; Thu, 04 Jun 2026 02:27:08 -0700 (PDT) MIME-Version: 1.0 References: In-Reply-To: From: Ashutosh Sharma Date: Thu, 4 Jun 2026 14:56:59 +0530 X-Gm-Features: AVHnY4KNSlC6EBGGORRFWHzWVjlyXCt7WZpERtWWTh3SxuBuMkM1ygEN0VtoMZ4 Message-ID: Subject: Re: synchronized_standby_slots behavior inconsistent with quorum-based synchronous replication To: "Zhijie Hou (Fujitsu)" Cc: shveta malik , Amit Kapila , Ajin Cherian , SATYANARAYANA NARLAPURAM , PostgreSQL-development , PostgreSQL Hackers Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk Hi, Thanks for your feedback. On Thu, Jun 4, 2026 at 1:54=E2=80=AFPM Zhijie Hou (Fujitsu) wrote: > > On Thursday, June 4, 2026 3:36 PM Ashutosh Sharma = wrote: > > On Thu, Jun 4, 2026 at 9:14=E2=80=AFAM shveta malik > > wrote: > > > > > > On Wed, Jun 3, 2026 at 4:30=E2=80=AFPM Ashutosh Sharma > > wrote: > > > > On Fri, May 15, 2026 at 9:28=E2=80=AFAM shveta malik > > wrote: > > > > > > > > > > > > > > > Ashutosh, while testing further, I noticed that > > > > > 'synchronized_standby_slots' does not filter duplicate entries. A= s an > > > > > example, if user ends up giving one entry twice in priority > > > > > configuration, then we will end up waiting on one slot twice rath= er > > > > > than waiting on 2 different slots. > > > > > > > > > > Example: > > > > > alter system set synchronized_standby_slots =3D 'FIRST 2 (standby= _1, > > > > > standby_1, standby_2, standby_3)'; > > > > > select pg_reload_conf(); > > > > > insert into tab1 values (10), (20), (30); > > > > > select pg_logical_slot_get_binary_changes('sub1', NULL, NULL, > > > > > 'proto_version', '4', 'publication_names', 'pub1'); > > > > > > > > > > The last statement works even though standby_2 and standby_3 do n= ot > > > > > exist. It consumes standby_1 twice and thinks that the required n= umber > > > > > of slots has caught-up. > > > > > > > > > > OTOH, if we use the same configuration for > > > > > 'synchronous_standby_names', it correctly waits for standby_2 and= does > > > > > not count on standby_1 twice. > > > > > > > > > > alter system set synchronous_standby_names =3D 'FIRST 2 (standby_= 1, > > > > > standby_1, standby_2, standby_3)'; > > > > > insert into tab1 values (10), (20), (30); ----> This will wait o= n standby_2 > > > > > > > > > > This is perhaps because 'synchronous_standby_names ' waits on act= ive > > > > > WAL senders rather than repeated strings in configuration. But ou= r > > > > > code changes wait on the names present in > > 'synchronized_standby_slots' > > > > > without filtering out duplicates. > > > > > > > > > > > > > May I know what your expectation is here? Would you like the check > > > > hook for synchronized_standby_slots to automatically resolve > > > > duplicates into a unique set of values, or should it detect duplica= te > > > > entries and raise an error so that the user can correct the > > > > configuration? > > > > > > > > If we automatically resolve duplicates, the user would still see th= e > > > > GUC configured exactly as they specified, even though it would not > > > > function the same way internally. For example, if a user sets: > > > > > > > > FIRST 2 (s1, s1, s1, s2) > > > > > > > > it might internally be resolved to: > > > > > > > > FIRST 2 (s1, s2) > > > > > > > > However, when the user runs SHOW, it would still display the origin= al > > > > configuration. This could give the user an incorrect impression of = how > > > > the setting is actually being interpreted. Because of this, I feel = we > > > > should treat duplicate entries as an invalid configuration and rais= e > > > > an error. > > > > > > > > As far as synchronous_standby_names is concerned, I can see that > > > > configurations such as: > > > > > > > > FIRST 2 (s1, s1, s1, s1) > > > > > > > > are currently accepted, which I don't think is correct either and > > > > should have been rejected, possibly resulted in the server startup > > > > failure. > > > > > > > > > > My preference, and original intent, was to accept duplicate entries > > > and skip them internally. Doc can be updated to say 'duplicate entrie= s > > > are skipped'. A server startup failure due to duplicate entries in a > > > GUC does not seem right to me. If the alter-system command fails due > > > to duplicate entries, that is still fine, but a startup failure seems > > > excessive. But let's see what others have to say on this. > > > > > > > Okay, the attached patch adds the capability to automatically remove > > duplicate entries from the synchronized_standby_slots list. > > Thanks for updating the patch. > > I agree with Shveta that reporting an ERROR is not ideal. I also think it= (ERROR) would > be inconsistent with existing GUCs, as most of them, such as > synchronous_standby_names, search_path, and session_preload_libraries, do= not > enforce uniqueness. > > The most similar GUC, synchronous_standby_names, also clarifies this in t= he > documentation: > > " There is no mechanism to enforce uniqueness of standby names. I= n case of > duplicates one of the matching standbys will be considered as hig= her priority, > though exactly which one is indeterminate."[1] > > > In N of M > > mode, if N > M after removing duplicate entries, an error is raised. > > I'm not entirely sure about this case. It seems similar to when the numbe= r of > specified slots is less than N (in ANY N or FIRST N), given that we want = to skip > duplicate slots. In that situation, the natural behavior to me would be t= o > simply block replication rather than raise an error. And > synchronous_standby_names would also simply block the transaction in this= case. > For duplicate entries themselves, I agree with the direction of not raising an error. Silently normalizing duplicates is reasonable for this GUC, especially if we document it clearly. A repeated slot name does not add any new information, so treating it as =E2=80=9Csame slot list= ed twice by mistake=E2=80=9D is practical. But for N > M after deduplication, I would still lean toward raising an err= or. Why I=E2=80=99d separate those cases: 1) Duplicate entries looks like a harmless normalization problem. ANY 2 (a, a, b) can be normalized to ANY 2 (a, b) without changing the user=E2=80=99s apparent intent much. 2) N > M after deduplication is not a transient runtime state. ANY 2 (a, a) becomes one unique slot. That configuration can never succeed unless the config itself changes. Blocking forever turns a static configuration mistake into an operational liveness problem. 3) N > M after deduplication is different from ordinary =E2=80=9Cnot enough standbys are currently available=E2=80=9D. If we configure ANY 2 (a, b) and only a is currently caught up, blocking makes sense because the situation may resolve at runtime. If we configure ANY 2 (a, a) and duplicates are ignored, there is no possible future runtime in which it succeeds without editing the GUC. That is why I think erroring is better. On the synchronous_standby_names comparison, I do not think it is fully analogous. The quoted documentation is about there being no reliable way to enforce uniqueness of standby names in the live system, because those names are matched against runtime standbys and the result can be indeterminate. Here, synchronized_standby_slots names concrete replication slots, which are stable object identifiers. Duplicate config entries are detectable and normalizable deterministically at GUC parse time. That gives us a cleaner option than synchronous_standby_names has. So my preferred behavior would be: 1) duplicate names: normalize, do not error 2) after normalization, if num_sync > unique_slots: error immediately -- With Regards, Ashutosh Sharma.