LWLock(轻量级锁)主要提供对共享存储器的数据结构的互斥访问。LWLock有两种锁模式,一种为排他模式,另一种为共享模式。如果要读共享内存中的内容,可以给要读取的部分加上共享锁(读锁),这样其他读操作就可以并发执行,同时保证不会有其他人修改这部分共享内存。当要修改共享内存时,需要加上排他锁(写锁),保证其他进程不会读写该共享内存。

LWLock(轻量级锁)利用SpinLock实现,当没有锁的竞争时可以很快获得或释放LWLock。当一个进程阻塞在一个轻量级锁上时,相当于阻塞在一个信号量上,所以不会消耗CPU时间,等待的进程将会以先来后到的顺序被授予锁。上述描述为早期PostgreSQL数据库版本中,轻量锁是借助自旋锁实现的,自旋锁负责保护轻量锁中的共享变量、引用计数、等待队列等。随着PG数据库不断进行优化,利用自旋锁直接保护轻量锁的方法会导致性能恶化,因此目前轻量锁也借助原子操作的原语(TAS/CAS)进行无锁保护。

特点:有等待队列、无死锁检测、能自动释放锁
轻量级锁不提供死锁检测,但轻量级锁管理器在elog恢复期间被自动释放,所以持有轻量级锁的期间调用elog发出错误消息不会出现轻量级锁未释放的问题。

数据结构

原版PG 8.4.1

typedef struct LwLock{
  slock_t mutex;  // 保护LwLock和进程队列
  bool releaseOK;
  char exclusive;  //0或1,持有排他LWLock锁的后端数目
  int shared;      //持有共享LWLock锁的后端数目(0..MaxBackends)
  PROC *head;      //进程等待队列的头
  PROC *tail;      //进程等待队列的尾,当头为空时,尾不确定
}

LWLock(轻量级锁)利用SpinLock实现,使用SpinLock对数据结构的mutex互斥量加/解锁即可实现对一个LWLock的互斥访问。LWLock有两种锁模式,一种为排他模式,另一种为共享模式。通过数据结构的exclusive和shared可以区分。系统用一个全局数组LWLockArray管理所有的LWLock。在PG中,有29个LWLock被系统默认使用(如OidGenLock、WALInsertLock、CheckpointLock等)。系统初始化LWLockArray时,为LWLockArray多分配了2个整型的空间,一个用来存储已分配的LWLock数量,另一个用来记录可分配的LWLock总数。
原版PG 12.6
对于数据库开发者而言,轻量锁有两种使用方法,一种是统一保存的Individual LWLocks,另一种是Builtin Tranches。实际上他们只是形式上不同,本质上没有区别。

typedef struct LWLock{
	uint16		tranche;		/* tranche ID */
	pg_atomic_uint32 state;		/* state of exclusive/nonexclusive lockers */
	proclist_head waiters;		/* list of waiting PGPROCs */
#ifdef LOCK_DEBUG
	pg_atomic_uint32 nwaiters;	/* number of waiters */
	struct PGPROC *owner;		/* last exclusive owner of the lock */
#endif
} LWLock;

在Individual LWLocks中,,每个LWLock都对应一个Tranche ID,它具有全局唯一性。在MainLWLockArray数组中的前面的都是Individual LWLocks。与Individual LWLocks不同,每个Builtin Tranche可能对应多个LWLock,它代表的是一组LWLocks,这组LWLocks虽然各自封锁各自的内容,但它们的功能相同

目前PG保存了44种Individual LWLocks,他们都被保存在src/backend/storage/Imgr/lwlocknames.txt文件中,在编译PG的过程中会通过这个文件生成一个新的头文件src/backend/storage/Imgr/lwlocknames.h。从定义可以看出,Individual LWLocks被保存在MainLWLockArray数组中,每种Individual LWLocks都有自己固定要保护的对象。

