PostgreSQL Source Code git master
lock.h File Reference
#include "lib/ilist.h"
#include "storage/lockdefs.h"
#include "storage/lwlock.h"
#include "storage/procnumber.h"
#include "storage/shmem.h"
#include "utils/timestamp.h"
Include dependency graph for lock.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  VirtualTransactionId
 
struct  LockMethodData
 
struct  LOCKTAG
 
struct  LOCK
 
struct  PROCLOCKTAG
 
struct  PROCLOCK
 
struct  LOCALLOCKTAG
 
struct  LOCALLOCKOWNER
 
struct  LOCALLOCK
 
struct  LockInstanceData
 
struct  LockData
 
struct  BlockedProcData
 
struct  BlockedProcsData
 

Macros

#define InvalidLocalTransactionId   0
 
#define LocalTransactionIdIsValid(lxid)   ((lxid) != InvalidLocalTransactionId)
 
#define VirtualTransactionIdIsValid(vxid)    (LocalTransactionIdIsValid((vxid).localTransactionId))
 
#define VirtualTransactionIdIsRecoveredPreparedXact(vxid)    ((vxid).procNumber == INVALID_PROC_NUMBER)
 
#define VirtualTransactionIdEquals(vxid1, vxid2)
 
#define SetInvalidVirtualTransactionId(vxid)
 
#define GET_VXID_FROM_PGPROC(vxid_dst, proc)
 
#define MAX_LOCKMODES   10
 
#define LOCKBIT_ON(lockmode)   (1 << (lockmode))
 
#define LOCKBIT_OFF(lockmode)   (~(1 << (lockmode)))
 
#define DEFAULT_LOCKMETHOD   1
 
#define USER_LOCKMETHOD   2
 
#define LOCKTAG_LAST_TYPE   LOCKTAG_APPLY_TRANSACTION
 
#define SET_LOCKTAG_RELATION(locktag, dboid, reloid)
 
#define SET_LOCKTAG_RELATION_EXTEND(locktag, dboid, reloid)
 
#define SET_LOCKTAG_DATABASE_FROZEN_IDS(locktag, dboid)
 
#define SET_LOCKTAG_PAGE(locktag, dboid, reloid, blocknum)
 
#define SET_LOCKTAG_TUPLE(locktag, dboid, reloid, blocknum, offnum)
 
#define SET_LOCKTAG_TRANSACTION(locktag, xid)
 
#define SET_LOCKTAG_VIRTUALTRANSACTION(locktag, vxid)
 
#define SET_LOCKTAG_SPECULATIVE_INSERTION(locktag, xid, token)
 
#define SET_LOCKTAG_OBJECT(locktag, dboid, classoid, objoid, objsubid)
 
#define SET_LOCKTAG_ADVISORY(locktag, id1, id2, id3, id4)
 
#define SET_LOCKTAG_APPLY_TRANSACTION(locktag, dboid, suboid, xid, objid)
 
#define LOCK_LOCKMETHOD(lock)   ((LOCKMETHODID) (lock).tag.locktag_lockmethodid)
 
#define LOCK_LOCKTAG(lock)   ((LockTagType) (lock).tag.locktag_type)
 
#define PROCLOCK_LOCKMETHOD(proclock)    LOCK_LOCKMETHOD(*((proclock).tag.myLock))
 
#define LOCALLOCK_LOCKMETHOD(llock)   ((llock).tag.lock.locktag_lockmethodid)
 
#define LOCALLOCK_LOCKTAG(llock)   ((LockTagType) (llock).tag.lock.locktag_type)
 
#define LockHashPartition(hashcode)    ((hashcode) % NUM_LOCK_PARTITIONS)
 
#define LockHashPartitionLock(hashcode)
 
#define LockHashPartitionLockByIndex(i)    (&MainLWLockArray[LOCK_MANAGER_LWLOCK_OFFSET + (i)].lock)
 
#define LockHashPartitionLockByProc(leader_pgproc)    LockHashPartitionLock(GetNumberFromPGProc(leader_pgproc))
 

Typedefs

typedef struct PGPROC PGPROC
 
typedef struct LockMethodData LockMethodData
 
typedef const LockMethodDataLockMethod
 
typedef uint16 LOCKMETHODID
 
typedef enum LockTagType LockTagType
 
typedef struct LOCKTAG LOCKTAG
 
typedef struct LOCK LOCK
 
typedef struct PROCLOCKTAG PROCLOCKTAG
 
typedef struct PROCLOCK PROCLOCK
 
typedef struct LOCALLOCKTAG LOCALLOCKTAG
 
typedef struct LOCALLOCKOWNER LOCALLOCKOWNER
 
typedef struct LOCALLOCK LOCALLOCK
 
typedef struct LockInstanceData LockInstanceData
 
typedef struct LockData LockData
 
typedef struct BlockedProcData BlockedProcData
 
typedef struct BlockedProcsData BlockedProcsData
 

Enumerations

enum  LockTagType {
  LOCKTAG_RELATION , LOCKTAG_RELATION_EXTEND , LOCKTAG_DATABASE_FROZEN_IDS , LOCKTAG_PAGE ,
  LOCKTAG_TUPLE , LOCKTAG_TRANSACTION , LOCKTAG_VIRTUALTRANSACTION , LOCKTAG_SPECULATIVE_TOKEN ,
  LOCKTAG_OBJECT , LOCKTAG_USERLOCK , LOCKTAG_ADVISORY , LOCKTAG_APPLY_TRANSACTION
}
 
enum  LockAcquireResult { LOCKACQUIRE_NOT_AVAIL , LOCKACQUIRE_OK , LOCKACQUIRE_ALREADY_HELD , LOCKACQUIRE_ALREADY_CLEAR }
 
enum  DeadLockState {
  DS_NOT_YET_CHECKED , DS_NO_DEADLOCK , DS_SOFT_DEADLOCK , DS_HARD_DEADLOCK ,
  DS_BLOCKED_BY_AUTOVACUUM
}
 

Functions

void LockManagerShmemInit (void)
 
Size LockManagerShmemSize (void)
 
void InitLockManagerAccess (void)
 
LockMethod GetLocksMethodTable (const LOCK *lock)
 
LockMethod GetLockTagsMethodTable (const LOCKTAG *locktag)
 
uint32 LockTagHashCode (const LOCKTAG *locktag)
 
bool DoLockModesConflict (LOCKMODE mode1, LOCKMODE mode2)
 
LockAcquireResult LockAcquire (const LOCKTAG *locktag, LOCKMODE lockmode, bool sessionLock, bool dontWait)
 
LockAcquireResult LockAcquireExtended (const LOCKTAG *locktag, LOCKMODE lockmode, bool sessionLock, bool dontWait, bool reportMemoryError, LOCALLOCK **locallockp, bool logLockFailure)
 
void AbortStrongLockAcquire (void)
 
void MarkLockClear (LOCALLOCK *locallock)
 
bool LockRelease (const LOCKTAG *locktag, LOCKMODE lockmode, bool sessionLock)
 
void LockReleaseAll (LOCKMETHODID lockmethodid, bool allLocks)
 
void LockReleaseSession (LOCKMETHODID lockmethodid)
 
void LockReleaseCurrentOwner (LOCALLOCK **locallocks, int nlocks)
 
void LockReassignCurrentOwner (LOCALLOCK **locallocks, int nlocks)
 
bool LockHeldByMe (const LOCKTAG *locktag, LOCKMODE lockmode, bool orstronger)
 
bool LockHasWaiters (const LOCKTAG *locktag, LOCKMODE lockmode, bool sessionLock)
 
VirtualTransactionIdGetLockConflicts (const LOCKTAG *locktag, LOCKMODE lockmode, int *countp)
 
void AtPrepare_Locks (void)
 
void PostPrepare_Locks (TransactionId xid)
 
bool LockCheckConflicts (LockMethod lockMethodTable, LOCKMODE lockmode, LOCK *lock, PROCLOCK *proclock)
 
void GrantLock (LOCK *lock, PROCLOCK *proclock, LOCKMODE lockmode)
 
void GrantAwaitedLock (void)
 
LOCALLOCKGetAwaitedLock (void)
 
void RemoveFromWaitQueue (PGPROC *proc, uint32 hashcode)
 
LockDataGetLockStatusData (void)
 
BlockedProcsDataGetBlockerStatusData (int blocked_pid)
 
xl_standby_lockGetRunningTransactionLocks (int *nlocks)
 
const char * GetLockmodeName (LOCKMETHODID lockmethodid, LOCKMODE mode)
 
void lock_twophase_recover (TransactionId xid, uint16 info, void *recdata, uint32 len)
 
void lock_twophase_postcommit (TransactionId xid, uint16 info, void *recdata, uint32 len)
 
void lock_twophase_postabort (TransactionId xid, uint16 info, void *recdata, uint32 len)
 
void lock_twophase_standby_recover (TransactionId xid, uint16 info, void *recdata, uint32 len)
 
DeadLockState DeadLockCheck (PGPROC *proc)
 
PGPROCGetBlockingAutoVacuumPgproc (void)
 
pg_noreturn void DeadLockReport (void)
 
void RememberSimpleDeadLock (PGPROC *proc1, LOCKMODE lockmode, LOCK *lock, PGPROC *proc2)
 
void InitDeadLockChecking (void)
 
int LockWaiterCount (const LOCKTAG *locktag)
 
void VirtualXactLockTableInsert (VirtualTransactionId vxid)
 
void VirtualXactLockTableCleanup (void)
 
bool VirtualXactLock (VirtualTransactionId vxid, bool wait)
 

Variables

PGDLLIMPORT int max_locks_per_xact
 
PGDLLIMPORT bool log_lock_failure
 
PGDLLIMPORT const char *const LockTagTypeNames []
 

Macro Definition Documentation

◆ DEFAULT_LOCKMETHOD

#define DEFAULT_LOCKMETHOD   1

Definition at line 126 of file lock.h.

◆ GET_VXID_FROM_PGPROC

#define GET_VXID_FROM_PGPROC (   vxid_dst,
  proc 
)
Value:
((vxid_dst).procNumber = (proc).vxid.procNumber, \
(vxid_dst).localTransactionId = (proc).vxid.lxid)

Definition at line 78 of file lock.h.

◆ InvalidLocalTransactionId

#define InvalidLocalTransactionId   0

Definition at line 66 of file lock.h.

◆ LOCALLOCK_LOCKMETHOD

#define LOCALLOCK_LOCKMETHOD (   llock)    ((llock).tag.lock.locktag_lockmethodid)

Definition at line 444 of file lock.h.

◆ LOCALLOCK_LOCKTAG

#define LOCALLOCK_LOCKTAG (   llock)    ((LockTagType) (llock).tag.lock.locktag_type)

Definition at line 445 of file lock.h.

◆ LocalTransactionIdIsValid

#define LocalTransactionIdIsValid (   lxid)    ((lxid) != InvalidLocalTransactionId)

Definition at line 67 of file lock.h.

◆ LOCK_LOCKMETHOD

#define LOCK_LOCKMETHOD (   lock)    ((LOCKMETHODID) (lock).tag.locktag_lockmethodid)

Definition at line 325 of file lock.h.

◆ LOCK_LOCKTAG

#define LOCK_LOCKTAG (   lock)    ((LockTagType) (lock).tag.locktag_type)

Definition at line 326 of file lock.h.

◆ LOCKBIT_OFF

#define LOCKBIT_OFF (   lockmode)    (~(1 << (lockmode)))

Definition at line 86 of file lock.h.

◆ LOCKBIT_ON

#define LOCKBIT_ON (   lockmode)    (1 << (lockmode))

Definition at line 85 of file lock.h.

◆ LockHashPartition

#define LockHashPartition (   hashcode)     ((hashcode) % NUM_LOCK_PARTITIONS)

Definition at line 525 of file lock.h.

◆ LockHashPartitionLock

#define LockHashPartitionLock (   hashcode)
Value:
LockHashPartition(hashcode)].lock)
LWLockPadded * MainLWLockArray
Definition: lwlock.c:199
#define LOCK_MANAGER_LWLOCK_OFFSET
Definition: lwlock.h:105
LWLock lock
Definition: lwlock.h:70

Definition at line 527 of file lock.h.

◆ LockHashPartitionLockByIndex

#define LockHashPartitionLockByIndex (   i)     (&MainLWLockArray[LOCK_MANAGER_LWLOCK_OFFSET + (i)].lock)

Definition at line 530 of file lock.h.

◆ LockHashPartitionLockByProc

#define LockHashPartitionLockByProc (   leader_pgproc)     LockHashPartitionLock(GetNumberFromPGProc(leader_pgproc))

Definition at line 542 of file lock.h.

◆ LOCKTAG_LAST_TYPE

#define LOCKTAG_LAST_TYPE   LOCKTAG_APPLY_TRANSACTION

Definition at line 153 of file lock.h.

◆ MAX_LOCKMODES

#define MAX_LOCKMODES   10

Definition at line 83 of file lock.h.

◆ PROCLOCK_LOCKMETHOD

#define PROCLOCK_LOCKMETHOD (   proclock)     LOCK_LOCKMETHOD(*((proclock).tag.myLock))

Definition at line 383 of file lock.h.

◆ SET_LOCKTAG_ADVISORY

#define SET_LOCKTAG_ADVISORY (   locktag,
  id1,
  id2,
  id3,
  id4 
)
Value:
((locktag).locktag_field1 = (id1), \
(locktag).locktag_field2 = (id2), \
(locktag).locktag_field3 = (id3), \
(locktag).locktag_field4 = (id4), \
(locktag).locktag_type = LOCKTAG_ADVISORY, \
(locktag).locktag_lockmethodid = USER_LOCKMETHOD)
@ LOCKTAG_ADVISORY
Definition: lock.h:148
#define USER_LOCKMETHOD
Definition: lock.h:127

Definition at line 271 of file lock.h.

◆ SET_LOCKTAG_APPLY_TRANSACTION

#define SET_LOCKTAG_APPLY_TRANSACTION (   locktag,
  dboid,
  suboid,
  xid,
  objid 
)
Value:
((locktag).locktag_field1 = (dboid), \
(locktag).locktag_field2 = (suboid), \
(locktag).locktag_field3 = (xid), \
(locktag).locktag_field4 = (objid), \
(locktag).locktag_type = LOCKTAG_APPLY_TRANSACTION, \
(locktag).locktag_lockmethodid = DEFAULT_LOCKMETHOD)
#define DEFAULT_LOCKMETHOD
Definition: lock.h:126
@ LOCKTAG_APPLY_TRANSACTION
Definition: lock.h:149

Definition at line 283 of file lock.h.

◆ SET_LOCKTAG_DATABASE_FROZEN_IDS

#define SET_LOCKTAG_DATABASE_FROZEN_IDS (   locktag,
  dboid 
)
Value:
((locktag).locktag_field1 = (dboid), \
(locktag).locktag_field2 = 0, \
(locktag).locktag_field3 = 0, \
(locktag).locktag_field4 = 0, \
(locktag).locktag_type = LOCKTAG_DATABASE_FROZEN_IDS, \
(locktag).locktag_lockmethodid = DEFAULT_LOCKMETHOD)
@ LOCKTAG_DATABASE_FROZEN_IDS
Definition: lock.h:140

Definition at line 200 of file lock.h.

◆ SET_LOCKTAG_OBJECT

#define SET_LOCKTAG_OBJECT (   locktag,
  dboid,
  classoid,
  objoid,
  objsubid 
)
Value:
((locktag).locktag_field1 = (dboid), \
(locktag).locktag_field2 = (classoid), \
(locktag).locktag_field3 = (objoid), \
(locktag).locktag_field4 = (objsubid), \
(locktag).locktag_type = LOCKTAG_OBJECT, \
(locktag).locktag_lockmethodid = DEFAULT_LOCKMETHOD)
@ LOCKTAG_OBJECT
Definition: lock.h:146

Definition at line 263 of file lock.h.

◆ SET_LOCKTAG_PAGE

#define SET_LOCKTAG_PAGE (   locktag,
  dboid,
  reloid,
  blocknum 
)
Value:
((locktag).locktag_field1 = (dboid), \
(locktag).locktag_field2 = (reloid), \
(locktag).locktag_field3 = (blocknum), \
(locktag).locktag_field4 = 0, \
(locktag).locktag_type = LOCKTAG_PAGE, \
(locktag).locktag_lockmethodid = DEFAULT_LOCKMETHOD)
@ LOCKTAG_PAGE
Definition: lock.h:141

Definition at line 209 of file lock.h.

◆ SET_LOCKTAG_RELATION

#define SET_LOCKTAG_RELATION (   locktag,
  dboid,
  reloid 
)
Value:
((locktag).locktag_field1 = (dboid), \
(locktag).locktag_field2 = (reloid), \
(locktag).locktag_field3 = 0, \
(locktag).locktag_field4 = 0, \
(locktag).locktag_type = LOCKTAG_RELATION, \
(locktag).locktag_lockmethodid = DEFAULT_LOCKMETHOD)
@ LOCKTAG_RELATION
Definition: lock.h:138

Definition at line 182 of file lock.h.

◆ SET_LOCKTAG_RELATION_EXTEND

#define SET_LOCKTAG_RELATION_EXTEND (   locktag,
  dboid,
  reloid 
)
Value:
((locktag).locktag_field1 = (dboid), \
(locktag).locktag_field2 = (reloid), \
(locktag).locktag_field3 = 0, \
(locktag).locktag_field4 = 0, \
(locktag).locktag_type = LOCKTAG_RELATION_EXTEND, \
(locktag).locktag_lockmethodid = DEFAULT_LOCKMETHOD)
@ LOCKTAG_RELATION_EXTEND
Definition: lock.h:139

Definition at line 191 of file lock.h.

◆ SET_LOCKTAG_SPECULATIVE_INSERTION

#define SET_LOCKTAG_SPECULATIVE_INSERTION (   locktag,
  xid,
  token 
)
Value:
((locktag).locktag_field1 = (xid), \
(locktag).locktag_field2 = (token), \
(locktag).locktag_field3 = 0, \
(locktag).locktag_field4 = 0, \
(locktag).locktag_type = LOCKTAG_SPECULATIVE_TOKEN, \
(locktag).locktag_lockmethodid = DEFAULT_LOCKMETHOD)
@ LOCKTAG_SPECULATIVE_TOKEN
Definition: lock.h:145

Definition at line 248 of file lock.h.

◆ SET_LOCKTAG_TRANSACTION

#define SET_LOCKTAG_TRANSACTION (   locktag,
  xid 
)
Value:
((locktag).locktag_field1 = (xid), \
(locktag).locktag_field2 = 0, \
(locktag).locktag_field3 = 0, \
(locktag).locktag_field4 = 0, \
(locktag).locktag_type = LOCKTAG_TRANSACTION, \
(locktag).locktag_lockmethodid = DEFAULT_LOCKMETHOD)
@ LOCKTAG_TRANSACTION
Definition: lock.h:143

Definition at line 227 of file lock.h.

◆ SET_LOCKTAG_TUPLE

#define SET_LOCKTAG_TUPLE (   locktag,
  dboid,
  reloid,
  blocknum,
  offnum 
)
Value:
((locktag).locktag_field1 = (dboid), \
(locktag).locktag_field2 = (reloid), \
(locktag).locktag_field3 = (blocknum), \
(locktag).locktag_field4 = (offnum), \
(locktag).locktag_type = LOCKTAG_TUPLE, \
(locktag).locktag_lockmethodid = DEFAULT_LOCKMETHOD)
@ LOCKTAG_TUPLE
Definition: lock.h:142

Definition at line 218 of file lock.h.

◆ SET_LOCKTAG_VIRTUALTRANSACTION

#define SET_LOCKTAG_VIRTUALTRANSACTION (   locktag,
  vxid 
)
Value:
((locktag).locktag_field1 = (vxid).procNumber, \
(locktag).locktag_field2 = (vxid).localTransactionId, \
(locktag).locktag_field3 = 0, \
(locktag).locktag_field4 = 0, \
(locktag).locktag_type = LOCKTAG_VIRTUALTRANSACTION, \
(locktag).locktag_lockmethodid = DEFAULT_LOCKMETHOD)
@ LOCKTAG_VIRTUALTRANSACTION
Definition: lock.h:144

Definition at line 236 of file lock.h.

◆ SetInvalidVirtualTransactionId

#define SetInvalidVirtualTransactionId (   vxid)
Value:
((vxid).procNumber = INVALID_PROC_NUMBER, \
(vxid).localTransactionId = InvalidLocalTransactionId)
#define InvalidLocalTransactionId
Definition: lock.h:66
#define INVALID_PROC_NUMBER
Definition: procnumber.h:26

Definition at line 75 of file lock.h.

◆ USER_LOCKMETHOD

#define USER_LOCKMETHOD   2

Definition at line 127 of file lock.h.

◆ VirtualTransactionIdEquals

#define VirtualTransactionIdEquals (   vxid1,
  vxid2 
)
Value:
((vxid1).procNumber == (vxid2).procNumber && \
(vxid1).localTransactionId == (vxid2).localTransactionId)

Definition at line 72 of file lock.h.

◆ VirtualTransactionIdIsRecoveredPreparedXact

#define VirtualTransactionIdIsRecoveredPreparedXact (   vxid)     ((vxid).procNumber == INVALID_PROC_NUMBER)

Definition at line 70 of file lock.h.

◆ VirtualTransactionIdIsValid

#define VirtualTransactionIdIsValid (   vxid)     (LocalTransactionIdIsValid((vxid).localTransactionId))

Definition at line 68 of file lock.h.

Typedef Documentation

◆ BlockedProcData

◆ BlockedProcsData

◆ LOCALLOCK

typedef struct LOCALLOCK LOCALLOCK

◆ LOCALLOCKOWNER

◆ LOCALLOCKTAG

typedef struct LOCALLOCKTAG LOCALLOCKTAG

◆ LOCK

typedef struct LOCK LOCK

◆ LockData

typedef struct LockData LockData

◆ LockInstanceData

◆ LockMethod

typedef const LockMethodData* LockMethod

Definition at line 117 of file lock.h.

◆ LockMethodData

◆ LOCKMETHODID

Definition at line 123 of file lock.h.

◆ LOCKTAG

typedef struct LOCKTAG LOCKTAG

◆ LockTagType

typedef enum LockTagType LockTagType

◆ PGPROC

typedef struct PGPROC PGPROC

