1 /*-------------------------------------------------------------------------
4 * POSTGRES lock manager code
6 * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * src/backend/storage/lmgr/lmgr.c
13 *-------------------------------------------------------------------------
18 #include "access/subtrans.h"
19 #include "access/transam.h"
20 #include "access/xact.h"
21 #include "catalog/catalog.h"
22 #include "miscadmin.h"
23 #include "storage/lmgr.h"
24 #include "storage/procarray.h"
25 #include "utils/inval.h"
29 * Per-backend counter for generating speculative insertion tokens.
31 * This may wrap around, but that's OK as it's only used for the short
32 * duration between inserting a tuple and checking that there are no (unique)
33 * constraint violations. It's theoretically possible that a backend sees a
34 * tuple that was speculatively inserted by another backend, but before it has
35 * started waiting on the token, the other backend completes its insertion,
36 * and then performs 2^32 unrelated insertions. And after all that, the
37 * first backend finally calls SpeculativeInsertionLockAcquire(), with the
38 * intention of waiting for the first insertion to complete, but ends up
39 * waiting for the latest unrelated insertion instead. Even then, nothing
40 * particularly bad happens: in the worst case they deadlock, causing one of
41 * the transactions to abort.
43 static uint32 speculativeInsertionToken = 0;
47 * Struct to hold context info for transaction lock waits.
49 * 'oper' is the operation that needs to wait for the other transaction; 'rel'
50 * and 'ctid' specify the address of the tuple being waited for.
52 typedef struct XactLockTableWaitInfo
57 } XactLockTableWaitInfo;
59 static void XactLockTableWaitErrorCb(void *arg);
62 * RelationInitLockInfo
63 * Initializes the lock information in a relation descriptor.
65 * relcache.c must call this during creation of any reldesc.
68 RelationInitLockInfo(Relation relation)
70 Assert(RelationIsValid(relation));
71 Assert(OidIsValid(RelationGetRelid(relation)));
73 relation->rd_lockInfo.lockRelId.relId = RelationGetRelid(relation);
75 if (relation->rd_rel->relisshared)
76 relation->rd_lockInfo.lockRelId.dbId = InvalidOid;
78 relation->rd_lockInfo.lockRelId.dbId = MyDatabaseId;
82 * SetLocktagRelationOid
83 * Set up a locktag for a relation, given only relation OID
86 SetLocktagRelationOid(LOCKTAG *tag, Oid relid)
90 if (IsSharedRelation(relid))
95 SET_LOCKTAG_RELATION(*tag, dbid, relid);
101 * Lock a relation given only its OID. This should generally be used
102 * before attempting to open the relation's relcache entry.
105 LockRelationOid(Oid relid, LOCKMODE lockmode)
108 LOCALLOCK *locallock;
109 LockAcquireResult res;
111 SetLocktagRelationOid(&tag, relid);
113 res = LockAcquireExtended(&tag, lockmode, false, false, true, &locallock);
116 * Now that we have the lock, check for invalidation messages, so that we
117 * will update or flush any stale relcache entry before we try to use it.
118 * RangeVarGetRelid() specifically relies on us for this. We can skip
119 * this in the not-uncommon case that we already had the same type of lock
120 * being requested, since then no one else could have modified the
121 * relcache entry in an undesirable way. (In the case where our own xact
122 * modifies the rel, the relcache update happens via
123 * CommandCounterIncrement, not here.)
125 * However, in corner cases where code acts on tables (usually catalogs)
126 * recursively, we might get here while still processing invalidation
127 * messages in some outer execution of this function or a sibling. The
128 * "cleared" status of the lock tells us whether we really are done
129 * absorbing relevant inval messages.
131 if (res != LOCKACQUIRE_ALREADY_CLEAR)
133 AcceptInvalidationMessages();
134 MarkLockClear(locallock);
139 * ConditionalLockRelationOid
141 * As above, but only lock if we can get the lock without blocking.
142 * Returns true iff the lock was acquired.
144 * NOTE: we do not currently need conditional versions of all the
145 * LockXXX routines in this file, but they could easily be added if needed.
148 ConditionalLockRelationOid(Oid relid, LOCKMODE lockmode)
151 LOCALLOCK *locallock;
152 LockAcquireResult res;
154 SetLocktagRelationOid(&tag, relid);
156 res = LockAcquireExtended(&tag, lockmode, false, true, true, &locallock);
158 if (res == LOCKACQUIRE_NOT_AVAIL)
162 * Now that we have the lock, check for invalidation messages; see notes
163 * in LockRelationOid.
165 if (res != LOCKACQUIRE_ALREADY_CLEAR)
167 AcceptInvalidationMessages();
168 MarkLockClear(locallock);
177 * Unlock, given a LockRelId. This is preferred over UnlockRelationOid
181 UnlockRelationId(LockRelId *relid, LOCKMODE lockmode)
185 SET_LOCKTAG_RELATION(tag, relid->dbId, relid->relId);
187 LockRelease(&tag, lockmode, false);
193 * Unlock, given only a relation Oid. Use UnlockRelationId if you can.
196 UnlockRelationOid(Oid relid, LOCKMODE lockmode)
200 SetLocktagRelationOid(&tag, relid);
202 LockRelease(&tag, lockmode, false);
208 * This is a convenience routine for acquiring an additional lock on an
209 * already-open relation. Never try to do "relation_open(foo, NoLock)"
210 * and then lock with this.
213 LockRelation(Relation relation, LOCKMODE lockmode)
216 LOCALLOCK *locallock;
217 LockAcquireResult res;
219 SET_LOCKTAG_RELATION(tag,
220 relation->rd_lockInfo.lockRelId.dbId,
221 relation->rd_lockInfo.lockRelId.relId);
223 res = LockAcquireExtended(&tag, lockmode, false, false, true, &locallock);
226 * Now that we have the lock, check for invalidation messages; see notes
227 * in LockRelationOid.
229 if (res != LOCKACQUIRE_ALREADY_CLEAR)
231 AcceptInvalidationMessages();
232 MarkLockClear(locallock);
237 * ConditionalLockRelation
239 * This is a convenience routine for acquiring an additional lock on an
240 * already-open relation. Never try to do "relation_open(foo, NoLock)"
241 * and then lock with this.
244 ConditionalLockRelation(Relation relation, LOCKMODE lockmode)
247 LOCALLOCK *locallock;
248 LockAcquireResult res;
250 SET_LOCKTAG_RELATION(tag,
251 relation->rd_lockInfo.lockRelId.dbId,
252 relation->rd_lockInfo.lockRelId.relId);
254 res = LockAcquireExtended(&tag, lockmode, false, true, true, &locallock);
256 if (res == LOCKACQUIRE_NOT_AVAIL)
260 * Now that we have the lock, check for invalidation messages; see notes
261 * in LockRelationOid.
263 if (res != LOCKACQUIRE_ALREADY_CLEAR)
265 AcceptInvalidationMessages();
266 MarkLockClear(locallock);
275 * This is a convenience routine for unlocking a relation without also
279 UnlockRelation(Relation relation, LOCKMODE lockmode)
283 SET_LOCKTAG_RELATION(tag,
284 relation->rd_lockInfo.lockRelId.dbId,
285 relation->rd_lockInfo.lockRelId.relId);
287 LockRelease(&tag, lockmode, false);
291 * CheckRelationLockedByMe
293 * Returns true if current transaction holds a lock on 'relation' of mode
294 * 'lockmode'. If 'orstronger' is true, a stronger lockmode is also OK.
295 * ("Stronger" is defined as "numerically higher", which is a bit
296 * semantically dubious but is OK for the purposes we use this for.)
299 CheckRelationLockedByMe(Relation relation, LOCKMODE lockmode, bool orstronger)
303 SET_LOCKTAG_RELATION(tag,
304 relation->rd_lockInfo.lockRelId.dbId,
305 relation->rd_lockInfo.lockRelId.relId);
307 if (LockHeldByMe(&tag, lockmode))
314 for (slockmode = lockmode + 1;
315 slockmode <= MaxLockMode;
318 if (LockHeldByMe(&tag, slockmode))
321 /* Sometimes this might be useful for debugging purposes */
322 elog(WARNING, "lock mode %s substituted for %s on relation %s",
323 GetLockmodeName(tag.locktag_lockmethodid, slockmode),
324 GetLockmodeName(tag.locktag_lockmethodid, lockmode),
325 RelationGetRelationName(relation));
336 * LockHasWaitersRelation
338 * This is a function to check whether someone else is waiting for a
339 * lock which we are currently holding.
342 LockHasWaitersRelation(Relation relation, LOCKMODE lockmode)
346 SET_LOCKTAG_RELATION(tag,
347 relation->rd_lockInfo.lockRelId.dbId,
348 relation->rd_lockInfo.lockRelId.relId);
350 return LockHasWaiters(&tag, lockmode, false);
354 * LockRelationIdForSession
356 * This routine grabs a session-level lock on the target relation. The
357 * session lock persists across transaction boundaries. It will be removed
358 * when UnlockRelationIdForSession() is called, or if an ereport(ERROR) occurs,
359 * or if the backend exits.
361 * Note that one should also grab a transaction-level lock on the rel
362 * in any transaction that actually uses the rel, to ensure that the
363 * relcache entry is up to date.
366 LockRelationIdForSession(LockRelId *relid, LOCKMODE lockmode)
370 SET_LOCKTAG_RELATION(tag, relid->dbId, relid->relId);
372 (void) LockAcquire(&tag, lockmode, true, false);
376 * UnlockRelationIdForSession
379 UnlockRelationIdForSession(LockRelId *relid, LOCKMODE lockmode)
383 SET_LOCKTAG_RELATION(tag, relid->dbId, relid->relId);
385 LockRelease(&tag, lockmode, true);
389 * LockRelationForExtension
391 * This lock tag is used to interlock addition of pages to relations.
392 * We need such locking because bufmgr/smgr definition of P_NEW is not
393 * race-condition-proof.
395 * We assume the caller is already holding some type of regular lock on
396 * the relation, so no AcceptInvalidationMessages call is needed here.
399 LockRelationForExtension(Relation relation, LOCKMODE lockmode)
403 SET_LOCKTAG_RELATION_EXTEND(tag,
404 relation->rd_lockInfo.lockRelId.dbId,
405 relation->rd_lockInfo.lockRelId.relId);
407 (void) LockAcquire(&tag, lockmode, false, false);
411 * ConditionalLockRelationForExtension
413 * As above, but only lock if we can get the lock without blocking.
414 * Returns true iff the lock was acquired.
417 ConditionalLockRelationForExtension(Relation relation, LOCKMODE lockmode)
421 SET_LOCKTAG_RELATION_EXTEND(tag,
422 relation->rd_lockInfo.lockRelId.dbId,
423 relation->rd_lockInfo.lockRelId.relId);
425 return (LockAcquire(&tag, lockmode, false, true) != LOCKACQUIRE_NOT_AVAIL);
429 * RelationExtensionLockWaiterCount
431 * Count the number of processes waiting for the given relation extension lock.
434 RelationExtensionLockWaiterCount(Relation relation)
438 SET_LOCKTAG_RELATION_EXTEND(tag,
439 relation->rd_lockInfo.lockRelId.dbId,
440 relation->rd_lockInfo.lockRelId.relId);
442 return LockWaiterCount(&tag);
446 * UnlockRelationForExtension
449 UnlockRelationForExtension(Relation relation, LOCKMODE lockmode)
453 SET_LOCKTAG_RELATION_EXTEND(tag,
454 relation->rd_lockInfo.lockRelId.dbId,
455 relation->rd_lockInfo.lockRelId.relId);
457 LockRelease(&tag, lockmode, false);
463 * Obtain a page-level lock. This is currently used by some index access
464 * methods to lock individual index pages.
467 LockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
471 SET_LOCKTAG_PAGE(tag,
472 relation->rd_lockInfo.lockRelId.dbId,
473 relation->rd_lockInfo.lockRelId.relId,
476 (void) LockAcquire(&tag, lockmode, false, false);
480 * ConditionalLockPage
482 * As above, but only lock if we can get the lock without blocking.
483 * Returns true iff the lock was acquired.
486 ConditionalLockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
490 SET_LOCKTAG_PAGE(tag,
491 relation->rd_lockInfo.lockRelId.dbId,
492 relation->rd_lockInfo.lockRelId.relId,
495 return (LockAcquire(&tag, lockmode, false, true) != LOCKACQUIRE_NOT_AVAIL);
502 UnlockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
506 SET_LOCKTAG_PAGE(tag,
507 relation->rd_lockInfo.lockRelId.dbId,
508 relation->rd_lockInfo.lockRelId.relId,
511 LockRelease(&tag, lockmode, false);
517 * Obtain a tuple-level lock. This is used in a less-than-intuitive fashion
518 * because we can't afford to keep a separate lock in shared memory for every
519 * tuple. See heap_lock_tuple before using this!
522 LockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode)
526 SET_LOCKTAG_TUPLE(tag,
527 relation->rd_lockInfo.lockRelId.dbId,
528 relation->rd_lockInfo.lockRelId.relId,
529 ItemPointerGetBlockNumber(tid),
530 ItemPointerGetOffsetNumber(tid));
532 (void) LockAcquire(&tag, lockmode, false, false);
536 * ConditionalLockTuple
538 * As above, but only lock if we can get the lock without blocking.
539 * Returns true iff the lock was acquired.
542 ConditionalLockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode)
546 SET_LOCKTAG_TUPLE(tag,
547 relation->rd_lockInfo.lockRelId.dbId,
548 relation->rd_lockInfo.lockRelId.relId,
549 ItemPointerGetBlockNumber(tid),
550 ItemPointerGetOffsetNumber(tid));
552 return (LockAcquire(&tag, lockmode, false, true) != LOCKACQUIRE_NOT_AVAIL);
559 UnlockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode)
563 SET_LOCKTAG_TUPLE(tag,
564 relation->rd_lockInfo.lockRelId.dbId,
565 relation->rd_lockInfo.lockRelId.relId,
566 ItemPointerGetBlockNumber(tid),
567 ItemPointerGetOffsetNumber(tid));
569 LockRelease(&tag, lockmode, false);
573 * XactLockTableInsert
575 * Insert a lock showing that the given transaction ID is running ---
576 * this is done when an XID is acquired by a transaction or subtransaction.
577 * The lock can then be used to wait for the transaction to finish.
580 XactLockTableInsert(TransactionId xid)
584 SET_LOCKTAG_TRANSACTION(tag, xid);
586 (void) LockAcquire(&tag, ExclusiveLock, false, false);
590 * XactLockTableDelete
592 * Delete the lock showing that the given transaction ID is running.
593 * (This is never used for main transaction IDs; those locks are only
594 * released implicitly at transaction end. But we do use it for subtrans IDs.)
597 XactLockTableDelete(TransactionId xid)
601 SET_LOCKTAG_TRANSACTION(tag, xid);
603 LockRelease(&tag, ExclusiveLock, false);
609 * Wait for the specified transaction to commit or abort. If an operation
610 * is specified, an error context callback is set up. If 'oper' is passed as
611 * None, no error context callback is set up.
613 * Note that this does the right thing for subtransactions: if we wait on a
614 * subtransaction, we will exit as soon as it aborts or its top parent commits.
615 * It takes some extra work to ensure this, because to save on shared memory
616 * the XID lock of a subtransaction is released when it ends, whether
617 * successfully or unsuccessfully. So we have to check if it's "still running"
618 * and if so wait for its parent.
621 XactLockTableWait(TransactionId xid, Relation rel, ItemPointer ctid,
625 XactLockTableWaitInfo info;
626 ErrorContextCallback callback;
630 * If an operation is specified, set up our verbose error context
633 if (oper != XLTW_None)
635 Assert(RelationIsValid(rel));
636 Assert(ItemPointerIsValid(ctid));
642 callback.callback = XactLockTableWaitErrorCb;
643 callback.arg = &info;
644 callback.previous = error_context_stack;
645 error_context_stack = &callback;
650 Assert(TransactionIdIsValid(xid));
651 Assert(!TransactionIdEquals(xid, GetTopTransactionIdIfAny()));
653 SET_LOCKTAG_TRANSACTION(tag, xid);
655 (void) LockAcquire(&tag, ShareLock, false, false);
657 LockRelease(&tag, ShareLock, false);
659 if (!TransactionIdIsInProgress(xid))
663 * If the Xid belonged to a subtransaction, then the lock would have
664 * gone away as soon as it was finished; for correct tuple visibility,
665 * the right action is to wait on its parent transaction to go away.
666 * But instead of going levels up one by one, we can just wait for the
667 * topmost transaction to finish with the same end result, which also
668 * incurs less locktable traffic.
670 * Some uses of this function don't involve tuple visibility -- such
671 * as when building snapshots for logical decoding. It is possible to
672 * see a transaction in ProcArray before it registers itself in the
673 * locktable. The topmost transaction in that case is the same xid,
674 * so we try again after a short sleep. (Don't sleep the first time
675 * through, to avoid slowing down the normal case.)
680 xid = SubTransGetTopmostTransaction(xid);
683 if (oper != XLTW_None)
684 error_context_stack = callback.previous;
688 * ConditionalXactLockTableWait
690 * As above, but only lock if we can get the lock without blocking.
691 * Returns true if the lock was acquired.
694 ConditionalXactLockTableWait(TransactionId xid)
701 Assert(TransactionIdIsValid(xid));
702 Assert(!TransactionIdEquals(xid, GetTopTransactionIdIfAny()));
704 SET_LOCKTAG_TRANSACTION(tag, xid);
706 if (LockAcquire(&tag, ShareLock, false, true) == LOCKACQUIRE_NOT_AVAIL)
709 LockRelease(&tag, ShareLock, false);
711 if (!TransactionIdIsInProgress(xid))
714 /* See XactLockTableWait about this case */
718 xid = SubTransGetTopmostTransaction(xid);
725 * SpeculativeInsertionLockAcquire
727 * Insert a lock showing that the given transaction ID is inserting a tuple,
728 * but hasn't yet decided whether it's going to keep it. The lock can then be
729 * used to wait for the decision to go ahead with the insertion, or aborting
732 * The token is used to distinguish multiple insertions by the same
733 * transaction. It is returned to caller.
736 SpeculativeInsertionLockAcquire(TransactionId xid)
740 speculativeInsertionToken++;
743 * Check for wrap-around. Zero means no token is held, so don't use that.
745 if (speculativeInsertionToken == 0)
746 speculativeInsertionToken = 1;
748 SET_LOCKTAG_SPECULATIVE_INSERTION(tag, xid, speculativeInsertionToken);
750 (void) LockAcquire(&tag, ExclusiveLock, false, false);
752 return speculativeInsertionToken;
756 * SpeculativeInsertionLockRelease
758 * Delete the lock showing that the given transaction is speculatively
762 SpeculativeInsertionLockRelease(TransactionId xid)
766 SET_LOCKTAG_SPECULATIVE_INSERTION(tag, xid, speculativeInsertionToken);
768 LockRelease(&tag, ExclusiveLock, false);
772 * SpeculativeInsertionWait
774 * Wait for the specified transaction to finish or abort the insertion of a
778 SpeculativeInsertionWait(TransactionId xid, uint32 token)
782 SET_LOCKTAG_SPECULATIVE_INSERTION(tag, xid, token);
784 Assert(TransactionIdIsValid(xid));
787 (void) LockAcquire(&tag, ShareLock, false, false);
788 LockRelease(&tag, ShareLock, false);
792 * XactLockTableWaitErrorContextCb
793 * Error context callback for transaction lock waits.
796 XactLockTableWaitErrorCb(void *arg)
798 XactLockTableWaitInfo *info = (XactLockTableWaitInfo *) arg;
801 * We would like to print schema name too, but that would require a
804 if (info->oper != XLTW_None &&
805 ItemPointerIsValid(info->ctid) && RelationIsValid(info->rel))
812 cxt = gettext_noop("while updating tuple (%u,%u) in relation \"%s\"");
815 cxt = gettext_noop("while deleting tuple (%u,%u) in relation \"%s\"");
818 cxt = gettext_noop("while locking tuple (%u,%u) in relation \"%s\"");
820 case XLTW_LockUpdated:
821 cxt = gettext_noop("while locking updated version (%u,%u) of tuple in relation \"%s\"");
823 case XLTW_InsertIndex:
824 cxt = gettext_noop("while inserting index tuple (%u,%u) in relation \"%s\"");
826 case XLTW_InsertIndexUnique:
827 cxt = gettext_noop("while checking uniqueness of tuple (%u,%u) in relation \"%s\"");
829 case XLTW_FetchUpdated:
830 cxt = gettext_noop("while rechecking updated tuple (%u,%u) in relation \"%s\"");
832 case XLTW_RecheckExclusionConstr:
833 cxt = gettext_noop("while checking exclusion constraint on tuple (%u,%u) in relation \"%s\"");
841 ItemPointerGetBlockNumber(info->ctid),
842 ItemPointerGetOffsetNumber(info->ctid),
843 RelationGetRelationName(info->rel));
848 * WaitForLockersMultiple
849 * Wait until no transaction holds locks that conflict with the given
850 * locktags at the given lockmode.
852 * To do this, obtain the current list of lockers, and wait on their VXIDs
853 * until they are finished.
855 * Note we don't try to acquire the locks on the given locktags, only the VXIDs
856 * of its lock holders; if somebody grabs a conflicting lock on the objects
857 * after we obtained our initial list of lockers, we will not wait for them.
860 WaitForLockersMultiple(List *locktags, LOCKMODE lockmode)
865 /* Done if no locks to wait for */
866 if (list_length(locktags) == 0)
869 /* Collect the transactions we need to wait on */
870 foreach(lc, locktags)
872 LOCKTAG *locktag = lfirst(lc);
874 holders = lappend(holders, GetLockConflicts(locktag, lockmode));
878 * Note: GetLockConflicts() never reports our own xid, hence we need not
879 * check for that. Also, prepared xacts are not reported, which is fine
880 * since they certainly aren't going to do anything anymore.
883 /* Finally wait for each such transaction to complete */
886 VirtualTransactionId *lockholders = lfirst(lc);
888 while (VirtualTransactionIdIsValid(*lockholders))
890 VirtualXactLock(*lockholders, true);
895 list_free_deep(holders);
901 * Same as WaitForLockersMultiple, for a single lock tag.
904 WaitForLockers(LOCKTAG heaplocktag, LOCKMODE lockmode)
908 l = list_make1(&heaplocktag);
909 WaitForLockersMultiple(l, lockmode);
917 * Obtain a lock on a general object of the current database. Don't use
918 * this for shared objects (such as tablespaces). It's unwise to apply it
919 * to relations, also, since a lock taken this way will NOT conflict with
920 * locks taken via LockRelation and friends.
923 LockDatabaseObject(Oid classid, Oid objid, uint16 objsubid,
928 SET_LOCKTAG_OBJECT(tag,
934 (void) LockAcquire(&tag, lockmode, false, false);
936 /* Make sure syscaches are up-to-date with any changes we waited for */
937 AcceptInvalidationMessages();
941 * UnlockDatabaseObject
944 UnlockDatabaseObject(Oid classid, Oid objid, uint16 objsubid,
949 SET_LOCKTAG_OBJECT(tag,
955 LockRelease(&tag, lockmode, false);
961 * Obtain a lock on a shared-across-databases object.
964 LockSharedObject(Oid classid, Oid objid, uint16 objsubid,
969 SET_LOCKTAG_OBJECT(tag,
975 (void) LockAcquire(&tag, lockmode, false, false);
977 /* Make sure syscaches are up-to-date with any changes we waited for */
978 AcceptInvalidationMessages();
985 UnlockSharedObject(Oid classid, Oid objid, uint16 objsubid,
990 SET_LOCKTAG_OBJECT(tag,
996 LockRelease(&tag, lockmode, false);
1000 * LockSharedObjectForSession
1002 * Obtain a session-level lock on a shared-across-databases object.
1003 * See LockRelationIdForSession for notes about session-level locks.
1006 LockSharedObjectForSession(Oid classid, Oid objid, uint16 objsubid,
1011 SET_LOCKTAG_OBJECT(tag,
1017 (void) LockAcquire(&tag, lockmode, true, false);
1021 * UnlockSharedObjectForSession
1024 UnlockSharedObjectForSession(Oid classid, Oid objid, uint16 objsubid,
1029 SET_LOCKTAG_OBJECT(tag,
1035 LockRelease(&tag, lockmode, true);
1040 * Append a description of a lockable object to buf.
1042 * Ideally we would print names for the numeric values, but that requires
1043 * getting locks on system tables, which might cause problems since this is
1044 * typically used to report deadlock situations.
1047 DescribeLockTag(StringInfo buf, const LOCKTAG *tag)
1049 switch ((LockTagType) tag->locktag_type)
1051 case LOCKTAG_RELATION:
1052 appendStringInfo(buf,
1053 _("relation %u of database %u"),
1054 tag->locktag_field2,
1055 tag->locktag_field1);
1057 case LOCKTAG_RELATION_EXTEND:
1058 appendStringInfo(buf,
1059 _("extension of relation %u of database %u"),
1060 tag->locktag_field2,
1061 tag->locktag_field1);
1064 appendStringInfo(buf,
1065 _("page %u of relation %u of database %u"),
1066 tag->locktag_field3,
1067 tag->locktag_field2,
1068 tag->locktag_field1);
1071 appendStringInfo(buf,
1072 _("tuple (%u,%u) of relation %u of database %u"),
1073 tag->locktag_field3,
1074 tag->locktag_field4,
1075 tag->locktag_field2,
1076 tag->locktag_field1);
1078 case LOCKTAG_TRANSACTION:
1079 appendStringInfo(buf,
1080 _("transaction %u"),
1081 tag->locktag_field1);
1083 case LOCKTAG_VIRTUALTRANSACTION:
1084 appendStringInfo(buf,
1085 _("virtual transaction %d/%u"),
1086 tag->locktag_field1,
1087 tag->locktag_field2);
1089 case LOCKTAG_SPECULATIVE_TOKEN:
1090 appendStringInfo(buf,
1091 _("speculative token %u of transaction %u"),
1092 tag->locktag_field2,
1093 tag->locktag_field1);
1095 case LOCKTAG_OBJECT:
1096 appendStringInfo(buf,
1097 _("object %u of class %u of database %u"),
1098 tag->locktag_field3,
1099 tag->locktag_field2,
1100 tag->locktag_field1);
1102 case LOCKTAG_USERLOCK:
1103 /* reserved for old contrib code, now on pgfoundry */
1104 appendStringInfo(buf,
1105 _("user lock [%u,%u,%u]"),
1106 tag->locktag_field1,
1107 tag->locktag_field2,
1108 tag->locktag_field3);
1110 case LOCKTAG_ADVISORY:
1111 appendStringInfo(buf,
1112 _("advisory lock [%u,%u,%u,%u]"),
1113 tag->locktag_field1,
1114 tag->locktag_field2,
1115 tag->locktag_field3,
1116 tag->locktag_field4);
1119 appendStringInfo(buf,
1120 _("unrecognized locktag type %d"),
1121 (int) tag->locktag_type);
1127 * GetLockNameFromTagType
1129 * Given locktag type, return the corresponding lock name.
1132 GetLockNameFromTagType(uint16 locktag_type)
1134 if (locktag_type > LOCKTAG_LAST_TYPE)
1136 return LockTagTypeNames[locktag_type];