# 0 is available; was formerly BufFreelistLock
ShmemIndexLock						1
OidGenLock							2
XidGenLock							3
ProcArrayLock						4
SInvalReadLock						5
SInvalWriteLock						6
WALBufMappingLock					7
WALWriteLock						8
ControlFileLock						9
CheckpointLock						10
CLogControlLock						11
SubtransControlLock					12
MultiXactGenLock					13
MultiXactOffsetControlLock			14
MultiXactMemberControlLock			15
RelCacheInitLock					16
CheckpointerCommLock				17
TwoPhaseStateLock					18
TablespaceCreateLock				19
BtreeVacuumLock						20
AddinShmemInitLock					21
AutovacuumLock						22
AutovacuumScheduleLock				23
SyncScanLock						24
RelationMappingLock					25
AsyncCtlLock						26
AsyncQueueLock						27
SerializableXactHashLock			28
SerializableFinishedListLock		29
SerializablePredicateLockListLock	30
OldSerXidLock						31
SyncRepLock							32
BackgroundWorkerLock				33
DynamicSharedMemoryControlLock		34
AutoFileLock						35
ReplicationSlotAllocationLock		36
ReplicationSlotControlLock			37
CommitTsControlLock					38
CommitTsLock						39
ReplicationOriginLock				40
MultiXactTruncationLock				41
OldSnapshotTimeMapLock				42
LogicalRepWorkerLock				43
CLogTruncationLock					44
# 45 was CLogTruncationLock until removal of BackendRandomLock
WrapLimitsVacuumLock				46
NotifyQueueTailLock					47

MainLWLockArray

MainLWLockArray是LWLockPadded数组指针,如下是该数组每个元素的定义

/* LWLock, padded to a full cache line size */
typedef union LWLockPadded {
	LWLock		lock;
	char		pad[LWLOCK_PADDED_SIZE];
} LWLockPadded;
/* This points to the main array of LWLocks in shared memory.  Backends inherit
 * the pointer by fork from the postmaster (except in the EXEC_BACKEND case,
 * where we have special measures to pass it down). */
LWLockPadded *MainLWLockArray = NULL;
//src/backend/storage/Imgr/lwlocknames.c
const char *const MainLWLockNames[] = {"<unassigned:0>","ShmemIndexLock","OidGenLock","XidGenLock","ProcArrayLock","SInvalReadLock","SInvalWriteLock","WALBufMappingLock","WALWriteLock","ControlFileLock","CheckpointLock","CLogControlLock","SubtransControlLock","MultiXactGenLock","MultiXactOffsetControlLock","MultiXactMemberControlLock","RelCacheInitLock","CheckpointerCommLock","TwoPhaseStateLock","TablespaceCreateLock","BtreeVacuumLock","AddinShmemInitLock","AutovacuumLock","AutovacuumScheduleLock","SyncScanLock","RelationMappingLock","AsyncCtlLock","AsyncQueueLock","SerializableXactHashLock","SerializableFinishedListLock","SerializablePredicateLockListLock","OldSerXidLock","SyncRepLock","BackgroundWorkerLock","DynamicSharedMemoryControlLock","AutoFileLock","ReplicationSlotAllocationLock","ReplicationSlotControlLock","CommitTsControlLock","CommitTsLock","ReplicationOriginLock","MultiXactTruncationLock","OldSnapshotTimeMapLock","LogicalRepWorkerLock","CLogTruncationLock","<unassigned:45>","WrapLimitsVacuumLock","NotifyQueueTailLock"
};
//src/backend/storage/Imgr/lwlocknames.h
#define ShmemIndexLock (&MainLWLockArray[1].lock)
#define OidGenLock (&MainLWLockArray[2].lock)
#define XidGenLock (&MainLWLockArray[3].lock)
#define ProcArrayLock (&MainLWLockArray[4].lock)
#define SInvalReadLock (&MainLWLockArray[5].lock)
#define SInvalWriteLock (&MainLWLockArray[6].lock)
#define WALBufMappingLock (&MainLWLockArray[7].lock)
#define WALWriteLock (&MainLWLockArray[8].lock)
#define ControlFileLock (&MainLWLockArray[9].lock)
#define CheckpointLock (&MainLWLockArray[10].lock)
#define CLogControlLock (&MainLWLockArray[11].lock)
#define SubtransControlLock (&MainLWLockArray[12].lock)
#define MultiXactGenLock (&MainLWLockArray[13].lock)
#define MultiXactOffsetControlLock (&MainLWLockArray[14].lock)
#define MultiXactMemberControlLock (&MainLWLockArray[15].lock)
#define RelCacheInitLock (&MainLWLockArray[16].lock)
#define CheckpointerCommLock (&MainLWLockArray[17].lock)
#define TwoPhaseStateLock (&MainLWLockArray[18].lock)
#define TablespaceCreateLock (&MainLWLockArray[19].lock)
#define BtreeVacuumLock (&MainLWLockArray[20].lock)
#define AddinShmemInitLock (&MainLWLockArray[21].lock)
#define AutovacuumLock (&MainLWLockArray[22].lock)
#define AutovacuumScheduleLock (&MainLWLockArray[23].lock)
#define SyncScanLock (&MainLWLockArray[24].lock)
#define RelationMappingLock (&MainLWLockArray[25].lock)
#define AsyncCtlLock (&MainLWLockArray[26].lock)
#define AsyncQueueLock (&MainLWLockArray[27].lock)
#define SerializableXactHashLock (&MainLWLockArray[28].lock)
#define SerializableFinishedListLock (&MainLWLockArray[29].lock)
#define SerializablePredicateLockListLock (&MainLWLockArray[30].lock)
#define OldSerXidLock (&MainLWLockArray[31].lock)
#define SyncRepLock (&MainLWLockArray[32].lock)
#define BackgroundWorkerLock (&MainLWLockArray[33].lock)
#define DynamicSharedMemoryControlLock (&MainLWLockArray[34].lock)
#define AutoFileLock (&MainLWLockArray[35].lock)
#define ReplicationSlotAllocationLock (&MainLWLockArray[36].lock)
#define ReplicationSlotControlLock (&MainLWLockArray[37].lock)
#define CommitTsControlLock (&MainLWLockArray[38].lock)
#define CommitTsLock (&MainLWLockArray[39].lock)
#define ReplicationOriginLock (&MainLWLockArray[40].lock)
#define MultiXactTruncationLock (&MainLWLockArray[41].lock)
#define OldSnapshotTimeMapLock (&MainLWLockArray[42].lock)
#define LogicalRepWorkerLock (&MainLWLockArray[43].lock)
#define CLogTruncationLock (&MainLWLockArray[44].lock)
#define WrapLimitsVacuumLock (&MainLWLockArray[46].lock)
#define NotifyQueueTailLock (&MainLWLockArray[47].lock)
#define NUM_INDIVIDUAL_LWLOCKS		48