Definition at line 29 of file lock.h.

◆ PROCLOCK

typedef struct PROCLOCK PROCLOCK

◆ PROCLOCKTAG

typedef struct PROCLOCKTAG PROCLOCKTAG

Enumeration Type Documentation

◆ DeadLockState

Enumerator
DS_NOT_YET_CHECKED 
DS_NO_DEADLOCK 
DS_SOFT_DEADLOCK 
DS_HARD_DEADLOCK 
DS_BLOCKED_BY_AUTOVACUUM 

Definition at line 509 of file lock.h.

510{
511 DS_NOT_YET_CHECKED, /* no deadlock check has run yet */
512 DS_NO_DEADLOCK, /* no deadlock detected */
513 DS_SOFT_DEADLOCK, /* deadlock avoided by queue rearrangement */
514 DS_HARD_DEADLOCK, /* deadlock, no way out but ERROR */
515 DS_BLOCKED_BY_AUTOVACUUM, /* no deadlock; queue blocked by autovacuum
516 * worker */
DeadLockState
Definition: lock.h:510
@ DS_HARD_DEADLOCK
Definition: lock.h:514
@ DS_BLOCKED_BY_AUTOVACUUM
Definition: lock.h:515
@ DS_NO_DEADLOCK
Definition: lock.h:512
@ DS_NOT_YET_CHECKED
Definition: lock.h:511
@ DS_SOFT_DEADLOCK
Definition: lock.h:513

◆ LockAcquireResult

Enumerator
LOCKACQUIRE_NOT_AVAIL 
LOCKACQUIRE_OK 
LOCKACQUIRE_ALREADY_HELD 
LOCKACQUIRE_ALREADY_CLEAR 

Definition at line 500 of file lock.h.

501{
502 LOCKACQUIRE_NOT_AVAIL, /* lock not available, and dontWait=true */
503 LOCKACQUIRE_OK, /* lock successfully acquired */
504 LOCKACQUIRE_ALREADY_HELD, /* incremented count for lock already held */
505 LOCKACQUIRE_ALREADY_CLEAR, /* incremented count for lock already clear */
LockAcquireResult
Definition: lock.h:501
@ LOCKACQUIRE_ALREADY_CLEAR
Definition: lock.h:505
@ LOCKACQUIRE_OK
Definition: lock.h:503
@ LOCKACQUIRE_ALREADY_HELD
Definition: lock.h:504
@ LOCKACQUIRE_NOT_AVAIL
Definition: lock.h:502

◆ LockTagType

Enumerator
LOCKTAG_RELATION 
LOCKTAG_RELATION_EXTEND 
LOCKTAG_DATABASE_FROZEN_IDS 
LOCKTAG_PAGE 
LOCKTAG_TUPLE 
LOCKTAG_TRANSACTION 
LOCKTAG_VIRTUALTRANSACTION 
LOCKTAG_SPECULATIVE_TOKEN 
LOCKTAG_OBJECT 
LOCKTAG_USERLOCK 
LOCKTAG_ADVISORY 
LOCKTAG_APPLY_TRANSACTION 

Definition at line 136 of file lock.h.

137{
138 LOCKTAG_RELATION, /* whole relation */
139 LOCKTAG_RELATION_EXTEND, /* the right to extend a relation */
140 LOCKTAG_DATABASE_FROZEN_IDS, /* pg_database.datfrozenxid */
141 LOCKTAG_PAGE, /* one page of a relation */
142 LOCKTAG_TUPLE, /* one physical tuple */
143 LOCKTAG_TRANSACTION, /* transaction (for waiting for xact done) */
144 LOCKTAG_VIRTUALTRANSACTION, /* virtual transaction (ditto) */
145 LOCKTAG_SPECULATIVE_TOKEN, /* speculative insertion Xid and token */
146 LOCKTAG_OBJECT, /* non-relation database object */
147 LOCKTAG_USERLOCK, /* reserved for old contrib/userlock code */
148 LOCKTAG_ADVISORY, /* advisory user locks */
149 LOCKTAG_APPLY_TRANSACTION, /* transaction being applied on a logical
150 * replication subscriber */
LockTagType
Definition: lock.h:137
@ LOCKTAG_USERLOCK
Definition: lock.h:147

Function Documentation

◆ AbortStrongLockAcquire()

void AbortStrongLockAcquire ( void  )

Definition at line 1856 of file lock.c.

1857{
1858 uint32 fasthashcode;
1859 LOCALLOCK *locallock = StrongLockInProgress;
1860
1861 if (locallock == NULL)
1862 return;
1863
1864 fasthashcode = FastPathStrongLockHashPartition(locallock->hashcode);
1865 Assert(locallock->holdsStrongLockCount == true);
1867 Assert(FastPathStrongRelationLocks->count[fasthashcode] > 0);
1868 FastPathStrongRelationLocks->count[fasthashcode]--;
1869 locallock->holdsStrongLockCount = false;
1870 StrongLockInProgress = NULL;
1872}
uint32_t uint32
Definition: c.h:502
Assert(PointerIsAligned(start, uint64))
#define FastPathStrongLockHashPartition(hashcode)
Definition: lock.c:300
static volatile FastPathStrongRelationLockData * FastPathStrongRelationLocks
Definition: lock.c:309
static LOCALLOCK * StrongLockInProgress
Definition: lock.c:324
#define SpinLockRelease(lock)
Definition: spin.h:61
#define SpinLockAcquire(lock)
Definition: spin.h:59
uint32 count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS]
Definition: lock.c:306
uint32 hashcode
Definition: lock.h:433
bool holdsStrongLockCount
Definition: lock.h:440

References Assert(), FastPathStrongRelationLockData::count, FastPathStrongLockHashPartition, FastPathStrongRelationLocks, LOCALLOCK::hashcode, LOCALLOCK::holdsStrongLockCount, FastPathStrongRelationLockData::mutex, SpinLockAcquire, SpinLockRelease, and StrongLockInProgress.

Referenced by LockAcquireExtended(), and LockErrorCleanup().

◆ AtPrepare_Locks()

void AtPrepare_Locks ( void  )

Definition at line 3434 of file lock.c.

3435{
3436 HASH_SEQ_STATUS status;
3437 LOCALLOCK *locallock;
3438
3439 /* First, verify there aren't locks of both xact and session level */
3441
3442 /* Now do the per-locallock cleanup work */
3444
3445 while ((locallock = (LOCALLOCK *) hash_seq_search(&status)) != NULL)
3446 {
3447 TwoPhaseLockRecord record;
3448 LOCALLOCKOWNER *lockOwners = locallock->lockOwners;
3449 bool haveSessionLock;
3450 bool haveXactLock;
3451 int i;
3452
3453 /*
3454 * Ignore VXID locks. We don't want those to be held by prepared
3455 * transactions, since they aren't meaningful after a restart.
3456 */
3458 continue;
3459
3460 /* Ignore it if we don't actually hold the lock */
3461 if (locallock->nLocks <= 0)
3462 continue;
3463
3464 /* Scan to see whether we hold it at session or transaction level */
3465 haveSessionLock = haveXactLock = false;
3466 for (i = locallock->numLockOwners - 1; i >= 0; i--)
3467 {
3468 if (lockOwners[i].owner == NULL)
3469 haveSessionLock = true;
3470 else
3471 haveXactLock = true;
3472 }
3473
3474 /* Ignore it if we have only session lock */
3475 if (!haveXactLock)
3476 continue;
3477
3478 /* This can't happen, because we already checked it */
3479 if (haveSessionLock)
3480 ereport(ERROR,
3481 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3482 errmsg("cannot PREPARE while holding both session-level and transaction-level locks on the same object")));
3483
3484 /*
3485 * If the local lock was taken via the fast-path, we need to move it
3486 * to the primary lock table, or just get a pointer to the existing
3487 * primary lock table entry if by chance it's already been
3488 * transferred.
3489 */
3490 if (locallock->proclock == NULL)
3491 {
3492 locallock->proclock = FastPathGetRelationLockEntry(locallock);
3493 locallock->lock = locallock->proclock->tag.myLock;
3494 }
3495
3496 /*
3497 * Arrange to not release any strong lock count held by this lock
3498 * entry. We must retain the count until the prepared transaction is
3499 * committed or rolled back.
3500 */
3501 locallock->holdsStrongLockCount = false;
3502
3503 /*
3504 * Create a 2PC record.
3505 */
3506 memcpy(&(record.locktag), &(locallock->tag.lock), sizeof(LOCKTAG));
3507 record.lockmode = locallock->tag.mode;
3508
3510 &record, sizeof(TwoPhaseLockRecord));
3511 }
3512}
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1420
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1385
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
int i
Definition: isn.c:74
static PROCLOCK * FastPathGetRelationLockEntry(LOCALLOCK *locallock)
Definition: lock.c:2914
static HTAB * LockMethodLocalHash
Definition: lock.c:320
static void CheckForSessionAndXactLocks(void)
Definition: lock.c:3346
LOCKTAG lock
Definition: lock.h:411
LOCKMODE mode
Definition: lock.h:412
LOCALLOCKOWNER * lockOwners
Definition: lock.h:439
LOCK * lock
Definition: lock.h:434
int64 nLocks
Definition: lock.h:436
int numLockOwners
Definition: lock.h:437
PROCLOCK * proclock
Definition: lock.h:435
LOCALLOCKTAG tag
Definition: lock.h:430
Definition: lock.h:166
uint8 locktag_type
Definition: lock.h:171
LOCK * myLock
Definition: lock.h:366
PROCLOCKTAG tag
Definition: lock.h:373
LOCKTAG locktag
Definition: lock.c:160
LOCKMODE lockmode
Definition: lock.c:161
void RegisterTwoPhaseRecord(TwoPhaseRmgrId rmid, uint16 info, const void *data, uint32 len)
Definition: twophase.c:1264
#define TWOPHASE_RM_LOCK_ID
Definition: twophase_rmgr.h:25

References CheckForSessionAndXactLocks(), ereport, errcode(), errmsg(), ERROR, FastPathGetRelationLockEntry(), hash_seq_init(), hash_seq_search(), LOCALLOCK::holdsStrongLockCount, i, LOCALLOCKTAG::lock, LOCALLOCK::lock, LockMethodLocalHash, TwoPhaseLockRecord::lockmode, LOCALLOCK::lockOwners, TwoPhaseLockRecord::locktag, LOCKTAG::locktag_type, LOCKTAG_VIRTUALTRANSACTION, LOCALLOCKTAG::mode, PROCLOCKTAG::myLock, LOCALLOCK::nLocks, LOCALLOCK::numLockOwners, LOCALLOCK::proclock, RegisterTwoPhaseRecord(), PROCLOCK::tag, LOCALLOCK::tag, and TWOPHASE_RM_LOCK_ID.

Referenced by PrepareTransaction().

◆ DeadLockCheck()

DeadLockState DeadLockCheck ( PGPROC proc)

Definition at line 220 of file deadlock.c.

221{
222 /* Initialize to "no constraints" */
223 nCurConstraints = 0;
225 nWaitOrders = 0;
226
227 /* Initialize to not blocked by an autovacuum worker */
229
230 /* Search for deadlocks and possible fixes */
231 if (DeadLockCheckRecurse(proc))
232 {
233 /*
234 * Call FindLockCycle one more time, to record the correct
235 * deadlockDetails[] for the basic state with no rearrangements.
236 */
237 int nSoftEdges;
238
239 TRACE_POSTGRESQL_DEADLOCK_FOUND();
240
241 nWaitOrders = 0;
242 if (!FindLockCycle(proc, possibleConstraints, &nSoftEdges))
243 elog(FATAL, "deadlock seems to have disappeared");
244
245 return DS_HARD_DEADLOCK; /* cannot find a non-deadlocked state */
246 }
247
248 /* Apply any needed rearrangements of wait queues */
249 for (int i = 0; i < nWaitOrders; i++)
250 {
251 LOCK *lock = waitOrders[i].lock;
252 PGPROC **procs = waitOrders[i].procs;
253 int nProcs = waitOrders[i].nProcs;
254 dclist_head *waitQueue = &lock->waitProcs;
255
256 Assert(nProcs == dclist_count(waitQueue));
257
258#ifdef DEBUG_DEADLOCK
259 PrintLockQueue(lock, "DeadLockCheck:");
260#endif
261
262 /* Reset the queue and re-add procs in the desired order */
263 dclist_init(waitQueue);
264 for (int j = 0; j < nProcs; j++)
265 dclist_push_tail(waitQueue, &procs[j]->links);
266
267#ifdef DEBUG_DEADLOCK
268 PrintLockQueue(lock, "rearranged to:");
269#endif
270
271 /* See if any waiters for the lock can be woken up now */
273 }
274
275 /* Return code tells caller if we had to escape a deadlock or not */
276 if (nWaitOrders > 0)
277 return DS_SOFT_DEADLOCK;
278 else if (blocking_autovacuum_proc != NULL)
280 else
281 return DS_NO_DEADLOCK;
282}
static WAIT_ORDER * waitOrders
Definition: deadlock.c:112
static bool FindLockCycle(PGPROC *checkProc, EDGE *softEdges, int *nSoftEdges)
Definition: deadlock.c:446
static bool DeadLockCheckRecurse(PGPROC *proc)
Definition: deadlock.c:312
static EDGE * possibleConstraints
Definition: deadlock.c:122
static int nWaitOrders
Definition: deadlock.c:113
static int nCurConstraints
Definition: deadlock.c:118
static PGPROC * blocking_autovacuum_proc
Definition: deadlock.c:129
static int nPossibleConstraints
Definition: deadlock.c:123
#define FATAL
Definition: elog.h:41
#define elog(elevel,...)
Definition: elog.h:225
static void dclist_push_tail(dclist_head *head, dlist_node *node)
Definition: ilist.h:709
static uint32 dclist_count(const dclist_head *head)
Definition: ilist.h:932
static void dclist_init(dclist_head *head)
Definition: ilist.h:671
int j
Definition: isn.c:75
LockMethod GetLocksMethodTable(const LOCK *lock)
Definition: lock.c:523
void ProcLockWakeup(LockMethod lockMethodTable, LOCK *lock)
Definition: proc.c:1688
Definition: lock.h:310
dclist_head waitProcs
Definition: lock.h:318
Definition: proc.h:163
PGPROC ** procs
Definition: deadlock.c:60
LOCK * lock
Definition: deadlock.c:59
int nProcs
Definition: deadlock.c:61
static struct link * links
Definition: zic.c:299

References Assert(), blocking_autovacuum_proc, dclist_count(), dclist_init(), dclist_push_tail(), DeadLockCheckRecurse(), DS_BLOCKED_BY_AUTOVACUUM, DS_HARD_DEADLOCK, DS_NO_DEADLOCK, DS_SOFT_DEADLOCK, elog, FATAL, FindLockCycle(), GetLocksMethodTable(), i, j, links, WAIT_ORDER::lock, nCurConstraints, nPossibleConstraints, WAIT_ORDER::nProcs, nWaitOrders, possibleConstraints, ProcLockWakeup(), WAIT_ORDER::procs, waitOrders, and LOCK::waitProcs.

Referenced by CheckDeadLock().

◆ DeadLockReport()

pg_noreturn void DeadLockReport ( void  )

Definition at line 1075 of file deadlock.c.

1076{
1077 StringInfoData clientbuf; /* errdetail for client */
1078 StringInfoData logbuf; /* errdetail for server log */
1079 StringInfoData locktagbuf;
1080 int i;
1081
1082 initStringInfo(&clientbuf);
1083 initStringInfo(&logbuf);
1084 initStringInfo(&locktagbuf);
1085
1086 /* Generate the "waits for" lines sent to the client */
1087 for (i = 0; i < nDeadlockDetails; i++)
1088 {
1090 int nextpid;
1091
1092 /* The last proc waits for the first one... */
1093 if (i < nDeadlockDetails - 1)
1094 nextpid = info[1].pid;
1095 else
1096 nextpid = deadlockDetails[0].pid;
1097
1098 /* reset locktagbuf to hold next object description */
1099 resetStringInfo(&locktagbuf);
1100
1101 DescribeLockTag(&locktagbuf, &info->locktag);
1102
1103 if (i > 0)
1104 appendStringInfoChar(&clientbuf, '\n');
1105
1106 appendStringInfo(&clientbuf,
1107 _("Process %d waits for %s on %s; blocked by process %d."),
1108 info->pid,
1110 info->lockmode),
1111 locktagbuf.data,
1112 nextpid);
1113 }
1114
1115 /* Duplicate all the above for the server ... */
1116 appendBinaryStringInfo(&logbuf, clientbuf.data, clientbuf.len);
1117
1118 /* ... and add info about query strings */
1119 for (i = 0; i < nDeadlockDetails; i++)
1120 {
1122
1123 appendStringInfoChar(&logbuf, '\n');
1124
1125 appendStringInfo(&logbuf,
1126 _("Process %d: %s"),
1127 info->pid,
1129 }
1130
1132
1133 ereport(ERROR,
1135 errmsg("deadlock detected"),
1136 errdetail_internal("%s", clientbuf.data),
1137 errdetail_log("%s", logbuf.data),
1138 errhint("See server log for query details.")));
1139}
const char * pgstat_get_backend_current_activity(int pid, bool checkUser)
static int nDeadlockDetails
Definition: deadlock.c:126
static DEADLOCK_INFO * deadlockDetails
Definition: deadlock.c:125
int errdetail_internal(const char *fmt,...)
Definition: elog.c:1230
int errhint(const char *fmt,...)
Definition: elog.c:1317
int errdetail_log(const char *fmt,...)
Definition: elog.c:1251
#define _(x)
Definition: elog.c:90
void DescribeLockTag(StringInfo buf, const LOCKTAG *tag)
Definition: lmgr.c:1243
const char * GetLockmodeName(LOCKMETHODID lockmethodid, LOCKMODE mode)
Definition: lock.c:4211
#define ERRCODE_T_R_DEADLOCK_DETECTED
Definition: pgbench.c:78
void pgstat_report_deadlock(void)
void resetStringInfo(StringInfo str)
Definition: stringinfo.c:126
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:145
void appendBinaryStringInfo(StringInfo str, const void *data, int datalen)
Definition: stringinfo.c:281
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:242
void initStringInfo(StringInfo str)
Definition: stringinfo.c:97
LOCKTAG locktag
Definition: deadlock.c:74
LOCKMODE lockmode
Definition: deadlock.c:75
uint8 locktag_lockmethodid
Definition: lock.h:172

References _, appendBinaryStringInfo(), appendStringInfo(), appendStringInfoChar(), StringInfoData::data, deadlockDetails, DescribeLockTag(), ereport, errcode(), ERRCODE_T_R_DEADLOCK_DETECTED, errdetail_internal(), errdetail_log(), errhint(), errmsg(), ERROR, GetLockmodeName(), i, initStringInfo(), StringInfoData::len, DEADLOCK_INFO::lockmode, DEADLOCK_INFO::locktag, LOCKTAG::locktag_lockmethodid, nDeadlockDetails, pgstat_get_backend_current_activity(), pgstat_report_deadlock(), DEADLOCK_INFO::pid, and resetStringInfo().

Referenced by LockAcquireExtended().

◆ DoLockModesConflict()

bool DoLockModesConflict ( LOCKMODE  mode1,
LOCKMODE  mode2 
)

Definition at line 619 of file lock.c.

620{
621 LockMethod lockMethodTable = LockMethods[DEFAULT_LOCKMETHOD];
622
623 if (lockMethodTable->conflictTab[mode1] & LOCKBIT_ON(mode2))
624 return true;
625
626 return false;
627}
static const LockMethod LockMethods[]
Definition: lock.c:150
#define LOCKBIT_ON(lockmode)
Definition: lock.h:85
const LOCKMASK * conflictTab
Definition: lock.h:112

References LockMethodData::conflictTab, DEFAULT_LOCKMETHOD, LOCKBIT_ON, and LockMethods.

Referenced by Do_MultiXactIdWait(), DoesMultiXactIdConflict(), initialize_reloptions(), and test_lockmode_for_conflict().

◆ GetAwaitedLock()

LOCALLOCK * GetAwaitedLock ( void  )

Definition at line 1894 of file lock.c.

1895{
1896 return awaitedLock;
1897}
static LOCALLOCK * awaitedLock
Definition: lock.c:325

References awaitedLock.

Referenced by LockErrorCleanup(), ProcessRecoveryConflictInterrupt(), and ProcSleep().

◆ GetBlockerStatusData()

BlockedProcsData * GetBlockerStatusData ( int  blocked_pid)

Definition at line 3954 of file lock.c.

3955{
3957 PGPROC *proc;
3958 int i;
3959
3961
3962 /*
3963 * Guess how much space we'll need, and preallocate. Most of the time
3964 * this will avoid needing to do repalloc while holding the LWLocks. (We
3965 * assume, but check with an Assert, that MaxBackends is enough entries
3966 * for the procs[] array; the other two could need enlargement, though.)
3967 */
3968 data->nprocs = data->nlocks = data->npids = 0;
3969 data->maxprocs = data->maxlocks = data->maxpids = MaxBackends;
3970 data->procs = (BlockedProcData *) palloc(sizeof(BlockedProcData) * data->maxprocs);
3971 data->locks = (LockInstanceData *) palloc(sizeof(LockInstanceData) * data->maxlocks);
3972 data->waiter_pids = (int *) palloc(sizeof(int) * data->maxpids);
3973
3974 /*
3975 * In order to search the ProcArray for blocked_pid and assume that that
3976 * entry won't immediately disappear under us, we must hold ProcArrayLock.
3977 * In addition, to examine the lock grouping fields of any other backend,
3978 * we must hold all the hash partition locks. (Only one of those locks is
3979 * actually relevant for any one lock group, but we can't know which one
3980 * ahead of time.) It's fairly annoying to hold all those locks
3981 * throughout this, but it's no worse than GetLockStatusData(), and it
3982 * does have the advantage that we're guaranteed to return a
3983 * self-consistent instantaneous state.
3984 */
3985 LWLockAcquire(ProcArrayLock, LW_SHARED);
3986
3987 proc = BackendPidGetProcWithLock(blocked_pid);
3988
3989 /* Nothing to do if it's gone */
3990 if (proc != NULL)
3991 {
3992 /*
3993 * Acquire lock on the entire shared lock data structure. See notes
3994 * in GetLockStatusData().
3995 */
3996 for (i = 0; i < NUM_LOCK_PARTITIONS; i++)
3998
3999 if (proc->lockGroupLeader == NULL)
4000 {
4001 /* Easy case, proc is not a lock group member */
4003 }
4004 else
4005 {
4006 /* Examine all procs in proc's lock group */
4007 dlist_iter iter;
4008
4010 {
4011 PGPROC *memberProc;
4012
4013 memberProc = dlist_container(PGPROC, lockGroupLink, iter.cur);
4015 }
4016 }
4017
4018 /*
4019 * And release locks. See notes in GetLockStatusData().
4020 */
4021 for (i = NUM_LOCK_PARTITIONS; --i >= 0;)
4023
4024 Assert(data->nprocs <= data->maxprocs);
4025 }
4026
4027 LWLockRelease(ProcArrayLock);
4028
4029 return data;
4030}
int MaxBackends
Definition: globals.c:145
#define dlist_foreach(iter, lhead)
Definition: ilist.h:623
#define dlist_container(type, membername, ptr)
Definition: ilist.h:593
static void GetSingleProcBlockerStatusData(PGPROC *blocked_proc, BlockedProcsData *data)
Definition: lock.c:4034
#define LockHashPartitionLockByIndex(i)
Definition: lock.h:530
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1179
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1899
#define NUM_LOCK_PARTITIONS
Definition: lwlock.h:97
@ LW_SHARED
Definition: lwlock.h:115
void * palloc(Size size)
Definition: mcxt.c:1317
const void * data
PGPROC * BackendPidGetProcWithLock(int pid)
Definition: procarray.c:3219
dlist_head lockGroupMembers
Definition: proc.h:306
PGPROC * lockGroupLeader
Definition: proc.h:305
dlist_node * cur
Definition: ilist.h:179

