您的位置:首页 > 科技 > 能源 > 大连网站制作报价_搜多多搜索引擎入口_网络营销方案策划书_滁州网站seo

大连网站制作报价_搜多多搜索引擎入口_网络营销方案策划书_滁州网站seo

2024/11/20 9:15:32 来源:https://blog.csdn.net/mirai_D_zoro/article/details/142532818  浏览:    关键词:大连网站制作报价_搜多多搜索引擎入口_网络营销方案策划书_滁州网站seo
大连网站制作报价_搜多多搜索引擎入口_网络营销方案策划书_滁州网站seo

概述

常规锁是数据库中实现的锁,它和自旋锁及轻量锁不同,自旋锁和轻量锁属于系统锁,主要用于保护数据库系统中的一些关键变量,服务于数据库内核的实现;常规锁属于事务锁,主要用于协调各种不同事务对数据库对象如表、页、元组等的并发访问。

内存结构

锁模式

常规锁根据其不同的使用场景,分为了8中锁模式,每种模式权限不同,这样就可以在不同的场景下通过申请不同模式的锁,从而控制锁的权限。

  • AccessShareLock
    访问共享锁,查询时会自动施加到被查询的表上。
  • RowShareLock
    行共享锁,当SQL语句中采用了select…for update 和for share语句时将使用行共享锁对表加锁。
  • RowExclusiveLock
    行排他锁,使用IUD语句时将使用行排它锁对表加锁,但只是一个意向锁,表明有事务对该表尽显IUD操作而已,并不会真正对行加锁,行锁另有其他的实现方法。
  • ShareUpdateExclusiveLock
    共享更新排它锁,使用vacuum或者create index concurrently语句时使用该锁。
  • ShareLock
    共享锁,使用不带concurrently选项的create index语句请求时用共享锁对表加锁。
  • ShareRowExclusiveLock
    共享行排它锁,类似与排它锁,但是允许行共享。任何数据库命令都不会请求这个锁,除了lock命令。如,lock table tb1 in share row exclusive mode
  • ExclusiveLock
    排它锁,阻塞行共享和select…for update语句。数据库中不会再用户表上自动请求这个锁,但是再系统表的可能会请求这个锁。
  • AccessExclusiveLock
    访问排它锁,执行alter table, truncate ,reindex,cluster,drop table 以及vacuum full等SQL命令时会添加该锁,是最高级别的锁。

锁的相容性矩阵

在这里插入图片描述

常用锁结构

常规锁主要保存在4个位置:

  • 主锁表: 在共享内存中,保存了一个锁对象的所有相关信息
  • 进程锁表:在共享内存中,保存了一个锁对象与当前进程的所有相关信息
  • 快速路径:在当前进程中,保存了弱锁的信息,避免频繁重复访问主锁表和进程锁表。
    从上面的锁模式相容性矩阵可以看出,AccessShareLock、RowShareLock、RowExclusiveLock这三个锁模式是互不冲突的,而且常用于DML操作,因此成为弱锁,剩余5个锁则为强锁。弱锁之间互不冲突,强锁和弱锁冲突。
  • 本地锁表:保存在当前进程中,对重复申请的锁进行计数,相当与本地缓存,避免重复访问主锁表和进程锁表。

所以申请锁时从上述4个位置查找的流程为:本地锁表–>快速路径–>进程锁表=主锁表,有三个全局变量控制,是哈希表

static HTAB *LockMethodLockHash;//本地锁表
static HTAB *LockMethodProcLockHash;//进程锁表
static HTAB *LockMethodLocalHash;//主锁表

结构体

锁相关的结构体主要就是上述几种类型,如下图
在这里插入图片描述

Lock

Lock结构体记录了主锁表中锁对象的所有相关信息,比如当前持有锁的信息,等待锁的信息,关联的进程等信息。