Builtin Tranche

小于NUM_INDIVIDUAL_LWLOCKS的tranche ID都被保留了,为Builtim tranches也保留了一下tranche id。

typedef enum BuiltinTrancheIds {
	LWTRANCHE_CLOG_BUFFERS = NUM_INDIVIDUAL_LWLOCKS, LWTRANCHE_COMMITTS_BUFFERS, LWTRANCHE_SUBTRANS_BUFFERS, LWTRANCHE_MXACTOFFSET_BUFFERS, LWTRANCHE_MXACTMEMBER_BUFFERS, LWTRANCHE_ASYNC_BUFFERS, LWTRANCHE_OLDSERXID_BUFFERS, LWTRANCHE_WAL_INSERT, LWTRANCHE_BUFFER_CONTENT, LWTRANCHE_BUFFER_IO_IN_PROGRESS, LWTRANCHE_REPLICATION_ORIGIN, LWTRANCHE_REPLICATION_SLOT_IO_IN_PROGRESS, LWTRANCHE_PROC, LWTRANCHE_BUFFER_MAPPING, LWTRANCHE_LOCK_MANAGER, LWTRANCHE_PREDICATE_LOCK_MANAGER, LWTRANCHE_PARALLEL_HASH_JOIN,LWTRANCHE_PARALLEL_QUERY_DSA, LWTRANCHE_SESSION_DSA, LWTRANCHE_SESSION_RECORD_TABLE, LWTRANCHE_SESSION_TYPMOD_TABLE, LWTRANCHE_SHARED_TUPLESTORE, LWTRANCHE_TBM, LWTRANCHE_PARALLEL_APPEND, LWTRANCHE_SXACT, LWTRANCHE_FIRST_USER_DEFINED
}			BuiltinTrancheIds;

NamedLWLockTranche是放置MainLWLockArray中的NUM_FIXED_LWLOCKS加命名tranche需要的KWLOCKS之后的。