References Assert(), BackendPidGetProcWithLock(), dlist_iter::cur, data, dlist_container, dlist_foreach, GetSingleProcBlockerStatusData(), i, PGPROC::lockGroupLeader, PGPROC::lockGroupMembers, LockHashPartitionLockByIndex, LW_SHARED, LWLockAcquire(), LWLockRelease(), MaxBackends, NUM_LOCK_PARTITIONS, and palloc().

Referenced by pg_blocking_pids().

◆ GetBlockingAutoVacuumPgproc()

PGPROC * GetBlockingAutoVacuumPgproc ( void  )

Definition at line 290 of file deadlock.c.

291{
292 PGPROC *ptr;
293
296
297 return ptr;
298}

References blocking_autovacuum_proc.

Referenced by ProcSleep().

◆ GetLockConflicts()

VirtualTransactionId * GetLockConflicts ( const LOCKTAG locktag,
LOCKMODE  lockmode,
int *  countp 
)

Definition at line 3025 of file lock.c.

3026{
3027 static VirtualTransactionId *vxids;
3028 LOCKMETHODID lockmethodid = locktag->locktag_lockmethodid;
3029 LockMethod lockMethodTable;
3030 LOCK *lock;
3031 LOCKMASK conflictMask;
3032 dlist_iter proclock_iter;
3033 PROCLOCK *proclock;
3034 uint32 hashcode;
3035 LWLock *partitionLock;
3036 int count = 0;
3037 int fast_count = 0;
3038
3039 if (lockmethodid <= 0 || lockmethodid >= lengthof(LockMethods))
3040 elog(ERROR, "unrecognized lock method: %d", lockmethodid);
3041 lockMethodTable = LockMethods[lockmethodid];
3042 if (lockmode <= 0 || lockmode > lockMethodTable->numLockModes)
3043 elog(ERROR, "unrecognized lock mode: %d", lockmode);
3044
3045 /*
3046 * Allocate memory to store results, and fill with InvalidVXID. We only
3047 * need enough space for MaxBackends + max_prepared_xacts + a terminator.
3048 * InHotStandby allocate once in TopMemoryContext.
3049 */
3050 if (InHotStandby)
3051 {
3052 if (vxids == NULL)
3053 vxids = (VirtualTransactionId *)
3055 sizeof(VirtualTransactionId) *
3057 }
3058 else
3059 vxids = (VirtualTransactionId *)
3062
3063 /* Compute hash code and partition lock, and look up conflicting modes. */
3064 hashcode = LockTagHashCode(locktag);
3065 partitionLock = LockHashPartitionLock(hashcode);
3066 conflictMask = lockMethodTable->conflictTab[lockmode];
3067
3068 /*
3069 * Fast path locks might not have been entered in the primary lock table.
3070 * If the lock we're dealing with could conflict with such a lock, we must
3071 * examine each backend's fast-path array for conflicts.
3072 */
3073 if (ConflictsWithRelationFastPath(locktag, lockmode))
3074 {
3075 int i;
3076 Oid relid = locktag->locktag_field2;
3078
3079 /* fast-path group the lock belongs to */
3080 uint32 group = FAST_PATH_REL_GROUP(relid);
3081
3082 /*
3083 * Iterate over relevant PGPROCs. Anything held by a prepared
3084 * transaction will have been transferred to the primary lock table,
3085 * so we need not worry about those. This is all a bit fuzzy, because
3086 * new locks could be taken after we've visited a particular
3087 * partition, but the callers had better be prepared to deal with that
3088 * anyway, since the locks could equally well be taken between the
3089 * time we return the value and the time the caller does something
3090 * with it.
3091 */
3092 for (i = 0; i < ProcGlobal->allProcCount; i++)
3093 {
3094 PGPROC *proc = &ProcGlobal->allProcs[i];
3095 uint32 j;
3096
3097 /* A backend never blocks itself */
3098 if (proc == MyProc)
3099 continue;
3100
3102
3103 /*
3104 * If the target backend isn't referencing the same database as
3105 * the lock, then we needn't examine the individual relation IDs
3106 * at all; none of them can be relevant.
3107 *
3108 * See FastPathTransferRelationLocks() for discussion of why we do
3109 * this test after acquiring the lock.
3110 *
3111 * Also skip groups without any registered fast-path locks.
3112 */
3113 if (proc->databaseId != locktag->locktag_field1 ||
3114 proc->fpLockBits[group] == 0)
3115 {
3116 LWLockRelease(&proc->fpInfoLock);
3117 continue;
3118 }
3119
3120 for (j = 0; j < FP_LOCK_SLOTS_PER_GROUP; j++)
3121 {
3122 uint32 lockmask;
3123
3124 /* index into the whole per-backend array */
3125 uint32 f = FAST_PATH_SLOT(group, j);
3126
3127 /* Look for an allocated slot matching the given relid. */
3128 if (relid != proc->fpRelId[f])
3129 continue;
3130 lockmask = FAST_PATH_GET_BITS(proc, f);
3131 if (!lockmask)
3132 continue;
3133 lockmask <<= FAST_PATH_LOCKNUMBER_OFFSET;
3134
3135 /*
3136 * There can only be one entry per relation, so if we found it
3137 * and it doesn't conflict, we can skip the rest of the slots.
3138 */
3139 if ((lockmask & conflictMask) == 0)
3140 break;
3141
3142 /* Conflict! */
3143 GET_VXID_FROM_PGPROC(vxid, *proc);
3144
3146 vxids[count++] = vxid;
3147 /* else, xact already committed or aborted */
3148
3149 /* No need to examine remaining slots. */
3150 break;
3151 }
3152
3153 LWLockRelease(&proc->fpInfoLock);
3154 }
3155 }
3156
3157 /* Remember how many fast-path conflicts we found. */
3158 fast_count = count;
3159
3160 /*
3161 * Look up the lock object matching the tag.
3162 */
3163 LWLockAcquire(partitionLock, LW_SHARED);
3164
3166 locktag,
3167 hashcode,
3168 HASH_FIND,
3169 NULL);
3170 if (!lock)
3171 {
3172 /*
3173 * If the lock object doesn't exist, there is nothing holding a lock
3174 * on this lockable object.
3175 */
3176 LWLockRelease(partitionLock);
3177 vxids[count].procNumber = INVALID_PROC_NUMBER;
3179 if (countp)
3180 *countp = count;
3181 return vxids;
3182 }
3183
3184 /*
3185 * Examine each existing holder (or awaiter) of the lock.
3186 */
3187 dlist_foreach(proclock_iter, &lock->procLocks)
3188 {
3189 proclock = dlist_container(PROCLOCK, lockLink, proclock_iter.cur);
3190
3191 if (conflictMask & proclock->holdMask)
3192 {
3193 PGPROC *proc = proclock->tag.myProc;
3194
3195 /* A backend never blocks itself */
3196 if (proc != MyProc)
3197 {
3199
3200 GET_VXID_FROM_PGPROC(vxid, *proc);
3201
3203 {
3204 int i;
3205
3206 /* Avoid duplicate entries. */
3207 for (i = 0; i < fast_count; ++i)
3208 if (VirtualTransactionIdEquals(vxids[i], vxid))
3209 break;
3210 if (i >= fast_count)
3211 vxids[count++] = vxid;
3212 }
3213 /* else, xact already committed or aborted */
3214 }
3215 }
3216 }
3217
3218 LWLockRelease(partitionLock);
3219
3220 if (count > MaxBackends + max_prepared_xacts) /* should never happen */
3221 elog(PANIC, "too many conflicting locks found");
3222
3223 vxids[count].procNumber = INVALID_PROC_NUMBER;
3225 if (countp)
3226 *countp = count;
3227 return vxids;
3228}
#define lengthof(array)
Definition: c.h:759
void * hash_search_with_hash_value(HTAB *hashp, const void *keyPtr, uint32 hashvalue, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:968
#define PANIC
Definition: elog.h:42
@ HASH_FIND
Definition: hsearch.h:113
#define FAST_PATH_LOCKNUMBER_OFFSET
Definition: lock.c:239
#define FAST_PATH_REL_GROUP(rel)
Definition: lock.c:214
#define FAST_PATH_SLOT(group, index)
Definition: lock.c:221
#define ConflictsWithRelationFastPath(locktag, mode)
Definition: lock.c:270
static HTAB * LockMethodLockHash
Definition: lock.c:318
#define FAST_PATH_GET_BITS(proc, n)
Definition: lock.c:242
uint32 LockTagHashCode(const LOCKTAG *locktag)
Definition: lock.c:553
uint16 LOCKMETHODID
Definition: lock.h:123
#define VirtualTransactionIdIsValid(vxid)
Definition: lock.h:68
#define LockHashPartitionLock(hashcode)
Definition: lock.h:527
#define GET_VXID_FROM_PGPROC(vxid_dst, proc)
Definition: lock.h:78
#define VirtualTransactionIdEquals(vxid1, vxid2)
Definition: lock.h:72
int LOCKMASK
Definition: lockdefs.h:25
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:1181
void * palloc0(Size size)
Definition: mcxt.c:1347
MemoryContext TopMemoryContext
Definition: mcxt.c:149
unsigned int Oid
Definition: postgres_ext.h:32
#define FP_LOCK_SLOTS_PER_GROUP
Definition: proc.h:84
PGPROC * MyProc
Definition: proc.c:66
PROC_HDR * ProcGlobal
Definition: proc.c:78
uint32 locktag_field1
Definition: lock.h:167
uint32 locktag_field2
Definition: lock.h:168
dlist_head procLocks
Definition: lock.h:317
Definition: lwlock.h:42
int numLockModes
Definition: lock.h:111
LWLock fpInfoLock
Definition: proc.h:294
Oid * fpRelId
Definition: proc.h:296
Oid databaseId
Definition: proc.h:208
uint64 * fpLockBits
Definition: proc.h:295
PGPROC * myProc
Definition: lock.h:367
Definition: lock.h:371
LOCKMASK holdMask
Definition: lock.h:377
PGPROC * allProcs
Definition: proc.h:372
uint32 allProcCount
Definition: proc.h:390
LocalTransactionId localTransactionId
Definition: lock.h:63
ProcNumber procNumber
Definition: lock.h:62
int max_prepared_xacts
Definition: twophase.c:115
#define InHotStandby
Definition: xlogutils.h:60

References PROC_HDR::allProcCount, PROC_HDR::allProcs, ConflictsWithRelationFastPath, LockMethodData::conflictTab, dlist_iter::cur, PGPROC::databaseId, dlist_container, dlist_foreach, elog, ERROR, FAST_PATH_GET_BITS, FAST_PATH_LOCKNUMBER_OFFSET, FAST_PATH_REL_GROUP, FAST_PATH_SLOT, FP_LOCK_SLOTS_PER_GROUP, PGPROC::fpInfoLock, PGPROC::fpLockBits, PGPROC::fpRelId, GET_VXID_FROM_PGPROC, HASH_FIND, hash_search_with_hash_value(), PROCLOCK::holdMask, i, InHotStandby, INVALID_PROC_NUMBER, InvalidLocalTransactionId, j, lengthof, VirtualTransactionId::localTransactionId, LockHashPartitionLock, LockMethodLockHash, LockMethods, LOCKTAG::locktag_field1, LOCKTAG::locktag_field2, LOCKTAG::locktag_lockmethodid, LockTagHashCode(), LW_SHARED, LWLockAcquire(), LWLockRelease(), max_prepared_xacts, MaxBackends, MemoryContextAlloc(), MyProc, PROCLOCKTAG::myProc, LockMethodData::numLockModes, palloc0(), PANIC, ProcGlobal, LOCK::procLocks, VirtualTransactionId::procNumber, PROCLOCK::tag, TopMemoryContext, VirtualTransactionIdEquals, and VirtualTransactionIdIsValid.

Referenced by ProcSleep(), ResolveRecoveryConflictWithLock(), and WaitForLockersMultiple().

◆ GetLockmodeName()

const char * GetLockmodeName ( LOCKMETHODID  lockmethodid,
LOCKMODE  mode 
)

Definition at line 4211 of file lock.c.

4212{
4213 Assert(lockmethodid > 0 && lockmethodid < lengthof(LockMethods));
4214 Assert(mode > 0 && mode <= LockMethods[lockmethodid]->numLockModes);
4215 return LockMethods[lockmethodid]->lockModeNames[mode];
4216}
static PgChecksumMode mode
Definition: pg_checksums.c:55
const char *const * lockModeNames
Definition: lock.h:113

References Assert(), lengthof, LockMethods, LockMethodData::lockModeNames, and mode.

Referenced by DeadLockReport(), LockAcquireExtended(), pg_lock_status(), and ProcSleep().

◆ GetLocksMethodTable()

LockMethod GetLocksMethodTable ( const LOCK lock)

Definition at line 523 of file lock.c.

524{
525 LOCKMETHODID lockmethodid = LOCK_LOCKMETHOD(*lock);
526
527 Assert(0 < lockmethodid && lockmethodid < lengthof(LockMethods));
528 return LockMethods[lockmethodid];
529}
#define LOCK_LOCKMETHOD(lock)
Definition: lock.h:325

References Assert(), lengthof, LOCK_LOCKMETHOD, and LockMethods.

Referenced by DeadLockCheck(), and FindLockCycleRecurseMember().

◆ GetLockStatusData()

LockData * GetLockStatusData ( void  )

Definition at line 3751 of file lock.c.

3752{
3753 LockData *data;
3754 PROCLOCK *proclock;
3755 HASH_SEQ_STATUS seqstat;
3756 int els;
3757 int el;
3758 int i;
3759
3760 data = (LockData *) palloc(sizeof(LockData));
3761
3762 /* Guess how much space we'll need. */
3763 els = MaxBackends;
3764 el = 0;
3765 data->locks = (LockInstanceData *) palloc(sizeof(LockInstanceData) * els);
3766
3767 /*
3768 * First, we iterate through the per-backend fast-path arrays, locking
3769 * them one at a time. This might produce an inconsistent picture of the
3770 * system state, but taking all of those LWLocks at the same time seems
3771 * impractical (in particular, note MAX_SIMUL_LWLOCKS). It shouldn't
3772 * matter too much, because none of these locks can be involved in lock
3773 * conflicts anyway - anything that might must be present in the main lock
3774 * table. (For the same reason, we don't sweat about making leaderPid
3775 * completely valid. We cannot safely dereference another backend's
3776 * lockGroupLeader field without holding all lock partition locks, and
3777 * it's not worth that.)
3778 */
3779 for (i = 0; i < ProcGlobal->allProcCount; ++i)
3780 {
3781 PGPROC *proc = &ProcGlobal->allProcs[i];
3782
3783 /* Skip backends with pid=0, as they don't hold fast-path locks */
3784 if (proc->pid == 0)
3785 continue;
3786
3788
3789 for (uint32 g = 0; g < FastPathLockGroupsPerBackend; g++)
3790 {
3791 /* Skip groups without registered fast-path locks */
3792 if (proc->fpLockBits[g] == 0)
3793 continue;
3794
3795 for (int j = 0; j < FP_LOCK_SLOTS_PER_GROUP; j++)
3796 {
3797 LockInstanceData *instance;
3798 uint32 f = FAST_PATH_SLOT(g, j);
3799 uint32 lockbits = FAST_PATH_GET_BITS(proc, f);
3800
3801 /* Skip unallocated slots */
3802 if (!lockbits)
3803 continue;
3804
3805 if (el >= els)
3806 {
3807 els += MaxBackends;
3808 data->locks = (LockInstanceData *)
3809 repalloc(data->locks, sizeof(LockInstanceData) * els);
3810 }
3811
3812 instance = &data->locks[el];
3813 SET_LOCKTAG_RELATION(instance->locktag, proc->databaseId,
3814 proc->fpRelId[f]);
3815 instance->holdMask = lockbits << FAST_PATH_LOCKNUMBER_OFFSET;
3816 instance->waitLockMode = NoLock;
3817 instance->vxid.procNumber = proc->vxid.procNumber;
3818 instance->vxid.localTransactionId = proc->vxid.lxid;
3819 instance->pid = proc->pid;
3820 instance->leaderPid = proc->pid;
3821 instance->fastpath = true;
3822
3823 /*
3824 * Successfully taking fast path lock means there were no
3825 * conflicting locks.
3826 */
3827 instance->waitStart = 0;
3828
3829 el++;
3830 }
3831 }
3832
3833 if (proc->fpVXIDLock)
3834 {
3836 LockInstanceData *instance;
3837
3838 if (el >= els)
3839 {
3840 els += MaxBackends;
3841 data->locks = (LockInstanceData *)
3842 repalloc(data->locks, sizeof(LockInstanceData) * els);
3843 }
3844
3845 vxid.procNumber = proc->vxid.procNumber;
3847
3848 instance = &data->locks[el];
3849 SET_LOCKTAG_VIRTUALTRANSACTION(instance->locktag, vxid);
3850 instance->holdMask = LOCKBIT_ON(ExclusiveLock);
3851 instance->waitLockMode = NoLock;
3852 instance->vxid.procNumber = proc->vxid.procNumber;
3853 instance->vxid.localTransactionId = proc->vxid.lxid;
3854 instance->pid = proc->pid;
3855 instance->leaderPid = proc->pid;
3856 instance->fastpath = true;
3857 instance->waitStart = 0;
3858
3859 el++;
3860 }
3861
3862 LWLockRelease(&proc->fpInfoLock);
3863 }
3864
3865 /*
3866 * Next, acquire lock on the entire shared lock data structure. We do
3867 * this so that, at least for locks in the primary lock table, the state
3868 * will be self-consistent.
3869 *
3870 * Since this is a read-only operation, we take shared instead of
3871 * exclusive lock. There's not a whole lot of point to this, because all
3872 * the normal operations require exclusive lock, but it doesn't hurt
3873 * anything either. It will at least allow two backends to do
3874 * GetLockStatusData in parallel.
3875 *
3876 * Must grab LWLocks in partition-number order to avoid LWLock deadlock.
3877 */
3878 for (i = 0; i < NUM_LOCK_PARTITIONS; i++)
3880
3881 /* Now we can safely count the number of proclocks */
3883 if (data->nelements > els)
3884 {
3885 els = data->nelements;
3886 data->locks = (LockInstanceData *)
3887 repalloc(data->locks, sizeof(LockInstanceData) * els);
3888 }
3889
3890 /* Now scan the tables to copy the data */
3892
3893 while ((proclock = (PROCLOCK *) hash_seq_search(&seqstat)))
3894 {
3895 PGPROC *proc = proclock->tag.myProc;
3896 LOCK *lock = proclock->tag.myLock;
3897 LockInstanceData *instance = &data->locks[el];
3898
3899 memcpy(&instance->locktag, &lock->tag, sizeof(LOCKTAG));
3900 instance->holdMask = proclock->holdMask;
3901 if (proc->waitLock == proclock->tag.myLock)
3902 instance->waitLockMode = proc->waitLockMode;
3903 else
3904 instance->waitLockMode = NoLock;
3905 instance->vxid.procNumber = proc->vxid.procNumber;
3906 instance->vxid.localTransactionId = proc->vxid.lxid;
3907 instance->pid = proc->pid;
3908 instance->leaderPid = proclock->groupLeader->pid;
3909 instance->fastpath = false;
3910 instance->waitStart = (TimestampTz) pg_atomic_read_u64(&proc->waitStart);
3911
3912 el++;
3913 }
3914
3915 /*
3916 * And release locks. We do this in reverse order for two reasons: (1)
3917 * Anyone else who needs more than one of the locks will be trying to lock
3918 * them in increasing order; we don't want to release the other process
3919 * until it can get all the locks it needs. (2) This avoids O(N^2)
3920 * behavior inside LWLockRelease.
3921 */
3922 for (i = NUM_LOCK_PARTITIONS; --i >= 0;)
3924
3925 Assert(el == data->nelements);
3926
3927 return data;
3928}
static uint64 pg_atomic_read_u64(volatile pg_atomic_uint64 *ptr)
Definition: atomics.h:467
int64 TimestampTz
Definition: timestamp.h:39
long hash_get_num_entries(HTAB *hashp)
Definition: dynahash.c:1341
int FastPathLockGroupsPerBackend
Definition: lock.c:202
static HTAB * LockMethodProcLockHash
Definition: lock.c:319
#define SET_LOCKTAG_VIRTUALTRANSACTION(locktag, vxid)
Definition: lock.h:236
#define SET_LOCKTAG_RELATION(locktag, dboid, reloid)
Definition: lock.h:182
#define NoLock
Definition: lockdefs.h:34
#define ExclusiveLock
Definition: lockdefs.h:42
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1544
LOCKTAG tag
Definition: lock.h:312
Definition: lock.h:467
LOCKMASK holdMask
Definition: lock.h:456
LOCKMODE waitLockMode
Definition: lock.h:457
bool fastpath
Definition: lock.h:463
LOCKTAG locktag
Definition: lock.h:455
TimestampTz waitStart
Definition: lock.h:459
int leaderPid
Definition: lock.h:462
VirtualTransactionId vxid
Definition: lock.h:458
struct PGPROC::@127 vxid
LocalTransactionId lxid
Definition: proc.h:201
pg_atomic_uint64 waitStart
Definition: proc.h:238
bool fpVXIDLock
Definition: proc.h:297
ProcNumber procNumber
Definition: proc.h:196
int pid
Definition: proc.h:183
LOCK * waitLock
Definition: proc.h:233
LOCKMODE waitLockMode
Definition: proc.h:235
LocalTransactionId fpLocalTransactionId
Definition: proc.h:298
PGPROC * groupLeader
Definition: lock.h:376

References PROC_HDR::allProcCount, PROC_HDR::allProcs, Assert(), data, PGPROC::databaseId, ExclusiveLock, FAST_PATH_GET_BITS, FAST_PATH_LOCKNUMBER_OFFSET, FAST_PATH_SLOT, LockInstanceData::fastpath, FastPathLockGroupsPerBackend, FP_LOCK_SLOTS_PER_GROUP, PGPROC::fpInfoLock, PGPROC::fpLocalTransactionId, PGPROC::fpLockBits, PGPROC::fpRelId, PGPROC::fpVXIDLock, PROCLOCK::groupLeader, hash_get_num_entries(), hash_seq_init(), hash_seq_search(), PROCLOCK::holdMask, LockInstanceData::holdMask, i, j, LockInstanceData::leaderPid, VirtualTransactionId::localTransactionId, LOCKBIT_ON, LockHashPartitionLockByIndex, LockMethodProcLockHash, LockInstanceData::locktag, LW_SHARED, LWLockAcquire(), LWLockRelease(), PGPROC::lxid, MaxBackends, PROCLOCKTAG::myLock, PROCLOCKTAG::myProc, NoLock, NUM_LOCK_PARTITIONS, palloc(), pg_atomic_read_u64(), LockInstanceData::pid, PGPROC::pid, ProcGlobal, VirtualTransactionId::procNumber, PGPROC::procNumber, repalloc(), SET_LOCKTAG_RELATION, SET_LOCKTAG_VIRTUALTRANSACTION, LOCK::tag, PROCLOCK::tag, LockInstanceData::vxid, PGPROC::vxid, PGPROC::waitLock, LockInstanceData::waitLockMode, PGPROC::waitLockMode, LockInstanceData::waitStart, and PGPROC::waitStart.

Referenced by pg_lock_status().

◆ GetLockTagsMethodTable()

LockMethod GetLockTagsMethodTable ( const LOCKTAG locktag)

Definition at line 535 of file lock.c.

536{
537 LOCKMETHODID lockmethodid = (LOCKMETHODID) locktag->locktag_lockmethodid;
538
539 Assert(0 < lockmethodid && lockmethodid < lengthof(LockMethods));
540 return LockMethods[lockmethodid];
541}

References Assert(), lengthof, LockMethods, and LOCKTAG::locktag_lockmethodid.

Referenced by pg_blocking_pids().

◆ GetRunningTransactionLocks()

xl_standby_lock * GetRunningTransactionLocks ( int *  nlocks)

Definition at line 4129 of file lock.c.

4130{
4131 xl_standby_lock *accessExclusiveLocks;
4132 PROCLOCK *proclock;
4133 HASH_SEQ_STATUS seqstat;
4134 int i;
4135 int index;
4136 int els;
4137
4138 /*
4139 * Acquire lock on the entire shared lock data structure.
4140 *
4141 * Must grab LWLocks in partition-number order to avoid LWLock deadlock.
4142 */
4143 for (i = 0; i < NUM_LOCK_PARTITIONS; i++)
4145
4146 /* Now we can safely count the number of proclocks */
4148
4149 /*
4150 * Allocating enough space for all locks in the lock table is overkill,
4151 * but it's more convenient and faster than having to enlarge the array.
4152 */
4153 accessExclusiveLocks = palloc(els * sizeof(xl_standby_lock));
4154
4155 /* Now scan the tables to copy the data */
4157
4158 /*
4159 * If lock is a currently granted AccessExclusiveLock then it will have
4160 * just one proclock holder, so locks are never accessed twice in this
4161 * particular case. Don't copy this code for use elsewhere because in the
4162 * general case this will give you duplicate locks when looking at
4163 * non-exclusive lock types.
4164 */
4165 index = 0;
4166 while ((proclock = (PROCLOCK *) hash_seq_search(&seqstat)))
4167 {
4168 /* make sure this definition matches the one used in LockAcquire */
4169 if ((proclock->holdMask & LOCKBIT_ON(AccessExclusiveLock)) &&
4171 {
4172 PGPROC *proc = proclock->tag.myProc;
4173 LOCK *lock = proclock->tag.myLock;
4174 TransactionId xid = proc->xid;
4175
4176 /*
4177 * Don't record locks for transactions if we know they have
4178 * already issued their WAL record for commit but not yet released
4179 * lock. It is still possible that we see locks held by already
4180 * complete transactions, if they haven't yet zeroed their xids.
4181 */
4182 if (!TransactionIdIsValid(xid))
4183 continue;
4184
4185 accessExclusiveLocks[index].xid = xid;
4186 accessExclusiveLocks[index].dbOid = lock->tag.locktag_field1;
4187 accessExclusiveLocks[index].relOid = lock->tag.locktag_field2;
4188
4189 index++;
4190 }
4191 }
4192
4193 Assert(index <= els);
4194
4195 /*
4196 * And release locks. We do this in reverse order for two reasons: (1)
4197 * Anyone else who needs more than one of the locks will be trying to lock
4198 * them in increasing order; we don't want to release the other process
4199 * until it can get all the locks it needs. (2) This avoids O(N^2)
4200 * behavior inside LWLockRelease.
4201 */
4202 for (i = NUM_LOCK_PARTITIONS; --i >= 0;)
4204
4205 *nlocks = index;
4206 return accessExclusiveLocks;
4207}
uint32 TransactionId
Definition: c.h:623
#define AccessExclusiveLock
Definition: lockdefs.h:43
TransactionId xid
Definition: proc.h:173
Definition: type.h:96
TransactionId xid
Definition: lockdefs.h:53
#define TransactionIdIsValid(xid)
Definition: transam.h:41

References AccessExclusiveLock, Assert(), xl_standby_lock::dbOid, hash_get_num_entries(), hash_seq_init(), hash_seq_search(), PROCLOCK::holdMask, i, LOCKBIT_ON, LockHashPartitionLockByIndex, LockMethodProcLockHash, LOCKTAG::locktag_field1, LOCKTAG::locktag_field2, LOCKTAG_RELATION, LOCKTAG::locktag_type, LW_SHARED, LWLockAcquire(), LWLockRelease(), PROCLOCKTAG::myLock, PROCLOCKTAG::myProc, NUM_LOCK_PARTITIONS, palloc(), xl_standby_lock::relOid, LOCK::tag, PROCLOCK::tag, TransactionIdIsValid, xl_standby_lock::xid, and PGPROC::xid.

Referenced by LogStandbySnapshot().

◆ GrantAwaitedLock()

void GrantAwaitedLock ( void  )

Definition at line 1885 of file lock.c.

1886{
1888}
static ResourceOwner awaitedOwner
Definition: lock.c:326
static void GrantLockLocal(LOCALLOCK *locallock, ResourceOwner owner)
Definition: lock.c:1788

References awaitedLock, awaitedOwner, and GrantLockLocal().

Referenced by LockErrorCleanup().

◆ GrantLock()

void GrantLock ( LOCK lock,
PROCLOCK proclock,
LOCKMODE  lockmode 
)

Definition at line 1654 of file lock.c.

1655{
1656 lock->nGranted++;
1657 lock->granted[lockmode]++;
1658 lock->grantMask |= LOCKBIT_ON(lockmode);
1659 if (lock->granted[lockmode] == lock->requested[lockmode])
1660 lock->waitMask &= LOCKBIT_OFF(lockmode);
1661 proclock->holdMask |= LOCKBIT_ON(lockmode);
1662 LOCK_PRINT("GrantLock", lock, lockmode);
1663 Assert((lock->nGranted > 0) && (lock->granted[lockmode] > 0));
1664 Assert(lock->nGranted <= lock->nRequested);
1665}
#define LOCK_PRINT(where, lock, type)
Definition: lock.c:402
#define LOCKBIT_OFF(lockmode)
Definition: lock.h:86
int nRequested
Definition: lock.h:320
int requested[MAX_LOCKMODES]
Definition: lock.h:319
int granted[MAX_LOCKMODES]
Definition: lock.h:321
LOCKMASK grantMask
Definition: lock.h:315
LOCKMASK waitMask
Definition: lock.h:316
int nGranted
Definition: lock.h:322

References Assert(), LOCK::granted, LOCK::grantMask, PROCLOCK::holdMask, LOCK_PRINT, LOCKBIT_OFF, LOCKBIT_ON, LOCK::nGranted, LOCK::nRequested, LOCK::requested, and LOCK::waitMask.

Referenced by FastPathGetRelationLockEntry(), FastPathTransferRelationLocks(), JoinWaitQueue(), lock_twophase_recover(), LockAcquireExtended(), ProcLockWakeup(), and VirtualXactLock().

◆ InitDeadLockChecking()

void InitDeadLockChecking ( void  )

Definition at line 144 of file deadlock.c.

145{
146 MemoryContext oldcxt;
147
148 /* Make sure allocations are permanent */
150
151 /*
152 * FindLockCycle needs at most MaxBackends entries in visitedProcs[] and
153 * deadlockDetails[].
154 */
155 visitedProcs = (PGPROC **) palloc(MaxBackends * sizeof(PGPROC *));
157
158 /*
159 * TopoSort needs to consider at most MaxBackends wait-queue entries, and
160 * it needn't run concurrently with FindLockCycle.
161 */
162 topoProcs = visitedProcs; /* re-use this space */
163 beforeConstraints = (int *) palloc(MaxBackends * sizeof(int));
164 afterConstraints = (int *) palloc(MaxBackends * sizeof(int));
165
166 /*
167 * We need to consider rearranging at most MaxBackends/2 wait queues
168 * (since it takes at least two waiters in a queue to create a soft edge),
169 * and the expanded form of the wait queues can't involve more than
170 * MaxBackends total waiters.
171 */
173 palloc((MaxBackends / 2) * sizeof(WAIT_ORDER));
174 waitOrderProcs = (PGPROC **) palloc(MaxBackends * sizeof(PGPROC *));
175
176 /*
177 * Allow at most MaxBackends distinct constraints in a configuration. (Is
178 * this enough? In practice it seems it should be, but I don't quite see
179 * how to prove it. If we run out, we might fail to find a workable wait
180 * queue rearrangement even though one exists.) NOTE that this number
181 * limits the maximum recursion depth of DeadLockCheckRecurse. Making it
182 * really big might potentially allow a stack-overflow problem.
183 */
186
187 /*
188 * Allow up to 3*MaxBackends constraints to be saved without having to
189 * re-run TestConfiguration. (This is probably more than enough, but we
190 * can survive if we run low on space by doing excess runs of
191 * TestConfiguration to re-compute constraint lists each time needed.) The
192 * last MaxBackends entries in possibleConstraints[] are reserved as
193 * output workspace for FindLockCycle.
194 */
196 "MAX_BACKENDS_BITS too big for * 4");
199 (EDGE *) palloc(maxPossibleConstraints * sizeof(EDGE));
200
201 MemoryContextSwitchTo(oldcxt);
202}
#define StaticAssertStmt(condition, errmessage)
Definition: c.h:909
static int maxPossibleConstraints
Definition: deadlock.c:124
static PGPROC ** waitOrderProcs
Definition: deadlock.c:114
static PGPROC ** visitedProcs
Definition: deadlock.c:103
static int * beforeConstraints
Definition: deadlock.c:108
static int * afterConstraints
Definition: deadlock.c:109
static int maxCurConstraints
Definition: deadlock.c:119
static EDGE * curConstraints
Definition: deadlock.c:117
static PGPROC ** topoProcs
Definition: deadlock.c:107
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
#define MAX_BACKENDS_BITS
Definition: procnumber.h:38
Definition: deadlock.c:48

References afterConstraints, beforeConstraints, curConstraints, deadlockDetails, MAX_BACKENDS_BITS, MaxBackends, maxCurConstraints, maxPossibleConstraints, MemoryContextSwitchTo(), palloc(), possibleConstraints, StaticAssertStmt, TopMemoryContext, topoProcs, visitedProcs, waitOrderProcs, and waitOrders.

Referenced by InitProcess().

◆ InitLockManagerAccess()

void InitLockManagerAccess ( void  )

Definition at line 501 of file lock.c.

502{
503 /*
504 * Allocate non-shared hash table for LOCALLOCK structs. This stores lock
505 * counts and resource owner information.
506 */
507 HASHCTL info;
508
509 info.keysize = sizeof(LOCALLOCKTAG);
510 info.entrysize = sizeof(LOCALLOCK);
511
512 LockMethodLocalHash = hash_create("LOCALLOCK hash",
513 16,
514 &info,
516}
HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:352
#define HASH_ELEM
Definition: hsearch.h:95
#define HASH_BLOBS
Definition: hsearch.h:97
struct LOCALLOCK LOCALLOCK
struct LOCALLOCKTAG LOCALLOCKTAG
Size keysize
Definition: hsearch.h:75
Size entrysize
Definition: hsearch.h:76

References HASHCTL::entrysize, HASH_BLOBS, hash_create(), HASH_ELEM, HASHCTL::keysize, and LockMethodLocalHash.

Referenced by BaseInit().

◆ lock_twophase_postabort()

void lock_twophase_postabort ( TransactionId  xid,
uint16  info,
void *  recdata,
uint32  len 
)

Definition at line 4554 of file lock.c.

4556{
4557 lock_twophase_postcommit(xid, info, recdata, len);
4558}
void lock_twophase_postcommit(TransactionId xid, uint16 info, void *recdata, uint32 len)
Definition: lock.c:4528
const void size_t len

References len, and lock_twophase_postcommit().

◆ lock_twophase_postcommit()

void lock_twophase_postcommit ( TransactionId  xid,
uint16  info,
void *  recdata,
uint32  len 
)

Definition at line 4528 of file lock.c.

4530{
4531 TwoPhaseLockRecord *rec = (TwoPhaseLockRecord *) recdata;
4532 PGPROC *proc = TwoPhaseGetDummyProc(xid, true);
4533 LOCKTAG *locktag;
4534 LOCKMETHODID lockmethodid;
4535 LockMethod lockMethodTable;
4536
4537 Assert(len == sizeof(TwoPhaseLockRecord));
4538 locktag = &rec->locktag;
4539 lockmethodid = locktag->locktag_lockmethodid;
4540
4541 if (lockmethodid <= 0 || lockmethodid >= lengthof(LockMethods))
4542 elog(ERROR, "unrecognized lock method: %d", lockmethodid);
4543 lockMethodTable = LockMethods[lockmethodid];
4544
4545 LockRefindAndRelease(lockMethodTable, proc, locktag, rec->lockmode, true);
4546}
static void LockRefindAndRelease(LockMethod lockMethodTable, PGPROC *proc, LOCKTAG *locktag, LOCKMODE lockmode, bool decrement_strong_lock_count)
Definition: lock.c:3242
PGPROC * TwoPhaseGetDummyProc(TransactionId xid, bool lock_held)
Definition: twophase.c:918

References Assert(), elog, ERROR, len, lengthof, LockMethods, TwoPhaseLockRecord::lockmode, LockRefindAndRelease(), TwoPhaseLockRecord::locktag, LOCKTAG::locktag_lockmethodid, and TwoPhaseGetDummyProc().

Referenced by lock_twophase_postabort().

◆ lock_twophase_recover()

void lock_twophase_recover ( TransactionId  xid,
uint16  info,
void *  recdata,
uint32  len 
)

Definition at line 4315 of file lock.c.

4317{
4318 TwoPhaseLockRecord *rec = (TwoPhaseLockRecord *) recdata;
4319 PGPROC *proc = TwoPhaseGetDummyProc(xid, false);
4320 LOCKTAG *locktag;
4321 LOCKMODE lockmode;
4322 LOCKMETHODID lockmethodid;
4323 LOCK *lock;
4324 PROCLOCK *proclock;
4325 PROCLOCKTAG proclocktag;
4326 bool found;
4327 uint32 hashcode;
4328 uint32 proclock_hashcode;
4329 int partition;
4330 LWLock *partitionLock;
4331 LockMethod lockMethodTable;
4332
4333 Assert(len == sizeof(TwoPhaseLockRecord));
4334 locktag = &rec->locktag;
4335 lockmode = rec->lockmode;
4336 lockmethodid = locktag->locktag_lockmethodid;
4337
4338 if (lockmethodid <= 0 || lockmethodid >= lengthof(LockMethods))
4339 elog(ERROR, "unrecognized lock method: %d", lockmethodid);
4340 lockMethodTable = LockMethods[lockmethodid];
4341
4342 hashcode = LockTagHashCode(locktag);
4343 partition = LockHashPartition(hashcode);
4344 partitionLock = LockHashPartitionLock(hashcode);
4345
4346 LWLockAcquire(partitionLock, LW_EXCLUSIVE);
4347
4348 /*
4349 * Find or create a lock with this tag.
4350 */
4352 locktag,
4353 hashcode,
4355 &found);
4356 if (!lock)
4357 {
4358 LWLockRelease(partitionLock);
4359 ereport(ERROR,
4360 (errcode(ERRCODE_OUT_OF_MEMORY),
4361 errmsg("out of shared memory"),
4362 errhint("You might need to increase \"%s\".", "max_locks_per_transaction")));
4363 }
4364
4365 /*
4366 * if it's a new lock object, initialize it
4367 */
4368 if (!found)
4369 {
4370 lock->grantMask = 0;
4371 lock->waitMask = 0;
4372 dlist_init(&lock->procLocks);
4373 dclist_init(&lock->waitProcs);
4374 lock->nRequested = 0;
4375 lock->nGranted = 0;
4376 MemSet(lock->requested, 0, sizeof(int) * MAX_LOCKMODES);
4377 MemSet(lock->granted, 0, sizeof(int) * MAX_LOCKMODES);
4378 LOCK_PRINT("lock_twophase_recover: new", lock, lockmode);
4379 }
4380 else
4381 {
4382 LOCK_PRINT("lock_twophase_recover: found", lock, lockmode);
4383 Assert((lock->nRequested >= 0) && (lock->requested[lockmode] >= 0));
4384 Assert((lock->nGranted >= 0) && (lock->granted[lockmode] >= 0));
4385 Assert(lock->nGranted <= lock->nRequested);
4386 }
4387
4388 /*
4389 * Create the hash key for the proclock table.
4390 */
4391 proclocktag.myLock = lock;
4392 proclocktag.myProc = proc;
4393
4394 proclock_hashcode = ProcLockHashCode(&proclocktag, hashcode);
4395
4396 /*
4397 * Find or create a proclock entry with this tag
4398 */
4400 &proclocktag,
4401 proclock_hashcode,
4403 &found);
4404 if (!proclock)
4405 {
4406 /* Oops, not enough shmem for the proclock */
4407 if (lock->nRequested == 0)
4408 {
4409 /*
4410 * There are no other requestors of this lock, so garbage-collect
4411 * the lock object. We *must* do this to avoid a permanent leak
4412 * of shared memory, because there won't be anything to cause
4413 * anyone to release the lock object later.
4414 */
4417 &(lock->tag),
4418 hashcode,
4420 NULL))
4421 elog(PANIC, "lock table corrupted");
4422 }
4423 LWLockRelease(partitionLock);
4424 ereport(ERROR,
4425 (errcode(ERRCODE_OUT_OF_MEMORY),
4426 errmsg("out of shared memory"),
4427 errhint("You might need to increase \"%s\".", "max_locks_per_transaction")));
4428 }
4429
4430 /*
4431 * If new, initialize the new entry
4432 */
4433 if (!found)
4434 {
4435 Assert(proc->lockGroupLeader == NULL);
4436 proclock->groupLeader = proc;
4437 proclock->holdMask = 0;
4438 proclock->releaseMask = 0;
4439 /* Add proclock to appropriate lists */
4440 dlist_push_tail(&lock->procLocks, &proclock->lockLink);
4441 dlist_push_tail(&proc->myProcLocks[partition],
4442 &proclock->procLink);
4443 PROCLOCK_PRINT("lock_twophase_recover: new", proclock);
4444 }
4445 else
4446 {
4447 PROCLOCK_PRINT("lock_twophase_recover: found", proclock);
4448 Assert((proclock->holdMask & ~lock->grantMask) == 0);
4449 }
4450
4451 /*
4452 * lock->nRequested and lock->requested[] count the total number of
4453 * requests, whether granted or waiting, so increment those immediately.
4454 */
4455 lock->nRequested++;
4456 lock->requested[lockmode]++;
4457 Assert((lock->nRequested > 0) && (lock->requested[lockmode] > 0));
4458
4459 /*
4460 * We shouldn't already hold the desired lock.
4461 */
4462 if (proclock->holdMask & LOCKBIT_ON(lockmode))
4463 elog(ERROR, "lock %s on object %u/%u/%u is already held",
4464 lockMethodTable->lockModeNames[lockmode],
4465 lock->tag.locktag_field1, lock->tag.locktag_field2,
4466 lock->tag.locktag_field3);
4467
4468 /*
4469 * We ignore any possible conflicts and just grant ourselves the lock. Not
4470 * only because we don't bother, but also to avoid deadlocks when
4471 * switching from standby to normal mode. See function comment.
4472 */
4473 GrantLock(lock, proclock, lockmode);
4474
4475 /*
4476 * Bump strong lock count, to make sure any fast-path lock requests won't
4477 * be granted without consulting the primary lock table.
4478 */
4479 if (ConflictsWithRelationFastPath(&lock->tag, lockmode))
4480 {
4481 uint32 fasthashcode = FastPathStrongLockHashPartition(hashcode);
4482
4484 FastPathStrongRelationLocks->count[fasthashcode]++;
4486 }
4487
4488 LWLockRelease(partitionLock);
4489}
#define MemSet(start, val, len)
Definition: c.h:991
@ HASH_REMOVE
Definition: hsearch.h:115
@ HASH_ENTER_NULL
Definition: hsearch.h:116
static void dlist_init(dlist_head *head)
Definition: ilist.h:314
static bool dlist_is_empty(const dlist_head *head)
Definition: ilist.h:336
static void dlist_push_tail(dlist_head *head, dlist_node *node)
Definition: ilist.h:364
static uint32 ProcLockHashCode(const PROCLOCKTAG *proclocktag, uint32 hashcode)
Definition: lock.c:601
void GrantLock(LOCK *lock, PROCLOCK *proclock, LOCKMODE lockmode)
Definition: lock.c:1654
#define PROCLOCK_PRINT(where, proclockP)
Definition: lock.c:403
#define MAX_LOCKMODES
Definition: lock.h:83
#define LockHashPartition(hashcode)
Definition: lock.h:525
int LOCKMODE
Definition: lockdefs.h:26
@ LW_EXCLUSIVE
Definition: lwlock.h:114
uint32 locktag_field3
Definition: lock.h:169
dlist_head myProcLocks[NUM_LOCK_PARTITIONS]
Definition: proc.h:262
dlist_node lockLink
Definition: lock.h:379
LOCKMASK releaseMask
Definition: lock.h:378
dlist_node procLink
Definition: lock.h:380

