Skip to content

Commit fe6bdc0

Browse files
committed
Make XactLockTableWait work for transactions that are not yet self-locked
XactLockTableWait assumed that its xid argument has already added itself to the lock table. That assumption led to another assumption that if locking the xid has succeeded but the xid is reported as still in progress, then the input xid must have been a subtransaction. These assumptions hold true for the original uses of this code in locking related to on-disk tuples, but they break down in logical replication slot snapshot building -- in particular, when a standby snapshot logged contains an xid that's already in ProcArray but not yet in the lock table. This leads to assertion failures that can be reproduced all the way back to 9.4, when logical decoding was introduced. To fix, change SubTransGetParent to SubTransGetTopmostTransaction which has a slightly different API: it returns the argument Xid if there is no parent, and it goes all the way to the top instead of moving up the levels one by one. Also, to avoid busy-waiting, add a 1ms sleep to give the other process time to register itself in the lock table. For consistency, change ConditionalXactLockTableWait the same way. Author: Petr Jelínek Discussion: https://postgr.es/m/1B3E32D8-FCF4-40B4-AEF9-5C0E3AC57969@postgrespro.ru Reported-by: Konstantin Knizhnik Diagnosed-by: Stas Kelvich, Petr Jelínek Reviewed-by: Andres Freund, Robert Haas
1 parent aa7d71b commit fe6bdc0

File tree

1 file changed

+28
-2
lines changed
  • src/backend/storage/lmgr

1 file changed

+28
-2
lines changed

src/backend/storage/lmgr/lmgr.c

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,7 @@ XactLockTableWait(TransactionId xid, Relation rel, ItemPointer ctid,
504504
LOCKTAG tag;
505505
XactLockTableWaitInfo info;
506506
ErrorContextCallback callback;
507+
bool first = true;
507508

508509
/*
509510
* If an operation is specified, set up our verbose error context
@@ -537,7 +538,26 @@ XactLockTableWait(TransactionId xid, Relation rel, ItemPointer ctid,
537538

538539
if (!TransactionIdIsInProgress(xid))
539540
break;
540-
xid = SubTransGetParent(xid);
541+
542+
/*
543+
* If the Xid belonged to a subtransaction, then the lock would have
544+
* gone away as soon as it was finished; for correct tuple visibility,
545+
* the right action is to wait on its parent transaction to go away.
546+
* But instead of going levels up one by one, we can just wait for the
547+
* topmost transaction to finish with the same end result, which also
548+
* incurs less locktable traffic.
549+
*
550+
* Some uses of this function don't involve tuple visibility -- such
551+
* as when building snapshots for logical decoding. It is possible to
552+
* see a transaction in ProcArray before it registers itself in the
553+
* locktable. The topmost transaction in that case is the same xid,
554+
* so we try again after a short sleep. (Don't sleep the first time
555+
* through, to avoid slowing down the normal case.)
556+
*/
557+
if (!first)
558+
pg_usleep(1000L);
559+
first = false;
560+
xid = SubTransGetTopmostTransaction(xid);
541561
}
542562

543563
if (oper != XLTW_None)
@@ -554,6 +574,7 @@ bool
554574
ConditionalXactLockTableWait(TransactionId xid)
555575
{
556576
LOCKTAG tag;
577+
bool first = true;
557578

558579
for (;;)
559580
{
@@ -569,7 +590,12 @@ ConditionalXactLockTableWait(TransactionId xid)
569590

570591
if (!TransactionIdIsInProgress(xid))
571592
break;
572-
xid = SubTransGetParent(xid);
593+
594+
/* See XactLockTableWait about this case */
595+
if (!first)
596+
pg_usleep(1000L);
597+
first = false;
598+
xid = SubTransGetTopmostTransaction(xid);
573599
}
574600

575601
return true;

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy