| 1 | /*------------------------------------------------------------------------- | 
|---|
| 2 | * | 
|---|
| 3 | * lock.h | 
|---|
| 4 | *	  POSTGRES low-level lock mechanism | 
|---|
| 5 | * | 
|---|
| 6 | * | 
|---|
| 7 | * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group | 
|---|
| 8 | * Portions Copyright (c) 1994, Regents of the University of California | 
|---|
| 9 | * | 
|---|
| 10 | * src/include/storage/lock.h | 
|---|
| 11 | * | 
|---|
| 12 | *------------------------------------------------------------------------- | 
|---|
| 13 | */ | 
|---|
| 14 | #ifndef LOCK_H_ | 
|---|
| 15 | #define LOCK_H_ | 
|---|
| 16 |  | 
|---|
| 17 | #ifdef FRONTEND | 
|---|
| 18 | #error "lock.h may not be included from frontend code" | 
|---|
| 19 | #endif | 
|---|
| 20 |  | 
|---|
| 21 | #include "storage/lockdefs.h" | 
|---|
| 22 | #include "storage/backendid.h" | 
|---|
| 23 | #include "storage/lwlock.h" | 
|---|
| 24 | #include "storage/shmem.h" | 
|---|
| 25 |  | 
|---|
| 26 |  | 
|---|
| 27 | /* struct PGPROC is declared in proc.h, but must forward-reference it */ | 
|---|
| 28 | typedef struct PGPROC PGPROC; | 
|---|
| 29 |  | 
|---|
| 30 | typedef struct PROC_QUEUE | 
|---|
| 31 | { | 
|---|
| 32 | SHM_QUEUE	links;			/* head of list of PGPROC objects */ | 
|---|
| 33 | int			size;			/* number of entries in list */ | 
|---|
| 34 | } PROC_QUEUE; | 
|---|
| 35 |  | 
|---|
| 36 | /* GUC variables */ | 
|---|
| 37 | extern int	max_locks_per_xact; | 
|---|
| 38 |  | 
|---|
| 39 | #ifdef LOCK_DEBUG | 
|---|
| 40 | extern int	Trace_lock_oidmin; | 
|---|
| 41 | extern bool Trace_locks; | 
|---|
| 42 | extern bool Trace_userlocks; | 
|---|
| 43 | extern int	Trace_lock_table; | 
|---|
| 44 | extern bool Debug_deadlocks; | 
|---|
| 45 | #endif							/* LOCK_DEBUG */ | 
|---|
| 46 |  | 
|---|
| 47 |  | 
|---|
| 48 | /* | 
|---|
| 49 | * Top-level transactions are identified by VirtualTransactionIDs comprising | 
|---|
| 50 | * the BackendId of the backend running the xact, plus a locally-assigned | 
|---|
| 51 | * LocalTransactionId.  These are guaranteed unique over the short term, | 
|---|
| 52 | * but will be reused after a database restart; hence they should never | 
|---|
| 53 | * be stored on disk. | 
|---|
| 54 | * | 
|---|
| 55 | * Note that struct VirtualTransactionId can not be assumed to be atomically | 
|---|
| 56 | * assignable as a whole.  However, type LocalTransactionId is assumed to | 
|---|
| 57 | * be atomically assignable, and the backend ID doesn't change often enough | 
|---|
| 58 | * to be a problem, so we can fetch or assign the two fields separately. | 
|---|
| 59 | * We deliberately refrain from using the struct within PGPROC, to prevent | 
|---|
| 60 | * coding errors from trying to use struct assignment with it; instead use | 
|---|
| 61 | * GET_VXID_FROM_PGPROC(). | 
|---|
| 62 | */ | 
|---|
| 63 | typedef struct | 
|---|
| 64 | { | 
|---|
| 65 | BackendId	backendId;		/* determined at backend startup */ | 
|---|
| 66 | LocalTransactionId localTransactionId;	/* backend-local transaction id */ | 
|---|
| 67 | } VirtualTransactionId; | 
|---|
| 68 |  | 
|---|
| 69 | #define InvalidLocalTransactionId		0 | 
|---|
| 70 | #define LocalTransactionIdIsValid(lxid) ((lxid) != InvalidLocalTransactionId) | 
|---|
| 71 | #define VirtualTransactionIdIsValid(vxid) \ | 
|---|
| 72 | (((vxid).backendId != InvalidBackendId) && \ | 
|---|
| 73 | LocalTransactionIdIsValid((vxid).localTransactionId)) | 
|---|
| 74 | #define VirtualTransactionIdEquals(vxid1, vxid2) \ | 
|---|
| 75 | ((vxid1).backendId == (vxid2).backendId && \ | 
|---|
| 76 | (vxid1).localTransactionId == (vxid2).localTransactionId) | 
|---|
| 77 | #define SetInvalidVirtualTransactionId(vxid) \ | 
|---|
| 78 | ((vxid).backendId = InvalidBackendId, \ | 
|---|
| 79 | (vxid).localTransactionId = InvalidLocalTransactionId) | 
|---|
| 80 | #define GET_VXID_FROM_PGPROC(vxid, proc) \ | 
|---|
| 81 | ((vxid).backendId = (proc).backendId, \ | 
|---|
| 82 | (vxid).localTransactionId = (proc).lxid) | 
|---|
| 83 |  | 
|---|
| 84 | /* MAX_LOCKMODES cannot be larger than the # of bits in LOCKMASK */ | 
|---|
| 85 | #define MAX_LOCKMODES		10 | 
|---|
| 86 |  | 
|---|
| 87 | #define LOCKBIT_ON(lockmode) (1 << (lockmode)) | 
|---|
| 88 | #define LOCKBIT_OFF(lockmode) (~(1 << (lockmode))) | 
|---|
| 89 |  | 
|---|
| 90 |  | 
|---|
| 91 | /* | 
|---|
| 92 | * This data structure defines the locking semantics associated with a | 
|---|
| 93 | * "lock method".  The semantics specify the meaning of each lock mode | 
|---|
| 94 | * (by defining which lock modes it conflicts with). | 
|---|
| 95 | * All of this data is constant and is kept in const tables. | 
|---|
| 96 | * | 
|---|
| 97 | * numLockModes -- number of lock modes (READ,WRITE,etc) that | 
|---|
| 98 | *		are defined in this lock method.  Must be less than MAX_LOCKMODES. | 
|---|
| 99 | * | 
|---|
| 100 | * conflictTab -- this is an array of bitmasks showing lock | 
|---|
| 101 | *		mode conflicts.  conflictTab[i] is a mask with the j-th bit | 
|---|
| 102 | *		turned on if lock modes i and j conflict.  Lock modes are | 
|---|
| 103 | *		numbered 1..numLockModes; conflictTab[0] is unused. | 
|---|
| 104 | * | 
|---|
| 105 | * lockModeNames -- ID strings for debug printouts. | 
|---|
| 106 | * | 
|---|
| 107 | * trace_flag -- pointer to GUC trace flag for this lock method.  (The | 
|---|
| 108 | * GUC variable is not constant, but we use "const" here to denote that | 
|---|
| 109 | * it can't be changed through this reference.) | 
|---|
| 110 | */ | 
|---|
| 111 | typedef struct LockMethodData | 
|---|
| 112 | { | 
|---|
| 113 | int			numLockModes; | 
|---|
| 114 | const LOCKMASK *conflictTab; | 
|---|
| 115 | const char *const *lockModeNames; | 
|---|
| 116 | const bool *trace_flag; | 
|---|
| 117 | } LockMethodData; | 
|---|
| 118 |  | 
|---|
| 119 | typedef const LockMethodData *LockMethod; | 
|---|
| 120 |  | 
|---|
| 121 | /* | 
|---|
| 122 | * Lock methods are identified by LOCKMETHODID.  (Despite the declaration as | 
|---|
| 123 | * uint16, we are constrained to 256 lockmethods by the layout of LOCKTAG.) | 
|---|
| 124 | */ | 
|---|
| 125 | typedef uint16 LOCKMETHODID; | 
|---|
| 126 |  | 
|---|
| 127 | /* These identify the known lock methods */ | 
|---|
| 128 | #define DEFAULT_LOCKMETHOD	1 | 
|---|
| 129 | #define USER_LOCKMETHOD		2 | 
|---|
| 130 |  | 
|---|
| 131 | /* | 
|---|
| 132 | * LOCKTAG is the key information needed to look up a LOCK item in the | 
|---|
| 133 | * lock hashtable.  A LOCKTAG value uniquely identifies a lockable object. | 
|---|
| 134 | * | 
|---|
| 135 | * The LockTagType enum defines the different kinds of objects we can lock. | 
|---|
| 136 | * We can handle up to 256 different LockTagTypes. | 
|---|
| 137 | */ | 
|---|
| 138 | typedef enum LockTagType | 
|---|
| 139 | { | 
|---|
| 140 | LOCKTAG_RELATION,			/* whole relation */ | 
|---|
| 141 | LOCKTAG_RELATION_EXTEND,	/* the right to extend a relation */ | 
|---|
| 142 | LOCKTAG_PAGE,				/* one page of a relation */ | 
|---|
| 143 | LOCKTAG_TUPLE,				/* one physical tuple */ | 
|---|
| 144 | LOCKTAG_TRANSACTION,		/* transaction (for waiting for xact done) */ | 
|---|
| 145 | LOCKTAG_VIRTUALTRANSACTION, /* virtual transaction (ditto) */ | 
|---|
| 146 | LOCKTAG_SPECULATIVE_TOKEN,	/* speculative insertion Xid and token */ | 
|---|
| 147 | LOCKTAG_OBJECT,				/* non-relation database object */ | 
|---|
| 148 | LOCKTAG_USERLOCK,			/* reserved for old contrib/userlock code */ | 
|---|
| 149 | LOCKTAG_ADVISORY			/* advisory user locks */ | 
|---|
| 150 | } LockTagType; | 
|---|
| 151 |  | 
|---|
| 152 | #define LOCKTAG_LAST_TYPE	LOCKTAG_ADVISORY | 
|---|
| 153 |  | 
|---|
| 154 | extern const char *const LockTagTypeNames[]; | 
|---|
| 155 |  | 
|---|
| 156 | /* | 
|---|
| 157 | * The LOCKTAG struct is defined with malice aforethought to fit into 16 | 
|---|
| 158 | * bytes with no padding.  Note that this would need adjustment if we were | 
|---|
| 159 | * to widen Oid, BlockNumber, or TransactionId to more than 32 bits. | 
|---|
| 160 | * | 
|---|
| 161 | * We include lockmethodid in the locktag so that a single hash table in | 
|---|
| 162 | * shared memory can store locks of different lockmethods. | 
|---|
| 163 | */ | 
|---|
| 164 | typedef struct LOCKTAG | 
|---|
| 165 | { | 
|---|
| 166 | uint32		locktag_field1; /* a 32-bit ID field */ | 
|---|
| 167 | uint32		locktag_field2; /* a 32-bit ID field */ | 
|---|
| 168 | uint32		locktag_field3; /* a 32-bit ID field */ | 
|---|
| 169 | uint16		locktag_field4; /* a 16-bit ID field */ | 
|---|
| 170 | uint8		locktag_type;	/* see enum LockTagType */ | 
|---|
| 171 | uint8		locktag_lockmethodid;	/* lockmethod indicator */ | 
|---|
| 172 | } LOCKTAG; | 
|---|
| 173 |  | 
|---|
| 174 | /* | 
|---|
| 175 | * These macros define how we map logical IDs of lockable objects into | 
|---|
| 176 | * the physical fields of LOCKTAG.  Use these to set up LOCKTAG values, | 
|---|
| 177 | * rather than accessing the fields directly.  Note multiple eval of target! | 
|---|
| 178 | */ | 
|---|
| 179 |  | 
|---|
| 180 | /* ID info for a relation is DB OID + REL OID; DB OID = 0 if shared */ | 
|---|
| 181 | #define SET_LOCKTAG_RELATION(locktag,dboid,reloid) \ | 
|---|
| 182 | ((locktag).locktag_field1 = (dboid), \ | 
|---|
| 183 | (locktag).locktag_field2 = (reloid), \ | 
|---|
| 184 | (locktag).locktag_field3 = 0, \ | 
|---|
| 185 | (locktag).locktag_field4 = 0, \ | 
|---|
| 186 | (locktag).locktag_type = LOCKTAG_RELATION, \ | 
|---|
| 187 | (locktag).locktag_lockmethodid = DEFAULT_LOCKMETHOD) | 
|---|
| 188 |  | 
|---|
| 189 | /* same ID info as RELATION */ | 
|---|
| 190 | #define SET_LOCKTAG_RELATION_EXTEND(locktag,dboid,reloid) \ | 
|---|
| 191 | ((locktag).locktag_field1 = (dboid), \ | 
|---|
| 192 | (locktag).locktag_field2 = (reloid), \ | 
|---|
| 193 | (locktag).locktag_field3 = 0, \ | 
|---|
| 194 | (locktag).locktag_field4 = 0, \ | 
|---|
| 195 | (locktag).locktag_type = LOCKTAG_RELATION_EXTEND, \ | 
|---|
| 196 | (locktag).locktag_lockmethodid = DEFAULT_LOCKMETHOD) | 
|---|
| 197 |  | 
|---|
| 198 | /* ID info for a page is RELATION info + BlockNumber */ | 
|---|
| 199 | #define SET_LOCKTAG_PAGE(locktag,dboid,reloid,blocknum) \ | 
|---|
| 200 | ((locktag).locktag_field1 = (dboid), \ | 
|---|
| 201 | (locktag).locktag_field2 = (reloid), \ | 
|---|
| 202 | (locktag).locktag_field3 = (blocknum), \ | 
|---|
| 203 | (locktag).locktag_field4 = 0, \ | 
|---|
| 204 | (locktag).locktag_type = LOCKTAG_PAGE, \ | 
|---|
| 205 | (locktag).locktag_lockmethodid = DEFAULT_LOCKMETHOD) | 
|---|
| 206 |  | 
|---|
| 207 | /* ID info for a tuple is PAGE info + OffsetNumber */ | 
|---|
| 208 | #define SET_LOCKTAG_TUPLE(locktag,dboid,reloid,blocknum,offnum) \ | 
|---|
| 209 | ((locktag).locktag_field1 = (dboid), \ | 
|---|
| 210 | (locktag).locktag_field2 = (reloid), \ | 
|---|
| 211 | (locktag).locktag_field3 = (blocknum), \ | 
|---|
| 212 | (locktag).locktag_field4 = (offnum), \ | 
|---|
| 213 | (locktag).locktag_type = LOCKTAG_TUPLE, \ | 
|---|
| 214 | (locktag).locktag_lockmethodid = DEFAULT_LOCKMETHOD) | 
|---|
| 215 |  | 
|---|
| 216 | /* ID info for a transaction is its TransactionId */ | 
|---|
| 217 | #define SET_LOCKTAG_TRANSACTION(locktag,xid) \ | 
|---|
| 218 | ((locktag).locktag_field1 = (xid), \ | 
|---|
| 219 | (locktag).locktag_field2 = 0, \ | 
|---|
| 220 | (locktag).locktag_field3 = 0, \ | 
|---|
| 221 | (locktag).locktag_field4 = 0, \ | 
|---|
| 222 | (locktag).locktag_type = LOCKTAG_TRANSACTION, \ | 
|---|
| 223 | (locktag).locktag_lockmethodid = DEFAULT_LOCKMETHOD) | 
|---|
| 224 |  | 
|---|
| 225 | /* ID info for a virtual transaction is its VirtualTransactionId */ | 
|---|
| 226 | #define SET_LOCKTAG_VIRTUALTRANSACTION(locktag,vxid) \ | 
|---|
| 227 | ((locktag).locktag_field1 = (vxid).backendId, \ | 
|---|
| 228 | (locktag).locktag_field2 = (vxid).localTransactionId, \ | 
|---|
| 229 | (locktag).locktag_field3 = 0, \ | 
|---|
| 230 | (locktag).locktag_field4 = 0, \ | 
|---|
| 231 | (locktag).locktag_type = LOCKTAG_VIRTUALTRANSACTION, \ | 
|---|
| 232 | (locktag).locktag_lockmethodid = DEFAULT_LOCKMETHOD) | 
|---|
| 233 |  | 
|---|
| 234 | /* | 
|---|
| 235 | * ID info for a speculative insert is TRANSACTION info + | 
|---|
| 236 | * its speculative insert counter. | 
|---|
| 237 | */ | 
|---|
| 238 | #define SET_LOCKTAG_SPECULATIVE_INSERTION(locktag,xid,token) \ | 
|---|
| 239 | ((locktag).locktag_field1 = (xid), \ | 
|---|
| 240 | (locktag).locktag_field2 = (token),		\ | 
|---|
| 241 | (locktag).locktag_field3 = 0, \ | 
|---|
| 242 | (locktag).locktag_field4 = 0, \ | 
|---|
| 243 | (locktag).locktag_type = LOCKTAG_SPECULATIVE_TOKEN, \ | 
|---|
| 244 | (locktag).locktag_lockmethodid = DEFAULT_LOCKMETHOD) | 
|---|
| 245 |  | 
|---|
| 246 | /* | 
|---|
| 247 | * ID info for an object is DB OID + CLASS OID + OBJECT OID + SUBID | 
|---|
| 248 | * | 
|---|
| 249 | * Note: object ID has same representation as in pg_depend and | 
|---|
| 250 | * pg_description, but notice that we are constraining SUBID to 16 bits. | 
|---|
| 251 | * Also, we use DB OID = 0 for shared objects such as tablespaces. | 
|---|
| 252 | */ | 
|---|
| 253 | #define SET_LOCKTAG_OBJECT(locktag,dboid,classoid,objoid,objsubid) \ | 
|---|
| 254 | ((locktag).locktag_field1 = (dboid), \ | 
|---|
| 255 | (locktag).locktag_field2 = (classoid), \ | 
|---|
| 256 | (locktag).locktag_field3 = (objoid), \ | 
|---|
| 257 | (locktag).locktag_field4 = (objsubid), \ | 
|---|
| 258 | (locktag).locktag_type = LOCKTAG_OBJECT, \ | 
|---|
| 259 | (locktag).locktag_lockmethodid = DEFAULT_LOCKMETHOD) | 
|---|
| 260 |  | 
|---|
| 261 | #define SET_LOCKTAG_ADVISORY(locktag,id1,id2,id3,id4) \ | 
|---|
| 262 | ((locktag).locktag_field1 = (id1), \ | 
|---|
| 263 | (locktag).locktag_field2 = (id2), \ | 
|---|
| 264 | (locktag).locktag_field3 = (id3), \ | 
|---|
| 265 | (locktag).locktag_field4 = (id4), \ | 
|---|
| 266 | (locktag).locktag_type = LOCKTAG_ADVISORY, \ | 
|---|
| 267 | (locktag).locktag_lockmethodid = USER_LOCKMETHOD) | 
|---|
| 268 |  | 
|---|
| 269 |  | 
|---|
| 270 | /* | 
|---|
| 271 | * Per-locked-object lock information: | 
|---|
| 272 | * | 
|---|
| 273 | * tag -- uniquely identifies the object being locked | 
|---|
| 274 | * grantMask -- bitmask for all lock types currently granted on this object. | 
|---|
| 275 | * waitMask -- bitmask for all lock types currently awaited on this object. | 
|---|
| 276 | * procLocks -- list of PROCLOCK objects for this lock. | 
|---|
| 277 | * waitProcs -- queue of processes waiting for this lock. | 
|---|
| 278 | * requested -- count of each lock type currently requested on the lock | 
|---|
| 279 | *		(includes requests already granted!!). | 
|---|
| 280 | * nRequested -- total requested locks of all types. | 
|---|
| 281 | * granted -- count of each lock type currently granted on the lock. | 
|---|
| 282 | * nGranted -- total granted locks of all types. | 
|---|
| 283 | * | 
|---|
| 284 | * Note: these counts count 1 for each backend.  Internally to a backend, | 
|---|
| 285 | * there may be multiple grabs on a particular lock, but this is not reflected | 
|---|
| 286 | * into shared memory. | 
|---|
| 287 | */ | 
|---|
| 288 | typedef struct LOCK | 
|---|
| 289 | { | 
|---|
| 290 | /* hash key */ | 
|---|
| 291 | LOCKTAG		tag;			/* unique identifier of lockable object */ | 
|---|
| 292 |  | 
|---|
| 293 | /* data */ | 
|---|
| 294 | LOCKMASK	grantMask;		/* bitmask for lock types already granted */ | 
|---|
| 295 | LOCKMASK	waitMask;		/* bitmask for lock types awaited */ | 
|---|
| 296 | SHM_QUEUE	procLocks;		/* list of PROCLOCK objects assoc. with lock */ | 
|---|
| 297 | PROC_QUEUE	waitProcs;		/* list of PGPROC objects waiting on lock */ | 
|---|
| 298 | int			requested[MAX_LOCKMODES];	/* counts of requested locks */ | 
|---|
| 299 | int			nRequested;		/* total of requested[] array */ | 
|---|
| 300 | int			granted[MAX_LOCKMODES]; /* counts of granted locks */ | 
|---|
| 301 | int			nGranted;		/* total of granted[] array */ | 
|---|
| 302 | } LOCK; | 
|---|
| 303 |  | 
|---|
| 304 | #define LOCK_LOCKMETHOD(lock) ((LOCKMETHODID) (lock).tag.locktag_lockmethodid) | 
|---|
| 305 |  | 
|---|
| 306 |  | 
|---|
| 307 | /* | 
|---|
| 308 | * We may have several different backends holding or awaiting locks | 
|---|
| 309 | * on the same lockable object.  We need to store some per-holder/waiter | 
|---|
| 310 | * information for each such holder (or would-be holder).  This is kept in | 
|---|
| 311 | * a PROCLOCK struct. | 
|---|
| 312 | * | 
|---|
| 313 | * PROCLOCKTAG is the key information needed to look up a PROCLOCK item in the | 
|---|
| 314 | * proclock hashtable.  A PROCLOCKTAG value uniquely identifies the combination | 
|---|
| 315 | * of a lockable object and a holder/waiter for that object.  (We can use | 
|---|
| 316 | * pointers here because the PROCLOCKTAG need only be unique for the lifespan | 
|---|
| 317 | * of the PROCLOCK, and it will never outlive the lock or the proc.) | 
|---|
| 318 | * | 
|---|
| 319 | * Internally to a backend, it is possible for the same lock to be held | 
|---|
| 320 | * for different purposes: the backend tracks transaction locks separately | 
|---|
| 321 | * from session locks.  However, this is not reflected in the shared-memory | 
|---|
| 322 | * state: we only track which backend(s) hold the lock.  This is OK since a | 
|---|
| 323 | * backend can never block itself. | 
|---|
| 324 | * | 
|---|
| 325 | * The holdMask field shows the already-granted locks represented by this | 
|---|
| 326 | * proclock.  Note that there will be a proclock object, possibly with | 
|---|
| 327 | * zero holdMask, for any lock that the process is currently waiting on. | 
|---|
| 328 | * Otherwise, proclock objects whose holdMasks are zero are recycled | 
|---|
| 329 | * as soon as convenient. | 
|---|
| 330 | * | 
|---|
| 331 | * releaseMask is workspace for LockReleaseAll(): it shows the locks due | 
|---|
| 332 | * to be released during the current call.  This must only be examined or | 
|---|
| 333 | * set by the backend owning the PROCLOCK. | 
|---|
| 334 | * | 
|---|
| 335 | * Each PROCLOCK object is linked into lists for both the associated LOCK | 
|---|
| 336 | * object and the owning PGPROC object.  Note that the PROCLOCK is entered | 
|---|
| 337 | * into these lists as soon as it is created, even if no lock has yet been | 
|---|
| 338 | * granted.  A PGPROC that is waiting for a lock to be granted will also be | 
|---|
| 339 | * linked into the lock's waitProcs queue. | 
|---|
| 340 | */ | 
|---|
| 341 | typedef struct PROCLOCKTAG | 
|---|
| 342 | { | 
|---|
| 343 | /* NB: we assume this struct contains no padding! */ | 
|---|
| 344 | LOCK	   *myLock;			/* link to per-lockable-object information */ | 
|---|
| 345 | PGPROC	   *myProc;			/* link to PGPROC of owning backend */ | 
|---|
| 346 | } PROCLOCKTAG; | 
|---|
| 347 |  | 
|---|
| 348 | typedef struct PROCLOCK | 
|---|
| 349 | { | 
|---|
| 350 | /* tag */ | 
|---|
| 351 | PROCLOCKTAG tag;			/* unique identifier of proclock object */ | 
|---|
| 352 |  | 
|---|
| 353 | /* data */ | 
|---|
| 354 | PGPROC	   *groupLeader;	/* proc's lock group leader, or proc itself */ | 
|---|
| 355 | LOCKMASK	holdMask;		/* bitmask for lock types currently held */ | 
|---|
| 356 | LOCKMASK	releaseMask;	/* bitmask for lock types to be released */ | 
|---|
| 357 | SHM_QUEUE	lockLink;		/* list link in LOCK's list of proclocks */ | 
|---|
| 358 | SHM_QUEUE	procLink;		/* list link in PGPROC's list of proclocks */ | 
|---|
| 359 | } PROCLOCK; | 
|---|
| 360 |  | 
|---|
| 361 | #define PROCLOCK_LOCKMETHOD(proclock) \ | 
|---|
| 362 | LOCK_LOCKMETHOD(*((proclock).tag.myLock)) | 
|---|
| 363 |  | 
|---|
| 364 | /* | 
|---|
| 365 | * Each backend also maintains a local hash table with information about each | 
|---|
| 366 | * lock it is currently interested in.  In particular the local table counts | 
|---|
| 367 | * the number of times that lock has been acquired.  This allows multiple | 
|---|
| 368 | * requests for the same lock to be executed without additional accesses to | 
|---|
| 369 | * shared memory.  We also track the number of lock acquisitions per | 
|---|
| 370 | * ResourceOwner, so that we can release just those locks belonging to a | 
|---|
| 371 | * particular ResourceOwner. | 
|---|
| 372 | * | 
|---|
| 373 | * When holding a lock taken "normally", the lock and proclock fields always | 
|---|
| 374 | * point to the associated objects in shared memory.  However, if we acquired | 
|---|
| 375 | * the lock via the fast-path mechanism, the lock and proclock fields are set | 
|---|
| 376 | * to NULL, since there probably aren't any such objects in shared memory. | 
|---|
| 377 | * (If the lock later gets promoted to normal representation, we may eventually | 
|---|
| 378 | * update our locallock's lock/proclock fields after finding the shared | 
|---|
| 379 | * objects.) | 
|---|
| 380 | * | 
|---|
| 381 | * Caution: a locallock object can be left over from a failed lock acquisition | 
|---|
| 382 | * attempt.  In this case its lock/proclock fields are untrustworthy, since | 
|---|
| 383 | * the shared lock object is neither held nor awaited, and hence is available | 
|---|
| 384 | * to be reclaimed.  If nLocks > 0 then these pointers must either be valid or | 
|---|
| 385 | * NULL, but when nLocks == 0 they should be considered garbage. | 
|---|
| 386 | */ | 
|---|
| 387 | typedef struct LOCALLOCKTAG | 
|---|
| 388 | { | 
|---|
| 389 | LOCKTAG		lock;			/* identifies the lockable object */ | 
|---|
| 390 | LOCKMODE	mode;			/* lock mode for this table entry */ | 
|---|
| 391 | } LOCALLOCKTAG; | 
|---|
| 392 |  | 
|---|
| 393 | typedef struct LOCALLOCKOWNER | 
|---|
| 394 | { | 
|---|
| 395 | /* | 
|---|
| 396 | * Note: if owner is NULL then the lock is held on behalf of the session; | 
|---|
| 397 | * otherwise it is held on behalf of my current transaction. | 
|---|
| 398 | * | 
|---|
| 399 | * Must use a forward struct reference to avoid circularity. | 
|---|
| 400 | */ | 
|---|
| 401 | struct ResourceOwnerData *owner; | 
|---|
| 402 | int64		nLocks;			/* # of times held by this owner */ | 
|---|
| 403 | } LOCALLOCKOWNER; | 
|---|
| 404 |  | 
|---|
| 405 | typedef struct LOCALLOCK | 
|---|
| 406 | { | 
|---|
| 407 | /* tag */ | 
|---|
| 408 | LOCALLOCKTAG tag;			/* unique identifier of locallock entry */ | 
|---|
| 409 |  | 
|---|
| 410 | /* data */ | 
|---|
| 411 | uint32		hashcode;		/* copy of LOCKTAG's hash value */ | 
|---|
| 412 | LOCK	   *lock;			/* associated LOCK object, if any */ | 
|---|
| 413 | PROCLOCK   *proclock;		/* associated PROCLOCK object, if any */ | 
|---|
| 414 | int64		nLocks;			/* total number of times lock is held */ | 
|---|
| 415 | int			numLockOwners;	/* # of relevant ResourceOwners */ | 
|---|
| 416 | int			maxLockOwners;	/* allocated size of array */ | 
|---|
| 417 | LOCALLOCKOWNER *lockOwners; /* dynamically resizable array */ | 
|---|
| 418 | bool		holdsStrongLockCount;	/* bumped FastPathStrongRelationLocks */ | 
|---|
| 419 | bool		lockCleared;	/* we read all sinval msgs for lock */ | 
|---|
| 420 | } LOCALLOCK; | 
|---|
| 421 |  | 
|---|
| 422 | #define LOCALLOCK_LOCKMETHOD(llock) ((llock).tag.lock.locktag_lockmethodid) | 
|---|
| 423 |  | 
|---|
| 424 |  | 
|---|
| 425 | /* | 
|---|
| 426 | * These structures hold information passed from lmgr internals to the lock | 
|---|
| 427 | * listing user-level functions (in lockfuncs.c). | 
|---|
| 428 | */ | 
|---|
| 429 |  | 
|---|
| 430 | typedef struct LockInstanceData | 
|---|
| 431 | { | 
|---|
| 432 | LOCKTAG		locktag;		/* tag for locked object */ | 
|---|
| 433 | LOCKMASK	holdMask;		/* locks held by this PGPROC */ | 
|---|
| 434 | LOCKMODE	waitLockMode;	/* lock awaited by this PGPROC, if any */ | 
|---|
| 435 | BackendId	backend;		/* backend ID of this PGPROC */ | 
|---|
| 436 | LocalTransactionId lxid;	/* local transaction ID of this PGPROC */ | 
|---|
| 437 | int			pid;			/* pid of this PGPROC */ | 
|---|
| 438 | int			leaderPid;		/* pid of group leader; = pid if no group */ | 
|---|
| 439 | bool		fastpath;		/* taken via fastpath? */ | 
|---|
| 440 | } LockInstanceData; | 
|---|
| 441 |  | 
|---|
| 442 | typedef struct LockData | 
|---|
| 443 | { | 
|---|
| 444 | int			nelements;		/* The length of the array */ | 
|---|
| 445 | LockInstanceData *locks;	/* Array of per-PROCLOCK information */ | 
|---|
| 446 | } LockData; | 
|---|
| 447 |  | 
|---|
| 448 | typedef struct BlockedProcData | 
|---|
| 449 | { | 
|---|
| 450 | int			pid;			/* pid of a blocked PGPROC */ | 
|---|
| 451 | /* Per-PROCLOCK information about PROCLOCKs of the lock the pid awaits */ | 
|---|
| 452 | /* (these fields refer to indexes in BlockedProcsData.locks[]) */ | 
|---|
| 453 | int			first_lock;		/* index of first relevant LockInstanceData */ | 
|---|
| 454 | int			num_locks;		/* number of relevant LockInstanceDatas */ | 
|---|
| 455 | /* PIDs of PGPROCs that are ahead of "pid" in the lock's wait queue */ | 
|---|
| 456 | /* (these fields refer to indexes in BlockedProcsData.waiter_pids[]) */ | 
|---|
| 457 | int			first_waiter;	/* index of first preceding waiter */ | 
|---|
| 458 | int			num_waiters;	/* number of preceding waiters */ | 
|---|
| 459 | } BlockedProcData; | 
|---|
| 460 |  | 
|---|
| 461 | typedef struct BlockedProcsData | 
|---|
| 462 | { | 
|---|
| 463 | BlockedProcData *procs;		/* Array of per-blocked-proc information */ | 
|---|
| 464 | LockInstanceData *locks;	/* Array of per-PROCLOCK information */ | 
|---|
| 465 | int		   *waiter_pids;	/* Array of PIDs of other blocked PGPROCs */ | 
|---|
| 466 | int			nprocs;			/* # of valid entries in procs[] array */ | 
|---|
| 467 | int			maxprocs;		/* Allocated length of procs[] array */ | 
|---|
| 468 | int			nlocks;			/* # of valid entries in locks[] array */ | 
|---|
| 469 | int			maxlocks;		/* Allocated length of locks[] array */ | 
|---|
| 470 | int			npids;			/* # of valid entries in waiter_pids[] array */ | 
|---|
| 471 | int			maxpids;		/* Allocated length of waiter_pids[] array */ | 
|---|
| 472 | } BlockedProcsData; | 
|---|
| 473 |  | 
|---|
| 474 |  | 
|---|
| 475 | /* Result codes for LockAcquire() */ | 
|---|
| 476 | typedef enum | 
|---|
| 477 | { | 
|---|
| 478 | LOCKACQUIRE_NOT_AVAIL,		/* lock not available, and dontWait=true */ | 
|---|
| 479 | LOCKACQUIRE_OK,				/* lock successfully acquired */ | 
|---|
| 480 | LOCKACQUIRE_ALREADY_HELD,	/* incremented count for lock already held */ | 
|---|
| 481 | LOCKACQUIRE_ALREADY_CLEAR	/* incremented count for lock already clear */ | 
|---|
| 482 | } LockAcquireResult; | 
|---|
| 483 |  | 
|---|
| 484 | /* Deadlock states identified by DeadLockCheck() */ | 
|---|
| 485 | typedef enum | 
|---|
| 486 | { | 
|---|
| 487 | DS_NOT_YET_CHECKED,			/* no deadlock check has run yet */ | 
|---|
| 488 | DS_NO_DEADLOCK,				/* no deadlock detected */ | 
|---|
| 489 | DS_SOFT_DEADLOCK,			/* deadlock avoided by queue rearrangement */ | 
|---|
| 490 | DS_HARD_DEADLOCK,			/* deadlock, no way out but ERROR */ | 
|---|
| 491 | DS_BLOCKED_BY_AUTOVACUUM	/* no deadlock; queue blocked by autovacuum | 
|---|
| 492 | * worker */ | 
|---|
| 493 | } DeadLockState; | 
|---|
| 494 |  | 
|---|
| 495 | /* | 
|---|
| 496 | * The lockmgr's shared hash tables are partitioned to reduce contention. | 
|---|
| 497 | * To determine which partition a given locktag belongs to, compute the tag's | 
|---|
| 498 | * hash code with LockTagHashCode(), then apply one of these macros. | 
|---|
| 499 | * NB: NUM_LOCK_PARTITIONS must be a power of 2! | 
|---|
| 500 | */ | 
|---|
| 501 | #define LockHashPartition(hashcode) \ | 
|---|
| 502 | ((hashcode) % NUM_LOCK_PARTITIONS) | 
|---|
| 503 | #define LockHashPartitionLock(hashcode) \ | 
|---|
| 504 | (&MainLWLockArray[LOCK_MANAGER_LWLOCK_OFFSET + \ | 
|---|
| 505 | LockHashPartition(hashcode)].lock) | 
|---|
| 506 | #define LockHashPartitionLockByIndex(i) \ | 
|---|
| 507 | (&MainLWLockArray[LOCK_MANAGER_LWLOCK_OFFSET + (i)].lock) | 
|---|
| 508 |  | 
|---|
| 509 | /* | 
|---|
| 510 | * The deadlock detector needs to be able to access lockGroupLeader and | 
|---|
| 511 | * related fields in the PGPROC, so we arrange for those fields to be protected | 
|---|
| 512 | * by one of the lock hash partition locks.  Since the deadlock detector | 
|---|
| 513 | * acquires all such locks anyway, this makes it safe for it to access these | 
|---|
| 514 | * fields without doing anything extra.  To avoid contention as much as | 
|---|
| 515 | * possible, we map different PGPROCs to different partition locks.  The lock | 
|---|
| 516 | * used for a given lock group is determined by the group leader's pgprocno. | 
|---|
| 517 | */ | 
|---|
| 518 | #define LockHashPartitionLockByProc(leader_pgproc) \ | 
|---|
| 519 | LockHashPartitionLock((leader_pgproc)->pgprocno) | 
|---|
| 520 |  | 
|---|
| 521 | /* | 
|---|
| 522 | * function prototypes | 
|---|
| 523 | */ | 
|---|
| 524 | extern void InitLocks(void); | 
|---|
| 525 | extern LockMethod GetLocksMethodTable(const LOCK *lock); | 
|---|
| 526 | extern LockMethod GetLockTagsMethodTable(const LOCKTAG *locktag); | 
|---|
| 527 | extern uint32 LockTagHashCode(const LOCKTAG *locktag); | 
|---|
| 528 | extern bool DoLockModesConflict(LOCKMODE mode1, LOCKMODE mode2); | 
|---|
| 529 | extern LockAcquireResult LockAcquire(const LOCKTAG *locktag, | 
|---|
| 530 | LOCKMODE lockmode, | 
|---|
| 531 | bool sessionLock, | 
|---|
| 532 | bool dontWait); | 
|---|
| 533 | extern LockAcquireResult LockAcquireExtended(const LOCKTAG *locktag, | 
|---|
| 534 | LOCKMODE lockmode, | 
|---|
| 535 | bool sessionLock, | 
|---|
| 536 | bool dontWait, | 
|---|
| 537 | bool reportMemoryError, | 
|---|
| 538 | LOCALLOCK **locallockp); | 
|---|
| 539 | extern void AbortStrongLockAcquire(void); | 
|---|
| 540 | extern void MarkLockClear(LOCALLOCK *locallock); | 
|---|
| 541 | extern bool LockRelease(const LOCKTAG *locktag, | 
|---|
| 542 | LOCKMODE lockmode, bool sessionLock); | 
|---|
| 543 | extern void LockReleaseAll(LOCKMETHODID lockmethodid, bool allLocks); | 
|---|
| 544 | extern void LockReleaseSession(LOCKMETHODID lockmethodid); | 
|---|
| 545 | extern void LockReleaseCurrentOwner(LOCALLOCK **locallocks, int nlocks); | 
|---|
| 546 | extern void LockReassignCurrentOwner(LOCALLOCK **locallocks, int nlocks); | 
|---|
| 547 | extern bool LockHeldByMe(const LOCKTAG *locktag, LOCKMODE lockmode); | 
|---|
| 548 | extern bool LockHasWaiters(const LOCKTAG *locktag, | 
|---|
| 549 | LOCKMODE lockmode, bool sessionLock); | 
|---|
| 550 | extern VirtualTransactionId *GetLockConflicts(const LOCKTAG *locktag, | 
|---|
| 551 | LOCKMODE lockmode, int *countp); | 
|---|
| 552 | extern void AtPrepare_Locks(void); | 
|---|
| 553 | extern void PostPrepare_Locks(TransactionId xid); | 
|---|
| 554 | extern int	LockCheckConflicts(LockMethod lockMethodTable, | 
|---|
| 555 | LOCKMODE lockmode, | 
|---|
| 556 | LOCK *lock, PROCLOCK *proclock); | 
|---|
| 557 | extern void GrantLock(LOCK *lock, PROCLOCK *proclock, LOCKMODE lockmode); | 
|---|
| 558 | extern void GrantAwaitedLock(void); | 
|---|
| 559 | extern void RemoveFromWaitQueue(PGPROC *proc, uint32 hashcode); | 
|---|
| 560 | extern Size LockShmemSize(void); | 
|---|
| 561 | extern LockData *GetLockStatusData(void); | 
|---|
| 562 | extern BlockedProcsData *GetBlockerStatusData(int blocked_pid); | 
|---|
| 563 |  | 
|---|
| 564 | extern xl_standby_lock *GetRunningTransactionLocks(int *nlocks); | 
|---|
| 565 | extern const char *GetLockmodeName(LOCKMETHODID lockmethodid, LOCKMODE mode); | 
|---|
| 566 |  | 
|---|
| 567 | extern void lock_twophase_recover(TransactionId xid, uint16 info, | 
|---|
| 568 | void *recdata, uint32 len); | 
|---|
| 569 | extern void lock_twophase_postcommit(TransactionId xid, uint16 info, | 
|---|
| 570 | void *recdata, uint32 len); | 
|---|
| 571 | extern void lock_twophase_postabort(TransactionId xid, uint16 info, | 
|---|
| 572 | void *recdata, uint32 len); | 
|---|
| 573 | extern void lock_twophase_standby_recover(TransactionId xid, uint16 info, | 
|---|
| 574 | void *recdata, uint32 len); | 
|---|
| 575 |  | 
|---|
| 576 | extern DeadLockState DeadLockCheck(PGPROC *proc); | 
|---|
| 577 | extern PGPROC *GetBlockingAutoVacuumPgproc(void); | 
|---|
| 578 | extern void DeadLockReport(void) pg_attribute_noreturn(); | 
|---|
| 579 | extern void RememberSimpleDeadLock(PGPROC *proc1, | 
|---|
| 580 | LOCKMODE lockmode, | 
|---|
| 581 | LOCK *lock, | 
|---|
| 582 | PGPROC *proc2); | 
|---|
| 583 | extern void InitDeadLockChecking(void); | 
|---|
| 584 |  | 
|---|
| 585 | extern int	LockWaiterCount(const LOCKTAG *locktag); | 
|---|
| 586 |  | 
|---|
| 587 | #ifdef LOCK_DEBUG | 
|---|
| 588 | extern void DumpLocks(PGPROC *proc); | 
|---|
| 589 | extern void DumpAllLocks(void); | 
|---|
| 590 | #endif | 
|---|
| 591 |  | 
|---|
| 592 | /* Lock a VXID (used to wait for a transaction to finish) */ | 
|---|
| 593 | extern void VirtualXactLockTableInsert(VirtualTransactionId vxid); | 
|---|
| 594 | extern void VirtualXactLockTableCleanup(void); | 
|---|
| 595 | extern bool VirtualXactLock(VirtualTransactionId vxid, bool wait); | 
|---|
| 596 |  | 
|---|
| 597 | #endif							/* LOCK_H */ | 
|---|
| 598 |  | 
|---|