References Assert(), ConflictsWithRelationFastPath, FastPathStrongRelationLockData::count, dclist_init(), dlist_init(), dlist_is_empty(), dlist_push_tail(), elog, ereport, errcode(), errhint(), errmsg(), ERROR, FastPathStrongLockHashPartition, FastPathStrongRelationLocks, LOCK::granted, GrantLock(), LOCK::grantMask, PROCLOCK::groupLeader, HASH_ENTER_NULL, HASH_REMOVE, hash_search_with_hash_value(), PROCLOCK::holdMask, len, lengthof, LOCK_PRINT, LOCKBIT_ON, PGPROC::lockGroupLeader, LockHashPartition, LockHashPartitionLock, PROCLOCK::lockLink, LockMethodLockHash, LockMethodProcLockHash, LockMethods, TwoPhaseLockRecord::lockmode, LockMethodData::lockModeNames, TwoPhaseLockRecord::locktag, LOCKTAG::locktag_field1, LOCKTAG::locktag_field2, LOCKTAG::locktag_field3, LOCKTAG::locktag_lockmethodid, LockTagHashCode(), LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MAX_LOCKMODES, MemSet, FastPathStrongRelationLockData::mutex, PROCLOCKTAG::myLock, PROCLOCKTAG::myProc, PGPROC::myProcLocks, LOCK::nGranted, LOCK::nRequested, PANIC, PROCLOCK::procLink, PROCLOCK_PRINT, ProcLockHashCode(), LOCK::procLocks, PROCLOCK::releaseMask, LOCK::requested, SpinLockAcquire, SpinLockRelease, LOCK::tag, TwoPhaseGetDummyProc(), LOCK::waitMask, and LOCK::waitProcs.