typedef enum LockTagType
{LOCKTAG_RELATION,			/* 表锁 */LOCKTAG_RELATION_EXTEND,	/* 对表进行扩展时加的锁*/LOCKTAG_DATABASE_FROZEN_IDS,	/* 数据库冻结ID时的锁 */LOCKTAG_PAGE,				/* 页锁 */LOCKTAG_TUPLE,				/* 行锁 */LOCKTAG_TRANSACTION,		/* 事务锁*/LOCKTAG_VIRTUALTRANSACTION, /* 虚拟事务锁 */LOCKTAG_SPECULATIVE_TOKEN,	/* UPSERT语句中需要等待confirm的元组加锁*/LOCKTAG_OBJECT,				/* 非表对象锁*/LOCKTAG_USERLOCK,			/* 用户锁 */LOCKTAG_ADVISORY			/* 咨询锁*/
} LockTagType;typedef struct LOCKTAG
{uint32		locktag_field1; /*  dboid */uint32		locktag_field2; /*  reloid */uint32		locktag_field3; /*  blocknum */uint16		locktag_field4; /*  forknum */uint8		locktag_type;	/* 锁类型,参见LockTagType类型 */uint8		locktag_lockmethodid;	/* lockmethod indicator: 锁方法,目前就两种:默认锁方法和用户锁方法 */
} LOCKTAG;typedef struct LOCK
{/* hash key */LOCKTAG		tag;			/* 标识符,全局唯一*//* data */LOCKMASK	grantMask;		/* 已经被持有的锁的掩码 */LOCKMASK	waitMask;		/* 正在等待的锁的掩码 */SHM_QUEUE	procLocks;		/* 当前锁相关联的进程锁表 */PROC_QUEUE	waitProcs;		/* 正在等待当前锁的进程锁表 */int requested[MAX_LOCKMODES];	/* 需要当前锁的会话的数量 */int nRequested;		/* 需索当前锁的所有会话数量 */int granted[MAX_LOCKMODES]; /* 已经持有当前锁的会话数 */int nGranted;		/* 已经持有当前锁的所有会话的数量 */
} LOCK;
LocalLock

本地锁表就是锁对象在本地进程的缓存,进程第一次申请一个锁对象后会将其放到本地锁表中,后面若是需要再申请该锁,则直接从本地锁表中获取即可,不需要再去主锁表申请,能大大提升性能。

typedef struct LOCALLOCKTAG
{LOCKTAG		lock;			/* 本地锁表的标识符*/LOCKMODE	mode;			/* 表的锁模式 */
} LOCALLOCKTAG;//本地锁表类型
typedef struct LOCALLOCK
{/* tag */LOCALLOCKTAG tag;			/* 锁标识符:  *//* data */uint32		hashcode;		/* 锁标识符的哈希值: */LOCK	   *lock;			/* 锁对象:*/PROCLOCK   *proclock;		/* 进程锁表对象 */int64		nLocks;			/* 锁被持有的最大次数 */int			numLockOwners;	/* 相关的resourceOwner数量: */int			maxLockOwners;	/* 分匹配的数组大小 */LOCALLOCKOWNER *lockOwners; /* 动态再分配*/bool		holdsStrongLockCount;	/* 是否持有强锁 */bool		lockCleared;	/* 锁是否已清理 */
} LOCALLOCK;
ProcLock

PROCLOCK结构记录进程锁表所有相关信息,它是锁对象与进程连接的纽带,这样就能通过Lock锁对象查找申请该锁对应的进程信息,也能通过Proc进程对象查找其申请的锁的信息。

typedef struct PROCLOCKTAG
{/* NB: we assume this struct contains no padding! */LOCK	   *myLock;			/* 关联的锁的信息 */PGPROC	   *myProc;			/* 关联的进程的信息 */
} PROCLOCKTAG;//进程锁表,每个需求锁的信息
typedef struct PROCLOCK
{/* tag */PROCLOCKTAG tag;			/* 进程锁表标识,全局唯一 *//* data */PGPROC	   *groupLeader;	/* 每个锁组的组长信息 */LOCKMASK	holdMask;		/* 当前持有锁的类型的掩码信息*/LOCKMASK	releaseMask;	/* 要释放的锁类型的掩码 */SHM_QUEUE	lockLink;		/* 进程锁表的锁链表*/SHM_QUEUE	procLink;		/* 进程锁表的进程链表*/
} PROCLOCK;