typedef struct NamedLWLockTranche {
	int			trancheId;
	char	   *trancheName;
} NamedLWLockTranche;
NamedLWLockTranche *NamedLWLockTrancheArray = NULL;
/* struct representing the LWLock tranche request for named tranche */
typedef struct NamedLWLockTrancheRequest {
	char		tranche_name[NAMEDATALEN];
	int			num_lwlocks;
} NamedLWLockTrancheRequest;
NamedLWLockTrancheRequest *NamedLWLockTrancheRequestArray = NULL;

RequestNamedLWLockTranche函数用于填充NamedLWLockTrancheRequest结构体。

void RequestNamedLWLockTranche(const char *tranche_name, int num_lwlocks) {
	NamedLWLockTrancheRequest *request;
	if (IsUnderPostmaster || !lock_named_request_allowed)
		return;					/* too late */
	if (NamedLWLockTrancheRequestArray == NULL) {
		NamedLWLockTrancheRequestsAllocated = 16;
		NamedLWLockTrancheRequestArray = (NamedLWLockTrancheRequest *)
			MemoryContextAlloc(TopMemoryContext, NamedLWLockTrancheRequestsAllocated * sizeof(NamedLWLockTrancheRequest));
	}
	if (NamedLWLockTrancheRequests >= NamedLWLockTrancheRequestsAllocated) {
		int			i = NamedLWLockTrancheRequestsAllocated;
		while (i <= NamedLWLockTrancheRequests) i *= 2;
		NamedLWLockTrancheRequestArray = (NamedLWLockTrancheRequest *)repalloc(NamedLWLockTrancheRequestArray, i * sizeof(NamedLWLockTrancheRequest));
		NamedLWLockTrancheRequestsAllocated = i;
	}
	request = &NamedLWLockTrancheRequestArray[NamedLWLockTrancheRequests];
	Assert(strlen(tranche_name) + 1 < NAMEDATALEN);
	StrNCpy(request->tranche_name, tranche_name, NAMEDATALEN);
	request->num_lwlocks = num_lwlocks;
	NamedLWLockTrancheRequests++;
}

初始化

CreateLWLocks为main LWLock数组和tranches分配共享内存,并初始化。最后注册所有的LWLock tranches。

/* Allocate shmem space for the main LWLock array and all tranches and initialize it.  We also register all the LWLock tranches here. */
void CreateLWLocks(void) {
	StaticAssertStmt(LW_VAL_EXCLUSIVE > (uint32) MAX_BACKENDS, "MAX_BACKENDS too big for lwlock.c");
	StaticAssertStmt(sizeof(LWLock) <= LWLOCK_MINIMAL_SIZE && sizeof(LWLock) <= LWLOCK_PADDED_SIZE,"Miscalculated LWLock padding");

	if (!IsUnderPostmaster) {
		Size		spaceLocks = LWLockShmemSize();
		int		   *LWLockCounter;
		char	   *ptr;
		/* Allocate space */
		ptr = (char *) ShmemAlloc(spaceLocks);
		/* Leave room for dynamic allocation of tranches */
		ptr += sizeof(int);
		/* Ensure desired alignment of LWLock array */
		ptr += LWLOCK_PADDED_SIZE - ((uintptr_t) ptr) % LWLOCK_PADDED_SIZE;
		MainLWLockArray = (LWLockPadded *) ptr;
		/* Initialize the dynamic-allocation counter for tranches, which is stored just before the first LWLock. */
		LWLockCounter = (int *) ((char *) MainLWLockArray - sizeof(int));
		*LWLockCounter = LWTRANCHE_FIRST_USER_DEFINED;
		/* Initialize all LWLocks */
		InitializeLWLocks();
	}
	/* Register all LWLock tranches */
	RegisterLWLockTranches();
}

Postmaster启动后需要在共享内存空间中为LWLock和tranche分配空间,计算LWLock数量的操作定义在函数LWLockShmemSize中。
shared lock tables被分区的数量NUM_LOCK_PARTITIONS(32),hared predicate lock tables被分区的数量NUM_PREDICATELOCK_PARTITIONS(32)。
NUM_FIXED_LWLOCKS等于(LOCK_MANAGER_LWLOCK_OFFSET + NUM_LOCK_PARTITIONS)+NUM_PREDICATELOCK_PARTITIONS,也就是等于(BUFFER_MAPPING_LWLOCK_OFFSET + NUM_BUFFER_PARTITIONS)+32+32,也就是等于NUM_INDIVIDUAL_LWLOCKS+128+32+32,也就是等于48+128+32+32

