LWLock*的本质
LWLock的锁操作,符合锁操作的技术本质,加锁同样是设置一个特定的标志位,释放锁是取消标识位。如下以CheckPoint相关操作为例,进行说明,其他类似。
PostgreSQL定义LWLock结构体如下:
typedef struct LWLock //LWLock锁的数据结构,绑定了锁、锁的属主、锁的等待者这三者,PostgreSQL 9.4.x之前的版本的实现方式有较大不同
{
uint16 tranche; /* tranche ID */ //LWLock上多了事务号,表明实施加锁操作的属主
pg_atomic_uint32 state; /* state of exclusive/nonexclusive lockers*/ //锁对象,一个标志对象,有多个标志位(通常是无符号32位数),即有32个标志位,不同标志位表达不同含义。之所以这样定义,是因为这样的锁需要同时表达多种含义(如设置为LW_FLAG_HAS_WAITERS同时还可设置为)
dlist_head waiters; /* list of waiting PGPROCs */ //本锁的等待队列,表明那些进程在等待本锁释放
#ifdef LOCK_DEBUG
pg_atomic_uint32 nwaiters; /*number of waiters */ //等待者的数量
structPGPROC *owner; /* last exclusive owner of the lock */ //排它锁的属主
#endif
} LWLock;
PostgreSQL定义了不同的标识符号,用以为“pg_atomic_uint32 state”标识不同的含义,已经在PostgreSQL中定义好的标识符号如下:
#define LW_FLAG_HAS_WAITERS ((uint32) 1 << 30) //标志,LWLock锁有等待者
#define LW_FLAG_RELEASE_OK ((uint32) 1 << 29) //标志,LWLock锁空闲,即没有施加锁(state值为“536870912”)
#define LW_FLAG_LOCKED ((uint32) 1 << 28) //标志,LWLock锁存在,即已被加锁(state值为“268435456”)
#define LW_VAL_EXCLUSIVE ((uint32) 1 << 24) //锁的模式,LWLock排它锁模式,加锁的标志位之一,供加锁操作时使用
#define LW_VAL_SHARED 1 //锁的模式,LWLock共享锁模式,加锁的标志位之一,供加锁操作时使用
#define LW_LOCK_MASK ((uint32) ((1 << 25)-1)) //标志,LWLock锁标志
/* Must be greater than MAX_BACKENDS - which is2^23-1, so we're fine. */
#define LW_SHARED_MASK ((uint32) ((1 << 24)-1)) //标志,LWLock存在共享锁
PostgreSQL定义LWLock结构体之后,一个LWLock对象就可以出现在其他需要被保护的对象中,如进程对象(PGPROC)。
struct PGPROC //进程的结构体,PostgreSQL是多进程结构
{...
/*Per-backend LWLock. Protects fieldsbelow (but not group fields). */
LWLock backendLock; //定义LWLock锁,用于保护进程结构体中的共享资源不受并发操作破坏
//如下对象被backendLock保护
/* Lockmanager da
uint64 fpLockBits; /* lock modes held for each fast-pathslot */
Oid fpRelId[FP_LOCK_SLOTS_PER_BACKEND]; /* slots for rel oids */
bool fpVXIDLock; /* are we holding a fast-path VXIDlock? */
LocalTransactionId fpLocalTransactionId; /* lxid for fast-path VXID lock */
...};
进程对象(PGPROC)通过InitProcGlobal()函数完成初始化,然后由此函数调用LWLockInitialize()函数完成对进程锁“backendLock”的初始化工作,即设置锁标志为“LW_FLAG_RELEASE_OK”。
void
InitProcGlobal(void)
{...
for (i =0; i < TotalProcs; i++)
{
/*
*Set up per-PGPROC semaphore, latch, and backendLock. Prepared xact
* dummy PGPROCs don't need these though- they're never associated
*with a real process
*/
if (i< MaxBackends + NUM_AUXILIARY_PROCS)
{
PGSemaphoreCreate(&(procs[i].sem));
InitSharedLatch(&(procs[i].procLatch));
LWLockInitialize(&(procs[i].backendLock), LWTRANCHE_PROC); //调用LWLockInitialize()初始化backendLock
}
...
}
...
}
而LWLockInitialize()函数要给“state”成员设置标识位为“LW_FLAG_RELEASE_OK”。
void
LWLockInitialize(LWLock *lock, int tranche_id)
{
pg_atomic_init_u32(&lock->state,LW_FLAG_RELEASE_OK); //设置无锁标志
#ifdef LOCK_DEBUG
pg_atomic_init_u32(&lock->nwaiters, 0);
#endif
lock->tranche = tranche_id;
dlist_init(&lock->waiters);
}