相关函数

LockAcquireExtended

该函数的作用就是申请一把常规锁。其申请流程就是判断申请的锁的位置,然后申请,先尝试从本地锁表中申请,然后尝试从快速路径中申请,最后是从主锁表和进程锁表申请。

从本地锁表申请

本地锁表是由一个全局变量LockMethodLocalHash记录,这是一个哈希表,申请本地锁表会根据申请的锁的类型和信息从LockMethodLocalHash中进行查找,并返回查找结果。
如果找到则增加锁计数后直接返回申请结果。如果本地锁表已经没有空间保存申请的锁的LockOwner信息,则扩容一倍。
如果没有找到,初始化一个空的本地锁表结构,后面在其他位置申请到后直接保存到本地锁表中。

    //去本地锁表查询,是一个哈希表,找到的话,返回找到的本地锁对象locallock = (LOCALLOCK *) hash_search(LockMethodLocalHash,(void *) &localtag,HASH_ENTER, &found);if (!found)//没有找到,先本地初始化一个空的本地锁表对象,后面从其他地方找到后会先放入本地锁表中{locallock->lock = NULL;locallock->proclock = NULL;locallock->hashcode = LockTagHashCode(&(localtag.lock));locallock->nLocks = 0;locallock->holdsStrongLockCount = false;locallock->lockCleared = false;locallock->numLockOwners = 0;locallock->maxLockOwners = 8;locallock->lockOwners = NULL;locallock->lockOwners = (LOCALLOCKOWNER *)MemoryContextAlloc(TopMemoryContext,locallock->maxLockOwners * sizeof(LOCALLOCKOWNER));}else//本地锁表找到了{if (locallock->numLockOwners >= locallock->maxLockOwners)//如果持有该锁的用户大于限制数量,再扩大一倍{int			newsize = locallock->maxLockOwners * 2;locallock->lockOwners = (LOCALLOCKOWNER *)repalloc(locallock->lockOwners,newsize * sizeof(LOCALLOCKOWNER));locallock->maxLockOwners = newsize;}}hashcode = locallock->hashcode;if (locallockp)*locallockp = locallock;//保存找到的本地锁if (locallock->nLocks > 0){GrantLockLocal(locallock, owner);//增加锁计数if (locallock->lockCleared) //返回结果return LOCKACQUIRE_ALREADY_CLEAR;elsereturn LOCKACQUIRE_ALREADY_HELD;}										  
从快速路径申请

