diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c index b19d1cf..261c5be 100644 --- a/src/backend/access/heap/heapam.c +++ b/src/backend/access/heap/heapam.c @@ -2494,7 +2494,7 @@ l1: if (infomask & HEAP_XMAX_IS_MULTI) { /* wait for multixact */ - MultiXactIdWait((MultiXactId) xwait); + MultiXactIdWait((MultiXactId) xwait, relation->rd_id); LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE); /* @@ -2520,7 +2520,7 @@ l1: else { /* wait for regular transaction to end */ - XactLockTableWait(xwait); + XactLockTableWait(xwait, relation->rd_id); LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE); /* @@ -2871,7 +2871,7 @@ l2: if (infomask & HEAP_XMAX_IS_MULTI) { /* wait for multixact */ - MultiXactIdWait((MultiXactId) xwait); + MultiXactIdWait((MultiXactId) xwait, relation->rd_id); LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE); /* @@ -2897,7 +2897,7 @@ l2: else { /* wait for regular transaction to end */ - XactLockTableWait(xwait); + XactLockTableWait(xwait, relation->rd_id); LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE); /* @@ -3612,14 +3612,14 @@ l3: /* wait for multixact to end */ if (nowait) { - if (!ConditionalMultiXactIdWait((MultiXactId) xwait)) + if (!ConditionalMultiXactIdWait((MultiXactId) xwait, relation->rd_id)) ereport(ERROR, (errcode(ERRCODE_LOCK_NOT_AVAILABLE), errmsg("could not obtain lock on row in relation \"%s\"", RelationGetRelationName(relation)))); } else - MultiXactIdWait((MultiXactId) xwait); + MultiXactIdWait((MultiXactId) xwait, relation->rd_id); LockBuffer(*buffer, BUFFER_LOCK_EXCLUSIVE); @@ -3647,14 +3647,14 @@ l3: /* wait for regular transaction to end */ if (nowait) { - if (!ConditionalXactLockTableWait(xwait)) + if (!ConditionalXactLockTableWait(xwait, relation->rd_id)) ereport(ERROR, (errcode(ERRCODE_LOCK_NOT_AVAILABLE), errmsg("could not obtain lock on row in relation \"%s\"", RelationGetRelationName(relation)))); } else - XactLockTableWait(xwait); + XactLockTableWait(xwait, relation->rd_id); LockBuffer(*buffer, BUFFER_LOCK_EXCLUSIVE); diff --git a/src/backend/access/nbtree/nbtinsert.c b/src/backend/access/nbtree/nbtinsert.c index 4432bb1..d48ffb2 100644 --- a/src/backend/access/nbtree/nbtinsert.c +++ b/src/backend/access/nbtree/nbtinsert.c @@ -165,7 +165,7 @@ top: { /* Have to wait for the other guy ... */ _bt_relbuf(rel, buf); - XactLockTableWait(xwait); + XactLockTableWait(xwait, heapRel->rd_id); /* start over... */ _bt_freestack(stack); goto top; diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c index 1ae6717..cd6db82 100644 --- a/src/backend/access/transam/multixact.c +++ b/src/backend/access/transam/multixact.c @@ -583,7 +583,7 @@ MultiXactIdSetOldestVisible(void) * of the containing tuple, so the caller needs to iterate on us somehow. */ void -MultiXactIdWait(MultiXactId multi) +MultiXactIdWait(MultiXactId multi, Oid relid) { TransactionId *members; int nmembers; @@ -601,7 +601,7 @@ MultiXactIdWait(MultiXactId multi) debug_elog4(DEBUG2, "MultiXactIdWait: waiting for %d (%u)", i, member); if (!TransactionIdIsCurrentTransactionId(member)) - XactLockTableWait(member); + XactLockTableWait(member, relid); } pfree(members); @@ -613,7 +613,7 @@ MultiXactIdWait(MultiXactId multi) * As above, but only lock if we can get the lock without blocking. */ bool -ConditionalMultiXactIdWait(MultiXactId multi) +ConditionalMultiXactIdWait(MultiXactId multi, Oid relid) { bool result = true; TransactionId *members; @@ -633,7 +633,7 @@ ConditionalMultiXactIdWait(MultiXactId multi) i, member); if (!TransactionIdIsCurrentTransactionId(member)) { - result = ConditionalXactLockTableWait(member); + result = ConditionalXactLockTableWait(member, relid); if (!result) break; } diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index 5892e44..73e2dfa 100644 --- a/src/backend/catalog/index.c +++ b/src/backend/catalog/index.c @@ -2335,7 +2335,7 @@ IndexBuildHeapScan(Relation heapRelation, * Must drop the lock on the buffer before we wait */ LockBuffer(scan->rs_cbuf, BUFFER_LOCK_UNLOCK); - XactLockTableWait(xwait); + XactLockTableWait(xwait, heapRelation->rd_id); goto recheck; } } @@ -2382,7 +2382,7 @@ IndexBuildHeapScan(Relation heapRelation, * Must drop the lock on the buffer before we wait */ LockBuffer(scan->rs_cbuf, BUFFER_LOCK_UNLOCK); - XactLockTableWait(xwait); + XactLockTableWait(xwait, heapRelation->rd_id); goto recheck; } diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index 9d5d829..88bb8f0 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -1836,7 +1836,7 @@ EvalPlanQualFetch(EState *estate, Relation relation, int lockmode, if (TransactionIdIsValid(SnapshotDirty.xmax)) { ReleaseBuffer(buffer); - XactLockTableWait(SnapshotDirty.xmax); + XactLockTableWait(SnapshotDirty.xmax, relation->rd_id); continue; /* loop back to repeat heap_fetch */ } diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c index 9206195..f48a24c 100644 --- a/src/backend/executor/execUtils.c +++ b/src/backend/executor/execUtils.c @@ -1291,7 +1291,7 @@ retry: if (TransactionIdIsValid(xwait)) { index_endscan(index_scan); - XactLockTableWait(xwait); + XactLockTableWait(xwait, heap->rd_id); goto retry; } diff --git a/src/backend/storage/lmgr/deadlock.c b/src/backend/storage/lmgr/deadlock.c index a0f7d34..67fb75e 100644 --- a/src/backend/storage/lmgr/deadlock.c +++ b/src/backend/storage/lmgr/deadlock.c @@ -916,7 +916,7 @@ DeadLockReport(void) /* reset locktagbuf to hold next object description */ resetStringInfo(&locktagbuf); - DescribeLockTag(&locktagbuf, &info->locktag); + DescribeLockTag(&locktagbuf, &info->locktag, false); if (i > 0) appendStringInfoChar(&clientbuf, '\n'); diff --git a/src/backend/storage/lmgr/lmgr.c b/src/backend/storage/lmgr/lmgr.c index 2b7a1db..20e935b 100644 --- a/src/backend/storage/lmgr/lmgr.c +++ b/src/backend/storage/lmgr/lmgr.c @@ -24,6 +24,7 @@ #include "storage/procarray.h" #include "utils/inval.h" +static Oid XactLockTableRelid = InvalidOid; /* Relid of table we are waiting for */ /* * RelationInitLockInfo @@ -481,10 +482,12 @@ XactLockTableDelete(TransactionId xid) * and if so wait for its parent. */ void -XactLockTableWait(TransactionId xid) +XactLockTableWait(TransactionId xid, Oid WaitRelid) { LOCKTAG tag; + XactLockTableRelid = WaitRelid; + for (;;) { Assert(TransactionIdIsValid(xid)); @@ -500,6 +503,8 @@ XactLockTableWait(TransactionId xid) break; xid = SubTransGetParent(xid); } + + XactLockTableRelid = InvalidOid; } /* @@ -509,10 +514,11 @@ XactLockTableWait(TransactionId xid) * Returns TRUE if the lock was acquired. */ bool -ConditionalXactLockTableWait(TransactionId xid) +ConditionalXactLockTableWait(TransactionId xid, Oid WaitRelid) { LOCKTAG tag; + XactLockTableRelid = WaitRelid; for (;;) { Assert(TransactionIdIsValid(xid)); @@ -521,7 +527,10 @@ ConditionalXactLockTableWait(TransactionId xid) SET_LOCKTAG_TRANSACTION(tag, xid); if (LockAcquire(&tag, ShareLock, false, true) == LOCKACQUIRE_NOT_AVAIL) + { + XactLockTableRelid = InvalidOid; return false; + } LockRelease(&tag, ShareLock, false); @@ -530,10 +539,21 @@ ConditionalXactLockTableWait(TransactionId xid) xid = SubTransGetParent(xid); } + XactLockTableRelid = InvalidOid; return true; } /* + * Return the relid of the table we are currently waiting on, to + * allow full reporting of lock waits. + */ +Oid +GetXactLockTableRelid(void) +{ + return XactLockTableRelid; +} + +/* * LockDatabaseObject * * Obtain a lock on a general object of the current database. Don't use @@ -664,9 +684,13 @@ UnlockSharedObjectForSession(Oid classid, Oid objid, uint16 objsubid, * Ideally we would print names for the numeric values, but that requires * getting locks on system tables, which might cause problems since this is * typically used to report deadlock situations. + * + * describeXact can be used by a backend that is describing a lock of type + * LOCKTAG_TRANSACTION that the backend is requesting. This information + * isn't available for locks requested or held by other backends. */ void -DescribeLockTag(StringInfo buf, const LOCKTAG *tag) +DescribeLockTag(StringInfo buf, const LOCKTAG *tag, bool describeXact) { switch ((LockTagType) tag->locktag_type) { @@ -698,7 +722,14 @@ DescribeLockTag(StringInfo buf, const LOCKTAG *tag) tag->locktag_field1); break; case LOCKTAG_TRANSACTION: - appendStringInfo(buf, + if (describeXact && OidIsValid(GetXactLockTableRelid())) + appendStringInfo(buf, + _("transaction %u on relation %u of database %u"), + tag->locktag_field1, + GetXactLockTableRelid(), + MyDatabaseId); + else + appendStringInfo(buf, _("transaction %u"), tag->locktag_field1); break; diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c index 2e012fa..5ec0eed 100644 --- a/src/backend/storage/lmgr/proc.c +++ b/src/backend/storage/lmgr/proc.c @@ -1128,7 +1128,7 @@ ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable) initStringInfo(&locktagbuf); initStringInfo(&logbuf); - DescribeLockTag(&locktagbuf, &lock->tag); + DescribeLockTag(&locktagbuf, &lock->tag, false); appendStringInfo(&logbuf, _("Process %d waits for %s on %s."), MyProcPid, @@ -1176,7 +1176,7 @@ ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable) long msecs; initStringInfo(&buf); - DescribeLockTag(&buf, &locallock->tag.lock); + DescribeLockTag(&buf, &locallock->tag.lock, true); modename = GetLockmodeName(locallock->tag.lock.locktag_lockmethodid, lockmode); TimestampDifference(get_timeout_start_time(DEADLOCK_TIMEOUT), diff --git a/src/include/access/multixact.h b/src/include/access/multixact.h index b5486be..6cca9fa 100644 --- a/src/include/access/multixact.h +++ b/src/include/access/multixact.h @@ -46,8 +46,8 @@ extern MultiXactId MultiXactIdCreate(TransactionId xid1, TransactionId xid2); extern MultiXactId MultiXactIdExpand(MultiXactId multi, TransactionId xid); extern bool MultiXactIdIsRunning(MultiXactId multi); extern bool MultiXactIdIsCurrent(MultiXactId multi); -extern void MultiXactIdWait(MultiXactId multi); -extern bool ConditionalMultiXactIdWait(MultiXactId multi); +extern void MultiXactIdWait(MultiXactId multi, Oid relid); +extern bool ConditionalMultiXactIdWait(MultiXactId multi, Oid relid); extern void MultiXactIdSetOldestMember(void); extern int GetMultiXactIdMembers(MultiXactId multi, TransactionId **xids); diff --git a/src/include/storage/lmgr.h b/src/include/storage/lmgr.h index 9b1fb93..5aee9f5 100644 --- a/src/include/storage/lmgr.h +++ b/src/include/storage/lmgr.h @@ -54,8 +54,9 @@ extern void UnlockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode); /* Lock an XID (used to wait for a transaction to finish) */ extern void XactLockTableInsert(TransactionId xid); extern void XactLockTableDelete(TransactionId xid); -extern void XactLockTableWait(TransactionId xid); -extern bool ConditionalXactLockTableWait(TransactionId xid); +extern void XactLockTableWait(TransactionId xid, Oid WaitRelid); +extern bool ConditionalXactLockTableWait(TransactionId xid, Oid WaitRelid); +extern Oid GetXactLockTableRelid(void); /* Lock a general object (other than a relation) of the current database */ extern void LockDatabaseObject(Oid classid, Oid objid, uint16 objsubid, @@ -75,6 +76,6 @@ extern void UnlockSharedObjectForSession(Oid classid, Oid objid, uint16 objsubid LOCKMODE lockmode); /* Describe a locktag for error messages */ -extern void DescribeLockTag(StringInfo buf, const LOCKTAG *tag); +extern void DescribeLockTag(StringInfo buf, const LOCKTAG *tag, bool describeXact); #endif /* LMGR_H */