diff --git a/src/include/storage/lock.h b/src/include/storage/lock.h index 55ffaa5e4a5..9505701a805 100644 --- a/src/include/storage/lock.h +++ b/src/include/storage/lock.h @@ -21,6 +21,7 @@ #include "access/transam.h" #include "lib/ilist.h" #include "storage/lockdefs.h" +#include "storage/locktag.h" #include "storage/lwlock.h" #include "storage/procnumber.h" #include "storage/shmem.h" @@ -117,178 +118,6 @@ typedef struct LockMethodData typedef const LockMethodData *LockMethod; -/* - * Lock methods are identified by LOCKMETHODID. (Despite the declaration as - * uint16, we are constrained to 256 lockmethods by the layout of LOCKTAG.) - */ -typedef uint16 LOCKMETHODID; - -/* These identify the known lock methods */ -#define DEFAULT_LOCKMETHOD 1 -#define USER_LOCKMETHOD 2 - -/* - * LOCKTAG is the key information needed to look up a LOCK item in the - * lock hashtable. A LOCKTAG value uniquely identifies a lockable object. - * - * The LockTagType enum defines the different kinds of objects we can lock. - * We can handle up to 256 different LockTagTypes. - */ -typedef enum LockTagType -{ - LOCKTAG_RELATION, /* whole relation */ - LOCKTAG_RELATION_EXTEND, /* the right to extend a relation */ - LOCKTAG_DATABASE_FROZEN_IDS, /* pg_database.datfrozenxid */ - LOCKTAG_PAGE, /* one page of a relation */ - LOCKTAG_TUPLE, /* one physical tuple */ - LOCKTAG_TRANSACTION, /* transaction (for waiting for xact done) */ - LOCKTAG_VIRTUALTRANSACTION, /* virtual transaction (ditto) */ - LOCKTAG_SPECULATIVE_TOKEN, /* speculative insertion Xid and token */ - LOCKTAG_OBJECT, /* non-relation database object */ - LOCKTAG_USERLOCK, /* reserved for old contrib/userlock code */ - LOCKTAG_ADVISORY, /* advisory user locks */ - LOCKTAG_APPLY_TRANSACTION, /* transaction being applied on a logical - * replication subscriber */ -} LockTagType; - -#define LOCKTAG_LAST_TYPE LOCKTAG_APPLY_TRANSACTION - -extern PGDLLIMPORT const char *const LockTagTypeNames[]; - -/* - * The LOCKTAG struct is defined with malice aforethought to fit into 16 - * bytes with no padding. Note that this would need adjustment if we were - * to widen Oid, BlockNumber, or TransactionId to more than 32 bits. - * - * We include lockmethodid in the locktag so that a single hash table in - * shared memory can store locks of different lockmethods. - */ -typedef struct LOCKTAG -{ - uint32 locktag_field1; /* a 32-bit ID field */ - uint32 locktag_field2; /* a 32-bit ID field */ - uint32 locktag_field3; /* a 32-bit ID field */ - uint16 locktag_field4; /* a 16-bit ID field */ - uint8 locktag_type; /* see enum LockTagType */ - uint8 locktag_lockmethodid; /* lockmethod indicator */ -} LOCKTAG; - -/* - * These macros define how we map logical IDs of lockable objects into - * the physical fields of LOCKTAG. Use these to set up LOCKTAG values, - * rather than accessing the fields directly. Note multiple eval of target! - */ - -/* ID info for a relation is DB OID + REL OID; DB OID = 0 if shared */ -#define SET_LOCKTAG_RELATION(locktag,dboid,reloid) \ - ((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) - -/* same ID info as RELATION */ -#define SET_LOCKTAG_RELATION_EXTEND(locktag,dboid,reloid) \ - ((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) - -/* ID info for frozen IDs is DB OID */ -#define SET_LOCKTAG_DATABASE_FROZEN_IDS(locktag,dboid) \ - ((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) - -/* ID info for a page is RELATION info + BlockNumber */ -#define SET_LOCKTAG_PAGE(locktag,dboid,reloid,blocknum) \ - ((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) - -/* ID info for a tuple is PAGE info + OffsetNumber */ -#define SET_LOCKTAG_TUPLE(locktag,dboid,reloid,blocknum,offnum) \ - ((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) - -/* ID info for a transaction is its TransactionId */ -#define SET_LOCKTAG_TRANSACTION(locktag,xid) \ - ((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) - -/* ID info for a virtual transaction is its VirtualTransactionId */ -#define SET_LOCKTAG_VIRTUALTRANSACTION(locktag,vxid) \ - ((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) - -/* - * ID info for a speculative insert is TRANSACTION info + - * its speculative insert counter. - */ -#define SET_LOCKTAG_SPECULATIVE_INSERTION(locktag,xid,token) \ - ((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) - -/* - * ID info for an object is DB OID + CLASS OID + OBJECT OID + SUBID - * - * Note: object ID has same representation as in pg_depend and - * pg_description, but notice that we are constraining SUBID to 16 bits. - * Also, we use DB OID = 0 for shared objects such as tablespaces. - */ -#define SET_LOCKTAG_OBJECT(locktag,dboid,classoid,objoid,objsubid) \ - ((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) - -#define SET_LOCKTAG_ADVISORY(locktag,id1,id2,id3,id4) \ - ((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) - -/* - * ID info for a remote transaction on a logical replication subscriber is: DB - * OID + SUBSCRIPTION OID + TRANSACTION ID + OBJID - */ -#define SET_LOCKTAG_APPLY_TRANSACTION(locktag,dboid,suboid,xid,objid) \ - ((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) - /* * Per-locked-object lock information: * diff --git a/src/include/storage/locktag.h b/src/include/storage/locktag.h new file mode 100644 index 00000000000..6b122497ec6 --- /dev/null +++ b/src/include/storage/locktag.h @@ -0,0 +1,190 @@ +/*------------------------------------------------------------------------- + * + * locktag.h + * LOCKTAG declarations, for lookups in the Postgres lock hashtable. + * + * + * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/storage/locktag.h + * + *------------------------------------------------------------------------- + */ + +#ifndef _PG_LOCKTAG_H_ +#define _PG_LOCKTAG_H_ + +/* + * Lock methods are identified by LOCKMETHODID. (Despite the declaration as + * uint16, we are constrained to 256 lockmethods by the layout of LOCKTAG.) + */ +typedef uint16 LOCKMETHODID; + +/* These identify the known lock methods */ +#define DEFAULT_LOCKMETHOD 1 +#define USER_LOCKMETHOD 2 + +/* + * LOCKTAG is the key information needed to look up a LOCK item in the + * lock hashtable. A LOCKTAG value uniquely identifies a lockable object. + * + * The LockTagType enum defines the different kinds of objects we can lock. + * We can handle up to 256 different LockTagTypes. + */ +typedef enum LockTagType +{ + LOCKTAG_RELATION, /* whole relation */ + LOCKTAG_RELATION_EXTEND, /* the right to extend a relation */ + LOCKTAG_DATABASE_FROZEN_IDS, /* pg_database.datfrozenxid */ + LOCKTAG_PAGE, /* one page of a relation */ + LOCKTAG_TUPLE, /* one physical tuple */ + LOCKTAG_TRANSACTION, /* transaction (for waiting for xact done) */ + LOCKTAG_VIRTUALTRANSACTION, /* virtual transaction (ditto) */ + LOCKTAG_SPECULATIVE_TOKEN, /* speculative insertion Xid and token */ + LOCKTAG_OBJECT, /* non-relation database object */ + LOCKTAG_USERLOCK, /* reserved for old contrib/userlock code */ + LOCKTAG_ADVISORY, /* advisory user locks */ + LOCKTAG_APPLY_TRANSACTION, /* transaction being applied on a logical + * replication subscriber */ +} LockTagType; + +#define LOCKTAG_LAST_TYPE LOCKTAG_APPLY_TRANSACTION + +extern PGDLLIMPORT const char *const LockTagTypeNames[]; + +/* + * The LOCKTAG struct is defined with malice aforethought to fit into 16 + * bytes with no padding. Note that this would need adjustment if we were + * to widen Oid, BlockNumber, or TransactionId to more than 32 bits. + * + * We include lockmethodid in the locktag so that a single hash table in + * shared memory can store locks of different lockmethods. + */ +typedef struct LOCKTAG +{ + uint32 locktag_field1; /* a 32-bit ID field */ + uint32 locktag_field2; /* a 32-bit ID field */ + uint32 locktag_field3; /* a 32-bit ID field */ + uint16 locktag_field4; /* a 16-bit ID field */ + uint8 locktag_type; /* see enum LockTagType */ + uint8 locktag_lockmethodid; /* lockmethod indicator */ +} LOCKTAG; + +/* + * These macros define how we map logical IDs of lockable objects into + * the physical fields of LOCKTAG. Use these to set up LOCKTAG values, + * rather than accessing the fields directly. Note multiple eval of target! + */ + +/* ID info for a relation is DB OID + REL OID; DB OID = 0 if shared */ +#define SET_LOCKTAG_RELATION(locktag,dboid,reloid) \ + ((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) + +/* same ID info as RELATION */ +#define SET_LOCKTAG_RELATION_EXTEND(locktag,dboid,reloid) \ + ((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) + +/* ID info for frozen IDs is DB OID */ +#define SET_LOCKTAG_DATABASE_FROZEN_IDS(locktag,dboid) \ + ((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) + +/* ID info for a page is RELATION info + BlockNumber */ +#define SET_LOCKTAG_PAGE(locktag,dboid,reloid,blocknum) \ + ((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) + +/* ID info for a tuple is PAGE info + OffsetNumber */ +#define SET_LOCKTAG_TUPLE(locktag,dboid,reloid,blocknum,offnum) \ + ((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) + +/* ID info for a transaction is its TransactionId */ +#define SET_LOCKTAG_TRANSACTION(locktag,xid) \ + ((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) + +/* ID info for a virtual transaction is its VirtualTransactionId */ +#define SET_LOCKTAG_VIRTUALTRANSACTION(locktag,vxid) \ + ((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) + +/* + * ID info for a speculative insert is TRANSACTION info + + * its speculative insert counter. + */ +#define SET_LOCKTAG_SPECULATIVE_INSERTION(locktag,xid,token) \ + ((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) + +/* + * ID info for an object is DB OID + CLASS OID + OBJECT OID + SUBID + * + * Note: object ID has same representation as in pg_depend and + * pg_description, but notice that we are constraining SUBID to 16 bits. + * Also, we use DB OID = 0 for shared objects such as tablespaces. + */ +#define SET_LOCKTAG_OBJECT(locktag,dboid,classoid,objoid,objsubid) \ + ((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) + +#define SET_LOCKTAG_ADVISORY(locktag,id1,id2,id3,id4) \ + ((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) + +/* + * ID info for a remote transaction on a logical replication subscriber is: DB + * OID + SUBSCRIPTION OID + TRANSACTION ID + OBJID + */ +#define SET_LOCKTAG_APPLY_TRANSACTION(locktag,dboid,suboid,xid,objid) \ + ((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) + +#endif /* _PG_LOCKTAG_H_ */