PostgreSQL V9.6 ExclusiveLock的用途

时间:2022-08-09 05:56:05

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); // ReplicationOriginRelationIdpg_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;

...

    }

...

}