1 创建劝告锁
pg_advisory_lock_int8(PG_FUNCTION_ARGS) //在指定对象上加派他式的劝告锁
{...
SET_LOCKTAG_INT64(tag, key);
(void) LockAcquire(&tag, ExclusiveLock, true, false);
...}
2 对于诸如VACUUM类似的操作在指定对象上加排它锁
btvacuumscan(...)
{...
for (;;)
{
/* Get the current relation length */
if (needLock)
LockRelationForExtension(rel, ExclusiveLock);
num_pages = RelationGetNumberOfBlocks(rel);
if (needLock)
UnlockRelationForExtension(rel, ExclusiveLock);
...
}
...
}
3 为系统表加锁
replorigin_create(char *roname)
{...
rel = heap_open(ReplicationOriginRelationId, ExclusiveLock); // ReplicationOriginRelationId,pg_replication_origin系统表的标识
...}
4 为对象加锁
GetLockStatusData(void)
{...
for (i = 0; i < ProcGlobal->allProcCount; ++i)
{...
for (f = 0; f < FP_LOCK_SLOTS_PER_BACKEND; ++f)
{
LockInstanceData *instance;
...
instance = &data->locks[el];
SET_LOCKTAG_RELATION(instance->locktag, proc->databaseId, proc->fpRelId[f]);
instance->holdMask = LOCKBIT_ON(ExclusiveLock);
...
}
...
}
...
}
其中,LockInstanceData定义如下:
typedef struct LockInstanceData
{
LOCKTAG locktag; /* 被加锁的对象的标识 */
LOCKMASK holdMask; /* locks held by this PGPROC,值为“LOCKBIT_ON(ExclusiveLock)”表示被加锁 */
LOCKMODE waitLockMode; /* lock awaited by this PGPROC, if any */
BackendId backend; /* backend ID of this PGPROC */
LocalTransactionId lxid; /* local transaction ID of this PGPROC */
int pid; /* pid of this PGPROC */
int leaderPid; /* pid of group leader; = pid if no group */
bool fastpath; /* taken via fastpath? */
} LockInstanceData;
5 为指定的Relation加锁(物理页面在缓存区的页)
RelationGetBufferForTuple(Relation relation, ...) //返回被pin住的且被排它锁锁住的buf页
{...
if (needLock)
{
if (!use_fsm)
LockRelationForExtension(relation, ExclusiveLock);
else if (!ConditionalLockRelationForExtension(relation, ExclusiveLock))
{
/* Couldn't get the lock immediately; wait for it. */
LockRelationForExtension(relation, ExclusiveLock); //在relation上加派他锁
...
/*
* If some other waiter has already extended the relation, we
* don't need to do so; just use the existing freespace.
*/
if (targetBlock != InvalidBlockNumber)
{
UnlockRelationForExtension(relation, ExclusiveLock);
goto loop;
}
...
}
}
...
}
6 为索引页加锁
ginInsertCleanup(GinState *ginstate, ...) //为指定的索引页加锁,本质上类似于为指定的Relation加锁
{
Relation index = ginstate->index; //一个index页,也是一个被“Relation”定义的对象
if (inVacuum)
{
/*
* We are called from [auto]vacuum/analyze or
* gin_clean_pending_list() and we would like to wait
* concurrent cleanup to finish.
*/
LockPage(index, GIN_METAPAGE_BLKNO, ExclusiveLock); //为指定的索引页加派他锁
...
}
else
{
/*
* We are called from regular insert and if we see
* concurrent cleanup just exit in hope that concurrent
* process will clean up pending list.
*/
if (!ConditionalLockPage(index, GIN_METAPAGE_BLKNO, ExclusiveLock))
return;
...
}
...
}