postgresql源码学习(十一)—— 常规锁④-冲突检测

67 篇文章 52 订阅
20 篇文章 0 订阅

       在主锁表和进程锁表中保存锁之后,就可以进行锁的冲突检测。如果检测到当前申请的锁模式与其他事务已持有锁冲突,则必须进入等待状态。

一、 函数调用

        冲突检测函数是LockCheckConflicts,其上层调用在我们之前提到过的LockAcquireExtended函数(当时我们只看了本地锁表相关代码,没有看全部)。

	//lockMethodTable->conflictTab[lockmode]获取与待申请锁模式冲突的锁模式,lock->waitMask中保存在这个锁上等待的其他事务想要申请的锁模式。如果两者有交集(按位与结果为true),说明申请申请的锁模式与其他事务正在等待的锁模式冲突,必须进入等待状态。
	if (lockMethodTable->conflictTab[lockmode] & lock->waitMask)
		found_conflict = true;
// 如果没有其他事务等待这个锁,则检查当前申请的锁模式,是否与其他事务已持有的锁冲突
// if部分是检查其他事务等待队列,else部分是检查其他事务已持锁队列
	else 
		found_conflict = LockCheckConflicts(lockMethodTable, lockmode,
											lock, proclock);

二、 LockCheckConflicts函数

       如上所述,LockCheckConflicts函数主要是检查当前申请的锁模式,是否与其他事务已持有的锁冲突。

/*
 * LockCheckConflicts -- test whether requested lock conflicts with those already granted
 * Returns true if conflict, false if no conflict.
 */
bool
LockCheckConflicts(LockMethod lockMethodTable,
				   LOCKMODE lockmode,
				   LOCK *lock,
				   PROCLOCK *proclock)
{
	int			numLockModes = lockMethodTable->numLockModes; 
	LOCKMASK	myLocks;
	int			conflictMask = lockMethodTable->conflictTab[lockmode]; //与待申请锁冲突的模式
	int			conflictsRemaining[MAX_LOCKMODES];
	int			totalConflictsRemaining = 0;
	int			i;
	SHM_QUEUE  *procLocks;
	PROCLOCK   *otherproclock;

	/*
	 * first check for global conflicts: If no locks conflict with my request,
	 * then I get the lock.
	 *
	 * Checking for conflict: lock->grantMask represents the types of
	 * currently held locks.  conflictTable[lockmode] has a bit set for each
	 * type of lock that conflicts with request.   Bitwise compare tells if
	 * there is a conflict.

     * lock->grantMask为其他事务当前已持有的锁模式,conflictMask为与待申请锁冲突的模式
	 */
	if (!(conflictMask & lock->grantMask)) //如果两者无交集,说明待申请的锁模式与其他事务已持有的锁模式均不冲突,可以直接获取
	{
		PROCLOCK_PRINT("LockCheckConflicts: no conflict", proclock);
		return false;  // Returns false if no conflict.
	}

	// proclock->holdMask 代表当前事务持有的该锁对象的某些模式
	myLocks = proclock->holdMask;
    // 循环分析8种锁模式
	for (i = 1; i <= numLockModes; i++)
	{
    // 待申请的锁模式conflictMask 与 当前锁模式i 不冲突,跳过
		if ((conflictMask & LOCKBIT_ON(i)) == 0)
		{
			conflictsRemaining[i] = 0;
			continue;
		}
    // 记录当前锁模式i 在lock中被授予了多少次
		conflictsRemaining[i] = lock->granted[i];
    // 如果当前会话持有了这个锁对象的第i个锁模式i,减去,因为自己和自己不冲突
		if (myLocks & LOCKBIT_ON(i))
			--conflictsRemaining[i];

    // 统计在所有锁模式上有多少事务持有这个锁,不包括自己
		totalConflictsRemaining += conflictsRemaining[i];
	}

	/* If no conflicts remain, we get the lock. 如果没有事务持有这个锁,直接获得锁 */
	if (totalConflictsRemaining == 0)
	{
		PROCLOCK_PRINT("LockCheckConflicts: resolved (simple)", proclock);
		return false;
	}

	/* If no group locking, it's definitely a conflict. 如果是单进程事务,且totalConflictsRemaining不等于0,暂时不能获得锁 */
	if (proclock->groupLeader == MyProc && MyProc->lockGroupLeader == NULL)
	{
		Assert(proclock->tag.myProc == MyProc);
		PROCLOCK_PRINT("LockCheckConflicts: conflicting (simple)",
					   proclock);
		return true;
	}

	/*
	 * The relation extension or page lock conflict even between the group members.
     * relation extension锁或者页锁可能出现在多进程(并行执行的)组成员之间
	 */
	if (LOCK_LOCKTAG(*lock) == LOCKTAG_RELATION_EXTEND ||
		(LOCK_LOCKTAG(*lock) == LOCKTAG_PAGE))
	{
		PROCLOCK_PRINT("LockCheckConflicts: conflicting (group)",
					   proclock);
		return true;
	}

	/*
	 * 对于多进程(并行执行的)事务,其组成员持有的锁是不冲突的,因此要在totalConflictsRemaining减去与当前事务有相同group leader的事务计数。如果最终totalConflictsRemaining等于0,则可以获得锁,否则说明有冲突。
	 */
	procLocks = &(lock->procLocks);
	otherproclock = (PROCLOCK *)
		SHMQueueNext(procLocks, procLocks, offsetof(PROCLOCK, lockLink));
	while (otherproclock != NULL)
	{
	//判断其他进程与当前事务所在进程是否有相同的group leader
		if (proclock != otherproclock &&
			proclock->groupLeader == otherproclock->groupLeader &&
			(otherproclock->holdMask & conflictMask) != 0)
		{
			int			intersectMask = otherproclock->holdMask & conflictMask;

			for (i = 1; i <= numLockModes; i++)
			{
				if ((intersectMask & LOCKBIT_ON(i)) != 0)
				{
					if (conflictsRemaining[i] <= 0)
						elog(PANIC, "proclocks held do not match lock");
					conflictsRemaining[i]--;
					totalConflictsRemaining--;
				}
			}

			if (totalConflictsRemaining == 0)
			{
				PROCLOCK_PRINT("LockCheckConflicts: resolved (group)",
							   proclock);
				return false;
			}
		}
		otherproclock = (PROCLOCK *)
			SHMQueueNext(procLocks, &otherproclock->lockLink,
						 offsetof(PROCLOCK, lockLink));
	}

	/* Nope, it's a real conflict. */
	PROCLOCK_PRINT("LockCheckConflicts: conflicting (group)", proclock);
	return true;
}

参考

PostgreSQL技术内幕:事务处理深度探索》第2章

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hehuyi_In

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值