◆ lock_twophase_standby_recover()

void lock_twophase_standby_recover ( TransactionId  xid,
uint16  info,
void *  recdata,
uint32  len 
)

Definition at line 4496 of file lock.c.

4498{
4499 TwoPhaseLockRecord *rec = (TwoPhaseLockRecord *) recdata;
4500 LOCKTAG *locktag;
4501 LOCKMODE lockmode;
4502 LOCKMETHODID lockmethodid;
4503
4504 Assert(len == sizeof(TwoPhaseLockRecord));
4505 locktag = &rec->locktag;
4506 lockmode = rec->lockmode;
4507 lockmethodid = locktag->locktag_lockmethodid;
4508
4509 if (lockmethodid <= 0 || lockmethodid >= lengthof(LockMethods))
4510 elog(ERROR, "unrecognized lock method: %d", lockmethodid);
4511
4512 if (lockmode == AccessExclusiveLock &&
4513 locktag->locktag_type == LOCKTAG_RELATION)
4514 {
4516 locktag->locktag_field1 /* dboid */ ,
4517 locktag->locktag_field2 /* reloid */ );
4518 }
4519}
void StandbyAcquireAccessExclusiveLock(TransactionId xid, Oid dbOid, Oid relOid)
Definition: standby.c:985

References AccessExclusiveLock, Assert(), elog, ERROR, len, lengthof, LockMethods, TwoPhaseLockRecord::lockmode, TwoPhaseLockRecord::locktag, LOCKTAG::locktag_field1, LOCKTAG::locktag_field2, LOCKTAG::locktag_lockmethodid, LOCKTAG_RELATION, LOCKTAG::locktag_type, and StandbyAcquireAccessExclusiveLock().

◆ LockAcquire()

LockAcquireResult LockAcquire ( const LOCKTAG locktag,
LOCKMODE  lockmode,
bool  sessionLock,
bool  dontWait 
)

◆ LockAcquireExtended()

LockAcquireResult LockAcquireExtended ( const LOCKTAG locktag,
LOCKMODE  lockmode,
bool  sessionLock,
bool  dontWait,
bool  reportMemoryError,
LOCALLOCK **  locallockp,
bool  logLockFailure 
)

Definition at line 832 of file lock.c.

839{
840 LOCKMETHODID lockmethodid = locktag->locktag_lockmethodid;
841 LockMethod lockMethodTable;
842 LOCALLOCKTAG localtag;
843 LOCALLOCK *locallock;
844 LOCK *lock;
845 PROCLOCK *proclock;
846 bool found;
847 ResourceOwner owner;
848 uint32 hashcode;
849 LWLock *partitionLock;
850 bool found_conflict;
851 ProcWaitStatus waitResult;
852 bool log_lock = false;
853
854 if (lockmethodid <= 0 || lockmethodid >= lengthof(LockMethods))
855 elog(ERROR, "unrecognized lock method: %d", lockmethodid);
856 lockMethodTable = LockMethods[lockmethodid];
857 if (lockmode <= 0 || lockmode > lockMethodTable->numLockModes)
858 elog(ERROR, "unrecognized lock mode: %d", lockmode);
859
860 if (RecoveryInProgress() && !InRecovery &&
861 (locktag->locktag_type == LOCKTAG_OBJECT ||
862 locktag->locktag_type == LOCKTAG_RELATION) &&
863 lockmode > RowExclusiveLock)
865 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
866 errmsg("cannot acquire lock mode %s on database objects while recovery is in progress",
867 lockMethodTable->lockModeNames[lockmode]),
868 errhint("Only RowExclusiveLock or less can be acquired on database objects during recovery.")));
869
870#ifdef LOCK_DEBUG
871 if (LOCK_DEBUG_ENABLED(locktag))
872 elog(LOG, "LockAcquire: lock [%u,%u] %s",
873 locktag->locktag_field1, locktag->locktag_field2,
874 lockMethodTable->lockModeNames[lockmode]);
875#endif
876
877 /* Identify owner for lock */
878 if (sessionLock)
879 owner = NULL;
880 else
881 owner = CurrentResourceOwner;
882
883 /*
884 * Find or create a LOCALLOCK entry for this lock and lockmode
885 */
886 MemSet(&localtag, 0, sizeof(localtag)); /* must clear padding */
887 localtag.lock = *locktag;
888 localtag.mode = lockmode;
889
891 &localtag,
892 HASH_ENTER, &found);
893
894 /*
895 * if it's a new locallock object, initialize it
896 */
897 if (!found)
898 {
899 locallock->lock = NULL;
900 locallock->proclock = NULL;
901 locallock->hashcode = LockTagHashCode(&(localtag.lock));
902 locallock->nLocks = 0;
903 locallock->holdsStrongLockCount = false;
904 locallock->lockCleared = false;
905 locallock->numLockOwners = 0;
906 locallock->maxLockOwners = 8;
907 locallock->lockOwners = NULL; /* in case next line fails */
908 locallock->lockOwners = (LOCALLOCKOWNER *)
910 locallock->maxLockOwners * sizeof(LOCALLOCKOWNER));
911 }
912 else
913 {
914 /* Make sure there will be room to remember the lock */
915 if (locallock->numLockOwners >= locallock->maxLockOwners)
916 {
917 int newsize = locallock->maxLockOwners * 2;
918
919 locallock->lockOwners = (LOCALLOCKOWNER *)
920 repalloc(locallock->lockOwners,
921 newsize * sizeof(LOCALLOCKOWNER));
922 locallock->maxLockOwners = newsize;
923 }
924 }
925 hashcode = locallock->hashcode;
926
927 if (locallockp)
928 *locallockp = locallock;
929
930 /*
931 * If we already hold the lock, we can just increase the count locally.
932 *
933 * If lockCleared is already set, caller need not worry about absorbing
934 * sinval messages related to the lock's object.
935 */
936 if (locallock->nLocks > 0)
937 {
938 GrantLockLocal(locallock, owner);
939 if (locallock->lockCleared)
941 else
943 }
944
945 /*
946 * We don't acquire any other heavyweight lock while holding the relation
947 * extension lock. We do allow to acquire the same relation extension
948 * lock more than once but that case won't reach here.
949 */
950 Assert(!IsRelationExtensionLockHeld);
951
952 /*
953 * Prepare to emit a WAL record if acquisition of this lock needs to be
954 * replayed in a standby server.
955 *
956 * Here we prepare to log; after lock is acquired we'll issue log record.
957 * This arrangement simplifies error recovery in case the preparation step
958 * fails.
959 *
960 * Only AccessExclusiveLocks can conflict with lock types that read-only
961 * transactions can acquire in a standby server. Make sure this definition
962 * matches the one in GetRunningTransactionLocks().
963 */
964 if (lockmode >= AccessExclusiveLock &&
965 locktag->locktag_type == LOCKTAG_RELATION &&
968 {
970 log_lock = true;
971 }
972
973 /*
974 * Attempt to take lock via fast path, if eligible. But if we remember
975 * having filled up the fast path array, we don't attempt to make any
976 * further use of it until we release some locks. It's possible that some
977 * other backend has transferred some of those locks to the shared hash
978 * table, leaving space free, but it's not worth acquiring the LWLock just
979 * to check. It's also possible that we're acquiring a second or third
980 * lock type on a relation we have already locked using the fast-path, but
981 * for now we don't worry about that case either.
982 */
983 if (EligibleForRelationFastPath(locktag, lockmode) &&
985 {
986 uint32 fasthashcode = FastPathStrongLockHashPartition(hashcode);
987 bool acquired;
988
989 /*
990 * LWLockAcquire acts as a memory sequencing point, so it's safe to
991 * assume that any strong locker whose increment to
992 * FastPathStrongRelationLocks->counts becomes visible after we test
993 * it has yet to begin to transfer fast-path locks.
994 */
996 if (FastPathStrongRelationLocks->count[fasthashcode] != 0)
997 acquired = false;
998 else
999 acquired = FastPathGrantRelationLock(locktag->locktag_field2,
1000 lockmode);
1002 if (acquired)
1003 {
1004 /*
1005 * The locallock might contain stale pointers to some old shared
1006 * objects; we MUST reset these to null before considering the
1007 * lock to be acquired via fast-path.
1008 */
1009 locallock->lock = NULL;
1010 locallock->proclock = NULL;
1011 GrantLockLocal(locallock, owner);
1012 return LOCKACQUIRE_OK;
1013 }
1014 }
1015
1016 /*
1017 * If this lock could potentially have been taken via the fast-path by
1018 * some other backend, we must (temporarily) disable further use of the
1019 * fast-path for this lock tag, and migrate any locks already taken via
1020 * this method to the main lock table.
1021 */
1022 if (ConflictsWithRelationFastPath(locktag, lockmode))
1023 {
1024 uint32 fasthashcode = FastPathStrongLockHashPartition(hashcode);
1025
1026 BeginStrongLockAcquire(locallock, fasthashcode);
1027 if (!FastPathTransferRelationLocks(lockMethodTable, locktag,
1028 hashcode))
1029 {
1031 if (locallock->nLocks == 0)
1032 RemoveLocalLock(locallock);
1033 if (locallockp)
1034 *locallockp = NULL;
1035 if (reportMemoryError)
1036 ereport(ERROR,
1037 (errcode(ERRCODE_OUT_OF_MEMORY),
1038 errmsg("out of shared memory"),
1039 errhint("You might need to increase \"%s\".", "max_locks_per_transaction")));
1040 else
1041 return LOCKACQUIRE_NOT_AVAIL;
1042 }
1043 }
1044
1045 /*
1046 * We didn't find the lock in our LOCALLOCK table, and we didn't manage to
1047 * take it via the fast-path, either, so we've got to mess with the shared
1048 * lock table.
1049 */
1050 partitionLock = LockHashPartitionLock(hashcode);
1051
1052 LWLockAcquire(partitionLock, LW_EXCLUSIVE);
1053
1054 /*
1055 * Find or create lock and proclock entries with this tag
1056 *
1057 * Note: if the locallock object already existed, it might have a pointer
1058 * to the lock already ... but we should not assume that that pointer is
1059 * valid, since a lock object with zero hold and request counts can go
1060 * away anytime. So we have to use SetupLockInTable() to recompute the
1061 * lock and proclock pointers, even if they're already set.
1062 */
1063 proclock = SetupLockInTable(lockMethodTable, MyProc, locktag,
1064 hashcode, lockmode);
1065 if (!proclock)
1066 {
1068 LWLockRelease(partitionLock);
1069 if (locallock->nLocks == 0)
1070 RemoveLocalLock(locallock);
1071 if (locallockp)
1072 *locallockp = NULL;
1073 if (reportMemoryError)
1074 ereport(ERROR,
1075 (errcode(ERRCODE_OUT_OF_MEMORY),
1076 errmsg("out of shared memory"),
1077 errhint("You might need to increase \"%s\".", "max_locks_per_transaction")));
1078 else
1079 return LOCKACQUIRE_NOT_AVAIL;
1080 }
1081 locallock->proclock = proclock;
1082 lock = proclock->tag.myLock;
1083 locallock->lock = lock;
1084
1085 /*
1086 * If lock requested conflicts with locks requested by waiters, must join
1087 * wait queue. Otherwise, check for conflict with already-held locks.
1088 * (That's last because most complex check.)
1089 */
1090 if (lockMethodTable->conflictTab[lockmode] & lock->waitMask)
1091 found_conflict = true;
1092 else
1093 found_conflict = LockCheckConflicts(lockMethodTable, lockmode,
1094 lock, proclock);
1095
1096 if (!found_conflict)
1097 {
1098 /* No conflict with held or previously requested locks */
1099 GrantLock(lock, proclock, lockmode);
1100 waitResult = PROC_WAIT_STATUS_OK;
1101 }
1102 else
1103 {
1104 /*
1105 * Join the lock's wait queue. We call this even in the dontWait
1106 * case, because JoinWaitQueue() may discover that we can acquire the
1107 * lock immediately after all.
1108 */
1109 waitResult = JoinWaitQueue(locallock, lockMethodTable, dontWait);
1110 }
1111
1112 if (waitResult == PROC_WAIT_STATUS_ERROR)
1113 {
1114 /*
1115 * We're not getting the lock because a deadlock was detected already
1116 * while trying to join the wait queue, or because we would have to
1117 * wait but the caller requested no blocking.
1118 *
1119 * Undo the changes to shared entries before releasing the partition
1120 * lock.
1121 */
1123
1124 if (proclock->holdMask == 0)
1125 {
1126 uint32 proclock_hashcode;
1127
1128 proclock_hashcode = ProcLockHashCode(&proclock->tag,
1129 hashcode);
1130 dlist_delete(&proclock->lockLink);
1131 dlist_delete(&proclock->procLink);
1133 &(proclock->tag),
1134 proclock_hashcode,
1136 NULL))
1137 elog(PANIC, "proclock table corrupted");
1138 }
1139 else
1140 PROCLOCK_PRINT("LockAcquire: did not join wait queue", proclock);
1141 lock->nRequested--;
1142 lock->requested[lockmode]--;
1143 LOCK_PRINT("LockAcquire: did not join wait queue",
1144 lock, lockmode);
1145 Assert((lock->nRequested > 0) &&
1146 (lock->requested[lockmode] >= 0));
1147 Assert(lock->nGranted <= lock->nRequested);
1148 LWLockRelease(partitionLock);
1149 if (locallock->nLocks == 0)
1150 RemoveLocalLock(locallock);
1151
1152 if (dontWait)
1153 {
1154 /*
1155 * Log lock holders and waiters as a detail log message if
1156 * logLockFailure = true and lock acquisition fails with dontWait
1157 * = true
1158 */
1159 if (logLockFailure)
1160 {
1162 lock_waiters_sbuf,
1163 lock_holders_sbuf;
1164 const char *modename;
1165 int lockHoldersNum = 0;
1166
1168 initStringInfo(&lock_waiters_sbuf);
1169 initStringInfo(&lock_holders_sbuf);
1170
1171 DescribeLockTag(&buf, &locallock->tag.lock);
1172 modename = GetLockmodeName(locallock->tag.lock.locktag_lockmethodid,
1173 lockmode);
1174
1175 /* Gather a list of all lock holders and waiters */
1176 LWLockAcquire(partitionLock, LW_SHARED);
1177 GetLockHoldersAndWaiters(locallock, &lock_holders_sbuf,
1178 &lock_waiters_sbuf, &lockHoldersNum);
1179 LWLockRelease(partitionLock);
1180
1181 ereport(LOG,
1182 (errmsg("process %d could not obtain %s on %s",
1183 MyProcPid, modename, buf.data),
1185 "Process holding the lock: %s, Wait queue: %s.",
1186 "Processes holding the lock: %s, Wait queue: %s.",
1187 lockHoldersNum,
1188 lock_holders_sbuf.data,
1189 lock_waiters_sbuf.data)));
1190
1191 pfree(buf.data);
1192 pfree(lock_holders_sbuf.data);
1193 pfree(lock_waiters_sbuf.data);
1194 }
1195 if (locallockp)
1196 *locallockp = NULL;
1197 return LOCKACQUIRE_NOT_AVAIL;
1198 }
1199 else
1200 {
1202 /* DeadLockReport() will not return */
1203 }
1204 }
1205
1206 /*
1207 * We are now in the lock queue, or the lock was already granted. If
1208 * queued, go to sleep.
1209 */
1210 if (waitResult == PROC_WAIT_STATUS_WAITING)
1211 {
1212 Assert(!dontWait);
1213 PROCLOCK_PRINT("LockAcquire: sleeping on lock", proclock);
1214 LOCK_PRINT("LockAcquire: sleeping on lock", lock, lockmode);
1215 LWLockRelease(partitionLock);
1216
1217 waitResult = WaitOnLock(locallock, owner);
1218
1219 /*
1220 * NOTE: do not do any material change of state between here and
1221 * return. All required changes in locktable state must have been
1222 * done when the lock was granted to us --- see notes in WaitOnLock.
1223 */
1224
1225 if (waitResult == PROC_WAIT_STATUS_ERROR)
1226 {
1227 /*
1228 * We failed as a result of a deadlock, see CheckDeadLock(). Quit
1229 * now.
1230 */
1231 Assert(!dontWait);
1233 /* DeadLockReport() will not return */
1234 }
1235 }
1236 else
1237 LWLockRelease(partitionLock);
1238 Assert(waitResult == PROC_WAIT_STATUS_OK);
1239
1240 /* The lock was granted to us. Update the local lock entry accordingly */
1241 Assert((proclock->holdMask & LOCKBIT_ON(lockmode)) != 0);
1242 GrantLockLocal(locallock, owner);
1243
1244 /*
1245 * Lock state is fully up-to-date now; if we error out after this, no
1246 * special error cleanup is required.
1247 */
1249
1250 /*
1251 * Emit a WAL record if acquisition of this lock needs to be replayed in a
1252 * standby server.
1253 */
1254 if (log_lock)
1255 {
1256 /*
1257 * Decode the locktag back to the original values, to avoid sending
1258 * lots of empty bytes with every message. See lock.h to check how a
1259 * locktag is defined for LOCKTAG_RELATION
1260 */
1262 locktag->locktag_field2);
1263 }
1264
1265 return LOCKACQUIRE_OK;
1266}
void DeadLockReport(void)
Definition: deadlock.c:1075
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:955
int errdetail_log_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n,...)
Definition: elog.c:1272
#define LOG
Definition: elog.h:31
int MyProcPid
Definition: globals.c:46
@ HASH_ENTER
Definition: hsearch.h:114
static void dlist_delete(dlist_node *node)
Definition: ilist.h:405
static void RemoveLocalLock(LOCALLOCK *locallock)
Definition: lock.c:1472
static PROCLOCK * SetupLockInTable(LockMethod lockMethodTable, PGPROC *proc, const LOCKTAG *locktag, uint32 hashcode, LOCKMODE lockmode)
Definition: lock.c:1279
static bool FastPathTransferRelationLocks(LockMethod lockMethodTable, const LOCKTAG *locktag, uint32 hashcode)
Definition: lock.c:2817
void AbortStrongLockAcquire(void)
Definition: lock.c:1856
static bool FastPathGrantRelationLock(Oid relid, LOCKMODE lockmode)
Definition: lock.c:2738
static int FastPathLocalUseCounts[FP_LOCK_GROUPS_PER_BACKEND_MAX]
Definition: lock.c:176
static ProcWaitStatus WaitOnLock(LOCALLOCK *locallock, ResourceOwner owner)
Definition: lock.c:1919
#define EligibleForRelationFastPath(locktag, mode)
Definition: lock.c:264
static void BeginStrongLockAcquire(LOCALLOCK *locallock, uint32 fasthashcode)
Definition: lock.c:1820
bool LockCheckConflicts(LockMethod lockMethodTable, LOCKMODE lockmode, LOCK *lock, PROCLOCK *proclock)
Definition: lock.c:1525
static void FinishStrongLockAcquire(void)
Definition: lock.c:1846
#define RowExclusiveLock
Definition: lockdefs.h:38
void pfree(void *pointer)
Definition: mcxt.c:1524
static char * buf
Definition: pg_test_fsync.c:72
ProcWaitStatus
Definition: proc.h:124
@ PROC_WAIT_STATUS_OK
Definition: proc.h:125
@ PROC_WAIT_STATUS_WAITING
Definition: proc.h:126
@ PROC_WAIT_STATUS_ERROR
Definition: proc.h:127
ResourceOwner CurrentResourceOwner
Definition: resowner.c:173
ProcWaitStatus JoinWaitQueue(LOCALLOCK *locallock, LockMethod lockMethodTable, bool dontWait)
Definition: proc.c:1089
void GetLockHoldersAndWaiters(LOCALLOCK *locallock, StringInfo lock_holders_sbuf, StringInfo lock_waiters_sbuf, int *lockHoldersNum)
Definition: proc.c:1849
void LogAccessExclusiveLockPrepare(void)
Definition: standby.c:1436
void LogAccessExclusiveLock(Oid dbOid, Oid relOid)
Definition: standby.c:1419
int maxLockOwners
Definition: lock.h:438
bool lockCleared
Definition: lock.h:441
bool RecoveryInProgress(void)
Definition: xlog.c:6380
#define XLogStandbyInfoActive()
Definition: xlog.h:123
bool InRecovery
Definition: xlogutils.c:50

