代码编织梦想

文章目录

  • 前言
  • 代码流程
  • 结构说明
  • 初始化过程
  • 代码附录
  • 结尾

前言

本文是基于postgresql 15的代码进行分析解读,演示是在centos8系统上进行。


 

代码流程

BaseInit

        InitCommunication

                CreateSharedMemoryAndSemaphores

                        CreateLWLocks

调用CreateLWLocks创建共享内存空间,并且初始化命名锁和tranche id等;因为是共享内存,所以只在master进程中初始化一次;BaseInit是在每个进程的主函数中调用。

 

结构说明

  • 锁的结构定义

/*

 * Code outside of lwlock.c should not manipulate the contents of this

 * structure directly, but we have to declare it here to allow LWLocks to be

 * incorporated into other data structures.

 */

typedef struct LWLock

{

    uint16      tranche;        /* tranche ID */

    ux_atomic_uint32 state;     /* state of exclusive/nonexclusive lockers */

    proclist_head waiters;      /* list of waiting UXPROCs */

#ifdef LOCK_DEBUG

    ux_atomic_uint32 nwaiters;  /* number of waiters */

    struct UXPROC *owner;       /* last exclusive owner of the lock */

#endif

} LWLock;

/* LWLock, padded to a full cache line size */

typedef union LWLockPadded

{

    LWLock      lock;

    char        pad[LWLOCK_PADDED_SIZE];

} LWLockPadded;

/* LWLock, minimally padded */

typedef union LWLockMinimallyPadded

{

    LWLock      lock;

    char        pad[LWLOCK_MINIMAL_SIZE];

} LWLockMinimallyPadded;

定义了两种 padded类型, full cache / minimal ,主要是针对扩展字节不同,full默认是128, minimal 可能是32/64;

extern UXDLLIMPORT LWLockPadded *MainLWLockArray;

extern char *MainLWLockNames[];

MainLWLockNames是整个lwlock的内存,信息记录总数组;

  • 每个进程记录了自己持有的锁信息

/*

 * We use this structure to keep track of locked LWLocks for release

 * during error recovery.  Normally, only a few will be held at once, but

 * occasionally the number can be much higher; for example, the ux_buffercache

 * extension locks all buffer partitions simultaneously.

 */

#define MAX_SIMUL_LWLOCKS        200

/* struct representing the LWLocks we're holding */

typedef struct LWLockHandle

{

LWLock           *lock;

LWLockMode        mode;

} LWLockHandle;

static int        num_held_lwlocks = 0;

static LWLockHandle held_lwlocks[MAX_SIMUL_LWLOCKS];

 

每个进程最多可以持有 MAX_SIMUL_LWLOCKS 这个多个锁;特别像extension会持有很多锁;

  • 通过extension注册的锁

/* struct representing the LWLock tranche request for named tranche */

typedef struct NamedLWLockTrancheRequest

{

char                tranche_name[NAMEDATALEN];

int                        num_lwlocks;

} NamedLWLockTrancheRequest;

NamedLWLockTrancheRequest *NamedLWLockTrancheRequestArray = NULL;

int                        NamedLWLockTrancheRequests = 0;

static int        NamedLWLockTrancheRequestsAllocated = 0;

在上面数组中注册lwlock name, 数量;

 /* struct for storing named tranche information */

typedef struct NamedLWLockTranche

{

    int         trancheId;

    char       *trancheName;

} NamedLWLockTranche;

NamedLWLockTranche *NamedLWLockTrancheArray = NULL;

初始化过程

CreateLWLocks的步骤:

        前三步只有在master中初始化,第四步每个进程都会初始化;

(1)MainLWLockArray  申请的共享内存的指针;前面留了一个整型空余;

LWLockShmemSize 获取lwlock占用的空间大小

(2) MainLWLockArray前的整型

        见附件一定义代码;

        2.1 赋初值为  LWTRANCHE_FIRST_USER_DEFINED是编译时确定的锁的数量,包括了保留的锁数量;

        2.2 在LWLockNewTrancheId()调用中,对于NamedLWLockTrancheArray增加的锁,它们的trancheid是这个计数进行递增后的值

        所以这个计数是所有lwlock的总数

(3)InitializeLWLocks 初始化锁的信息

        3.1 保留锁信息初始化

        也就是ID < NUM_INDIVIDUAL_LWLOCKS的锁;

        初始化四类信息:

                锁释放标志,置为LW_FLAG_RELEASE_OK

                如果是调试状态,锁的等待数量置为0

                tranche id 置为数据下标

                锁等待者列表置为空

        3.2 buffer mapping lwlock 初始化

          也就是 ID < NUM_BUFFER_PARTITIONS

        也是四类信息的初始化,但是tranche id 都为 LWTRANCHE_BUFFER_MAPPING

        3.3 lock manage lwlock 初始化

        也就是 ID < NUM_LOCK_PARTITIONS

        也是四类信息的初始化,但是tranche id 都为 LWTRANCHE_LOCK_MANAGER

        3.4 predicate lock manage lwlock 初始化

        也就是 ID < NUM_PREDICATELOCK_PARTITIONS

        也是四类信息的初始化,但是tranche id 都为 LWTRANCHE_PREDICATE_LOCK_MANAGER

3.5 如果 NamedLWLockTrancheRequests > 0;也就是有extension中注册了锁

这部分锁初始化由三部分构成:

        一是名字name初始化;

        二是trancheArray的初始化

        三是lock的四类信息的初始化

        此时,MainLWLockArray 在上面 保留锁和编译时生成的锁之后,按上面三部分 分成了三段,

        第一段是lock,锁的数量由 NumLWLocksForNamedTranches()来统计;

        第二段是tranche Array,每个成员是NamedLWLockTranche结构;

                tranche id是由LWLockNewTrancheId()来获取;

                NamedLWLockTranche *NamedLWLockTrancheArray 这个全局变量这指向这一段的起始位置

        第三段是lock name,这里按char带结束符的字符串一个接一个存放;第二段中的trancheName来引用;

