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 1w4dxb-002OsT-33 for pgsql-hackers@arkaria.postgresql.org; Mon, 23 Mar 2026 12:00:44 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1w4dxa-00HQL0-1U for pgsql-hackers@arkaria.postgresql.org; Mon, 23 Mar 2026 12:00:42 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1w4dxa-00HQKg-06 for pgsql-hackers@lists.postgresql.org; Mon, 23 Mar 2026 12:00:42 +0000 Received: from mail-wm1-x32c.google.com ([2a00:1450:4864:20::32c]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.98.2) (envelope-from ) id 1w4dxW-00000000cSk-0XMJ for pgsql-hackers@lists.postgresql.org; Mon, 23 Mar 2026 12:00:41 +0000 Received: by mail-wm1-x32c.google.com with SMTP id 5b1f17b1804b1-486fc4725f0so34320135e9.1 for ; Mon, 23 Mar 2026 05:00:37 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cybertec.at; s=google; t=1774267237; x=1774872037; darn=lists.postgresql.org; h=message-id:date:mime-version:comments:references:in-reply-to :subject:cc:to:from:from:to:cc:subject:date:message-id:reply-to; bh=DhuwhhScTRXGXolL87zCv00kDF0gAAxAlsaQ8hwpWNI=; b=S8A713y4TsIHL++2HO3EoudDC7RUU3fhvzx8qMMNggCp0uyz9+Mpkb//3EdVU/kSOn D/Tta81v702i/3Q91iqc1djndG+msdoEJRu/YMsLSVcYiTUpmM7O5jdYIMjRZA/QB2l2 qmsdQ4lcuBQ+LCYL2O6ZagarBv8G9Tk9EdlOhBOKZA25PlzTy0tUxa7wqhK+Q1DW91bz GV9qq29XtF3UuZfMiae4kcuv1VoWEm/MWSl1yXbMiEuVELuADlmS55hABOx+Iu9XAdfA GDhUglDhiQxel8vrCJWf12A/Jt5Z66cfa8Ba6JkTBiKidZOaMlc7kYW0osrj7PuvgGiF xdgw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1774267237; x=1774872037; h=message-id:date:mime-version:comments:references:in-reply-to :subject:cc:to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject :date:message-id:reply-to; bh=DhuwhhScTRXGXolL87zCv00kDF0gAAxAlsaQ8hwpWNI=; b=V6aeXkDOYfSgj6qBn53Job2ADecr5PM5pCJrzYWsOo+A23EgsyjQZ0UgiVcSv5U4x4 0iyo8lQSAqJh+OfTFfyT23prgP5oqbA/ymsF2Jugn6pSK2wWYnbabTGEsEZ72uISptq7 CBBkHoHL1KgL3Zi1xzl8gyk3LKpymYMPMGymBjZq952JU9mlD+DGH33ymTFXt1xfgYc6 in+r0lNJt9vHyofoKw86YSTpBMKdq/U1wUeYJwtmZokE2JpPUaYvgbRGIlU06LpmYaZE 55HJDIgR+90lrrZr6GV0suxQRizPi1HKvDH205Z6h20iRkksibFqNZ6gtxmBBEZW8QLu jv4w== X-Forwarded-Encrypted: i=1; AJvYcCWUTLR9bYeI7WXSSY1zN0ZvYDaauNYSgJIB48f+ruDorb6ZnkpRTYz4yhsoQg5wjCkcLv9utl7H9OCvdP4J@lists.postgresql.org X-Gm-Message-State: AOJu0YzRasx2/qWIst94I7yH78pDc1erd7OlGtwf2XjQZ6ZDA3xutlOO DNpyD4JdgJa4p7B+InePdElxFixFkkZ3hLCO7zZnjgolmzofj6pvyp+ajP2pbbL4Bao= X-Gm-Gg: ATEYQzwT6kZ0y0h4fzSbjRcXBbUCSxRYW6V8AkdXMGZRdLFdYR0DxbvfhyrEsuFZ6iZ TURQaRFs3eSK++i6xO7MBVUrYPTT+tfC/oG3CJI7HzclV9QBG4+xSi+x8nSBgKMMGyLrqDk2iwv CGBIa2PzLTx4ioor8BkTRCYvMtfpk9gfwlSCCgaqauddfV5FwpLI0gtnBT0MDu11wcLTKygeqYL icDQ7x3/VO8FNfd90fi3WOJbUzCUB4uNjvJA6dw5c5+6BEZs81psv4eU7WSBGLLjr497W0+h6RJ MiOMzLCmRwacWpfCFfQdEtAu1xQBl8JgHpsBky2l16XV1Gj95jVlVhIY1WDfSLoVM9zTnypZlbt HKRKdygEkOQ0KDV9Ma5NJZKJHEhUU4mJQ7mH8SbzChpJOwQFIzTUSLSVPH7y30OQzdg7er/E02z nt4QhkVHoDvwpLLB6dVwEkDGy9nfGVrMaiGKJptTJBIORq9bw= X-Received: by 2002:a05:600c:a408:b0:485:fbd2:f72 with SMTP id 5b1f17b1804b1-486fe8a2aa6mr131976715e9.1.1774267235673; Mon, 23 Mar 2026 05:00:35 -0700 (PDT) Received: from localhost (109-81-168-142.rct.o2.cz. [109.81.168.142]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-43b647120a1sm29981570f8f.30.2026.03.23.05.00.34 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 23 Mar 2026 05:00:35 -0700 (PDT) From: Antonin Houska To: Srinath Reddy Sadipiralla Cc: alvherre@alvh.no-ip.org, Mihail Nikalayeu , Pg Hackers , Robert Treat Subject: Re: Adding REPACK [concurrently] In-reply-to: <29157.1774029970@localhost> References: <202602241757.6ac3iss2u4vo@alvherre.pgsql> <9116.1772009759@localhost> <100248.1772048475@localhost> <4200.1772781295@localhost> <29157.1774029970@localhost> Comments: In-reply-to Antonin Houska message dated "Fri, 20 Mar 2026 19:06:10 +0100." X-Mailer: MH-E 8.6+git; nmh 1.8; GNU Emacs 28.3 MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Date: Mon, 23 Mar 2026 13:00:34 +0100 Message-ID: <46846.1774267234@localhost> List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --=-=-= Content-Type: text/plain Antonin Houska wrote: > Antonin Houska wrote: > > > Antonin Houska wrote: > > > > > Srinath Reddy Sadipiralla wrote: > > > > > > > The concurrency test failed once. I tried to reproduce the below scenario > > > > but no luck,i think the reason the assert failure happened because > > > > after speculative insert there might be no spec CONFIRM or ABORT, thoughts? > > > > > > Perhaps, I'll try. I'm not sure the REPACK decoding worker does anthing > > > special regarding decoding. If you happen to see the problem again, please try > > > to preserve the related WAL segments - if this is a bug in PG executor, > > > pg_waldump might reveal that. > > > > I could not reproduce the failure, and have no idea how speculative insert can > > stay w/o CONFIRM / ABORT record. The only problem I could imagine is that > > change_useless_for_repack() filters out the CONFIRM / ABORT record > > accidentally, but neither code review nor debugger proves that > > theory. (Actually if this was the problem, the test failure probably wouldn't > > be that rare.) > > I confirm that I was able to reproduce the crash using debugger and your more > recent diagnosis [1]. Indeed, filtering was the problem. > > Unfortunately, I wasn't able to make the crash easily reproducible using > isolation tester. The problem is that the logical decoding is performed by a > background worker, and when the backend executing REPACK waits for the > background worker, which in turn waits on an injection point, the isolation > tester does not recognize that it's effectively the backend who is waiting on > the injection point. Therefore the isolation tester does not proceed to the > next step. I could not resist digging in it deeper :-) Attached is a test that reproduces the crash - it includes the isolation tester enhancement that I posted separately [1]. It crashes reliably with v43 [2] if your fix v43-0005 is omitted. [1] https://www.postgresql.org/message-id/4703.1774250534%40localhost [2] https://www.postgresql.org/message-id/202603191855.fzsgsnyzfvpt%40alvherre.pgsql -- Antonin Houska Web: https://www.cybertec-postgresql.com --=-=-= Content-Type: text/x-diff Content-Disposition: attachment; filename=nocfbot-Reproduce-filtering-issue.patch From f3a1371656da372e26cb56bf543cbaa0c99720a8 Mon Sep 17 00:00:00 2001 From: Antonin Houska Date: Mon, 23 Mar 2026 12:50:15 +0100 Subject: [PATCH] Reproduce filtering issue. --- contrib/test_decoding/expected/filtering.out | 74 ++++++++++++++ contrib/test_decoding/specs/filtering.spec | 101 +++++++++++++++++++ src/backend/executor/nodeModifyTable.c | 2 + src/backend/replication/logical/snapbuild.c | 3 + src/test/isolation/isolationtester.c | 9 +- 5 files changed, 188 insertions(+), 1 deletion(-) create mode 100644 contrib/test_decoding/expected/filtering.out create mode 100644 contrib/test_decoding/specs/filtering.spec diff --git a/contrib/test_decoding/expected/filtering.out b/contrib/test_decoding/expected/filtering.out new file mode 100644 index 00000000000..6ba9690509f --- /dev/null +++ b/contrib/test_decoding/expected/filtering.out @@ -0,0 +1,74 @@ +Parsed test spec with 5 sessions + +starting permutation: s1_assign_xid s3_repack s2_assign_xid s1_rollback s4_insert s5_wakeup_snapbuild s2_rollback s5_wakeup_insert_speculative s4_insert_commit s5_wakeup_repack +injection_points_attach +----------------------- + +(1 row) + +injection_points_attach +----------------------- + +(1 row) + +step s1_assign_xid: + BEGIN; + CREATE TABLE c(i int); + +step s3_repack: + REPACK (CONCURRENTLY) a; + +step s2_assign_xid: + BEGIN; + CREATE TABLE d(i int); + +step s1_rollback: + ROLLBACK; + +step s4_insert: + BEGIN; + INSERT INTO t(i) + SELECT max(i) + 1 FROM t ON CONFLICT (i) DO UPDATE SET i=EXCLUDED.i; + +step s5_wakeup_snapbuild: + SELECT injection_points_wakeup('snapbuild-full'); + +injection_points_wakeup +----------------------- + +(1 row) + +step s2_rollback: + ROLLBACK; + +step s5_wakeup_insert_speculative: + SELECT injection_points_wakeup('insert-speculative-before-confirm'); + +injection_points_wakeup +----------------------- + +(1 row) + +step s4_insert: <... completed> +step s4_insert_commit: + COMMIT; + +step s5_wakeup_repack: + SELECT injection_points_wakeup('repack-concurrently-before-lock'); + +injection_points_wakeup +----------------------- + +(1 row) + +step s3_repack: <... completed> +injection_points_detach +----------------------- + +(1 row) + +injection_points_detach +----------------------- + +(1 row) + diff --git a/contrib/test_decoding/specs/filtering.spec b/contrib/test_decoding/specs/filtering.spec new file mode 100644 index 00000000000..a02c9f8facb --- /dev/null +++ b/contrib/test_decoding/specs/filtering.spec @@ -0,0 +1,101 @@ +setup +{ + CREATE TABLE a(i int primary key, j int) WITH (autovacuum_enabled = off); + INSERT INTO a(i, j) VALUES (1, 1), (2, 2); + CREATE TABLE t(i int primary key); + INSERT INTO t(i) VALUES (1); + CREATE EXTENSION injection_points; +} + +session s1 +step s1_assign_xid +{ + BEGIN; + CREATE TABLE c(i int); +} +step s1_rollback +{ + ROLLBACK; +} + +session s2 +step s2_assign_xid +{ + BEGIN; + CREATE TABLE d(i int); +} +step s2_rollback +{ + ROLLBACK; +} + +session s3 +setup +{ + SELECT injection_points_attach('snapbuild-full', 'wait'); + SELECT injection_points_attach('repack-concurrently-before-lock', 'wait'); +} +step s3_repack +{ + REPACK (CONCURRENTLY) a; +} +teardown +{ + SELECT injection_points_detach('repack-concurrently-before-lock'); + SELECT injection_points_detach('snapbuild-full'); +} + +session s4 +setup +{ + SELECT injection_points_set_local(); + SELECT injection_points_attach('insert-speculative-before-confirm', 'wait'); +} +step s4_insert +{ + BEGIN; + INSERT INTO t(i) + SELECT max(i) + 1 FROM t ON CONFLICT (i) DO UPDATE SET i=EXCLUDED.i; +} +step s4_insert_commit +{ + COMMIT; +} +teardown +{ + SELECT injection_points_detach('insert-speculative-before-confirm'); +} + +session s5 +step s5_wakeup_snapbuild +{ + SELECT injection_points_wakeup('snapbuild-full'); +} +step s5_wakeup_insert_speculative +{ + SELECT injection_points_wakeup('insert-speculative-before-confirm'); +} +step s5_wakeup_repack +{ + SELECT injection_points_wakeup('repack-concurrently-before-lock'); +} + +permutation +# Bring the snapshot builder to the FULL_SNAPSHOT state. +s1_assign_xid +s3_repack +s2_assign_xid +s1_rollback +# Perform the speculative insert, but no confirmation so far. The snapshot +# builder should decode it. +s4_insert +# Let the snapshout builder achieve CONSISTENT state and finish the setup. +s5_wakeup_snapbuild +s2_rollback +# While REPACK is waiting on repack-concurrently-before-lock, let the insert +# get confirmed. Relation filtering is now enabled. +s5_wakeup_insert_speculative +s4_insert_commit +# REPACK should now decode the speculative insert and decode the speculative +# insert (with the confirmation record filtered out). +s5_wakeup_repack diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c index 680c29f35d5..6d5482e5746 100644 --- a/src/backend/executor/nodeModifyTable.c +++ b/src/backend/executor/nodeModifyTable.c @@ -1232,6 +1232,8 @@ ExecInsert(ModifyTableContext *context, slot, arbiterIndexes, &specConflict); + INJECTION_POINT("insert-speculative-before-confirm", NULL); + /* adjust the tuple's state accordingly */ table_tuple_complete_speculative(resultRelationDesc, slot, specToken, !specConflict); diff --git a/src/backend/replication/logical/snapbuild.c b/src/backend/replication/logical/snapbuild.c index fbdd4600a2b..883e5b6e18f 100644 --- a/src/backend/replication/logical/snapbuild.c +++ b/src/backend/replication/logical/snapbuild.c @@ -141,6 +141,7 @@ #include "storage/procarray.h" #include "storage/standby.h" #include "utils/builtins.h" +#include "utils/injection_point.h" #include "utils/memutils.h" #include "utils/snapmgr.h" #include "utils/snapshot.h" @@ -1390,6 +1391,8 @@ SnapBuildFindSnapshot(SnapBuild *builder, XLogRecPtr lsn, xl_running_xacts *runn builder->state = SNAPBUILD_FULL_SNAPSHOT; builder->next_phase_at = running->nextXid; + INJECTION_POINT("snapbuild-full", NULL); + ereport(LOG, errmsg("logical decoding found initial consistent point at %X/%08X", LSN_FORMAT_ARGS(lsn)), diff --git a/src/test/isolation/isolationtester.c b/src/test/isolation/isolationtester.c index 440c875b8ac..8f17ee412c9 100644 --- a/src/test/isolation/isolationtester.c +++ b/src/test/isolation/isolationtester.c @@ -216,15 +216,22 @@ main(int argc, char **argv) * exactly expect concurrent use of test tables. However, autovacuum will * occasionally take AccessExclusiveLock to truncate a table, and we must * ignore that transient wait. + * + * If the session's backend is blocked, and if its background worker is + * waiting on an injection point, we assume that the injection point is + * the reason for the backend to be blocked. That's what we check in the + * second query of the UNION. XXX Should we use a separate query for that? */ initPQExpBuffer(&wait_query); appendPQExpBufferStr(&wait_query, + "WITH blocking(res) AS (" "SELECT pg_catalog.pg_isolation_test_session_is_blocked($1, '{"); /* The spec syntax requires at least one session; assume that here. */ appendPQExpBufferStr(&wait_query, conns[1].backend_pid_str); for (i = 2; i < nconns; i++) appendPQExpBuffer(&wait_query, ",%s", conns[i].backend_pid_str); - appendPQExpBufferStr(&wait_query, "}')"); + appendPQExpBufferStr(&wait_query, "}') UNION " + "SELECT pg_catalog.pg_isolation_test_session_is_blocked(pid, '{}') FROM pg_stat_activity WHERE leader_pid=$1) SELECT bool_or(res) FROM blocking"); res = PQprepare(conns[0].conn, PREP_WAITING, wait_query.data, 0, NULL); if (PQresultStatus(res) != PGRES_COMMAND_OK) -- 2.47.3 --=-=-=--