References AbortStrongLockAcquire(), AccessExclusiveLock, Assert(), BeginStrongLockAcquire(), buf, ConflictsWithRelationFastPath, LockMethodData::conflictTab, FastPathStrongRelationLockData::count, CurrentResourceOwner, StringInfoData::data, DeadLockReport(), DescribeLockTag(), dlist_delete(), EligibleForRelationFastPath, elog, ereport, errcode(), errdetail_log_plural(), errhint(), errmsg(), ERROR, FAST_PATH_REL_GROUP, FastPathGrantRelationLock(), FastPathLocalUseCounts, FastPathStrongLockHashPartition, FastPathStrongRelationLocks, FastPathTransferRelationLocks(), FinishStrongLockAcquire(), FP_LOCK_SLOTS_PER_GROUP, PGPROC::fpInfoLock, GetLockHoldersAndWaiters(), GetLockmodeName(), GrantLock(), GrantLockLocal(), HASH_ENTER, HASH_REMOVE, hash_search(), hash_search_with_hash_value(), LOCALLOCK::hashcode, PROCLOCK::holdMask, LOCALLOCK::holdsStrongLockCount, initStringInfo(), InRecovery, JoinWaitQueue(), lengthof, LOCALLOCKTAG::lock, LOCALLOCK::lock, LOCK_PRINT, LOCKACQUIRE_ALREADY_CLEAR, LOCKACQUIRE_ALREADY_HELD, LOCKACQUIRE_NOT_AVAIL, LOCKACQUIRE_OK, LOCKBIT_ON, LockCheckConflicts(), LOCALLOCK::lockCleared, LockHashPartitionLock, PROCLOCK::lockLink, LockMethodLocalHash, LockMethodProcLockHash, LockMethods, LockMethodData::lockModeNames, LOCALLOCK::lockOwners, LOCKTAG::locktag_field1, LOCKTAG::locktag_field2, LOCKTAG::locktag_lockmethodid, LOCKTAG_OBJECT, LOCKTAG_RELATION, LOCKTAG::locktag_type, LockTagHashCode(), LOG, LogAccessExclusiveLock(), LogAccessExclusiveLockPrepare(), LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockRelease(), LOCALLOCK::maxLockOwners, MemoryContextAlloc(), MemSet, LOCALLOCKTAG::mode, PROCLOCKTAG::myLock, MyProc, MyProcPid, LOCK::nGranted, LOCALLOCK::nLocks, LOCK::nRequested, LockMethodData::numLockModes, LOCALLOCK::numLockOwners, PANIC, pfree(), PROC_WAIT_STATUS_ERROR, PROC_WAIT_STATUS_OK, PROC_WAIT_STATUS_WAITING, PROCLOCK::procLink, LOCALLOCK::proclock, PROCLOCK_PRINT, ProcLockHashCode(), RecoveryInProgress(), RemoveLocalLock(), repalloc(), LOCK::requested, RowExclusiveLock, SetupLockInTable(), PROCLOCK::tag, LOCALLOCK::tag, TopMemoryContext, LOCK::waitMask, WaitOnLock(), and XLogStandbyInfoActive.

Referenced by ConditionalLockDatabaseObject(), ConditionalLockRelation(), ConditionalLockRelationOid(), ConditionalLockSharedObject(), ConditionalLockTuple(), ConditionalXactLockTableWait(), LockAcquire(), LockRelation(), LockRelationId(), and LockRelationOid().

◆ LockCheckConflicts()

bool LockCheckConflicts ( LockMethod  lockMethodTable,
LOCKMODE  lockmode,
LOCK lock,
PROCLOCK proclock 
)

Definition at line 1525 of file lock.c.

1529{
1530 int numLockModes = lockMethodTable->numLockModes;
1531 LOCKMASK myLocks;
1532 int conflictMask = lockMethodTable->conflictTab[lockmode];
1533 int conflictsRemaining[MAX_LOCKMODES];
1534 int totalConflictsRemaining = 0;
1535 dlist_iter proclock_iter;
1536 int i;
1537
1538 /*
1539 * first check for global conflicts: If no locks conflict with my request,
1540 * then I get the lock.
1541 *
1542 * Checking for conflict: lock->grantMask represents the types of
1543 * currently held locks. conflictTable[lockmode] has a bit set for each
1544 * type of lock that conflicts with request. Bitwise compare tells if
1545 * there is a conflict.
1546 */
1547 if (!(conflictMask & lock->grantMask))
1548 {
1549 PROCLOCK_PRINT("LockCheckConflicts: no conflict", proclock);
1550 return false;
1551 }
1552
1553 /*
1554 * Rats. Something conflicts. But it could still be my own lock, or a
1555 * lock held by another member of my locking group. First, figure out how
1556 * many conflicts remain after subtracting out any locks I hold myself.
1557 */
1558 myLocks = proclock->holdMask;
1559 for (i = 1; i <= numLockModes; i++)
1560 {
1561 if ((conflictMask & LOCKBIT_ON(i)) == 0)
1562 {
1563 conflictsRemaining[i] = 0;
1564 continue;
1565 }
1566 conflictsRemaining[i] = lock->granted[i];
1567 if (myLocks & LOCKBIT_ON(i))
1568 --conflictsRemaining[i];
1569 totalConflictsRemaining += conflictsRemaining[i];
1570 }
1571
1572 /* If no conflicts remain, we get the lock. */
1573 if (totalConflictsRemaining == 0)
1574 {
1575 PROCLOCK_PRINT("LockCheckConflicts: resolved (simple)", proclock);
1576 return false;
1577 }
1578
1579 /* If no group locking, it's definitely a conflict. */
1580 if (proclock->groupLeader == MyProc && MyProc->lockGroupLeader == NULL)
1581 {
1582 Assert(proclock->tag.myProc == MyProc);
1583 PROCLOCK_PRINT("LockCheckConflicts: conflicting (simple)",
1584 proclock);
1585 return true;
1586 }
1587
1588 /*
1589 * The relation extension lock conflict even between the group members.
1590 */
1592 {
1593 PROCLOCK_PRINT("LockCheckConflicts: conflicting (group)",
1594 proclock);
1595 return true;
1596 }
1597
1598 /*
1599 * Locks held in conflicting modes by members of our own lock group are
1600 * not real conflicts; we can subtract those out and see if we still have
1601 * a conflict. This is O(N) in the number of processes holding or
1602 * awaiting locks on this object. We could improve that by making the
1603 * shared memory state more complex (and larger) but it doesn't seem worth
1604 * it.
1605 */
1606 dlist_foreach(proclock_iter, &lock->procLocks)
1607 {
1608 PROCLOCK *otherproclock =
1609 dlist_container(PROCLOCK, lockLink, proclock_iter.cur);
1610
1611 if (proclock != otherproclock &&
1612 proclock->groupLeader == otherproclock->groupLeader &&
1613 (otherproclock->holdMask & conflictMask) != 0)
1614 {
1615 int intersectMask = otherproclock->holdMask & conflictMask;
1616
1617 for (i = 1; i <= numLockModes; i++)
1618 {
1619 if ((intersectMask & LOCKBIT_ON(i)) != 0)
1620 {
1621 if (conflictsRemaining[i] <= 0)
1622 elog(PANIC, "proclocks held do not match lock");
1623 conflictsRemaining[i]--;
1624 totalConflictsRemaining--;
1625 }
1626 }
1627
1628 if (totalConflictsRemaining == 0)
1629 {
1630 PROCLOCK_PRINT("LockCheckConflicts: resolved (group)",
1631 proclock);
1632 return false;
1633 }
1634 }
1635 }
1636
1637 /* Nope, it's a real conflict. */
1638 PROCLOCK_PRINT("LockCheckConflicts: conflicting (group)", proclock);
1639 return true;
1640}
#define LOCK_LOCKTAG(lock)
Definition: lock.h:326

References Assert(), LockMethodData::conflictTab, dlist_iter::cur, dlist_container, dlist_foreach, elog, LOCK::granted, LOCK::grantMask, PROCLOCK::groupLeader, PROCLOCK::holdMask, i, LOCK_LOCKTAG, LOCKBIT_ON, PGPROC::lockGroupLeader, LOCKTAG_RELATION_EXTEND, MAX_LOCKMODES, MyProc, PROCLOCKTAG::myProc, LockMethodData::numLockModes, PANIC, PROCLOCK_PRINT, LOCK::procLocks, and PROCLOCK::tag.

Referenced by JoinWaitQueue(), LockAcquireExtended(), and ProcLockWakeup().

◆ LockHasWaiters()

bool LockHasWaiters ( const LOCKTAG locktag,
LOCKMODE  lockmode,
bool  sessionLock 
)

Definition at line 692 of file lock.c.

693{
694 LOCKMETHODID lockmethodid = locktag->locktag_lockmethodid;
695 LockMethod lockMethodTable;
696 LOCALLOCKTAG localtag;
697 LOCALLOCK *locallock;
698 LOCK *lock;
699 PROCLOCK *proclock;
700 LWLock *partitionLock;
701 bool hasWaiters = false;
702
703 if (lockmethodid <= 0 || lockmethodid >= lengthof(LockMethods))
704 elog(ERROR, "unrecognized lock method: %d", lockmethodid);
705 lockMethodTable = LockMethods[lockmethodid];
706 if (lockmode <= 0 || lockmode > lockMethodTable->numLockModes)
707 elog(ERROR, "unrecognized lock mode: %d", lockmode);
708
709#ifdef LOCK_DEBUG
710 if (LOCK_DEBUG_ENABLED(locktag))
711 elog(LOG, "LockHasWaiters: lock [%u,%u] %s",
712 locktag->locktag_field1, locktag->locktag_field2,
713 lockMethodTable->lockModeNames[lockmode]);
714#endif
715
716 /*
717 * Find the LOCALLOCK entry for this lock and lockmode
718 */
719 MemSet(&localtag, 0, sizeof(localtag)); /* must clear padding */
720 localtag.lock = *locktag;
721 localtag.mode = lockmode;
722
724 &localtag,
725 HASH_FIND, NULL);
726
727 /*
728 * let the caller print its own error message, too. Do not ereport(ERROR).
729 */
730 if (!locallock || locallock->nLocks <= 0)
731 {
732 elog(WARNING, "you don't own a lock of type %s",
733 lockMethodTable->lockModeNames[lockmode]);
734 return false;
735 }
736
737 /*
738 * Check the shared lock table.
739 */
740 partitionLock = LockHashPartitionLock(locallock->hashcode);
741
742 LWLockAcquire(partitionLock, LW_SHARED);
743
744 /*
745 * We don't need to re-find the lock or proclock, since we kept their
746 * addresses in the locallock table, and they couldn't have been removed
747 * while we were holding a lock on them.
748 */
749 lock = locallock->lock;
750 LOCK_PRINT("LockHasWaiters: found", lock, lockmode);
751 proclock = locallock->proclock;
752 PROCLOCK_PRINT("LockHasWaiters: found", proclock);
753
754 /*
755 * Double-check that we are actually holding a lock of the type we want to
756 * release.
757 */
758 if (!(proclock->holdMask & LOCKBIT_ON(lockmode)))
759 {
760 PROCLOCK_PRINT("LockHasWaiters: WRONGTYPE", proclock);
761 LWLockRelease(partitionLock);
762 elog(WARNING, "you don't own a lock of type %s",
763 lockMethodTable->lockModeNames[lockmode]);
764 RemoveLocalLock(locallock);
765 return false;
766 }
767
768 /*
769 * Do the checking.
770 */
771 if ((lockMethodTable->conflictTab[lockmode] & lock->waitMask) != 0)
772 hasWaiters = true;
773
774 LWLockRelease(partitionLock);
775
776 return hasWaiters;
777}
#define WARNING
Definition: elog.h:36

References LockMethodData::conflictTab, elog, ERROR, HASH_FIND, hash_search(), LOCALLOCK::hashcode, PROCLOCK::holdMask, lengthof, LOCALLOCKTAG::lock, LOCALLOCK::lock, LOCK_PRINT, LOCKBIT_ON, LockHashPartitionLock, LockMethodLocalHash, LockMethods, LockMethodData::lockModeNames, LOCKTAG::locktag_field1, LOCKTAG::locktag_field2, LOCKTAG::locktag_lockmethodid, LOG, LW_SHARED, LWLockAcquire(), LWLockRelease(), MemSet, LOCALLOCKTAG::mode, LOCALLOCK::nLocks, LockMethodData::numLockModes, LOCALLOCK::proclock, PROCLOCK_PRINT, RemoveLocalLock(), LOCK::waitMask, and WARNING.

Referenced by LockHasWaitersRelation().

◆ LockHeldByMe()

bool LockHeldByMe ( const LOCKTAG locktag,
LOCKMODE  lockmode,
bool  orstronger 
)

Definition at line 639 of file lock.c.

641{
642 LOCALLOCKTAG localtag;
643 LOCALLOCK *locallock;
644
645 /*
646 * See if there is a LOCALLOCK entry for this lock and lockmode
647 */
648 MemSet(&localtag, 0, sizeof(localtag)); /* must clear padding */
649 localtag.lock = *locktag;
650 localtag.mode = lockmode;
651
653 &localtag,
654 HASH_FIND, NULL);
655
656 if (locallock && locallock->nLocks > 0)
657 return true;
658
659 if (orstronger)
660 {
661 LOCKMODE slockmode;
662
663 for (slockmode = lockmode + 1;
664 slockmode <= MaxLockMode;
665 slockmode++)
666 {
667 if (LockHeldByMe(locktag, slockmode, false))
668 return true;
669 }
670 }
671
672 return false;
673}
bool LockHeldByMe(const LOCKTAG *locktag, LOCKMODE lockmode, bool orstronger)
Definition: lock.c:639
#define MaxLockMode
Definition: lockdefs.h:45

References HASH_FIND, hash_search(), LOCALLOCKTAG::lock, LockHeldByMe(), LockMethodLocalHash, MaxLockMode, MemSet, LOCALLOCKTAG::mode, and LOCALLOCK::nLocks.

Referenced by CheckRelationLockedByMe(), CheckRelationOidLockedByMe(), and LockHeldByMe().

◆ LockManagerShmemInit()

void LockManagerShmemInit ( void  )

Definition at line 440 of file lock.c.

441{
442 HASHCTL info;
443 long init_table_size,
444 max_table_size;
445 bool found;
446
447 /*
448 * Compute init/max size to request for lock hashtables. Note these
449 * calculations must agree with LockManagerShmemSize!
450 */
451 max_table_size = NLOCKENTS();
452 init_table_size = max_table_size / 2;
453
454 /*
455 * Allocate hash table for LOCK structs. This stores per-locked-object
456 * information.
457 */
458 info.keysize = sizeof(LOCKTAG);
459 info.entrysize = sizeof(LOCK);
461
462 LockMethodLockHash = ShmemInitHash("LOCK hash",
463 init_table_size,
464 max_table_size,
465 &info,
467
468 /* Assume an average of 2 holders per lock */
469 max_table_size *= 2;
470 init_table_size *= 2;
471
472 /*
473 * Allocate hash table for PROCLOCK structs. This stores
474 * per-lock-per-holder information.
475 */
476 info.keysize = sizeof(PROCLOCKTAG);
477 info.entrysize = sizeof(PROCLOCK);
478 info.hash = proclock_hash;
480
481 LockMethodProcLockHash = ShmemInitHash("PROCLOCK hash",
482 init_table_size,
483 max_table_size,
484 &info,
486
487 /*
488 * Allocate fast-path structures.
489 */
491 ShmemInitStruct("Fast Path Strong Relation Lock Data",
492 sizeof(FastPathStrongRelationLockData), &found);
493 if (!found)
495}
#define HASH_FUNCTION
Definition: hsearch.h:98
#define HASH_PARTITION
Definition: hsearch.h:92
#define NLOCKENTS()
Definition: lock.c:56
static uint32 proclock_hash(const void *key, Size keysize)
Definition: lock.c:570
struct LOCK LOCK
struct PROCLOCK PROCLOCK
struct LOCKTAG LOCKTAG
struct PROCLOCKTAG PROCLOCKTAG
HTAB * ShmemInitHash(const char *name, long init_size, long max_size, HASHCTL *infoP, int hash_flags)
Definition: shmem.c:327
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:382
#define SpinLockInit(lock)
Definition: spin.h:57
HashValueFunc hash
Definition: hsearch.h:78
long num_partitions
Definition: hsearch.h:68

References HASHCTL::entrysize, FastPathStrongRelationLocks, HASHCTL::hash, HASH_BLOBS, HASH_ELEM, HASH_FUNCTION, HASH_PARTITION, HASHCTL::keysize, LockMethodLockHash, LockMethodProcLockHash, FastPathStrongRelationLockData::mutex, NLOCKENTS, NUM_LOCK_PARTITIONS, HASHCTL::num_partitions, proclock_hash(), ShmemInitHash(), ShmemInitStruct(), and SpinLockInit.

Referenced by CreateOrAttachShmemStructs().

◆ LockManagerShmemSize()

Size LockManagerShmemSize ( void  )

Definition at line 3714 of file lock.c.

3715{
3716 Size size = 0;
3717 long max_table_size;
3718
3719 /* lock hash table */
3720 max_table_size = NLOCKENTS();
3721 size = add_size(size, hash_estimate_size(max_table_size, sizeof(LOCK)));
3722
3723 /* proclock hash table */
3724 max_table_size *= 2;
3725 size = add_size(size, hash_estimate_size(max_table_size, sizeof(PROCLOCK)));
3726
3727 /*
3728 * Since NLOCKENTS is only an estimate, add 10% safety margin.
3729 */
3730 size = add_size(size, size / 10);
3731
3732 return size;
3733}
size_t Size
Definition: c.h:576
Size hash_estimate_size(long num_entries, Size entrysize)
Definition: dynahash.c:783
Size add_size(Size s1, Size s2)
Definition: shmem.c:488

References add_size(), hash_estimate_size(), and NLOCKENTS.

Referenced by CalculateShmemSize().

◆ LockReassignCurrentOwner()

void LockReassignCurrentOwner ( LOCALLOCK **  locallocks,
int  nlocks 
)

Definition at line 2662 of file lock.c.

2663{
2665
2666 Assert(parent != NULL);
2667
2668 if (locallocks == NULL)
2669 {
2670 HASH_SEQ_STATUS status;
2671 LOCALLOCK *locallock;
2672
2674
2675 while ((locallock = (LOCALLOCK *) hash_seq_search(&status)) != NULL)
2676 LockReassignOwner(locallock, parent);
2677 }
2678 else
2679 {
2680 int i;
2681
2682 for (i = nlocks - 1; i >= 0; i--)
2683 LockReassignOwner(locallocks[i], parent);
2684 }
2685}
static void LockReassignOwner(LOCALLOCK *locallock, ResourceOwner parent)
Definition: lock.c:2692
ResourceOwner ResourceOwnerGetParent(ResourceOwner owner)
Definition: resowner.c:905

References Assert(), CurrentResourceOwner, hash_seq_init(), hash_seq_search(), i, LockMethodLocalHash, LockReassignOwner(), and ResourceOwnerGetParent().

Referenced by ResourceOwnerReleaseInternal().

◆ LockRelease()

bool LockRelease ( const LOCKTAG locktag,
LOCKMODE  lockmode,
bool  sessionLock 
)

Definition at line 2058 of file lock.c.

2059{
2060 LOCKMETHODID lockmethodid = locktag->locktag_lockmethodid;
2061 LockMethod lockMethodTable;
2062 LOCALLOCKTAG localtag;
2063 LOCALLOCK *locallock;
2064 LOCK *lock;
2065 PROCLOCK *proclock;
2066 LWLock *partitionLock;
2067 bool wakeupNeeded;
2068
2069 if (lockmethodid <= 0 || lockmethodid >= lengthof(LockMethods))
2070 elog(ERROR, "unrecognized lock method: %d", lockmethodid);
2071 lockMethodTable = LockMethods[lockmethodid];
2072 if (lockmode <= 0 || lockmode > lockMethodTable->numLockModes)
2073 elog(ERROR, "unrecognized lock mode: %d", lockmode);
2074
2075#ifdef LOCK_DEBUG
2076 if (LOCK_DEBUG_ENABLED(locktag))
2077 elog(LOG, "LockRelease: lock [%u,%u] %s",
2078 locktag->locktag_field1, locktag->locktag_field2,
2079 lockMethodTable->lockModeNames[lockmode]);
2080#endif
2081
2082 /*
2083 * Find the LOCALLOCK entry for this lock and lockmode
2084 */
2085 MemSet(&localtag, 0, sizeof(localtag)); /* must clear padding */
2086 localtag.lock = *locktag;
2087 localtag.mode = lockmode;
2088
2090 &localtag,
2091 HASH_FIND, NULL);
2092
2093 /*
2094 * let the caller print its own error message, too. Do not ereport(ERROR).
2095 */
2096 if (!locallock || locallock->nLocks <= 0)
2097 {
2098 elog(WARNING, "you don't own a lock of type %s",
2099 lockMethodTable->lockModeNames[lockmode]);
2100 return false;
2101 }
2102
2103 /*
2104 * Decrease the count for the resource owner.
2105 */
2106 {
2107 LOCALLOCKOWNER *lockOwners = locallock->lockOwners;
2108 ResourceOwner owner;
2109 int i;
2110
2111 /* Identify owner for lock */
2112 if (sessionLock)
2113 owner = NULL;
2114 else
2115 owner = CurrentResourceOwner;
2116
2117 for (i = locallock->numLockOwners - 1; i >= 0; i--)
2118 {
2119 if (lockOwners[i].owner == owner)
2120 {
2121 Assert(lockOwners[i].nLocks > 0);
2122 if (--lockOwners[i].nLocks == 0)
2123 {
2124 if (owner != NULL)
2125 ResourceOwnerForgetLock(owner, locallock);
2126 /* compact out unused slot */
2127 locallock->numLockOwners--;
2128 if (i < locallock->numLockOwners)
2129 lockOwners[i] = lockOwners[locallock->numLockOwners];
2130 }
2131 break;
2132 }
2133 }
2134 if (i < 0)
2135 {
2136 /* don't release a lock belonging to another owner */
2137 elog(WARNING, "you don't own a lock of type %s",
2138 lockMethodTable->lockModeNames[lockmode]);
2139 return false;
2140 }
2141 }
2142
2143 /*
2144 * Decrease the total local count. If we're still holding the lock, we're
2145 * done.
2146 */
2147 locallock->nLocks--;
2148
2149 if (locallock->nLocks > 0)
2150 return true;
2151
2152 /*
2153 * At this point we can no longer suppose we are clear of invalidation
2154 * messages related to this lock. Although we'll delete the LOCALLOCK
2155 * object before any intentional return from this routine, it seems worth
2156 * the trouble to explicitly reset lockCleared right now, just in case
2157 * some error prevents us from deleting the LOCALLOCK.
2158 */
2159 locallock->lockCleared = false;
2160
2161 /* Attempt fast release of any lock eligible for the fast path. */
2162 if (EligibleForRelationFastPath(locktag, lockmode) &&
2164 {
2165 bool released;
2166
2167 /*
2168 * We might not find the lock here, even if we originally entered it
2169 * here. Another backend may have moved it to the main table.
2170 */
2172 released = FastPathUnGrantRelationLock(locktag->locktag_field2,
2173 lockmode);
2175 if (released)
2176 {
2177 RemoveLocalLock(locallock);
2178 return true;
2179 }
2180 }
2181
2182 /*
2183 * Otherwise we've got to mess with the shared lock table.
2184 */
2185 partitionLock = LockHashPartitionLock(locallock->hashcode);
2186
2187 LWLockAcquire(partitionLock, LW_EXCLUSIVE);
2188
2189 /*
2190 * Normally, we don't need to re-find the lock or proclock, since we kept
2191 * their addresses in the locallock table, and they couldn't have been
2192 * removed while we were holding a lock on them. But it's possible that
2193 * the lock was taken fast-path and has since been moved to the main hash
2194 * table by another backend, in which case we will need to look up the
2195 * objects here. We assume the lock field is NULL if so.
2196 */
2197 lock = locallock->lock;
2198 if (!lock)
2199 {
2200 PROCLOCKTAG proclocktag;
2201
2202 Assert(EligibleForRelationFastPath(locktag, lockmode));
2204 locktag,
2205 locallock->hashcode,
2206 HASH_FIND,
2207 NULL);
2208 if (!lock)
2209 elog(ERROR, "failed to re-find shared lock object");
2210 locallock->lock = lock;
2211
2212 proclocktag.myLock = lock;
2213 proclocktag.myProc = MyProc;
2215 &proclocktag,
2216 HASH_FIND,
2217 NULL);
2218 if (!locallock->proclock)
2219 elog(ERROR, "failed to re-find shared proclock object");
2220 }
2221 LOCK_PRINT("LockRelease: found", lock, lockmode);
2222 proclock = locallock->proclock;
2223 PROCLOCK_PRINT("LockRelease: found", proclock);
2224
2225 /*
2226 * Double-check that we are actually holding a lock of the type we want to
2227 * release.
2228 */
2229 if (!(proclock->holdMask & LOCKBIT_ON(lockmode)))
2230 {
2231 PROCLOCK_PRINT("LockRelease: WRONGTYPE", proclock);
2232 LWLockRelease(partitionLock);
2233 elog(WARNING, "you don't own a lock of type %s",
2234 lockMethodTable->lockModeNames[lockmode]);
2235 RemoveLocalLock(locallock);
2236 return false;
2237 }
2238
2239 /*
2240 * Do the releasing. CleanUpLock will waken any now-wakable waiters.
2241 */
2242 wakeupNeeded = UnGrantLock(lock, lockmode, proclock, lockMethodTable);
2243
2244 CleanUpLock(lock, proclock,
2245 lockMethodTable, locallock->hashcode,
2246 wakeupNeeded);
2247
2248 LWLockRelease(partitionLock);
2249
2250 RemoveLocalLock(locallock);
2251 return true;
2252}
static bool UnGrantLock(LOCK *lock, LOCKMODE lockmode, PROCLOCK *proclock, LockMethod lockMethodTable)
Definition: lock.c:1677
static void CleanUpLock(LOCK *lock, PROCLOCK *proclock, LockMethod lockMethodTable, uint32 hashcode, bool wakeupNeeded)
Definition: lock.c:1734
static bool FastPathUnGrantRelationLock(Oid relid, LOCKMODE lockmode)
Definition: lock.c:2781
void ResourceOwnerForgetLock(ResourceOwner owner, LOCALLOCK *locallock)
Definition: resowner.c:1082

