LWLock在PostgreSQL中的作用
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加以保护。
SpinLock与LWLock比较
从系统的生命周期看,这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;