#define NUM_INDIVIDUAL_LWLOCKS		48
/* Number of partitions of the shared buffer mapping hashtable */
#define NUM_BUFFER_PARTITIONS  128
/* Number of partitions the shared lock tables are divided into */
#define LOG2_NUM_LOCK_PARTITIONS  4
#define NUM_LOCK_PARTITIONS  (1 << LOG2_NUM_LOCK_PARTITIONS),
/* Number of partitions the shared predicate lock tables are divided into */
#define LOG2_NUM_PREDICATELOCK_PARTITIONS  4
#define NUM_PREDICATELOCK_PARTITIONS  (1 << LOG2_NUM_PREDICATELOCK_PARTITIONS)
/* Offsets for various chunks of preallocated lwlocks. */
#define BUFFER_MAPPING_LWLOCK_OFFSET	NUM_INDIVIDUAL_LWLOCKS
#define LOCK_MANAGER_LWLOCK_OFFSET		(BUFFER_MAPPING_LWLOCK_OFFSET + NUM_BUFFER_PARTITIONS)
#define PREDICATELOCK_MANAGER_LWLOCK_OFFSET (LOCK_MANAGER_LWLOCK_OFFSET + NUM_LOCK_PARTITIONS)
#define NUM_FIXED_LWLOCKS (PREDICATELOCK_MANAGER_LWLOCK_OFFSET + NUM_PREDICATELOCK_PARTITIONS)

LWLockShmemSize函数先计算numLocks(NUM_FIXED_LWLOCKS+NamedLWLockTrancheRequests[每个Tranche所需的锁的数量相加])所需的内存(numLocks*sizeof(LWLockPadded)),加上sizeof(int) + LWLOCK_PADDED_SIZE,加上NamedLWLockTrancheRequests[strlen(NamedLWLockTrancheRequestArray[i].tranche_name) + 1]名字的长度,加上NamedLWLockTrancheRequests[mul_size(NamedLWLockTrancheRequests, sizeof(NamedLWLockTranche))]自身结构体长度。

/* Compute shmem space needed for LWLocks and named tranches. */
Size LWLockShmemSize(void) {
	Size		size;
	int			i;
	int			numLocks = NUM_FIXED_LWLOCKS;
	numLocks += NumLWLocksByNamedTranches();
	/* Space for the LWLock array. */
	size = mul_size(numLocks, sizeof(LWLockPadded));
	/* Space for dynamic allocation counter, plus room for alignment. */
	size = add_size(size, sizeof(int) + LWLOCK_PADDED_SIZE);
	/* space for named tranches. */
	size = add_size(size, mul_size(NamedLWLockTrancheRequests, sizeof(NamedLWLockTranche)));
	/* space for name of each tranche. */
	for (i = 0; i < NamedLWLockTrancheRequests; i++)
		size = add_size(size, strlen(NamedLWLockTrancheRequestArray[i].tranche_name) + 1);
	/* Disallow named LWLocks' requests after startup */
	lock_named_request_allowed = false;
	return size;
}
/* Compute number of LWLocks required by named tranches.  These will be allocated in the main array. */
static int NumLWLocksByNamedTranches(void) {
	int			numLocks = 0;
	int			i;
	for (i = 0; i < NamedLWLockTrancheRequests; i++)
		numLocks += NamedLWLockTrancheRequestArray[i].num_lwlocks;
	return numLocks;
}

初始化LWLock和named tranches

LWLockInitialize函数用于初始化lwlock,对lock中的state进行pg_atomic_init_u32。对waiters调用proclist_init进行初始化。

/* LWLockInitialize - initialize a new lwlock; it's initially unlocked */
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;
	proclist_init(&lock->waiters);
}

InitializeLWLocks初始化individual LWLocks和named tranches,individual LWLocks包含INDIVIDUAL_LWLOCKS、BUFFER_PARTITIONS、LOCK_PARTITIONS、PREDICATELOCK_PARTITIONS

