Thread
-
Re: Adding REPACK [concurrently]
Antonin Houska <ah@cybertec.at> — 2026-05-04T13:24:49Z
Mihail Nikalayeu <mihailnikalayeu@gmail.com> wrote: > On Mon, Apr 27, 2026 at 6:25 AM Amit Kapila <amit.kapila16@gmail.com> wrote: > > Alvaro, others, what is your take on this? > > I agree with you here - we should AT LEAST make that an ERROR instead > of an assert and also check it during cache access (not only during > the scan because of cache misses). > But I think it will still be fragile in case of some extensions installed. > > Anyway... We also have an issue with correctness right now. > > I took the old stress test from [0] (the first two) and it fails now, > even with the fix from [1] ("Possible premature SNAPBUILD_CONSISTENT > with DB-specific running_xacts"). > > It looks like [1] fixes 008_repack_concurrently.pl, but > 007_repack_concurrently.pl fails anyway, including > > pgbench: error: client 1 script 0 aborted in command 10 query 0: > ERROR: could not create unique index "tbl_pkey_repacknew" > # DETAIL: Key (i)=(383) is duplicated. > and > 'pgbench: error: pgbench:client 23 script 0 aborted in command 31 > query 0: ERROR: division by zero > > Last one is not MVCC-related; you can see from the logs that it > performs something like SELECT (509063) / 0 when the table sum > changes. > > Setting need_shared_catalogs = true make them pass, so something is > wrong with its correctness. Thanks for testing again. Whether we keep the "database specific slots" or not, it'd be good to know what exactly the reason of these errors is. I wonder if the feature just exposes a problem that remains shadowed otherwise, due to the contention on replication slot. I'm going to investigate. -- Antonin Houska Web: https://www.cybertec-postgresql.com -
Re: Adding REPACK [concurrently]
Antonin Houska <ah@cybertec.at> — 2026-05-05T12:47:46Z
Antonin Houska <ah@cybertec.at> wrote: > Mihail Nikalayeu <mihailnikalayeu@gmail.com> wrote: > > > On Mon, Apr 27, 2026 at 6:25 AM Amit Kapila <amit.kapila16@gmail.com> wrote: > > > Alvaro, others, what is your take on this? > > > > I agree with you here - we should AT LEAST make that an ERROR instead > > of an assert and also check it during cache access (not only during > > the scan because of cache misses). > > But I think it will still be fragile in case of some extensions installed. > > > > Anyway... We also have an issue with correctness right now. > > > > I took the old stress test from [0] (the first two) and it fails now, > > even with the fix from [1] ("Possible premature SNAPBUILD_CONSISTENT > > with DB-specific running_xacts"). > > > > It looks like [1] fixes 008_repack_concurrently.pl, but > > 007_repack_concurrently.pl fails anyway, including > > > > pgbench: error: client 1 script 0 aborted in command 10 query 0: > > ERROR: could not create unique index "tbl_pkey_repacknew" > > # DETAIL: Key (i)=(383) is duplicated. > > and > > 'pgbench: error: pgbench:client 23 script 0 aborted in command 31 > > query 0: ERROR: division by zero > > > > Last one is not MVCC-related; you can see from the logs that it > > performs something like SELECT (509063) / 0 when the table sum > > changes. > > > > Setting need_shared_catalogs = true make them pass, so something is > > wrong with its correctness. > > Thanks for testing again. Whether we keep the "database specific slots" or > not, it'd be good to know what exactly the reason of these errors is. I wonder > if the feature just exposes a problem that remains shadowed otherwise, due to > the contention on replication slot. I'm going to investigate. I think the problem is that with database-specific snapshot, SnapBuildProcessRunningXacts() returns early, w/o adjusting builder->xmin /* * Database specific transaction info may exist to reach CONSISTENT state * faster, however the code below makes no use of it. Moreover, such * record might cause problems because the following normal (cluster-wide) * record can have lower value of oldestRunningXid. In that case, let's * wait with the cleanup for the next regular cluster-wide record. */ if (OidIsValid(running->dbid)) return; and thus some transactions whose XID is below running->oldestRunningXid may continue to be incorrectly considered running. I originally thought that this should not happen because such transactions will be added to the builder's array of committed transactions by SnapBuildCommitTxn() anyway. However, I failed to notice that COMMIT record of a transaction listed in the xl_running_xacts WAL record is not guaranteed to follow the xl_running_xacts record in WAL. In other words, even if xl_running_xacts is created before a COMMIT record of the contained transaction, it may end up at higher LSN in WAL. So the cleanup I relied on might not take place. I've got no good idea how to fix that. Not sure I'm able to pursue the "database-specific snapshots" feature now. -- Antonin Houska Web: https://www.cybertec-postgresql.com -
Re: Adding REPACK [concurrently]
Alvaro Herrera <alvherre@alvh.no-ip.org> — 2026-05-05T15:02:39Z
On 2026-May-05, Antonin Houska wrote: > However, I failed to notice that COMMIT record of > a transaction listed in the xl_running_xacts WAL record is not guaranteed to > follow the xl_running_xacts record in WAL. In other words, even if > xl_running_xacts is created before a COMMIT record of the contained > transaction, it may end up at higher LSN in WAL. So the cleanup I relied on > might not take place. That's pretty bad news. > I've got no good idea how to fix that. Not sure I'm able to pursue the > "database-specific snapshots" feature now. It appears that the only reasonable course of action at this point is to revert 0d3dba38c777. -- Álvaro Herrera Breisgau, Deutschland — https://www.EnterpriseDB.com/
-
Re: Adding REPACK [concurrently]
Alvaro Herrera <alvherre@alvh.no-ip.org> — 2026-05-05T15:04:42Z
On 2026-Apr-30, Mihail Nikalayeu wrote: > P.S. > I think it is good idea to add these stress tests to the source tree, > perhaps with some kind PG_TEST_EXTRA=stress (as done in [1]). Yeah, agreed. I'll see to that shortly. -- Álvaro Herrera 48°01'N 7°57'E — https://www.EnterpriseDB.com/ "I am amazed at [the pgsql-sql] mailing list for the wonderful support, and lack of hesitasion in answering a lost soul's question, I just wished the rest of the mailing list could be like this." (Fotis) https://postgr.es/m/200606261359.k5QDxE2p004593@auth-smtp.hol.gr -
Re: Adding REPACK [concurrently]
Antonin Houska <ah@cybertec.at> — 2026-05-06T08:25:44Z
Alvaro Herrera <alvherre@alvh.no-ip.org> wrote: > On 2026-May-05, Antonin Houska wrote: > > > However, I failed to notice that COMMIT record of > > a transaction listed in the xl_running_xacts WAL record is not guaranteed to > > follow the xl_running_xacts record in WAL. In other words, even if > > xl_running_xacts is created before a COMMIT record of the contained > > transaction, it may end up at higher LSN in WAL. So the cleanup I relied on > > might not take place. > > That's pretty bad news. > > > I've got no good idea how to fix that. One idea occurred to me yet, effectively it's just a cleanup. Part of it was already proposed [1]. [1] https://www.postgresql.org/message-id/flat/CAHg%2BQDcQak4jx_6X2_Ws98rzG%3DxBARLjqm_%3D56wTRUtNsY4DZQ%40mail.gmail.com -- Antonin Houska Web: https://www.cybertec-postgresql.com
-
Re: Adding REPACK [concurrently]
Amit Kapila <amit.kapila16@gmail.com> — 2026-05-08T12:25:12Z
On Wed, May 6, 2026 at 1:55 PM Antonin Houska <ah@cybertec.at> wrote: > > Alvaro Herrera <alvherre@alvh.no-ip.org> wrote: > > > On 2026-May-05, Antonin Houska wrote: > > > > > However, I failed to notice that COMMIT record of > > > a transaction listed in the xl_running_xacts WAL record is not guaranteed to > > > follow the xl_running_xacts record in WAL. In other words, even if > > > xl_running_xacts is created before a COMMIT record of the contained > > > transaction, it may end up at higher LSN in WAL. So the cleanup I relied on > > > might not take place. > > > > That's pretty bad news. > > > > > I've got no good idea how to fix that. > > One idea occurred to me yet, effectively it's just a cleanup. Part of it was > already proposed [1]. > Some issues/inefficiencies regarding this fix and base code related to db-specific snapshots built during decoding: * After fix, whenever a db-specific decoder sees a cluster-wide xl_running_xacts record, it unconditionally calls LogStandbySnapshot(MyDatabaseId) and returns. This triggers for every cluster-wide record the decoder encounters (including post snapbuild's CONSISTENT state) , for the entire duration of the decoding session. LogStandbySnapshot acquires ProcArrayLock + XidGenLock, calls GetRunningTransactionData, and writes WAL. With N active db-specific decoding sessions, each cluster-wide record now triggers N additional WAL writes. Additionally, LogStandbySnapshot also logs AccessExclusiveLocks before the running_xacts record. Physical standbys skip db-specific XLOG_RUNNING_XACTS records via standby_redo(), but they do process the preceding XLOG_STANDBY_LOCK records. The same locks may already have been logged in the most recent cluster-wide snapshot. Physical standbys could end up processing these lock records twice which may not be harmful because I think we avoid re-acquiring the lock but still it is a new overhead in the system. * When a cluster-wide running_xacts record arrives: SnapBuildProcessRunningXacts calls LogStandbySnapshot and returns early. ReorderBufferAbortOld is called, but with the cluster-wide oldestRunningXid, which could lag far behind the db-specific value (due to a long-running transaction in another database). When a db-specific record arrives: SnapBuildProcessRunningXacts processes it and advances builder->xmin with the db-specific (more current) oldestRunningXid. But ReorderBufferAbortOld is NOT called for db-specific records. This means the reorder buffer is cleaned up using a conservative, potentially very old, cluster-wide oldestRunningXid, even though builder->xmin has already advanced much further. The reorder buffer holds stale entries longer than necessary, increasing memory pressure. * I also see a design level problem with plugins that have need_shared_catalogs=false and use failover slots. IIUC, the db-specific optimization was designed around a live decoding session on the primary which can emit and immediately read its own db-specific records in the WAL stream to reach consistent state. The LogicalSlotAdvanceAndCheckSnapState path used by slotsync has a bounded WAL window and cannot exploit the feedback loop, making the two mechanisms fundamentally incompatible. I know the slot created by pgrepack doesn't enable failover option but we have not even added any guards or thought about db-specific snapbuilds with other parts of the system that rely on cluster-wide running_xact records, so there could be more problems which we don't see with the current set of tests. -- With Regards, Amit Kapila.
-
Re: Adding REPACK [concurrently]
Alvaro Herrera <alvherre@alvh.no-ip.org> — 2026-05-08T13:58:18Z
On 2026-May-08, Amit Kapila wrote: > On Wed, May 6, 2026 at 1:55 PM Antonin Houska <ah@cybertec.at> wrote: > > One idea occurred to me yet, effectively it's just a cleanup. Part of it was > > already proposed [1]. Hmm, I think this cleanup makes sense. If I apply the test patches (0001 and 0002 here), they fail almost immediately; but after applying 0003 all is again well. I think these tests are a good thing to have in the tree, even if we end up reverting db-specific snapshots later. After some back and forth, I modified the tests slightly so that the search PG_TEST_EXTRA for the string "stress_concurrently=N". The N can be changed so that the tests run for longer; if not given, it's taken as 1, and the tests run for around 6 seconds (so N=10 means runs for a minute). I think this is a convenient gadget for other tests of this kind on CONCURRENTLY commands, such as the one proposed for CIC elsewhere. As written, these tests would run nowhere until we add that string in some buildfarm animal. I debated with myself whether to assume N=1 when the string is not given. I still think that's a good idea but perhaps we should have something to prevent it from running by default when under Valgrind or other slow things like that. In normal conditions, the total runtime is not affected when they are run with N=1 as part of the whole test suite. > Some issues/inefficiencies regarding this fix and base code related to > db-specific snapshots built during decoding: [...] Thanks for spending time reviewing this code. I think none of these problems are fundamental in nature, but they are obviously worth addressing for 19. If we hit some roadblock, we can still revert only db-specific snapshots. -- Álvaro Herrera PostgreSQL Developer — https://www.EnterpriseDB.com/ "Puedes vivir sólo una vez, pero si lo haces bien, una vez es suficiente"
-
Re: Adding REPACK [concurrently]
Masahiko Sawada <sawada.mshk@gmail.com> — 2026-05-08T23:22:15Z
On Fri, May 8, 2026 at 6:58 AM Alvaro Herrera <alvherre@alvh.no-ip.org> wrote: > > On 2026-May-08, Amit Kapila wrote: > > > On Wed, May 6, 2026 at 1:55 PM Antonin Houska <ah@cybertec.at> wrote: > > > Some issues/inefficiencies regarding this fix and base code related to > > db-specific snapshots built during decoding: [...] > > Thanks for spending time reviewing this code. I think none of these > problems are fundamental in nature, but they are obviously worth > addressing for 19. If we hit some roadblock, we can still revert only > db-specific snapshots. > I'm still studying REPACK (CONCURRENTLY), and I have a question about db-specific decoder; as far as I read the codes, any decoding plugin can use db-specific decoder by setting need_shared_catalog=false but should we prevent such slots from being created on standbys? I'm a bit concerned that plugin developers inadvertently set need_shared_catalog=false in the startup callback and users would create such slots on standbys. For instance, if we create a logical slot with pgrepack plugin on the standby, we would get an assertion failure as the db-specific decoder tries to call LogStandbySnapshot() via SnapBuildProcessRunningXacts(). Even if we add !RecoveryInProgress() check there, the db-specific decoder on standbys requires for the primary server to run a REPACK (CONCURRENTLY). Regards, -- Masahiko Sawada Amazon Web Services: https://aws.amazon.com
-
Re: Adding REPACK [concurrently]
Amit Kapila <amit.kapila16@gmail.com> — 2026-05-10T11:24:29Z
On Fri, May 8, 2026 at 7:28 PM Alvaro Herrera <alvherre@alvh.no-ip.org> wrote: > > On 2026-May-08, Amit Kapila wrote: > > > Some issues/inefficiencies regarding this fix and base code related to > > db-specific snapshots built during decoding: [...] > > Thanks for spending time reviewing this code. I think none of these > problems are fundamental in nature, but they are obviously worth > addressing for 19. If we hit some roadblock, we can still revert only > db-specific snapshots. > IIUC, the emails by Andres [1][2] on db-specific snapshots sound like concerns which are fundamental in nature. Apart from that as well, I think the first point mentioned in my email [3] should be at least addressed as that causes additional WAL even after reaching consistent_state for each runing_xact record for a db-specific decoder. [1] - https://www.postgresql.org/message-id/cdgw4sbbfcgk6du3iv54r2dgiy4tfywoklbotlmj4irxavdcr3%40glxfw5jj277q [2] - https://www.postgresql.org/message-id/pveffyxhnuurhb44uzqlwo3rkyzorkfh2rot7uwzlf2axhfvbp%407nrs2omysxkc [3] - https://www.postgresql.org/message-id/CAA4eK1LygCDP3FiFzXY9iVNFcHxhf7TT_DFf7tryTu2oipmfpA%40mail.gmail.com -- With Regards, Amit Kapila.
-
Re: Adding REPACK [concurrently]
Amit Kapila <amit.kapila16@gmail.com> — 2026-05-10T11:31:04Z
On Tue, May 5, 2026 at 6:17 PM Antonin Houska <ah@cybertec.at> wrote: > > Antonin Houska <ah@cybertec.at> wrote: > > I think the problem is that with database-specific snapshot, > SnapBuildProcessRunningXacts() returns early, w/o adjusting builder->xmin > > /* > * Database specific transaction info may exist to reach CONSISTENT state > * faster, however the code below makes no use of it. Moreover, such > * record might cause problems because the following normal (cluster-wide) > * record can have lower value of oldestRunningXid. In that case, let's > * wait with the cleanup for the next regular cluster-wide record. > */ > if (OidIsValid(running->dbid)) > return; > > and thus some transactions whose XID is below running->oldestRunningXid may > continue to be incorrectly considered running. > > I originally thought that this should not happen because such transactions > will be added to the builder's array of committed transactions by > SnapBuildCommitTxn() anyway. However, I failed to notice that COMMIT record of > a transaction listed in the xl_running_xacts WAL record is not guaranteed to > follow the xl_running_xacts record in WAL. In other words, even if > xl_running_xacts is created before a COMMIT record of the contained > transaction, it may end up at higher LSN in WAL. So the cleanup I relied on > might not take place. > BTW, is it possible to write a test by using injection_points or via manual steps (by using debugger, etc) so that we can more clearly understand this problem and proposed fix? -- With Regards, Amit Kapila.
-
Re: Adding REPACK [concurrently]
Antonin Houska <ah@cybertec.at> — 2026-05-11T15:17:52Z
Amit Kapila <amit.kapila16@gmail.com> wrote: > On Tue, May 5, 2026 at 6:17 PM Antonin Houska <ah@cybertec.at> wrote: > > > > Antonin Houska <ah@cybertec.at> wrote: > > > > I think the problem is that with database-specific snapshot, > > SnapBuildProcessRunningXacts() returns early, w/o adjusting builder->xmin > > > > /* > > * Database specific transaction info may exist to reach CONSISTENT state > > * faster, however the code below makes no use of it. Moreover, such > > * record might cause problems because the following normal (cluster-wide) > > * record can have lower value of oldestRunningXid. In that case, let's > > * wait with the cleanup for the next regular cluster-wide record. > > */ > > if (OidIsValid(running->dbid)) > > return; > > > > and thus some transactions whose XID is below running->oldestRunningXid may > > continue to be incorrectly considered running. > > > > I originally thought that this should not happen because such transactions > > will be added to the builder's array of committed transactions by > > SnapBuildCommitTxn() anyway. However, I failed to notice that COMMIT record of > > a transaction listed in the xl_running_xacts WAL record is not guaranteed to > > follow the xl_running_xacts record in WAL. In other words, even if > > xl_running_xacts is created before a COMMIT record of the contained > > transaction, it may end up at higher LSN in WAL. So the cleanup I relied on > > might not take place. > > > > BTW, is it possible to write a test by using injection_points or via > manual steps (by using debugger, etc) so that we can more clearly > understand this problem and proposed fix? So far I could observe the situation in WAL, but have no idea how it can happen. For example, transaction 49242 gets committed here rmgr: Transaction len (rec/tot): 46/ 46, tx: 49242, lsn: 0/18BC28C8, prev 0/18BC2890, desc: COMMIT 2026-05-11 16:38:16.603265 CEST and then it appears in the 'xids' list of RUNNING_XACTS: rmgr: Standby len (rec/tot): 106/ 106, tx: 0, lsn: 0/18BC3140, prev 0/18BC3100, desc: RUNNING_XACTS nextXid 49255 latestCompletedXid 49241 oldestRunningXid 49242; 13 xacts: 49248 49249 49246 49243 49252 49251 49244 49245 49242 49250 49253 49254 49247; dbid:5 I thought the situation is quite common (and therefore nothing of SnapBuildProcessRunningXacts() should be skipped), but when trying to reproduce the problem, I noticed that LogStandbySnapshot() shouldn't allow that ordering issue when logical decoding is enabled: /* * GetRunningTransactionData() acquired ProcArrayLock, we must release it. * For Hot Standby this can be done before inserting the WAL record * because ProcArrayApplyRecoveryInfo() rechecks the commit status using * the clog. For logical decoding, though, the lock can't be released * early because the clog might be "in the future" from the POV of the * historic snapshot. This would allow for situations where we're waiting * for the end of a transaction listed in the xl_running_xacts record * which, according to the WAL, has committed before the xl_running_xacts * record. Fortunately this routine isn't executed frequently, and it's * only a shared lock. */ if (!logical_decoding_enabled) LWLockRelease(ProcArrayLock); So I don't have the answer right now. -- Antonin Houska Web: https://www.cybertec-postgresql.com
-
Re: Adding REPACK [concurrently]
Antonin Houska <ah@cybertec.at> — 2026-05-11T19:30:01Z
Antonin Houska <ah@cybertec.at> wrote: > Amit Kapila <amit.kapila16@gmail.com> wrote: > > > On Tue, May 5, 2026 at 6:17 PM Antonin Houska <ah@cybertec.at> wrote: > > > > > > Antonin Houska <ah@cybertec.at> wrote: > > > > > > I think the problem is that with database-specific snapshot, > > > SnapBuildProcessRunningXacts() returns early, w/o adjusting builder->xmin > > > > > > /* > > > * Database specific transaction info may exist to reach CONSISTENT state > > > * faster, however the code below makes no use of it. Moreover, such > > > * record might cause problems because the following normal (cluster-wide) > > > * record can have lower value of oldestRunningXid. In that case, let's > > > * wait with the cleanup for the next regular cluster-wide record. > > > */ > > > if (OidIsValid(running->dbid)) > > > return; > > > > > > and thus some transactions whose XID is below running->oldestRunningXid may > > > continue to be incorrectly considered running. > > > > > > I originally thought that this should not happen because such transactions > > > will be added to the builder's array of committed transactions by > > > SnapBuildCommitTxn() anyway. However, I failed to notice that COMMIT record of > > > a transaction listed in the xl_running_xacts WAL record is not guaranteed to > > > follow the xl_running_xacts record in WAL. In other words, even if > > > xl_running_xacts is created before a COMMIT record of the contained > > > transaction, it may end up at higher LSN in WAL. So the cleanup I relied on > > > might not take place. > > > > > > > BTW, is it possible to write a test by using injection_points or via > > manual steps (by using debugger, etc) so that we can more clearly > > understand this problem and proposed fix? > > So far I could observe the situation in WAL, but have no idea how it can > happen. For example, transaction 49242 gets committed here > > rmgr: Transaction len (rec/tot): 46/ 46, tx: 49242, lsn: 0/18BC28C8, prev > 0/18BC2890, desc: COMMIT 2026-05-11 16:38:16.603265 CEST > > and then it appears in the 'xids' list of RUNNING_XACTS: > > rmgr: Standby len (rec/tot): 106/ 106, tx: 0, lsn: > 0/18BC3140, prev 0/18BC3100, desc: RUNNING_XACTS nextXid 49255 > latestCompletedXid 49241 oldestRunningXid 49242; 13 xacts: 49248 49249 49246 > 49243 49252 49251 49244 49245 49242 49250 49253 49254 49247; dbid:5 > > > I thought the situation is quite common (and therefore nothing of > SnapBuildProcessRunningXacts() should be skipped), but when trying to > reproduce the problem, I noticed that LogStandbySnapshot() shouldn't allow > that ordering issue when logical decoding is enabled: > > /* > * GetRunningTransactionData() acquired ProcArrayLock, we must release it. > * For Hot Standby this can be done before inserting the WAL record > * because ProcArrayApplyRecoveryInfo() rechecks the commit status using > * the clog. For logical decoding, though, the lock can't be released > * early because the clog might be "in the future" from the POV of the > * historic snapshot. This would allow for situations where we're waiting > * for the end of a transaction listed in the xl_running_xacts record > * which, according to the WAL, has committed before the xl_running_xacts > * record. Fortunately this routine isn't executed frequently, and it's > * only a shared lock. > */ > if (!logical_decoding_enabled) > LWLockRelease(ProcArrayLock); > > So I don't have the answer right now. I think now that "waiting for the end of a transaction listed in the xl_running_xacts record" in the comment is about transaction removal from procarray. However, the COMMIT record can still be ahead of xl_running_xacts because RecordTransactionCommit() is called before ProcArrayEndTransaction(). I'll think again if the whole problem can be reproduced with injection points. -- Antonin Houska Web: https://www.cybertec-postgresql.com
-
RE: Adding REPACK [concurrently]
Hayato Kuroda (Fujitsu) <kuroda.hayato@fujitsu.com> — 2026-05-12T02:25:47Z
Dear Antonin, FYI, I have also been spending time to reproduce the failure but I have not done yet. > So far I could observe the situation in WAL, but have no idea how it can > happen. Not sure it matches with your situation, but I could reproduce the situation by using gdb. 0. initialized an instance with wal_level=logical and defined a table. 1. established a connection 2. attached the backend via gdb 3. added a breakpoint in ProcArrayEndTransaction 4. committed a transaction, and it would stop at the breakpoint 5. established another connection 6. ran REPACK CONCURRENTLY 7. detached from the first backend. 8. all commands would finish. This could allow that COMMIT record exists ahead the RUNNING_XACTS record. When the backend reaches CommitTransaction()->ProcArrayEndTransaction(), the commit record has already been serialized, but the transaction is still marked as active on the proc array. Above workload allowed that repack worker could check in-between. [1]: ``` rmgr: Transaction len (rec/tot): 46/ 46, tx: 695, lsn: 0/018B89C0, prev 0/018B8980, desc: COMMIT 2026-05-12 11:11:31.588061 JST rmgr: Standby len (rec/tot): 58/ 58, tx: 0, lsn: 0/018B89F0, prev 0/018B89C0, desc: RUNNING_XACTS nextXid 696 latestCompletedXid 694 oldestRunningXid 695; 1 xacts: 695; dbid: 0 rmgr: Standby len (rec/tot): 58/ 58, tx: 0, lsn: 0/018B8A30, prev 0/018B89F0, desc: RUNNING_XACTS nextXid 696 latestCompletedXid 694 oldestRunningXid 695; 1 xacts: 695; dbid: 5 ``` Best regards, Hayato Kuroda FUJITSU LIMITED
-
Re: Adding REPACK [concurrently]
Amit Kapila <amit.kapila16@gmail.com> — 2026-05-12T07:57:29Z
On Tue, May 12, 2026 at 1:00 AM Antonin Houska <ah@cybertec.at> wrote: > > Antonin Houska <ah@cybertec.at> wrote: > > > Amit Kapila <amit.kapila16@gmail.com> wrote: > > > > > On Tue, May 5, 2026 at 6:17 PM Antonin Houska <ah@cybertec.at> wrote: > > > > > > > > Antonin Houska <ah@cybertec.at> wrote: > > > > > > > > I think the problem is that with database-specific snapshot, > > > > SnapBuildProcessRunningXacts() returns early, w/o adjusting builder->xmin > > > > > > > > /* > > > > * Database specific transaction info may exist to reach CONSISTENT state > > > > * faster, however the code below makes no use of it. Moreover, such > > > > * record might cause problems because the following normal (cluster-wide) > > > > * record can have lower value of oldestRunningXid. In that case, let's > > > > * wait with the cleanup for the next regular cluster-wide record. > > > > */ > > > > if (OidIsValid(running->dbid)) > > > > return; > > > > > > > > and thus some transactions whose XID is below running->oldestRunningXid may > > > > continue to be incorrectly considered running. > > > > > > > > I originally thought that this should not happen because such transactions > > > > will be added to the builder's array of committed transactions by > > > > SnapBuildCommitTxn() anyway. However, I failed to notice that COMMIT record of > > > > a transaction listed in the xl_running_xacts WAL record is not guaranteed to > > > > follow the xl_running_xacts record in WAL. In other words, even if > > > > xl_running_xacts is created before a COMMIT record of the contained > > > > transaction, it may end up at higher LSN in WAL. So the cleanup I relied on > > > > might not take place. > > > > > > > > > > BTW, is it possible to write a test by using injection_points or via > > > manual steps (by using debugger, etc) so that we can more clearly > > > understand this problem and proposed fix? > > > > So far I could observe the situation in WAL, but have no idea how it can > > happen. For example, transaction 49242 gets committed here > > > > rmgr: Transaction len (rec/tot): 46/ 46, tx: 49242, lsn: 0/18BC28C8, prev > > 0/18BC2890, desc: COMMIT 2026-05-11 16:38:16.603265 CEST > > > > and then it appears in the 'xids' list of RUNNING_XACTS: > > > > rmgr: Standby len (rec/tot): 106/ 106, tx: 0, lsn: > > 0/18BC3140, prev 0/18BC3100, desc: RUNNING_XACTS nextXid 49255 > > latestCompletedXid 49241 oldestRunningXid 49242; 13 xacts: 49248 49249 49246 > > 49243 49252 49251 49244 49245 49242 49250 49253 49254 49247; dbid:5 > > > > > > I thought the situation is quite common (and therefore nothing of > > SnapBuildProcessRunningXacts() should be skipped), but when trying to > > reproduce the problem, I noticed that LogStandbySnapshot() shouldn't allow > > that ordering issue when logical decoding is enabled: > > > > /* > > * GetRunningTransactionData() acquired ProcArrayLock, we must release it. > > * For Hot Standby this can be done before inserting the WAL record > > * because ProcArrayApplyRecoveryInfo() rechecks the commit status using > > * the clog. For logical decoding, though, the lock can't be released > > * early because the clog might be "in the future" from the POV of the > > * historic snapshot. This would allow for situations where we're waiting > > * for the end of a transaction listed in the xl_running_xacts record > > * which, according to the WAL, has committed before the xl_running_xacts > > * record. Fortunately this routine isn't executed frequently, and it's > > * only a shared lock. > > */ > > if (!logical_decoding_enabled) > > LWLockRelease(ProcArrayLock); > > > > So I don't have the answer right now. > > I think now that "waiting for the end of a transaction listed in the > xl_running_xacts record" in the comment is about transaction removal from > procarray. However, the COMMIT record can still be ahead of xl_running_xacts > because RecordTransactionCommit() is called before > ProcArrayEndTransaction(). > I see your point. Due to this, once the xmin regresses based on cluster-wide running_xact, some transaction could appear to be running when it should have appeared as committed. However, still it is not clear how it could lead to one update in the transaction as successfully decoded and another one to be skipped. One theory could be that before the second update, somehow invalidation happens and when decoding tries to reload the catalog to decode second update, the relation is not visible because xmin has regressed and the update is somehow skipped. I can't see how it can happen in code but something like that is happening. Assuming, the problematic case is something like what I described, even than the fix of skipping cluster-wide running xacts and instead LOG db-specific running_xacts to help updating builder's xmin sounds inelegant and probably inefficient. For example, I think such a dependency means we can never enable db-specific snapshots on standby. -- With Regards, Amit Kapila.
-
Re: Adding REPACK [concurrently]
Antonin Houska <ah@cybertec.at> — 2026-05-12T11:08:20Z
Amit Kapila <amit.kapila16@gmail.com> wrote: > On Tue, May 12, 2026 at 1:00 AM Antonin Houska <ah@cybertec.at> wrote: > > > > Antonin Houska <ah@cybertec.at> wrote: > > > > > Amit Kapila <amit.kapila16@gmail.com> wrote: > > > > > > > On Tue, May 5, 2026 at 6:17 PM Antonin Houska <ah@cybertec.at> wrote: > > > > > > > > > > Antonin Houska <ah@cybertec.at> wrote: > > > > > > > > > > I think the problem is that with database-specific snapshot, > > > > > SnapBuildProcessRunningXacts() returns early, w/o adjusting builder->xmin > > > > > > > > > > /* > > > > > * Database specific transaction info may exist to reach CONSISTENT state > > > > > * faster, however the code below makes no use of it. Moreover, such > > > > > * record might cause problems because the following normal (cluster-wide) > > > > > * record can have lower value of oldestRunningXid. In that case, let's > > > > > * wait with the cleanup for the next regular cluster-wide record. > > > > > */ > > > > > if (OidIsValid(running->dbid)) > > > > > return; > > > > > > > > > > and thus some transactions whose XID is below running->oldestRunningXid may > > > > > continue to be incorrectly considered running. > > > > > > > > > > I originally thought that this should not happen because such transactions > > > > > will be added to the builder's array of committed transactions by > > > > > SnapBuildCommitTxn() anyway. However, I failed to notice that COMMIT record of > > > > > a transaction listed in the xl_running_xacts WAL record is not guaranteed to > > > > > follow the xl_running_xacts record in WAL. In other words, even if > > > > > xl_running_xacts is created before a COMMIT record of the contained > > > > > transaction, it may end up at higher LSN in WAL. So the cleanup I relied on > > > > > might not take place. > > > > > > > > > > > > > BTW, is it possible to write a test by using injection_points or via > > > > manual steps (by using debugger, etc) so that we can more clearly > > > > understand this problem and proposed fix? > > > > > > So far I could observe the situation in WAL, but have no idea how it can > > > happen. For example, transaction 49242 gets committed here > > > > > > rmgr: Transaction len (rec/tot): 46/ 46, tx: 49242, lsn: 0/18BC28C8, prev > > > 0/18BC2890, desc: COMMIT 2026-05-11 16:38:16.603265 CEST > > > > > > and then it appears in the 'xids' list of RUNNING_XACTS: > > > > > > rmgr: Standby len (rec/tot): 106/ 106, tx: 0, lsn: > > > 0/18BC3140, prev 0/18BC3100, desc: RUNNING_XACTS nextXid 49255 > > > latestCompletedXid 49241 oldestRunningXid 49242; 13 xacts: 49248 49249 49246 > > > 49243 49252 49251 49244 49245 49242 49250 49253 49254 49247; dbid:5 > > > > > > > > > I thought the situation is quite common (and therefore nothing of > > > SnapBuildProcessRunningXacts() should be skipped), but when trying to > > > reproduce the problem, I noticed that LogStandbySnapshot() shouldn't allow > > > that ordering issue when logical decoding is enabled: > > > > > > /* > > > * GetRunningTransactionData() acquired ProcArrayLock, we must release it. > > > * For Hot Standby this can be done before inserting the WAL record > > > * because ProcArrayApplyRecoveryInfo() rechecks the commit status using > > > * the clog. For logical decoding, though, the lock can't be released > > > * early because the clog might be "in the future" from the POV of the > > > * historic snapshot. This would allow for situations where we're waiting > > > * for the end of a transaction listed in the xl_running_xacts record > > > * which, according to the WAL, has committed before the xl_running_xacts > > > * record. Fortunately this routine isn't executed frequently, and it's > > > * only a shared lock. > > > */ > > > if (!logical_decoding_enabled) > > > LWLockRelease(ProcArrayLock); > > > > > > So I don't have the answer right now. > > > > I think now that "waiting for the end of a transaction listed in the > > xl_running_xacts record" in the comment is about transaction removal from > > procarray. However, the COMMIT record can still be ahead of xl_running_xacts > > because RecordTransactionCommit() is called before > > ProcArrayEndTransaction(). > > > > I see your point. Due to this, once the xmin regresses based on > cluster-wide running_xact, some transaction could appear to be running > when it should have appeared as committed. The problem is that xmin does not advance when it should. Attached is a test that reproduces the problem (it includes [1], to handle injection points in background worker), I hope the comments in the specification file are helpful. It's actually not exactly the problem reported in the stress test, but IMO the core issue is the same: effects of some transactions are lost. In the stress test, tuple deletion was lost, so the error was "could not create unique index". Here I only demonstrate lost INSERT. > Assuming, the problematic case is something > like what I described, even than the fix of skipping cluster-wide > running xacts and instead LOG db-specific running_xacts to help > updating builder's xmin sounds inelegant and probably inefficient. For > example, I think such a dependency means we can never enable > db-specific snapshots on standby. ok [1] https://www.postgresql.org/message-id/4703.1774250534%40localhost -- Antonin Houska Web: https://www.cybertec-postgresql.com
-
Re: Adding REPACK [concurrently]
Amit Kapila <amit.kapila16@gmail.com> — 2026-05-13T12:34:17Z
On Tue, May 12, 2026 at 4:38 PM Antonin Houska <ah@cybertec.at> wrote: > > Amit Kapila <amit.kapila16@gmail.com> wrote: > > > > > I see your point. Due to this, once the xmin regresses based on > > cluster-wide running_xact, some transaction could appear to be running > > when it should have appeared as committed. > > The problem is that xmin does not advance when it should. Attached is a test > that reproduces the problem (it includes [1], to handle injection points in > background worker), I hope the comments in the specification file are helpful. > Yes, the comments were helpful. IIUC, the test skipped insert into repack_test because the transaction doing that insert happened before the snapbuild reached FULL_SNAPSHOT/CONSISTENT state, so its commit is not decoded. Then we also didn't update builder->xmin after reaching CONSISTENT state in the last running_xact record for MyDatabase. So, the insert is neither covered in initial copy, nor decoded, so after repack (concurrently) is finished the table is empty. I think the patch proposed will fix this specific issue but apart from other points raised for this patch few more are: (a) Post CONSISTENT state, for cleanup of db_specific snapshots, we need to separately again LOG db-specific running xacts whenever we encounter another running_xacts, (b) Other point is that because repack-concurrently always use full-snapshot, the serialization of snapshot is useless because it can't be used by others. > It's actually not exactly the problem reported in the stress test, but IMO the > core issue is the same: effects of some transactions are lost. In the stress > test, tuple deletion was lost, so the error was "could not create unique > index". Here I only demonstrate lost INSERT. > > > Assuming, the problematic case is something > > like what I described, even than the fix of skipping cluster-wide > > running xacts and instead LOG db-specific running_xacts to help > > updating builder's xmin sounds inelegant and probably inefficient. For > > example, I think such a dependency means we can never enable > > db-specific snapshots on standby. > > ok > So now the question is where do we go from here. I am not confident that the current code to achieve db-specific snapshots in logical decoding is the best possible solution both because of the drawbacks (like we won't be able to enable this on standby) and inefficiencies pointed out by me in this and previous emails in this work. -- With Regards, Amit Kapila.
-
Re: Adding REPACK [concurrently]
Alvaro Herrera <alvherre@alvh.no-ip.org> — 2026-05-13T16:58:14Z
Hello Amit, On 2026-May-13, Amit Kapila wrote: > So now the question is where do we go from here. I am not confident > that the current code to achieve db-specific snapshots in logical > decoding is the best possible solution both because of the drawbacks > (like we won't be able to enable this on standby) and inefficiencies > pointed out by me in this and previous emails in this work. This is a fair question. I don't think we have time to go much further on this aspect before beta 1, so we either accept this patch, fix the inefficiencies you pointed out and keep db-specific snapshots, or we revert db-specific snapshots and go back to the standard snapshot-taking technique for REPACK in 19 and see what we can improve for 20. Now, the worst consequence of reverting db-specific snapshots is that you will only be able to run REPACK in a single database at a time (because any subsequent REPACK will have to wait until the first one finishes before being able to get its snapshot). In most normal cases this is probably not a big deal. But if you have a multitenant system, and you want your users to be able to run REPACK on their tables, you may be a bit screwed. So I hesitate to just go and revert it without offering those people any alternative. (It's also possible that being unable to run more than one REPACK at a time is not so big a deal. After all, it's supposed to be an infrequent operation. And users probably don't or shouldn't have multi-terabyte tables in multitenant databases anyway.) I'm not sure I understand the point of the standby. I mean, you can't run REPACK on the standby anyway, so I don't see this as a very problematic restriction. Do you have other reasons for wanting a db-specific snapshot in a standby? -- Álvaro Herrera PostgreSQL Developer — https://www.EnterpriseDB.com/
-
Re: Adding REPACK [concurrently]
Amit Kapila <amit.kapila16@gmail.com> — 2026-05-14T07:02:25Z
On Wed, May 13, 2026 at 10:28 PM Alvaro Herrera <alvherre@alvh.no-ip.org> wrote: > > Hello Amit, > > On 2026-May-13, Amit Kapila wrote: > > > So now the question is where do we go from here. I am not confident > > that the current code to achieve db-specific snapshots in logical > > decoding is the best possible solution both because of the drawbacks > > (like we won't be able to enable this on standby) and inefficiencies > > pointed out by me in this and previous emails in this work. > > This is a fair question. I don't think we have time to go much further > on this aspect before beta 1, so we either accept this patch, fix the > inefficiencies you pointed out and keep db-specific snapshots, > I don't think it would be easy to address these inefficiencies before beta 1. The root of those inefficiencies is that the patch reuses the cluster-wide running_xact WAL infrastructure to log db-specific running transactions, and then tries to feed that into the existing snapbuild machinery to reach a consistent state. As another example of this mismatch that occurred to me today: in SnapBuildCommitTxn, we are tracking the committed_xip array for all cluster-wide XIDs, even when using a db-specific snapshot. A db-specific snapshot shouldn't need to care about XIDs from other databases. We only try to take care of it in one part of the system where process running_xacts record. I admit that I don't know at this stage what exactly we should do about it but all such things deserve a discussion and careful thought. The broader issue is that the entire logical decoding mechanism is designed to process cluster-wide transactions. This patch tries to bypass that foundational assumption, but only during the initial snapshot construction while processing running_xacts record. To be clear, I am not against the idea of db-specific snapshots to enable concurrent repacks. My concern is simply the time required to get the architecture right. In its current state, we need more time to carefully consider how this db-specific concept interacts with the rest of the logical decoding machinery, which is built for cluster-wide records. > or we > revert db-specific snapshots and go back to the standard snapshot-taking > technique for REPACK in 19 and see what we can improve for 20. > > Now, the worst consequence of reverting db-specific snapshots is that > you will only be able to run REPACK in a single database at a time > (because any subsequent REPACK will have to wait until the first one > finishes before being able to get its snapshot). In most normal cases > this is probably not a big deal. But if you have a multitenant system, > and you want your users to be able to run REPACK on their tables, you > may be a bit screwed. So I hesitate to just go and revert it without > offering those people any alternative. > I understand your point but I feel we can extend the current feature in future versions to address such cases (allow REPACK CONCURRENTLY on tables in multiple-databases simultaneously). For now, they may need to rely on REPACK without CONCURRENTLY option, if they want to use it for multiple databases simultaneously. > (It's also possible that being unable to run more than one REPACK at a > time is not so big a deal. After all, it's supposed to be an infrequent > operation. And users probably don't or shouldn't have multi-terabyte > tables in multitenant databases anyway.) > > I'm not sure I understand the point of the standby. I mean, you can't > run REPACK on the standby anyway, so I don't see this as a very > problematic restriction. Do you have other reasons for wanting a > db-specific snapshot in a standby? > We are exposing need_shared_catalogs as a generic plugin option, defined as: 'it can be set to false if one is certain the plugin functions do not access shared system catalogs.' This implies it can be used for purposes other than REPACK. For example, one can imagine a single-database audit plugin that only cares about data modifications within a specific database. By setting need_shared_catalogs = false on a standby, it could reach a CONSISTENT state much faster, perfectly serving its needs. While such a plugin might not exist right now, my broader point is this: when we expose a generic facility, it can and will be used in ways beyond our initial core use cases. We should try to ensure the design doesn't permanently preclude such extensions. With the current design choice, we are painting ourselves into a corner where this feature cannot easily be extended to standbys even in the future. -- With Regards, Amit Kapila.
-
Re: Adding REPACK [concurrently]
Alvaro Herrera <alvherre@alvh.no-ip.org> — 2026-05-19T18:52:13Z
On 2026-May-14, Amit Kapila wrote: > The broader issue is that the entire logical decoding mechanism is > designed to process cluster-wide transactions. This patch tries to > bypass that foundational assumption, but only during the initial > snapshot construction while processing running_xacts record. > > To be clear, I am not against the idea of db-specific snapshots to > enable concurrent repacks. My concern is simply the time required to > get the architecture right. In its current state, we need more time to > carefully consider how this db-specific concept interacts with the > rest of the logical decoding machinery, which is built for > cluster-wide records. Hmm. So at this point I have to admit that the time I'll have before beta 1 is going to be very scarce. You're probably right that it's better to revert db-specific snapshots in pg19, and try again for 20. The revert should be a simple patch. -- Álvaro Herrera 48°01'N 7°57'E — https://www.EnterpriseDB.com/
-
Re: Adding REPACK [concurrently]
Amit Kapila <amit.kapila16@gmail.com> — 2026-05-23T15:29:35Z
On Tue, May 19, 2026 at 11:52 AM Alvaro Herrera <alvherre@alvh.no-ip.org> wrote: > > On 2026-May-14, Amit Kapila wrote: > > > The broader issue is that the entire logical decoding mechanism is > > designed to process cluster-wide transactions. This patch tries to > > bypass that foundational assumption, but only during the initial > > snapshot construction while processing running_xacts record. > > > > To be clear, I am not against the idea of db-specific snapshots to > > enable concurrent repacks. My concern is simply the time required to > > get the architecture right. In its current state, we need more time to > > carefully consider how this db-specific concept interacts with the > > rest of the logical decoding machinery, which is built for > > cluster-wide records. > > Hmm. So at this point I have to admit that the time I'll have before > beta 1 is going to be very scarce. You're probably right that it's > better to revert db-specific snapshots in pg19, and try again for 20. > Sounds reasonable. > The revert should be a simple patch. > I also think so. -- With Regards, Amit Kapila.
-
Re: Adding REPACK [concurrently]
Alvaro Herrera <alvherre@alvh.no-ip.org> — 2026-05-24T11:29:28Z
On 2026-May-23, Amit Kapila wrote: > > The revert should be a simple patch. > > I also think so. Okay, pushed the revert after seeing it pass CI: https://cirrus-ci.com/build/5520722497372160 Thanks! -- Álvaro Herrera 48°01'N 7°57'E — https://www.EnterpriseDB.com/