References Assert(), CleanUpLock(), CurrentResourceOwner, EligibleForRelationFastPath, elog, ERROR, FAST_PATH_REL_GROUP, FastPathLocalUseCounts, FastPathUnGrantRelationLock(), PGPROC::fpInfoLock, HASH_FIND, hash_search(), hash_search_with_hash_value(), LOCALLOCK::hashcode, PROCLOCK::holdMask, i, lengthof, LOCALLOCKTAG::lock, LOCALLOCK::lock, LOCK_PRINT, LOCKBIT_ON, LOCALLOCK::lockCleared, LockHashPartitionLock, LockMethodLocalHash, LockMethodLockHash, LockMethodProcLockHash, LockMethods, LockMethodData::lockModeNames, LOCALLOCK::lockOwners, LOCKTAG::locktag_field1, LOCKTAG::locktag_field2, LOCKTAG::locktag_lockmethodid, LOG, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MemSet, LOCALLOCKTAG::mode, PROCLOCKTAG::myLock, MyProc, PROCLOCKTAG::myProc, LOCALLOCK::nLocks, LockMethodData::numLockModes, LOCALLOCK::numLockOwners, LOCALLOCK::proclock, PROCLOCK_PRINT, RemoveLocalLock(), ResourceOwnerForgetLock(), UnGrantLock(), and WARNING.

Referenced by ConditionalXactLockTableWait(), pg_advisory_unlock_int4(), pg_advisory_unlock_int8(), pg_advisory_unlock_shared_int4(), pg_advisory_unlock_shared_int8(), ReleaseLockIfHeld(), SearchSysCacheLocked1(), SpeculativeInsertionLockRelease(), SpeculativeInsertionWait(), StandbyReleaseXidEntryLocks(), UnlockApplyTransactionForSession(), UnlockDatabaseObject(), UnlockPage(), UnlockRelation(), UnlockRelationForExtension(), UnlockRelationId(), UnlockRelationIdForSession(), UnlockRelationOid(), UnlockSharedObject(), UnlockSharedObjectForSession(), UnlockTuple(), VirtualXactLock(), XactLockForVirtualXact(), XactLockTableDelete(), and XactLockTableWait().

◆ LockReleaseAll()

void LockReleaseAll ( LOCKMETHODID  lockmethodid,
bool  allLocks 
)

Definition at line 2263 of file lock.c.

2264{
2265 HASH_SEQ_STATUS status;
2266 LockMethod lockMethodTable;
2267 int i,
2268 numLockModes;
2269 LOCALLOCK *locallock;
2270 LOCK *lock;
2271 int partition;
2272 bool have_fast_path_lwlock = false;
2273
2274 if (lockmethodid <= 0 || lockmethodid >= lengthof(LockMethods))
2275 elog(ERROR, "unrecognized lock method: %d", lockmethodid);
2276 lockMethodTable = LockMethods[lockmethodid];
2277
2278#ifdef LOCK_DEBUG
2279 if (*(lockMethodTable->trace_flag))
2280 elog(LOG, "LockReleaseAll: lockmethod=%d", lockmethodid);
2281#endif
2282
2283 /*
2284 * Get rid of our fast-path VXID lock, if appropriate. Note that this is
2285 * the only way that the lock we hold on our own VXID can ever get
2286 * released: it is always and only released when a toplevel transaction
2287 * ends.
2288 */
2289 if (lockmethodid == DEFAULT_LOCKMETHOD)
2291
2292 numLockModes = lockMethodTable->numLockModes;
2293
2294 /*
2295 * First we run through the locallock table and get rid of unwanted
2296 * entries, then we scan the process's proclocks and get rid of those. We
2297 * do this separately because we may have multiple locallock entries
2298 * pointing to the same proclock, and we daren't end up with any dangling
2299 * pointers. Fast-path locks are cleaned up during the locallock table
2300 * scan, though.
2301 */
2303
2304 while ((locallock = (LOCALLOCK *) hash_seq_search(&status)) != NULL)
2305 {
2306 /*
2307 * If the LOCALLOCK entry is unused, something must've gone wrong
2308 * while trying to acquire this lock. Just forget the local entry.
2309 */
2310 if (locallock->nLocks == 0)
2311 {
2312 RemoveLocalLock(locallock);
2313 continue;
2314 }
2315
2316 /* Ignore items that are not of the lockmethod to be removed */
2317 if (LOCALLOCK_LOCKMETHOD(*locallock) != lockmethodid)
2318 continue;
2319
2320 /*
2321 * If we are asked to release all locks, we can just zap the entry.
2322 * Otherwise, must scan to see if there are session locks. We assume
2323 * there is at most one lockOwners entry for session locks.
2324 */
2325 if (!allLocks)
2326 {
2327 LOCALLOCKOWNER *lockOwners = locallock->lockOwners;
2328
2329 /* If session lock is above array position 0, move it down to 0 */
2330 for (i = 0; i < locallock->numLockOwners; i++)
2331 {
2332 if (lockOwners[i].owner == NULL)
2333 lockOwners[0] = lockOwners[i];
2334 else
2335 ResourceOwnerForgetLock(lockOwners[i].owner, locallock);
2336 }
2337
2338 if (locallock->numLockOwners > 0 &&
2339 lockOwners[0].owner == NULL &&
2340 lockOwners[0].nLocks > 0)
2341 {
2342 /* Fix the locallock to show just the session locks */
2343 locallock->nLocks = lockOwners[0].nLocks;
2344 locallock->numLockOwners = 1;
2345 /* We aren't deleting this locallock, so done */
2346 continue;
2347 }
2348 else
2349 locallock->numLockOwners = 0;
2350 }
2351
2352#ifdef USE_ASSERT_CHECKING
2353
2354 /*
2355 * Tuple locks are currently held only for short durations within a
2356 * transaction. Check that we didn't forget to release one.
2357 */
2358 if (LOCALLOCK_LOCKTAG(*locallock) == LOCKTAG_TUPLE && !allLocks)
2359 elog(WARNING, "tuple lock held at commit");
2360#endif
2361
2362 /*
2363 * If the lock or proclock pointers are NULL, this lock was taken via
2364 * the relation fast-path (and is not known to have been transferred).
2365 */
2366 if (locallock->proclock == NULL || locallock->lock == NULL)
2367 {
2368 LOCKMODE lockmode = locallock->tag.mode;
2369 Oid relid;
2370
2371 /* Verify that a fast-path lock is what we've got. */
2372 if (!EligibleForRelationFastPath(&locallock->tag.lock, lockmode))
2373 elog(PANIC, "locallock table corrupted");
2374
2375 /*
2376 * If we don't currently hold the LWLock that protects our
2377 * fast-path data structures, we must acquire it before attempting
2378 * to release the lock via the fast-path. We will continue to
2379 * hold the LWLock until we're done scanning the locallock table,
2380 * unless we hit a transferred fast-path lock. (XXX is this
2381 * really such a good idea? There could be a lot of entries ...)
2382 */
2383 if (!have_fast_path_lwlock)
2384 {
2386 have_fast_path_lwlock = true;
2387 }
2388
2389 /* Attempt fast-path release. */
2390 relid = locallock->tag.lock.locktag_field2;
2391 if (FastPathUnGrantRelationLock(relid, lockmode))
2392 {
2393 RemoveLocalLock(locallock);
2394 continue;
2395 }
2396
2397 /*
2398 * Our lock, originally taken via the fast path, has been
2399 * transferred to the main lock table. That's going to require
2400 * some extra work, so release our fast-path lock before starting.
2401 */
2403 have_fast_path_lwlock = false;
2404
2405 /*
2406 * Now dump the lock. We haven't got a pointer to the LOCK or
2407 * PROCLOCK in this case, so we have to handle this a bit
2408 * differently than a normal lock release. Unfortunately, this
2409 * requires an extra LWLock acquire-and-release cycle on the
2410 * partitionLock, but hopefully it shouldn't happen often.
2411 */
2412 LockRefindAndRelease(lockMethodTable, MyProc,
2413 &locallock->tag.lock, lockmode, false);
2414 RemoveLocalLock(locallock);
2415 continue;
2416 }
2417
2418 /* Mark the proclock to show we need to release this lockmode */
2419 if (locallock->nLocks > 0)
2420 locallock->proclock->releaseMask |= LOCKBIT_ON(locallock->tag.mode);
2421
2422 /* And remove the locallock hashtable entry */
2423 RemoveLocalLock(locallock);
2424 }
2425
2426 /* Done with the fast-path data structures */
2427 if (have_fast_path_lwlock)
2429
2430 /*
2431 * Now, scan each lock partition separately.
2432 */
2433 for (partition = 0; partition < NUM_LOCK_PARTITIONS; partition++)
2434 {
2435 LWLock *partitionLock;
2436 dlist_head *procLocks = &MyProc->myProcLocks[partition];
2437 dlist_mutable_iter proclock_iter;
2438
2439 partitionLock = LockHashPartitionLockByIndex(partition);
2440
2441 /*
2442 * If the proclock list for this partition is empty, we can skip
2443 * acquiring the partition lock. This optimization is trickier than
2444 * it looks, because another backend could be in process of adding
2445 * something to our proclock list due to promoting one of our
2446 * fast-path locks. However, any such lock must be one that we
2447 * decided not to delete above, so it's okay to skip it again now;
2448 * we'd just decide not to delete it again. We must, however, be
2449 * careful to re-fetch the list header once we've acquired the
2450 * partition lock, to be sure we have a valid, up-to-date pointer.
2451 * (There is probably no significant risk if pointer fetch/store is
2452 * atomic, but we don't wish to assume that.)
2453 *
2454 * XXX This argument assumes that the locallock table correctly
2455 * represents all of our fast-path locks. While allLocks mode
2456 * guarantees to clean up all of our normal locks regardless of the
2457 * locallock situation, we lose that guarantee for fast-path locks.
2458 * This is not ideal.
2459 */
2460 if (dlist_is_empty(procLocks))
2461 continue; /* needn't examine this partition */
2462
2463 LWLockAcquire(partitionLock, LW_EXCLUSIVE);
2464
2465 dlist_foreach_modify(proclock_iter, procLocks)
2466 {
2467 PROCLOCK *proclock = dlist_container(PROCLOCK, procLink, proclock_iter.cur);
2468 bool wakeupNeeded = false;
2469
2470 Assert(proclock->tag.myProc == MyProc);
2471
2472 lock = proclock->tag.myLock;
2473
2474 /* Ignore items that are not of the lockmethod to be removed */
2475 if (LOCK_LOCKMETHOD(*lock) != lockmethodid)
2476 continue;
2477
2478 /*
2479 * In allLocks mode, force release of all locks even if locallock
2480 * table had problems
2481 */
2482 if (allLocks)
2483 proclock->releaseMask = proclock->holdMask;
2484 else
2485 Assert((proclock->releaseMask & ~proclock->holdMask) == 0);
2486
2487 /*
2488 * Ignore items that have nothing to be released, unless they have
2489 * holdMask == 0 and are therefore recyclable
2490 */
2491 if (proclock->releaseMask == 0 && proclock->holdMask != 0)
2492 continue;
2493
2494 PROCLOCK_PRINT("LockReleaseAll", proclock);
2495 LOCK_PRINT("LockReleaseAll", lock, 0);
2496 Assert(lock->nRequested >= 0);
2497 Assert(lock->nGranted >= 0);
2498 Assert(lock->nGranted <= lock->nRequested);
2499 Assert((proclock->holdMask & ~lock->grantMask) == 0);
2500
2501 /*
2502 * Release the previously-marked lock modes
2503 */
2504 for (i = 1; i <= numLockModes; i++)
2505 {
2506 if (proclock->releaseMask & LOCKBIT_ON(i))
2507 wakeupNeeded |= UnGrantLock(lock, i, proclock,
2508 lockMethodTable);
2509 }
2510 Assert((lock->nRequested >= 0) && (lock->nGranted >= 0));
2511 Assert(lock->nGranted <= lock->nRequested);
2512 LOCK_PRINT("LockReleaseAll: updated", lock, 0);
2513
2514 proclock->releaseMask = 0;
2515
2516 /* CleanUpLock will wake up waiters if needed. */
2517 CleanUpLock(lock, proclock,
2518 lockMethodTable,
2519 LockTagHashCode(&lock->tag),
2520 wakeupNeeded);
2521 } /* loop over PROCLOCKs within this partition */
2522
2523 LWLockRelease(partitionLock);
2524 } /* loop over partitions */
2525
2526#ifdef LOCK_DEBUG
2527 if (*(lockMethodTable->trace_flag))
2528 elog(LOG, "LockReleaseAll done");
2529#endif
2530}
#define dlist_foreach_modify(iter, lhead)
Definition: ilist.h:640
void VirtualXactLockTableCleanup(void)
Definition: lock.c:4601
#define LOCALLOCK_LOCKMETHOD(llock)
Definition: lock.h:444
#define LOCALLOCK_LOCKTAG(llock)
Definition: lock.h:445
int64 nLocks
Definition: lock.h:424
const bool * trace_flag
Definition: lock.h:114
dlist_node * cur
Definition: ilist.h:200

References Assert(), CleanUpLock(), dlist_mutable_iter::cur, DEFAULT_LOCKMETHOD, dlist_container, dlist_foreach_modify, dlist_is_empty(), EligibleForRelationFastPath, elog, ERROR, FastPathUnGrantRelationLock(), PGPROC::fpInfoLock, LOCK::grantMask, hash_seq_init(), hash_seq_search(), PROCLOCK::holdMask, i, lengthof, LOCALLOCK_LOCKMETHOD, LOCALLOCK_LOCKTAG, LOCALLOCKTAG::lock, LOCALLOCK::lock, LOCK_LOCKMETHOD, LOCK_PRINT, LOCKBIT_ON, LockHashPartitionLockByIndex, LockMethodLocalHash, LockMethods, LOCALLOCK::lockOwners, LockRefindAndRelease(), LOCKTAG::locktag_field2, LOCKTAG_TUPLE, LockTagHashCode(), LOG, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), LOCALLOCKTAG::mode, PROCLOCKTAG::myLock, MyProc, PROCLOCKTAG::myProc, PGPROC::myProcLocks, LOCK::nGranted, LOCALLOCKOWNER::nLocks, LOCALLOCK::nLocks, LOCK::nRequested, NUM_LOCK_PARTITIONS, LockMethodData::numLockModes, LOCALLOCK::numLockOwners, LOCALLOCKOWNER::owner, PANIC, LOCALLOCK::proclock, PROCLOCK_PRINT, PROCLOCK::releaseMask, RemoveLocalLock(), ResourceOwnerForgetLock(), LOCK::tag, PROCLOCK::tag, LOCALLOCK::tag, LockMethodData::trace_flag, UnGrantLock(), VirtualXactLockTableCleanup(), and WARNING.

Referenced by DiscardAll(), logicalrep_worker_onexit(), ProcReleaseLocks(), and ShutdownPostgres().

◆ LockReleaseCurrentOwner()

void LockReleaseCurrentOwner ( LOCALLOCK **  locallocks,
int  nlocks 
)

Definition at line 2567 of file lock.c.

2568{
2569 if (locallocks == NULL)
2570 {
2571 HASH_SEQ_STATUS status;
2572 LOCALLOCK *locallock;
2573
2575
2576 while ((locallock = (LOCALLOCK *) hash_seq_search(&status)) != NULL)
2577 ReleaseLockIfHeld(locallock, false);
2578 }
2579 else
2580 {
2581 int i;
2582
2583 for (i = nlocks - 1; i >= 0; i--)
2584 ReleaseLockIfHeld(locallocks[i], false);
2585 }
2586}
static void ReleaseLockIfHeld(LOCALLOCK *locallock, bool sessionLock)
Definition: lock.c:2602

References hash_seq_init(), hash_seq_search(), i, LockMethodLocalHash, and ReleaseLockIfHeld().

Referenced by ResourceOwnerReleaseInternal().

◆ LockReleaseSession()

void LockReleaseSession ( LOCKMETHODID  lockmethodid)

Definition at line 2537 of file lock.c.

2538{
2539 HASH_SEQ_STATUS status;
2540 LOCALLOCK *locallock;
2541
2542 if (lockmethodid <= 0 || lockmethodid >= lengthof(LockMethods))
2543 elog(ERROR, "unrecognized lock method: %d", lockmethodid);
2544
2546
2547 while ((locallock = (LOCALLOCK *) hash_seq_search(&status)) != NULL)
2548 {
2549 /* Ignore items that are not of the specified lock method */
2550 if (LOCALLOCK_LOCKMETHOD(*locallock) != lockmethodid)
2551 continue;
2552
2553 ReleaseLockIfHeld(locallock, true);
2554 }
2555}

References elog, ERROR, hash_seq_init(), hash_seq_search(), lengthof, LOCALLOCK_LOCKMETHOD, LockMethodLocalHash, LockMethods, and ReleaseLockIfHeld().

Referenced by pg_advisory_unlock_all().

◆ LockTagHashCode()

uint32 LockTagHashCode ( const LOCKTAG locktag)

