PostgreSQL V9.6 LWLock实现分析(九)

时间:2020-12-02 05:56:21

LWLockPostgreSQL中的作用

    PostgreSQL中,LWLock锁可以加在特定的对象上,如对某个进程加锁,以获取其上锁的状态信息:

GetLockStatusData(void)

{...

    for (i =0; i < ProcGlobal->allProcCount; ++i)

    {

        PGPROC              *proc = &ProcGlobal->allProcs[i];

...

        LWLockAcquire(&proc->backendLock,LW_SHARED);  //proc->backendLock锁对象上加轻量的共享锁

    ...}

...}

    另外,PostgreSQL中,LWLock锁也可以在其它特定对象上加排它锁,如在ProcArrayLock上加锁:

void

analyze_rel(Oid relid, RangeVar *relation, int options,

           VacuumParams *params, List *va_cols, bool in_outer_xact,

           BufferAccessStrategy bstrategy)

{...

    /*

     * OK,let's do it.  First let other backendsknow I'm in ANALYZE.

     */

    // ProcArrayLock宏定义,进程数组锁: #define ProcArrayLock(&MainLWLockArray[4].lock)

    LWLockAcquire(ProcArrayLock,LW_EXCLUSIVE);  //ProcArrayLock锁对象上加轻量的排它锁

   MyPgXact->vacuumFlags |= PROC_IN_ANALYZE; 

    LWLockRelease(ProcArrayLock);  //快速释放锁

...}

    buf上加锁或释放锁:

LockBuffer(Buffer buffer, int mode) //buf上加锁或释放锁

{...

    buf =GetBufferDescriptor(buffer - 1); //获取buf

 

    if (mode== BUFFER_LOCK_UNLOCK)

       LWLockRelease(BufferDescriptorGetContentLock(buf)); //buf上释放锁

    else if(mode == BUFFER_LOCK_SHARE)

       LWLockAcquire(BufferDescriptorGetContentLock(buf),LW_SHARED); //buf上加锁

    else if(mode == BUFFER_LOCK_EXCLUSIVE)

       LWLockAcquire(BufferDescriptorGetContentLock(buf),LW_EXCLUSIVE); //buf上加锁

    else

       elog(ERROR, "unrecognized buffer lock mode: %d", mode);

}

 

缓存区的*管理

    共享缓存区的读写,存在竞争操作,因而需要使用锁进行保护。PostgreSQL使用LWLock锁的来保护共享缓存区,但是对共享缓存区采取分段保护的策略,即把共享缓存区分为几个子块,每个子块使用一个LWLock锁进行保护,这样做的好处,能增大对共享缓存区的并发访问粒度、减少竞争冲突。

/*

 * The sharedbuffer mapping table is partitioned to reducecontention.

 * Todetermine which partition lock a given tag requires, compute the tag's

 * hash codewith BufTableHashCode(), then apply BufMappingPartitionLock().

 * NB:NUM_BUFFER_PARTITIONS must be a power of 2!

 */

#define BufTableHashPartition(hashcode)\

   ((hashcode) % NUM_BUFFER_PARTITIONS)

#define BufMappingPartitionLock(hashcode)\

    (&MainLWLockArray[BUFFER_MAPPING_LWLOCK_OFFSET+ \

       BufTableHashPartition(hashcode)].lock)

#define BufMappingPartitionLockByIndex(i)\

   (&MainLWLockArray[BUFFER_MAPPING_LWLOCK_OFFSET + (i)].lock)

    同理,锁管理器的共享的Hash表(LockHashPartitionLock)、谓词锁的共享Hash表(PredicateLockHashPartitionLock),也被分段后用不同的LWLock加以保护。

SpinLockLWLock比较

   从系统的生命周期看,这2种锁,因加锁对象都是系统层级所以都是在系统初始化期间建立;但是使用的范围和粒度看却不同:SpinLock锁的粒度非常小,通常保护的都是结构体,是对“自我”的保护;LWLock锁的粒度相对大一些,通常保护的是内存结构一级的对象,如一个hash表,这个属于“系统业务”级别的保护。从下面这个示例,我们可以体会这个差别。

typedef struct pgssSharedState  //本结构体中的两种锁的详细用法,可以参见:pg_stat_statements_internal()

{

    LWLock     *lock;               /*protects hashtable search/modification */   //用以保护“static HTAB*pgss_hash

   double      cur_median_usage;    /* current median usage in hashtable */

    Size        mean_query_len;      /* current mean entry text length */

    slock_t    mutex;               /*protects following fields only: */         //用以保护pgssSharedState这个结构体自身的数据

    Size        extent;              /* currentextent of query file */

    int         n_writers;           /* number of active writers to query file */

    int         gc_count;            /* query file garbage collection cyclecount */

} pgssSharedState;