`

pg启动过程中的那些事七:初始化共享内存和信号一:初始化shmemIndex和信号

阅读更多

 

       pg 现在要初始化另一块内存——共享内存 shared memory (以后 shared memory 有时会简写成 shmem ),在这块内存里, pg 存放数据、锁、各种 backend 进程等。

1 先上个图,看一下函数调用过程梗概,中间略过部分细节


 

初始化共享内存方法调用流程图

 

2 计算 shared memory 大小

话说 main()-> ->PostmasterMain()-> ->reset_shared() ,在 reset_shared () 这个函数里, pg 首先计算干 xxx 一堆事需要的内存大小 size ,然后分之。

首先我们看看都计算了哪些内存, 估算使用动态哈希表管理共享内存需要的内存;计算数据池及管理需要的内存(根据shared_buffer );计算锁表需要的共享内存;计算xlogclog 需要的共享内存;计算共享进程、子事务、并发控制、轻量级锁、backend 进程、后台写等需要的共享内存等,这些共享内存统统累加到size 。计算shared memory 共享内存代码如下:

        size = 100000;

        size = add_size(size, hash_estimate_size(SHMEM_INDEX_SIZE,

                                                  sizeof (ShmemIndexEnt)));

        size = add_size(size, BufferShmemSize());

        size = add_size(size, LockShmemSize());

        size = add_size(size, ProcGlobalShmemSize());

        size = add_size(size, XLOGShmemSize());

        size = add_size(size, CLOGShmemSize());

        size = add_size(size, SUBTRANSShmemSize());

        size = add_size(size, TwoPhaseShmemSize());

        size = add_size(size, MultiXactShmemSize());

        size = add_size(size, LWLockShmemSize());

        size = add_size(size, ProcArrayShmemSize());

        size = add_size(size, BackendStatusShmemSize());

        size = add_size(size, SInvalShmemSize());

        size = add_size(size, BgWriterShmemSize());

        size = add_size(size, BTreeShmemSize());

        size = add_size(size, SyncScanShmemSize());

        size = add_size(size, ShmemBackendArraySize());

2 分配并初始化 shared memory

计算好需要的共享内存大小 size 后调用 PGSharedMemoryCreate() 函数分配共享内存。 PGSharedMemoryCreate() 函数创建给定大小的共享内存段并初始化一个 PGShmemHeader 结构类型标准头,且给释放内存注册回调函数。如果发现死 postgres 段就回收,但是和非 postgres 内存段碰撞后 pg 不会失败。这儿的想法是检测和重用崩溃的 postmaster backend 进程已经分配的 key

PGSharedMemoryCreate () 分配内存是先根据 postmaster 进程端口号计算找一个空闲 IPC key 的起始值。接着调用 InternalIpcMemoryCreate() 函数, 尝试根据给定 IPC key 调用 shmget() 函数 创建共享内存段。如果给定 key 的内存段已经存在就失败返回 NULL 。如果成功,把该内存段 attach 到当前进程 postmaster 并返回该内存段地址。调用 on_shmem_exit() 函数注册 detach delete 该段内存时的回调函数 IpcMemoryDelete() IpcMemoryDetach()on_shmem_exit_list 数组

       on_shmem_exit() 函数注册函数到以 ONEXIT 结构为元素的数组on_shmem_exit_list[MAX_ON_EXITS] 中以供shmem_exit() 函数执行时调用。ONEXIT 结构结构定义见下面。

static struct ONEXIT

{

    void         (*function) (int code, Datum arg);

    Datum       arg;

}   on_proc_exit_list[MAX_ON_EXITS], on_shmem_exit_list[MAX_ON_EXITS];

 

    接着调用RecordSharedMemoryInLockFile() 函数把IPC keyshmid 记录到postmaster.pid 文件,然后从InternalIpcMemoryCreate() 返回到 PGSharedMemoryCreate() 函数,再接着在分配到的共享内存的头部放一个 PGShmemHeader (结构定义见下面)结构实例并初始化其成员,使全局静态PGShmemHeader * 类型变量ShmemSegHdr 指到这个结构。然后调用PGReserveSemaphores() 函数分配存放信号的数组需要的内存到mySemSet 数组并用 on_shmem_exit() 函数注册 ReleaseSemaphores() 函数 on_shmem_exit_list 数组,这个数组大小和backend 进程数有关。

typedef struct PGShmemHeader    /* standard header for all Postgres shmem */

{

    int32       magic;          /* magic # to identify Postgres segments */

#define PGShmemMagic  679834894

    pid_t       creatorPID;     /* PID of creating process */

    Size        totalsize;      /* total size of segment */

    Size        freeoffset;     /* offset to first free space */

    void             *index;         /* pointer to ShmemIndex table */

#ifndef WIN32                   /* Windows doesn't have useful inode#s */

    dev_t       device;         /* device data directory is on */

    ino_t       inode;          /* inode number of data directory */

#endif

} PGShmemHeader;

 

       现在到了 InitShmemAllocation() 函数,调用SpinLockInit() 给该共享内存初始化spinlockShmemLock 以备shmem 分配时使用。再调用ShmemAlloc() (这个涉及到pg 的另一块内存——共享内存/shared memory/shmem 的管理机制,到pg 的内存管理机制时在讨论。共享内存占pg 整个使用内存的90% 以上)给事务管理器transaction manager shmem 上分配一个VariableCacheData 类型的空间赋给VariableCacheData * 类型变量ShmemVariableCache 以备后用。

接着调用CreateLWLocks() 计算需要的LWLock 锁(关于pg 中的锁到并发控制的时候再讨论)的数目,并根据计算的数目分配LWLock 数组需要的空间。每个内存块(根据设定,一般8k )需要两个LWLock ,还有clogsubtrans 等需要的,这个数目会比较大,在我PCshared_buffer200MB 时这个数目是50,000+

3 分配并初始化 shmem 索引 "ShmemIndex" ——可扩展哈希表

下来调用InitShmemIndex() 初始化一个pg 的可扩展哈希表(见pg 中的数据结构一) "ShmemIndex" 作为共享内存/shared memory/shmem 的索引。Pg 基于该索引表 "ShmemIndex" 管理shmem 内存。这里就是HTABHASHHDRHashSegmentHashBucketHashElemen 等等一堆招呼,可扩展哈希表 "ShmemIndex" 诞生了。其中的HTABTopMemoryContext 里,其它在shmem 里, "ShmemIndex" 哈希表里存的是ShmemIndexEnt 类型实例,记录shmem 里每个内存块的名字、大小及偏移信息。按默认信息创建的 "ShmemIndex" 哈希表可以管理64M 以上个内存片段(每个哈希桶的开链表按1 个元素计算),结构见下图。

typedef struct

{

    char         key[SHMEM_INDEX_KEYSIZE];       /* string name */

    void             *location;      /* location in shared mem */

    Size        size;           /* # bytes allocated for the structure */

} ShmemIndexEnt;

 

static PGShmemHeader *ShmemSegHdr;      /* shared mem segment header */

 


共享内存及其索引 "ShmemIndex" 结构图

 

这一节就到这儿吧。

  • 大小: 82.9 KB
  • 大小: 133.7 KB
0
0
分享到:
评论

相关推荐

    共享内存实现代码shmem

    在这个“共享内存实现代码shmem”的示例中,我们将深入探讨如何在编程中创建、写入和读取共享内存。 首先,我们要知道在Unix-like系统(如Linux)中,共享内存主要通过`sys/shm.h`头文件中的函数来操作,比如`...

    Linux下系统V共享内存的保存与恢复.pdf

    1. **引入锁机制**:为了解决并发访问的问题,可以在创建和删除共享内存时引入自旋锁或读写锁,保证在保存和恢复过程中的数据一致性。 2. **内存映射和物理分布**:需要记录每个共享内存段的物理地址和映射信息,...

    py_boost_shmem:在boost之间映射共享内存的示例

    py_boost_shmem 在boost :: interprocess和Python的mmap之间映射共享内存的示例。 我在将python(使用mmap模块)中的共享内存连接到使用boost :: interprocess创建的C ++中的共享内存时遇到问题。 我开始工作了,想...

    shmem_fs.rar_memory

    标题“shmem_fs.rar_memory”涉及的是Linux内核中的共享内存(Shared Memory)子系统,尤其是与内存管理相关的部分。共享内存是一种高效的进程间通信(IPC, Inter-Process Communication)机制,它允许多个进程直接...

    libandroid-shmem:使用Ashmem在Android上进行System V共享内存仿真

    libandroid-shmem 在使用ashmem在Android上进行System V共享内存(shmget,shmat,shmdt和shmctl)仿真。 它创建的共享内存段将在创建过程销毁它们或死时自动销毁,这与System V共享内存行为不同。 基于先前工作。...

    shmem_sem.c

    利用信号量实现的共享内存同步实验,详看博客

    Python并行数值计算

    下面通过一个示例来展示如何使用`multiprocessing`模块中的`RawArray`对象创建一个共享内存数组,并将其转换为NumPy数组格式: ```python import ctypes import multiprocessing as mp import numpy as np # 创建...

    glance, top和ps察看进程内存数据之间的关系及计算

    glance的Memory Report中,Text、Data、Stack和Shmem分别代表程序的可执行代码、动态分配的数据、局部变量和共享内存。"Other"则涵盖了非以上四类的内存,比如MEMMAP(内存映射,包括动态链接库的代码和数据部分)、...

    shmem.c文件

    共享内存的基础实验代码,详看博客http://blog.csdn.net/mybelief321

    shmaps:具有STL容器和TTL支持的永久共享内存(进程间)映射

    shmaps持久共享内存键值存储,支持自定义STL容器和TTL。提出的解决方案使您可以在共享内存段中组织多个独立的映射(键-值)存储。基于boost / interprocess和libcuckoo无锁映射。局限性:您不能将STL容器用于键或值...

    postgresql--内核分析--多进程结构

    - `src/backend/utils/misc/pg_shmem.c`文件中实现了共享内存的相关功能,这对于多进程之间的通信非常重要。 #### 五、PostgreSQL与MySQL对比 **1. PostgreSQL文件目录组织**: - 整体代码结构清晰,遵循了良好的...

    龙芯 3A双路服务器的网络性能分析

    中,文章列举了几个关键的读写函数,如`REG_RD/REG_WR`用于读取和写入PCI内存地址,`bnx2_reg_rd_ind()/bnx2_reg_wr_ind()`用于基于端口索引的读写操作,`Bnx2_shmem_rd()/bnx2_shmem_wr()`访问MCP的共享内存,以及`...

    shmem.c 文件

    详情看博客http://blog.csdn.net/mybelief321/article/details/9170041

    WindRiver虚拟化笔记

    - **SHMEM**: 共享内存,用于实现虚拟化环境中不同操作系统之间的数据交换。 #### 三、配置步骤详解 ##### 1. 安装WindRiver Workbench (on host) - 在主机上安装WindRiver Workbench,安装过程中可参考默认配置...

    nginx中共享内存的使用详解

    本文介绍在nginx的代码中与共享内存相关的功能,包括ngx_shmem与ngx_slab的使用与注意事项,但不包括ngx_slab中实现的内存管理算法。 ngx_shmem的使用 ngx_shmem.c/h文件只是对mmap()/munmap()系统调用或者shmget()...

    java调试参数

    在Java开发过程中,调试是确保程序正确性和性能优化的关键步骤之一。通过合理设置Java调试参数,开发者可以在开发、测试甚至生产环境中对Java应用程序进行远程调试,这对于定位问题、理解程序运行时的行为至关重要。...

    jdwpTransport_java_

    "dt_shmem"使用共享内存,适用于同一主机上的进程间通信;"dt_pipe"则通过命名管道进行通信,同样适用于本地调试场景。 当开发者在调试Java应用时,可以通过指定-JDWP选项来配置JDWP Transport,例如: ``` java -...

    HP JDK MEM 管理

    - **SHMEM_MAGIC**:提供更大的共享内存空间,特别适用于需要大量共享内存的应用场景,比如分布式计算环境。 综上所述,HP-UX中的内存管理机制提供了灵活的内存布局选择,以适应不同类型的可执行文件和应用程序的...

    PostgreSQL Hook编程介绍

    在PostgreSQL初始化时,它会检查全局函数指针ClientAuthentication_hook是否被设置,如果已经设置,则在客户端认证过程中执行它。 此外,还有一些钩子是专门为了优化查询性能而设计的。例如,explain_get_index_...

Global site tag (gtag.js) - Google Analytics