这部分的数据来源NamedLWLockTrancheRequestArray,extension需要在这个数组中先注册,数组元素个数由NamedLWLockTrancheRequests记录;

  (4)注册extension的锁到各个进程中

static const char **LWLockTrancheNames = NULL;

static int        LWLockTrancheNamesAllocated = 0;

就是初始化上面这两个全局变量,每个进程都会初始化;

在contextmemory中分配内存给LWLockTrancheNames ,这是一个字符指针的数组,下标是trancheid,指向NamedLWLockTrancheArray 中的name,也就是共享内存中的name;LWLockTrancheNamesAllocated 是数据分配的大小;

附件一:

/*

 * Every tranche ID less than NUM_INDIVIDUAL_LWLOCKS is reserved; also,

 * we reserve additional tranche IDs for builtin tranches not included in

 * the set of individual LWLocks.  A call to LWLockNewTrancheId will never

 * return a value less than LWTRANCHE_FIRST_USER_DEFINED.

 */

typedef enum BuiltinTrancheIds

{

LWTRANCHE_XACT_BUFFER = NUM_INDIVIDUAL_LWLOCKS,

LWTRANCHE_COMMITTS_BUFFER,

LWTRANCHE_SUBTRANS_BUFFER,

LWTRANCHE_MULTIXACTOFFSET_BUFFER,

LWTRANCHE_MULTIXACTMEMBER_BUFFER,

LWTRANCHE_NOTIFY_BUFFER,

LWTRANCHE_SERIAL_BUFFER,

LWTRANCHE_WAL_INSERT,

LWTRANCHE_BUFFER_CONTENT,

LWTRANCHE_REPLICATION_ORIGIN_STATE,

LWTRANCHE_REPLICATION_SLOT_IO,

LWTRANCHE_LOCK_FASTPATH,

LWTRANCHE_BUFFER_MAPPING,

LWTRANCHE_LOCK_MANAGER,

LWTRANCHE_PREDICATE_LOCK_MANAGER,

LWTRANCHE_PARALLEL_HASH_JOIN,

LWTRANCHE_PARALLEL_QUERY_DSA,

LWTRANCHE_PER_SESSION_DSA,

LWTRANCHE_PER_SESSION_RECORD_TYPE,

LWTRANCHE_PER_SESSION_RECORD_TYPMOD,

LWTRANCHE_SHARED_TUPLESTORE,

LWTRANCHE_SHARED_TIDBITMAP,

LWTRANCHE_PARALLEL_APPEND,

LWTRANCHE_PER_XACT_PREDICATE_LIST,

LWTRANCHE_PGSTATS_DSA,

LWTRANCHE_PGSTATS_HASH,

LWTRANCHE_PGSTATS_DATA,

LWTRANCHE_FIRST_USER_DEFINED

}                        BuiltinTrancheIds;


结尾

作者邮箱:study@senllang.onaliyun.com
如有错误或者疏漏欢迎指出,互相学习。

注:未经同意,不得转载!

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/senllang/article/details/127169482

PostgreSQL中的锁--spinLock、LWLock、Lock-爱代码爱编程

一、PostgreSQL中的锁 PostgreSQL中根据不同对象,不同使用场景,使用到了三种锁,即spinLock,LWLock,Lock 1.spinLock SpinLock也就是所谓的自旋锁,是并发场景下(多进程/线程),保护共享资源的一种机制。实现的成本最低,一般是使用基于硬件的TAS操作(test-and-set来实现的)。显著的特点是审

PostgreSQL:初始化数据库-爱代码爱编程

一、初始化数据库的命令 #!/bin/bash adduser postgres PGHOME="/opt/common/postgresql" # PostgreSQL 命令的位置 datadir="/opt/data/pgdata-13.1" # 数据库文件的位置,在执行这个脚本前,这个目录必须不存在 mkdir -p ${datadir} #

postgreSQL源码分析综述-爱代码爱编程

2021SC@SDUSC 目录 综合分析安装过程主要源码分工情况我的任务分析方式 综合分析 经过小组讨论和分析,大家一致认为postgreSQL的核心部分在于对SQL功能的实现。而postgreSQL的核心代码则在于其后端的完成实现。 由上图,可以看出postgresql处理查询请求(核心功能)都是依托postgres这个进程完成的。而查询请求

基于java演唱会购票系统计算机毕业设计源码+系统+数据库+lw文档+部署_ssh 演唱会门票预约管理系统-爱代码爱编程

基于JAVA演唱会购票系统计算机毕业设计源码+系统+数据库+lw文档+部署 基于JAVA演唱会购票系统计算机毕业设计源码+系统+数据库+lw文档+部署 本源码技术栈: 项目架构:B/S架构 开发语言:Java语言 开发软件:idea eclipse 前端技术:Layui、HTML、CSS、JS、JQuery等技术 后端技术

pycharm连接远程数据库_pycharm连接clickhouse-爱代码爱编程

创建连接 首先我们需要点击Database,创建所需的数据库连接(这里使用PostgreSQL做演示)。 配置SSH信息 随后在弹出的窗口中选择SSH/SSL一栏,勾选User SSH tunnel 点击小省略号

(附源码)计算机毕业设计ssm宠物短期寄养平台_基于ssm宠物寄养中心系统-爱代码爱编程

项目运行 环境配置: Jdk1.8 + Tomcat7.0 + Mysql + HBuilderX(Webstorm也行)+ Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM + mybatis + Maven + Vue 等等组成,B/S模式 + Maven管理等等。