Definition at line 553 of file lock.c.

554{
555 return get_hash_value(LockMethodLockHash, locktag);
556}
uint32 get_hash_value(HTAB *hashp, const void *keyPtr)
Definition: dynahash.c:911

References get_hash_value(), and LockMethodLockHash.

Referenced by CheckDeadLock(), GetLockConflicts(), lock_twophase_recover(), LockAcquireExtended(), LockRefindAndRelease(), LockReleaseAll(), LockWaiterCount(), proclock_hash(), and VirtualXactLock().

◆ LockWaiterCount()

int LockWaiterCount ( const LOCKTAG locktag)

Definition at line 4812 of file lock.c.

4813{
4814 LOCKMETHODID lockmethodid = locktag->locktag_lockmethodid;
4815 LOCK *lock;
4816 bool found;
4817 uint32 hashcode;
4818 LWLock *partitionLock;
4819 int waiters = 0;
4820
4821 if (lockmethodid <= 0 || lockmethodid >= lengthof(LockMethods))
4822 elog(ERROR, "unrecognized lock method: %d", lockmethodid);
4823
4824 hashcode = LockTagHashCode(locktag);
4825 partitionLock = LockHashPartitionLock(hashcode);
4826 LWLockAcquire(partitionLock, LW_EXCLUSIVE);
4827
4829 locktag,
4830 hashcode,
4831 HASH_FIND,
4832 &found);
4833 if (found)
4834 {
4835 Assert(lock != NULL);
4836 waiters = lock->nRequested;
4837 }
4838 LWLockRelease(partitionLock);
4839
4840 return waiters;
4841}

References Assert(), elog, ERROR, HASH_FIND, hash_search_with_hash_value(), lengthof, LockHashPartitionLock, LockMethodLockHash, LockMethods, LOCKTAG::locktag_lockmethodid, LockTagHashCode(), LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), and LOCK::nRequested.

Referenced by RelationExtensionLockWaiterCount().

◆ MarkLockClear()

void MarkLockClear ( LOCALLOCK locallock)

◆ PostPrepare_Locks()

void PostPrepare_Locks ( TransactionId  xid)

Definition at line 3530 of file lock.c.

3531{
3532 PGPROC *newproc = TwoPhaseGetDummyProc(xid, false);
3533 HASH_SEQ_STATUS status;
3534 LOCALLOCK *locallock;
3535 LOCK *lock;
3536 PROCLOCK *proclock;
3537 PROCLOCKTAG proclocktag;
3538 int partition;
3539
3540 /* Can't prepare a lock group follower. */
3541 Assert(MyProc->lockGroupLeader == NULL ||
3543
3544 /* This is a critical section: any error means big trouble */
3546
3547 /*
3548 * First we run through the locallock table and get rid of unwanted
3549 * entries, then we scan the process's proclocks and transfer them to the
3550 * target proc.
3551 *
3552 * We do this separately because we may have multiple locallock entries
3553 * pointing to the same proclock, and we daren't end up with any dangling
3554 * pointers.
3555 */
3557
3558 while ((locallock = (LOCALLOCK *) hash_seq_search(&status)) != NULL)
3559 {
3560 LOCALLOCKOWNER *lockOwners = locallock->lockOwners;
3561 bool haveSessionLock;
3562 bool haveXactLock;
3563 int i;
3564
3565 if (locallock->proclock == NULL || locallock->lock == NULL)
3566 {
3567 /*
3568 * We must've run out of shared memory while trying to set up this
3569 * lock. Just forget the local entry.
3570 */
3571 Assert(locallock->nLocks == 0);
3572 RemoveLocalLock(locallock);
3573 continue;
3574 }
3575
3576 /* Ignore VXID locks */
3578 continue;
3579
3580 /* Scan to see whether we hold it at session or transaction level */
3581 haveSessionLock = haveXactLock = false;
3582 for (i = locallock->numLockOwners - 1; i >= 0; i--)
3583 {
3584 if (lockOwners[i].owner == NULL)
3585 haveSessionLock = true;
3586 else
3587 haveXactLock = true;
3588 }
3589
3590 /* Ignore it if we have only session lock */
3591 if (!haveXactLock)
3592 continue;
3593
3594 /* This can't happen, because we already checked it */
3595 if (haveSessionLock)
3596 ereport(PANIC,
3597 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3598 errmsg("cannot PREPARE while holding both session-level and transaction-level locks on the same object")));
3599
3600 /* Mark the proclock to show we need to release this lockmode */
3601 if (locallock->nLocks > 0)
3602 locallock->proclock->releaseMask |= LOCKBIT_ON(locallock->tag.mode);
3603
3604 /* And remove the locallock hashtable entry */
3605 RemoveLocalLock(locallock);
3606 }
3607
3608 /*
3609 * Now, scan each lock partition separately.
3610 */
3611 for (partition = 0; partition < NUM_LOCK_PARTITIONS; partition++)
3612 {
3613 LWLock *partitionLock;
3614 dlist_head *procLocks = &(MyProc->myProcLocks[partition]);
3615 dlist_mutable_iter proclock_iter;
3616
3617 partitionLock = LockHashPartitionLockByIndex(partition);
3618
3619 /*
3620 * If the proclock list for this partition is empty, we can skip
3621 * acquiring the partition lock. This optimization is safer than the
3622 * situation in LockReleaseAll, because we got rid of any fast-path
3623 * locks during AtPrepare_Locks, so there cannot be any case where
3624 * another backend is adding something to our lists now. For safety,
3625 * though, we code this the same way as in LockReleaseAll.
3626 */
3627 if (dlist_is_empty(procLocks))
3628 continue; /* needn't examine this partition */
3629
3630 LWLockAcquire(partitionLock, LW_EXCLUSIVE);
3631
3632 dlist_foreach_modify(proclock_iter, procLocks)
3633 {
3634 proclock = dlist_container(PROCLOCK, procLink, proclock_iter.cur);
3635
3636 Assert(proclock->tag.myProc == MyProc);
3637
3638 lock = proclock->tag.myLock;
3639
3640 /* Ignore VXID locks */
3642 continue;
3643
3644 PROCLOCK_PRINT("PostPrepare_Locks", proclock);
3645 LOCK_PRINT("PostPrepare_Locks", lock, 0);
3646 Assert(lock->nRequested >= 0);
3647 Assert(lock->nGranted >= 0);
3648 Assert(lock->nGranted <= lock->nRequested);
3649 Assert((proclock->holdMask & ~lock->grantMask) == 0);
3650
3651 /* Ignore it if nothing to release (must be a session lock) */
3652 if (proclock->releaseMask == 0)
3653 continue;
3654
3655 /* Else we should be releasing all locks */
3656 if (proclock->releaseMask != proclock->holdMask)
3657 elog(PANIC, "we seem to have dropped a bit somewhere");
3658
3659 /*
3660 * We cannot simply modify proclock->tag.myProc to reassign
3661 * ownership of the lock, because that's part of the hash key and
3662 * the proclock would then be in the wrong hash chain. Instead
3663 * use hash_update_hash_key. (We used to create a new hash entry,
3664 * but that risks out-of-memory failure if other processes are
3665 * busy making proclocks too.) We must unlink the proclock from
3666 * our procLink chain and put it into the new proc's chain, too.
3667 *
3668 * Note: the updated proclock hash key will still belong to the
3669 * same hash partition, cf proclock_hash(). So the partition lock
3670 * we already hold is sufficient for this.
3671 */
3672 dlist_delete(&proclock->procLink);
3673
3674 /*
3675 * Create the new hash key for the proclock.
3676 */
3677 proclocktag.myLock = lock;
3678 proclocktag.myProc = newproc;
3679
3680 /*
3681 * Update groupLeader pointer to point to the new proc. (We'd
3682 * better not be a member of somebody else's lock group!)
3683 */
3684 Assert(proclock->groupLeader == proclock->tag.myProc);
3685 proclock->groupLeader = newproc;
3686
3687 /*
3688 * Update the proclock. We should not find any existing entry for
3689 * the same hash key, since there can be only one entry for any
3690 * given lock with my own proc.
3691 */
3693 proclock,
3694 &proclocktag))
3695 elog(PANIC, "duplicate entry found while reassigning a prepared transaction's locks");
3696
3697 /* Re-link into the new proc's proclock list */
3698 dlist_push_tail(&newproc->myProcLocks[partition], &proclock->procLink);
3699
3700 PROCLOCK_PRINT("PostPrepare_Locks: updated", proclock);
3701 } /* loop over PROCLOCKs within this partition */
3702
3703 LWLockRelease(partitionLock);
3704 } /* loop over partitions */
3705
3707}
bool hash_update_hash_key(HTAB *hashp, void *existingEntry, const void *newKeyPtr)
Definition: dynahash.c:1145
#define START_CRIT_SECTION()
Definition: miscadmin.h:149
#define END_CRIT_SECTION()
Definition: miscadmin.h:151

References Assert(), dlist_mutable_iter::cur, dlist_container, dlist_delete(), dlist_foreach_modify, dlist_is_empty(), dlist_push_tail(), elog, END_CRIT_SECTION, ereport, errcode(), errmsg(), LOCK::grantMask, PROCLOCK::groupLeader, hash_seq_init(), hash_seq_search(), hash_update_hash_key(), PROCLOCK::holdMask, i, LOCALLOCKTAG::lock, LOCALLOCK::lock, LOCK_PRINT, LOCKBIT_ON, PGPROC::lockGroupLeader, LockHashPartitionLockByIndex, LockMethodLocalHash, LockMethodProcLockHash, LOCALLOCK::lockOwners, LOCKTAG::locktag_type, LOCKTAG_VIRTUALTRANSACTION, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), LOCALLOCKTAG::mode, PROCLOCKTAG::myLock, MyProc, PROCLOCKTAG::myProc, PGPROC::myProcLocks, LOCK::nGranted, LOCALLOCK::nLocks, LOCK::nRequested, NUM_LOCK_PARTITIONS, LOCALLOCK::numLockOwners, PANIC, PROCLOCK::procLink, LOCALLOCK::proclock, PROCLOCK_PRINT, PROCLOCK::releaseMask, RemoveLocalLock(), START_CRIT_SECTION, LOCK::tag, PROCLOCK::tag, LOCALLOCK::tag, and TwoPhaseGetDummyProc().

Referenced by PrepareTransaction().

◆ RememberSimpleDeadLock()

void RememberSimpleDeadLock ( PGPROC proc1,
LOCKMODE  lockmode,
LOCK lock,
PGPROC proc2 
)

Definition at line 1147 of file deadlock.c.

1151{
1152 DEADLOCK_INFO *info = &deadlockDetails[0];
1153
1154 info->locktag = lock->tag;
1155 info->lockmode = lockmode;
1156 info->pid = proc1->pid;
1157 info++;
1158 info->locktag = proc2->waitLock->tag;
1159 info->lockmode = proc2->waitLockMode;
1160 info->pid = proc2->pid;
1161 nDeadlockDetails = 2;
1162}

References deadlockDetails, DEADLOCK_INFO::lockmode, DEADLOCK_INFO::locktag, nDeadlockDetails, DEADLOCK_INFO::pid, PGPROC::pid, LOCK::tag, PGPROC::waitLock, and PGPROC::waitLockMode.

Referenced by JoinWaitQueue().

◆ RemoveFromWaitQueue()

void RemoveFromWaitQueue ( PGPROC proc,
uint32  hashcode 
)

Definition at line 2002 of file lock.c.

2003{
2004 LOCK *waitLock = proc->waitLock;
2005 PROCLOCK *proclock = proc->waitProcLock;
2006 LOCKMODE lockmode = proc->waitLockMode;
2007 LOCKMETHODID lockmethodid = LOCK_LOCKMETHOD(*waitLock);
2008
2009 /* Make sure proc is waiting */
2011 Assert(proc->links.next != NULL);
2012 Assert(waitLock);
2013 Assert(!dclist_is_empty(&waitLock->waitProcs));
2014 Assert(0 < lockmethodid && lockmethodid < lengthof(LockMethods));
2015
2016 /* Remove proc from lock's wait queue */
2017 dclist_delete_from_thoroughly(&waitLock->waitProcs, &proc->links);
2018
2019 /* Undo increments of request counts by waiting process */
2020 Assert(waitLock->nRequested > 0);
2021 Assert(waitLock->nRequested > proc->waitLock->nGranted);
2022 waitLock->nRequested--;
2023 Assert(waitLock->requested[lockmode] > 0);
2024 waitLock->requested[lockmode]--;
2025 /* don't forget to clear waitMask bit if appropriate */
2026 if (waitLock->granted[lockmode] == waitLock->requested[lockmode])
2027 waitLock->waitMask &= LOCKBIT_OFF(lockmode);
2028
2029 /* Clean up the proc's own state, and pass it the ok/fail signal */
2030 proc->waitLock = NULL;
2031 proc->waitProcLock = NULL;
2033
2034 /*
2035 * Delete the proclock immediately if it represents no already-held locks.
2036 * (This must happen now because if the owner of the lock decides to
2037 * release it, and the requested/granted counts then go to zero,
2038 * LockRelease expects there to be no remaining proclocks.) Then see if
2039 * any other waiters for the lock can be woken up now.
2040 */
2041 CleanUpLock(waitLock, proclock,
2042 LockMethods[lockmethodid], hashcode,
2043 true);
2044}
static bool dclist_is_empty(const dclist_head *head)
Definition: ilist.h:682
static void dclist_delete_from_thoroughly(dclist_head *head, dlist_node *node)
Definition: ilist.h:776
PROCLOCK * waitProcLock
Definition: proc.h:234
ProcWaitStatus waitStatus
Definition: proc.h:168
dlist_node links
Definition: proc.h:164
dlist_node * next
Definition: ilist.h:140

References Assert(), CleanUpLock(), dclist_delete_from_thoroughly(), dclist_is_empty(), LOCK::granted, lengthof, PGPROC::links, LOCK_LOCKMETHOD, LOCKBIT_OFF, LockMethods, dlist_node::next, LOCK::nGranted, LOCK::nRequested, PROC_WAIT_STATUS_ERROR, PROC_WAIT_STATUS_WAITING, LOCK::requested, PGPROC::waitLock, PGPROC::waitLockMode, LOCK::waitMask, PGPROC::waitProcLock, LOCK::waitProcs, and PGPROC::waitStatus.

Referenced by CheckDeadLock(), and LockErrorCleanup().

◆ VirtualXactLock()

bool VirtualXactLock ( VirtualTransactionId  vxid,
bool  wait 
)

Definition at line 4701 of file lock.c.

4702{
4703 LOCKTAG tag;
4704 PGPROC *proc;
4706
4708
4710 /* no vxid lock; localTransactionId is a normal, locked XID */
4711 return XactLockForVirtualXact(vxid, vxid.localTransactionId, wait);
4712
4714
4715 /*
4716 * If a lock table entry must be made, this is the PGPROC on whose behalf
4717 * it must be done. Note that the transaction might end or the PGPROC
4718 * might be reassigned to a new backend before we get around to examining
4719 * it, but it doesn't matter. If we find upon examination that the
4720 * relevant lxid is no longer running here, that's enough to prove that
4721 * it's no longer running anywhere.
4722 */
4723 proc = ProcNumberGetProc(vxid.procNumber);
4724 if (proc == NULL)
4725 return XactLockForVirtualXact(vxid, InvalidTransactionId, wait);
4726
4727 /*
4728 * We must acquire this lock before checking the procNumber and lxid
4729 * against the ones we're waiting for. The target backend will only set
4730 * or clear lxid while holding this lock.
4731 */
4733
4734 if (proc->vxid.procNumber != vxid.procNumber
4736 {
4737 /* VXID ended */
4738 LWLockRelease(&proc->fpInfoLock);
4739 return XactLockForVirtualXact(vxid, InvalidTransactionId, wait);
4740 }
4741
4742 /*
4743 * If we aren't asked to wait, there's no need to set up a lock table
4744 * entry. The transaction is still in progress, so just return false.
4745 */
4746 if (!wait)
4747 {
4748 LWLockRelease(&proc->fpInfoLock);
4749 return false;
4750 }
4751
4752 /*
4753 * OK, we're going to need to sleep on the VXID. But first, we must set
4754 * up the primary lock table entry, if needed (ie, convert the proc's
4755 * fast-path lock on its VXID to a regular lock).
4756 */
4757 if (proc->fpVXIDLock)
4758 {
4759 PROCLOCK *proclock;
4760 uint32 hashcode;
4761 LWLock *partitionLock;
4762
4763 hashcode = LockTagHashCode(&tag);
4764
4765 partitionLock = LockHashPartitionLock(hashcode);
4766 LWLockAcquire(partitionLock, LW_EXCLUSIVE);
4767
4769 &tag, hashcode, ExclusiveLock);
4770 if (!proclock)
4771 {
4772 LWLockRelease(partitionLock);
4773 LWLockRelease(&proc->fpInfoLock);
4774 ereport(ERROR,
4775 (errcode(ERRCODE_OUT_OF_MEMORY),
4776 errmsg("out of shared memory"),
4777 errhint("You might need to increase \"%s\".", "max_locks_per_transaction")));
4778 }
4779 GrantLock(proclock->tag.myLock, proclock, ExclusiveLock);
4780
4781 LWLockRelease(partitionLock);
4782
4783 proc->fpVXIDLock = false;
4784 }
4785
4786 /*
4787 * If the proc has an XID now, we'll avoid a TwoPhaseGetXidByVirtualXID()
4788 * search. The proc might have assigned this XID but not yet locked it,
4789 * in which case the proc will lock this XID before releasing the VXID.
4790 * The fpInfoLock critical section excludes VirtualXactLockTableCleanup(),
4791 * so we won't save an XID of a different VXID. It doesn't matter whether
4792 * we save this before or after setting up the primary lock table entry.
4793 */
4794 xid = proc->xid;
4795
4796 /* Done with proc->fpLockBits */
4797 LWLockRelease(&proc->fpInfoLock);
4798
4799 /* Time to wait. */
4800 (void) LockAcquire(&tag, ShareLock, false, false);
4801
4802 LockRelease(&tag, ShareLock, false);
4803 return XactLockForVirtualXact(vxid, xid, wait);
4804}
static bool XactLockForVirtualXact(VirtualTransactionId vxid, TransactionId xid, bool wait)
Definition: lock.c:4650
LockAcquireResult LockAcquire(const LOCKTAG *locktag, LOCKMODE lockmode, bool sessionLock, bool dontWait)
Definition: lock.c:805
bool LockRelease(const LOCKTAG *locktag, LOCKMODE lockmode, bool sessionLock)
Definition: lock.c:2058
#define VirtualTransactionIdIsRecoveredPreparedXact(vxid)
Definition: lock.h:70
#define ShareLock
Definition: lockdefs.h:40
PGPROC * ProcNumberGetProc(ProcNumber procNumber)
Definition: procarray.c:3138
#define InvalidTransactionId
Definition: transam.h:31

References Assert(), DEFAULT_LOCKMETHOD, ereport, errcode(), errhint(), errmsg(), ERROR, ExclusiveLock, PGPROC::fpInfoLock, PGPROC::fpLocalTransactionId, PGPROC::fpVXIDLock, GrantLock(), InvalidTransactionId, VirtualTransactionId::localTransactionId, LockAcquire(), LockHashPartitionLock, LockMethods, LockRelease(), LockTagHashCode(), LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), PROCLOCKTAG::myLock, VirtualTransactionId::procNumber, PGPROC::procNumber, ProcNumberGetProc(), SET_LOCKTAG_VIRTUALTRANSACTION, SetupLockInTable(), ShareLock, PROCLOCK::tag, VirtualTransactionIdIsRecoveredPreparedXact, VirtualTransactionIdIsValid, PGPROC::vxid, XactLockForVirtualXact(), and PGPROC::xid.

Referenced by ResolveRecoveryConflictWithVirtualXIDs(), WaitForLockersMultiple(), and WaitForOlderSnapshots().

◆ VirtualXactLockTableCleanup()

void VirtualXactLockTableCleanup ( void  )

Definition at line 4601 of file lock.c.

4602{
4603 bool fastpath;
4604 LocalTransactionId lxid;
4605
4607
4608 /*
4609 * Clean up shared memory state.
4610 */
4612
4613 fastpath = MyProc->fpVXIDLock;
4615 MyProc->fpVXIDLock = false;
4617
4619
4620 /*
4621 * If fpVXIDLock has been cleared without touching fpLocalTransactionId,
4622 * that means someone transferred the lock to the main lock table.
4623 */
4624 if (!fastpath && LocalTransactionIdIsValid(lxid))
4625 {
4627 LOCKTAG locktag;
4628
4629 vxid.procNumber = MyProcNumber;
4630 vxid.localTransactionId = lxid;
4631 SET_LOCKTAG_VIRTUALTRANSACTION(locktag, vxid);
4632
4634 &locktag, ExclusiveLock, false);
4635 }
4636}
uint32 LocalTransactionId
Definition: c.h:625
ProcNumber MyProcNumber
Definition: globals.c:89
#define LocalTransactionIdIsValid(lxid)
Definition: lock.h:67

References Assert(), DEFAULT_LOCKMETHOD, ExclusiveLock, PGPROC::fpInfoLock, PGPROC::fpLocalTransactionId, PGPROC::fpVXIDLock, INVALID_PROC_NUMBER, InvalidLocalTransactionId, VirtualTransactionId::localTransactionId, LocalTransactionIdIsValid, LockMethods, LockRefindAndRelease(), LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MyProc, MyProcNumber, VirtualTransactionId::procNumber, PGPROC::procNumber, SET_LOCKTAG_VIRTUALTRANSACTION, and PGPROC::vxid.

Referenced by LockReleaseAll(), and ShutdownRecoveryTransactionEnvironment().

◆ VirtualXactLockTableInsert()

Variable Documentation

◆ LockTagTypeNames

PGDLLIMPORT const char* const LockTagTypeNames[]
extern

Definition at line 28 of file lockfuncs.c.

Referenced by GetLockNameFromTagType(), and pg_lock_status().

◆ log_lock_failure

PGDLLIMPORT bool log_lock_failure
extern

Definition at line 54 of file lock.c.

Referenced by heap_acquire_tuplock(), heap_lock_tuple(), and heapam_tuple_lock().

◆ max_locks_per_xact

PGDLLIMPORT int max_locks_per_xact
extern