PostgreSQL数据库Imgr——Relation Lock

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);
	}
}
上一篇:Postgresql+Keepalived高可用方案


下一篇:【PostgreSQL教程】· PostgreSQL报错提示:Is the PostgreSQL Server Running Locally and Accepting?