从快速路径申请,分为申请弱锁和强锁。
本地进程最多保存16把弱锁,这是因为本地进程PGPROC->fpRelId是一个长度为16的数组,它里面保存的是本地进程只有锁的表的OID信息,这就限制了弱锁的数量。

  • 申请弱锁
    • 判断是否为弱锁,其判断条件为:
      1. 锁类型是表锁,锁模式<4,即前三种锁,通过EligibleForRelationFastPath宏判断
         #define EligibleForRelationFastPath(locktag, mode) \
      
    ((locktag)->locktag_lockmethodid == DEFAULT_LOCKMETHOD &&
    (locktag)->locktag_type == LOCKTAG_RELATION &&
    (locktag)->locktag_field1 == MyDatabaseId &&
    MyDatabaseId != InvalidOid &&
    (mode) < ShareUpdateExclusiveLock)
    ```
    2. 本地保存的快速路径锁数量小于16
    • 获取强锁的哈希码
    • 判断强锁是否存在,根据全局变量FastPathStrongRelationLocks来判断,如果存在,则申请失败
    • 如果强锁不存在,则申请弱锁
    • 申请到弱锁,更新锁计数并返回
	if (EligibleForRelationFastPath(locktag, lockmode) &&FastPathLocalUseCount < FP_LOCK_SLOTS_PER_BACKEND)//判断是否为弱锁:最大可持有16个 {uint32		fasthashcode = FastPathStrongLockHashPartition(hashcode);//获取强锁的哈希码bool		acquired;LWLockAcquire(&MyProc->fpInfoLock, LW_EXCLUSIVE);if (FastPathStrongRelationLocks->count[fasthashcode] != 0)//判断该强锁是否已存在,若已存在则申请失败acquired = false;elseacquired = FastPathGrantRelationLock(locktag->locktag_field2,lockmode);//申请弱锁LWLockRelease(&MyProc->fpInfoLock);if (acquired)//申请到弱锁,直接返回{locallock->lock = NULL;locallock->proclock = NULL;GrantLockLocal(locallock, owner);//增加锁计数return LOCKACQUIRE_OK;}}     
  • 申请强锁
    • 判断是否为强锁
      判断锁模式等信息,根据ConflictsWithRelationFastPath宏判断
#define ConflictsWithRelationFastPath(locktag, mode) \((locktag)->locktag_lockmethodid == DEFAULT_LOCKMETHOD && \(locktag)->locktag_type == LOCKTAG_RELATION && \(locktag)->locktag_field1 != InvalidOid && \(mode) > ShareUpdateExclusiveLock)//判断是否为强锁	
- 获取强锁哈希码
- 申请强锁
- 如果申请到强锁,则将其他进程保存的该锁的弱锁转移到主锁表中
	if (ConflictsWithRelationFastPath(locktag, lockmode)){uint32		fasthashcode = FastPathStrongLockHashPartition(hashcode);//获取哈希码BeginStrongLockAcquire(locallock, fasthashcode);//申请强锁//将其他事务保存的弱锁保存到主锁表中,因为有了强锁之后,强锁与弱锁就冲突了if (!FastPathTransferRelationLocks(lockMethodTable, locktag,hashcode)){AbortStrongLockAcquire();//终止获取强锁if (locallock->nLocks == 0)RemoveLocalLock(locallock); //如果引用计数为0,就删除本地锁elsereturn LOCKACQUIRE_NOT_AVAIL;}}
从主锁表申请

如果本地锁表和快速路径都没申请到锁,则需要去主锁表中申请了,调用SetupLockInTable函数申请,申请到之后,还需要进行锁冲突检测,如果没有冲突,就可以直接获取这个锁了,但是如果有锁冲突,就需要将自己放到等待队列上等待了。主要流程如下:

  • 先申请主锁表的轻量锁MainLWLockArray,因为要访问共享内存,以排他模式申请
	partitionLock = LockHashPartitionLock(hashcode);LWLockAcquire(partitionLock, LW_EXCLUSIVE);
  • 调用SetupLockInTable函数申请,该函数会先去主锁表和进程锁表中查找要申请的锁,如果没有找到,则需要申请内存来保存申请的锁的信息。
	proclock = SetupLockInTable(lockMethodTable, MyProc, locktag,hashcode, lockmode);//去主锁表中寻找if (!proclock)return LOCKACQUIRE_NOT_AVAIL;
  • 将申请到锁保存到本地锁表中,下一次再申请就可以直接从本地锁表中申请了
	locallock->proclock = proclock;lock = proclock->tag.myLock;locallock->lock = lock;
  • 检查锁是否与其他锁冲突,如果没有冲突更新锁计数
	if (lockMethodTable->conflictTab[lockmode] & lock->waitMask)found_conflict = true;elsefound_conflict = LockCheckConflicts(lockMethodTable, lockmode,lock, proclock);if (!found_conflict){GrantLock(lock, proclock, lockmode);GrantLockLocal(locallock, owner);
  • 如果锁冲突,但不需要等待,则删除当前记录的锁信息,直接返回获取失败,是否需要等待由传入的参数dontWait确定
		if (dontWait){AbortStrongLockAcquire();if (proclock->holdMask == 0){uint32		proclock_hashcode;proclock_hashcode = ProcLockHashCode(&proclock->tag, hashcode);SHMQueueDelete(&proclock->lockLink);SHMQueueDelete(&proclock->procLink);}lock->nRequested--;lock->requested[lockmode]--;LOCK_PRINT("LockAcquire: conditional lock failed", lock, lockmode);Assert((lock->nRequested > 0) && (lock->requested[lockmode] >= 0));Assert(lock->nGranted <= lock->nRequested);LWLockRelease(partitionLock);if (locallock->nLocks == 0)RemoveLocalLock(locallock);if (locallockp)*locallockp = NULL;return LOCKACQUIRE_NOT_AVAIL;}
  • 如果锁冲突,且需要等待,调用WaitOnLock函数等待锁的释放。
MyProc->heldLocks = proclock->holdMask;
WaitOnLock(locallock, owner);//不能获取到锁,进入等待队列等待
  • 释放MainLWLockArray锁
LWLockRelease(partitionLock);

SetupLockInTable

从主锁表和进程锁表中查找一个锁对象,如果找不到就创建一个新的。

  • 查询主锁表,从全局变量LockMethodLockHash中查询
	lock = (LOCK *) hash_search_with_hash_value(LockMethodLockHash,(const void *) locktag,hashcode,HASH_ENTER_NULL,&found);
  • 没查到,创建新的锁对象
	if (!found)//没有找到,创建一个新的锁对象{lock->grantMask = 0;lock->waitMask = 0;SHMQueueInit(&(lock->procLocks));ProcQueueInit(&(lock->waitProcs));lock->nRequested = 0;lock->nGranted = 0;MemSet(lock->requested, 0, sizeof(int) * MAX_LOCKMODES);MemSet(lock->granted, 0, sizeof(int) * MAX_LOCKMODES);LOCK_PRINT("LockAcquire: new", lock, lockmode);
  • 查询进程锁表,从全局变量LockMethodProcLockHash中查询
	proclocktag.myLock = lock;//获取进程锁表的tag信息proclocktag.myProc = proc;proclock_hashcode = ProcLockHashCode(&proclocktag, hashcode);proclock = (PROCLOCK *) hash_search_with_hash_value(LockMethodProcLockHash,(void *) &proclocktag,proclock_hashcode,HASH_ENTER_NULL,&found);
  • 没查到,创建新的进程锁表对象
	if (!found)//如果没找到就是创建一个新的进程锁表{uint32		partition = LockHashPartition(hashcode);proclock->groupLeader = proc->lockGroupLeader != NULL ?proc->lockGroupLeader : proc;proclock->holdMask = 0;proclock->releaseMask = 0;SHMQueueInsertBefore(&lock->procLocks, &proclock->lockLink);SHMQueueInsertBefore(&(proc->myProcLocks[partition]),&proclock->procLink);PROCLOCK_PRINT("LockAcquire: new", proclock);}

LockCheckConflicts

检查当前要申请的锁是否与其他的进程持有的锁冲突,主要通过主锁表中的conflicttab的掩码值与要申请的锁的掩码进行比较得出结果。如果存在多进程的情况(即group),还需要排除掉同group的冲突锁,最终得出是否冲突的结果。

  • 判断要申请的锁是否与主锁表中的其他锁冲突,没有冲突直接返回
	if (!(conflictMask & lock->grantMask))//判断当前锁模式掩码与冲突的掩码。得出是否存在冲突{PROCLOCK_PRINT("LockCheckConflicts: no conflict", proclock);return false;//都不冲突}
  • 如果存在冲突,遍历所有的锁模式,判断冲突的锁进程的数量,去掉当前进程,如果数量为0,表示为没有冲突
	myLocks = proclock->holdMask;for (i = 1; i <= numLockModes; i++)//遍历所有锁模式{if ((conflictMask & LOCKBIT_ON(i)) == 0)//指定的锁模式上不存在冲突{conflictsRemaining[i] = 0;continue;}conflictsRemaining[i] = lock->granted[i];//第i个模式在Lock上被授予了多少次了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;}
  • 如果数量不为0,且没有group,那么存在冲突
	//如果有冲突的锁,且Groupleader是自己即单进程,则有冲突if (proclock->groupLeader == MyProc && MyProc->lockGroupLeader == NULL){Assert(proclock->tag.myProc == MyProc);PROCLOCK_PRINT("LockCheckConflicts: conflicting (simple)",proclock);return true;}
  • 如果存在group,则遍历每个进程,减去与当前进程同一个group的进程,得到剩余的总数量,如果为0,不存在冲突,否则存在冲突
	procLocks = &(lock->procLocks);otherproclock = (PROCLOCK *)SHMQueueNext(procLocks, procLocks, offsetof(PROCLOCK, lockLink));//遍历所有其他的进程,减去与当前进程一个group的冲突的锁,减完如果为0就没有冲突,否则就有冲突while (otherproclock != NULL){if (proclock != otherproclock &&proclock->groupLeader == otherproclock->groupLeader &&(otherproclock->holdMask & conflictMask) != 0)//其他的进程且与当前进程在一个group中,且存在锁冲突{int			intersectMask = otherproclock->holdMask & conflictMask;//是否冲突for (i = 1; i <= numLockModes; i++)//遍历所有锁模式{if ((intersectMask & LOCKBIT_ON(i)) != 0)//冲突{conflictsRemaining[i]--;//因为是同组的,所以冲突的就不是冲突了,减掉totalConflictsRemaining--;}}if (totalConflictsRemaining == 0)//所有冲突的锁都符合,那么就不存在锁冲突了{PROCLOCK_PRINT("LockCheckConflicts: resolved (group)",proclock);return false;}}otherproclock = (PROCLOCK *)SHMQueueNext(procLocks, &otherproclock->lockLink,offsetof(PROCLOCK, lockLink));//遍历下一个}

FastPathGrantRelationLock

申请快速路径的弱锁,每个进程最多能持有16个弱锁,所以预留的槽位只有16个,遍历 每个槽位,找到没被占用的槽位,然后将要申请的锁信息填入该槽位占住即可。

static bool
FastPathGrantRelationLock(Oid relid, LOCKMODE lockmode)
{uint32		f;uint32		unused_slot = FP_LOCK_SLOTS_PER_BACKEND;/* Scan for existing entry for this relid, remembering empty slot. */for (f = 0; f < FP_LOCK_SLOTS_PER_BACKEND; f++)//遍历每一个槽位,通16个槽位{if (FAST_PATH_GET_BITS(MyProc, f) == 0)//判断是否还未被占用unused_slot = f;else if (MyProc->fpRelId[f] == relid)//判断当前表是否已经申请过{Assert(!FAST_PATH_CHECK_LOCKMODE(MyProc, f, lockmode));FAST_PATH_SET_LOCKMODE(MyProc, f, lockmode);return true;}}/* If no existing entry, use any empty slot. */if (unused_slot < FP_LOCK_SLOTS_PER_BACKEND){MyProc->fpRelId[unused_slot] = relid;//占用空闲的槽位FAST_PATH_SET_LOCKMODE(MyProc, unused_slot, lockmode);//更新锁标记++FastPathLocalUseCount;//更新快速路径计数return true;}/* No existing entry, and no empty slot. */return false;
}

BeginStrongLockAcquire

申请强锁,就是更新全局变量FastPathStrongRelationLocks的值,然后将本地锁表的holdsStrongLockCount设置为true

BeginStrongLockAcquire(LOCALLOCK *locallock, uint32 fasthashcode)
{SpinLockAcquire(&FastPathStrongRelationLocks->mutex);//修改全局变量,先申请锁FastPathStrongRelationLocks->count[fasthashcode]++;//更新对应的强锁计数locallock->holdsStrongLockCount = true;//标记一下,本地锁表申请的有强锁StrongLockInProgress = locallock;//当前的锁是强锁SpinLockRelease(&FastPathStrongRelationLocks->mutex);//释放锁
}

FastPathTransferRelationLocks

获取到强锁以后,如果其他进程的快速路径上还保存有对应的弱锁,就需要将这些弱锁挪到主锁表中,否则这些快速路径上的弱锁将因为与强锁冲突而失效。
该函数会遍历所有的进程,所有的进程保存在全局变量ProcGlobal->allProcs中,然后查找对应的弱锁,找到后挪到主锁表中,主要流程如下:

  • 遍历每个进程,如果跟持锁的数据库信息不一致,直接跳过
  • 遍历每个进程上的弱锁的槽位(16个),弱锁相关的表ID跟申请的不一致或对应槽位未被使用,直接跳过
  • 遍历每个弱锁模式(3个),若该模式弱锁不存在,直接跳过
  • 走到这里,就说明该进程的某个槽位存在弱锁且与申请的强锁冲突,去主锁表中重新创建该锁(即将该弱锁转移到主锁表中)。
  • 清空该进程上相关的弱锁信息
FastPathTransferRelationLocks(LockMethod lockMethodTable, const LOCKTAG *locktag,uint32 hashcode)
{LWLock	   *partitionLock = LockHashPartitionLock(hashcode);Oid			relid = locktag->locktag_field2;uint32		i;for (i = 0; i < ProcGlobal->allProcCount; i++)//遍历所有的进程{PGPROC	   *proc = &ProcGlobal->allProcs[i];//取一个进程uint32		f;LWLockAcquire(&proc->fpInfoLock, LW_EXCLUSIVE);//获取该进程上的快速路径锁,锁住后禁止其他进程访问该进程相关的快速路径的信息if (proc->databaseId != locktag->locktag_field1)//如果不然会同一个数据库,可以直接跳过,因为不相关{LWLockRelease(&proc->fpInfoLock);continue;}for (f = 0; f < FP_LOCK_SLOTS_PER_BACKEND; f++)//遍历进程上的所有弱锁槽位{uint32		lockmode;/* Look for an allocated slot matching the given relid. */if (relid != proc->fpRelId[f] || FAST_PATH_GET_BITS(proc, f) == 0)//表ID或持锁信息不符合要求,跳过continue;/* Find or create lock object. */LWLockAcquire(partitionLock, LW_EXCLUSIVE);//主锁表加锁for (lockmode = FAST_PATH_LOCKNUMBER_OFFSET;lockmode < FAST_PATH_LOCKNUMBER_OFFSET + FAST_PATH_BITS_PER_SLOT;++lockmode)//遍历每种弱锁模式{PROCLOCK   *proclock;if (!FAST_PATH_CHECK_LOCKMODE(proc, f, lockmode))//不存在弱锁,跳过continue;proclock = SetupLockInTable(lockMethodTable, proc, locktag,hashcode, lockmode);//在主锁表中创建或申请对应的锁if (!proclock){LWLockRelease(partitionLock);LWLockRelease(&proc->fpInfoLock);return false;}GrantLock(proclock->tag.myLock, proclock, lockmode);//更新锁计数FAST_PATH_CLEAR_LOCKMODE(proc, f, lockmode);//清空该进程上的弱锁计数}LWLockRelease(partitionLock);/* No need to examine remaining slots. */break;}LWLockRelease(&proc->fpInfoLock);}return true;
}

WaitOnLock

当前进程睡眠并等待其期望的锁释放,调用ProcSleep函数睡眠,ProcSleep函数中又会调用CheckDeadLock函数进行死锁检测。

【参考】

  1. 《PostgreSQL数据库内核分析》
  2. 《Postgresql技术内幕-事务处理深度探索》
  3. 《PostgreSQL指南:内幕探索》
  4. pg14源码

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com