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

来源:未知 责任编辑:智问网络 发表时间:2013-09-26 23:54 点击:
  pg现在要初始化另一块内存——共享内存shared memory(以后shared memory有时会简写成shmem),在这块内存里,pg存放数据、锁、各种backend进程等。

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

 

\

 

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

 

2计算shared memory大小

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

        首先我们看看都计算了哪些内存,估算使用动态哈希表管理共享内存需要的内存;计算数据池及管理需要的内存(根据shared_buffer);计算锁表需要的共享内存;计算xlog、clog需要的共享内存;计算共享进程、子事务、并发控制、轻量级锁、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 key和shmid记录到postmaster.pid文件,然后从InternalIpcMemoryCreate()返回到PGSharedMemoryCreate()函数,再接着在分配到的共享内存的头部放一个PGShmemHeader(结构定义见下面)结构实例并初始化其成员,使全局静态PGShmemHeader *类型变量ShmemSegHdr指到这个结构。然后调用PGReserveSemaphores()函数分配存放信号的数组需要的内存到mySemSet数组并用on_shmem_exit()函数注册ReleaseSemaphores()函数到on_shmem_exit_list数组,这个数组大小和backend进程数有关。

typedef structPGShmemHeader    /*standard header for all Postgres shmem */

{

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

#define PGShmemMagic  679834894

    pid_t       creatorPID;     /* PID ofcreating process */

    Size        totalsize;      /* total size ofsegment */

    Size        freeoffset;     /* offset tofirst 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()给该共享内存初始化spinlock锁ShmemLock以备shmem分配时使用。再调用ShmemAlloc()(这个涉及到pg的另一块内存——共享内存/shared memory/shmem的管理机制,到pg的内存管理机制时在讨论。共享内存占pg整个使用内存的90%以上)给事务管理器transaction manager 在shmem上分配一个VariableCacheData 类型的空间赋给VariableCacheData *类型变量ShmemVariableCache以备后用。

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

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

        下来调用InitShmemIndex()初始化一个pg的可扩展哈希表(见pg中的数据结构一)"ShmemIndex"作为共享内存/sharedmemory/shmem的索引。Pg基于该索引表"ShmemIndex"管理shmem内存。这里就是HTAB、HASHHDR、HashSegment、HashBucket、HashElemen等等一堆招呼,可扩展哈希表"ShmemIndex"诞生了。其中的HTAB在TopMemoryContext里,其它在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"结构图

 

这一节就到这儿吧

    发表评论
    请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
    用户名: 验证码:点击我更换图片
    最新评论 更多>>

    推荐热点

    • Request.ServerVariables 参数大全
    • 执行全文索引时出现权限不足的解决方法
    • 导入excel文件处理流程节点的解决方案
    • 查看sql修改痕迹(SQL Change Tracking on Table)
    • MongoDB安装为Windows服务方法与注意事项
    • App数据层设计及云存储使用指南
    • PostgreSQL启动过程中的那些事三:加载GUC参数
    • 写给MongoDB开发者的50条建议Tip1
    • Percolator与分布式事务思考(二)
    网站首页 - 友情链接 - 网站地图 - TAG标签 - RSS订阅 - 内容搜索
    Copyright © 2008-2015 计算机技术学习交流网. 版权所有

    豫ICP备11007008号-1