tranche idlock number
01
NUM_INDIVIDUAL_LWLOCKS-11
LWTRANCHE_BUFFER_MAPPINGNUM_LOCK_PARTITIONS
LWTRANCHE_LOCK_MANAGERNUM_LOCK_PARTITIONS
LWTRANCHE_PREDICATE_LOCK_MANAGERNUM_PREDICATELOCK_PARTITIONS
LWTRANCHE_PREDICATE_LOCK_MANAGERNUM_PREDICATELOCK_PARTITIONS
后面是NanedLWLOCKTranch
/* Initialize LWLocks that are fixed and those belonging to named tranches. */
static void InitializeLWLocks(void) {
	int			numNamedLocks = NumLWLocksByNamedTranches();
	int			id;
	int			i;
	int			j;
	LWLockPadded *lock;
	/* Initialize all individual LWLocks in main array */
	for (id = 0, lock = MainLWLockArray; id < NUM_INDIVIDUAL_LWLOCKS; id++, lock++)
		LWLockInitialize(&lock->lock, id);
	/* Initialize buffer mapping LWLocks in main array */
	lock = MainLWLockArray + NUM_INDIVIDUAL_LWLOCKS;
	for (id = 0; id < NUM_BUFFER_PARTITIONS; id++, lock++)
		LWLockInitialize(&lock->lock, LWTRANCHE_BUFFER_MAPPING);
	/* Initialize lmgrs' LWLocks in main array */
	lock = MainLWLockArray + NUM_INDIVIDUAL_LWLOCKS + NUM_BUFFER_PARTITIONS;
	for (id = 0; id < NUM_LOCK_PARTITIONS; id++, lock++)
		LWLockInitialize(&lock->lock, LWTRANCHE_LOCK_MANAGER);
	/* Initialize predicate lmgrs' LWLocks in main array */
	lock = MainLWLockArray + NUM_INDIVIDUAL_LWLOCKS + NUM_BUFFER_PARTITIONS + NUM_LOCK_PARTITIONS;
	for (id = 0; id < NUM_PREDICATELOCK_PARTITIONS; id++, lock++)
		LWLockInitialize(&lock->lock, LWTRANCHE_PREDICATE_LOCK_MANAGER);

NamedLWLockTrancheArray指针指向NUM_FIXED_LWLOCKS加上命名Tranche需要的LWLOCKS之后的内存,trancheNames指向NamedLWLockTrancheArray指针加上(NamedLWLockTrancheRequests * sizeof(NamedLWLockTranche)[NamedLWLockTranche是命名Tranche内存]。

	/* Initialize named tranches. */
	if (NamedLWLockTrancheRequests > 0) {
		char	   *trancheNames;
		NamedLWLockTrancheArray = (NamedLWLockTranche *) &MainLWLockArray[NUM_FIXED_LWLOCKS + numNamedLocks];
		trancheNames = (char *) NamedLWLockTrancheArray + (NamedLWLockTrancheRequests * sizeof(NamedLWLockTranche));
		lock = &MainLWLockArray[NUM_FIXED_LWLOCKS];

		for (i = 0; i < NamedLWLockTrancheRequests; i++) {
			NamedLWLockTrancheRequest *request;
			NamedLWLockTranche *tranche;
			char	   *name;
			request = &NamedLWLockTrancheRequestArray[i];
			tranche = &NamedLWLockTrancheArray[i];
			name = trancheNames;
			trancheNames += strlen(request->tranche_name) + 1;
			strcpy(name, request->tranche_name);
			tranche->trancheId = LWLockNewTrancheId();
			tranche->trancheName = name;
			for (j = 0; j < request->num_lwlocks; j++, lock++)
				LWLockInitialize(&lock->lock, tranche->trancheId);
		}
	}
}

RegisterLWLockTranches函数为fixed LWLock注册命名tranches.

/* Register named tranches and tranches for fixed LWLocks. */
static void RegisterLWLockTranches(void) {
	int			i;
	if (LWLockTrancheArray == NULL) {
		LWLockTranchesAllocated = 128;
		LWLockTrancheArray = (const char **) MemoryContextAllocZero(TopMemoryContext, LWLockTranchesAllocated * sizeof(char *));
		Assert(LWLockTranchesAllocated >= LWTRANCHE_FIRST_USER_DEFINED);
	}
	for (i = 0; i < NUM_INDIVIDUAL_LWLOCKS; ++i) LWLockRegisterTranche(i, MainLWLockNames[i]);
	LWLockRegisterTranche(LWTRANCHE_BUFFER_MAPPING, "buffer_mapping");
	LWLockRegisterTranche(LWTRANCHE_LOCK_MANAGER, "lock_manager");
	LWLockRegisterTranche(LWTRANCHE_PREDICATE_LOCK_MANAGER, "predicate_lock_manager");
	LWLockRegisterTranche(LWTRANCHE_PARALLEL_QUERY_DSA, "parallel_query_dsa");
	LWLockRegisterTranche(LWTRANCHE_SESSION_DSA, "session_dsa");
	LWLockRegisterTranche(LWTRANCHE_SESSION_RECORD_TABLE, "session_record_table");
	LWLockRegisterTranche(LWTRANCHE_SESSION_TYPMOD_TABLE, "session_typmod_table");
	LWLockRegisterTranche(LWTRANCHE_SHARED_TUPLESTORE, "shared_tuplestore");
	LWLockRegisterTranche(LWTRANCHE_TBM, "tbm");
	LWLockRegisterTranche(LWTRANCHE_PARALLEL_APPEND, "parallel_append");
	LWLockRegisterTranche(LWTRANCHE_PARALLEL_HASH_JOIN, "parallel_hash_join");
	LWLockRegisterTranche(LWTRANCHE_SXACT, "serializable_xact");
	/* Register named tranches. */
	for (i = 0; i < NamedLWLockTrancheRequests; i++)
		LWLockRegisterTranche(NamedLWLockTrancheArray[i].trancheId,NamedLWLockTrancheArray[i].trancheName);
}

LWLockRegisterTranche为当前process注册在查找表中注册一个tranch ID.

/* Register a tranche ID in the lookup table for the current process.  This
 * routine will save a pointer to the tranche name passed as an argument,
 * so the name should be allocated in a backend-lifetime context
 * (TopMemoryContext, static variable, or similar). */
void LWLockRegisterTranche(int tranche_id, const char *tranche_name) {
	Assert(LWLockTrancheArray != NULL);
	if (tranche_id >= LWLockTranchesAllocated) {
		int			i = LWLockTranchesAllocated;
		int			j = LWLockTranchesAllocated;
		while (i <= tranche_id) i *= 2;
		LWLockTrancheArray = (const char **) repalloc(LWLockTrancheArray, i * sizeof(char *));
		LWLockTranchesAllocated = i;
		while (j < LWLockTranchesAllocated)
			LWLockTrancheArray[j++] = NULL;
	}
	LWLockTrancheArray[tranche_id] = tranche_name;
}

扩展方法

为了方便用户在Extension模块中使用轻量锁,轻量锁模块还提供了两种扩展方法。
方法一:通过RequestNameLWLockTranche函数和GetNamedLWLockTranche函数来实现。其中,RequestNameLWLockTranche函数负责注册Tranche的名字以及自己所需的轻量锁的数量,GetNamedLWLockTranche函数负责根据Tranche Name来获得对应的轻量锁。每个Tranche都有自己唯一的ID,也在全局范围内有一个唯一的名字,也就是说Tranche ID和Tranche Name是一一对应的关系
RequestNameLWLockTranche函数–》它或影响轻量锁的计数数量
InitializeLWLocks函数–》根据RequestNameLWLockTranche函数提供的数量,在共享内存中初始化足够多的轻量锁,注意这些轻量锁在内存中是连续的
GetNamedLWLockTranche函数–》根据Tranche Name可以获得轻量锁数组的首地址
方法二:通过LWLockNewTrancheId函数获得新的Tranche ID,然后将Tranche ID和Tranche Name通过LWLockRegisterTranche函数建立联系,然后由LWLockInitialize函数来初始化轻量锁。
LWLockNewTrancheId函数–》获得自己的Tranche ID
LWLockRegisterTranche函数–》建立Tranche ID和Tranche Name之间的关联
LWLockInitialize函数–》这里初始化的轻量锁是由Extension模块自己在共享内存中保留的空间

带你了解Greenplum的锁管理机制

更多推荐

PostgreSQL数据库锁机制——读写锁LWLock