RelationInitLockInfo
锁信息LockInfoData结构体,主要用于存放relation识别符和数据库识别符。
typedef struct LockInfoData
{
LockRelId lockRelId;
} LockInfoData;
typedef struct LockRelId {
Oid relId; /* a relation identifier */
Oid dbId; /* a database identifier */
} LockRelId;
RelationInitLockInfo函数为relation描述符初始化锁信息LockInfoData,其中relation->rd_rel是FormData_pg_class结构体,其成员也就是pg_class关于该relatioin的条目。relisshared描述的是该relation是否是跨数据库共享的。下面的逻辑就是对rd_lockInfo.lockRelId.dbId进行初始化,如果是跨数据库共享,就将InvaliOid放到该变量中。
/* RelationInitLockInfo
* Initializes the lock information in a relation descriptor.
* relcache.c must call this during creation of any reldesc. */
void RelationInitLockInfo(Relation relation) {
Assert(RelationIsValid(relation));
Assert(OidIsValid(RelationGetRelid(relation)));
relation->rd_lockInfo.lockRelId.relId = RelationGetRelid(relation);
if (relation->rd_rel->relisshared) relation->rd_lockInfo.lockRelId.dbId = InvalidOid;
else relation->rd_lockInfo.lockRelId.dbId = MyDatabaseId;
}
SetLocktagRelationOid
SetLocktagRelationOid函数创建LOCKTAG结构体,我们知道主锁表用来保存当前数据库中所有事务的锁对象(也就是Lock结构体),其存储在共享内存中。对应该哈希表来说,其键是LOCKTAG,值是LOCK结构体,这里就是初始化LOCKTAG结构体。初始化宏如SET_LOCKTAG_RELATION所示。
/* SetLocktagRelationOid Set up a locktag for a relation, given only relation OID */
static inline void SetLocktagRelationOid(LOCKTAG *tag, Oid relid) {
Oid dbid;
if (IsSharedRelation(relid)) dbid = InvalidOid;
else dbid = MyDatabaseId;
SET_LOCKTAG_RELATION(*tag, dbid, relid);
}
/* 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)
LockRelationOid
LockRelationOid函数通过OID锁定relation。该函数在尝试打开relcache entry前调用。调用LockAcquireExtended函数获取表锁。
/* LockRelationOid
* Lock a relation given only its OID. This should generally be used before attempting to open the relation's relcache entry. */
void LockRelationOid(Oid relid, LOCKMODE lockmode) {
LOCKTAG tag;
LOCALLOCK *locallock;
LockAcquireResult res;
SetLocktagRelationOid(&tag, relid);
res = LockAcquireExtended(&tag, lockmode, false, false, true, &locallock);
/* Now that we have the lock, check for invalidation messages, so that we
* will update or flush any stale relcache entry before we try to use it.
* RangeVarGetRelid() specifically relies on us for this. We can skip
* this in the not-uncommon case that we already had the same type of lock
* being requested, since then no one else could have modified the
* relcache entry in an undesirable way. (In the case where our own xact
* modifies the rel, the relcache update happens via
* CommandCounterIncrement, not here.)
* However, in corner cases where code acts on tables (usually catalogs)
* recursively, we might get here while still processing invalidation
* messages in some outer execution of this function or a sibling. The
* "cleared" status of the lock tells us whether we really are done
* absorbing relevant inval messages. */
if (res != LOCKACQUIRE_ALREADY_CLEAR) {
AcceptInvalidationMessages();
MarkLockClear(locallock);
}
}