设为首页 收藏本站
查看: 1094|回复: 0

[经验分享] PostgreSQL启动过程中的那些事七:初始化共享内存和信号一:初始化shmemIndex和信号

[复制链接]

尚未签到

发表于 2016-11-21 08:08:06 | 显示全部楼层 |阅读模式
pg现在要初始化另一块内存——共享内存shared memory(以后shared memory有时会简写成shmem),在这块内存里,pg存放数据、锁、各种backend进程等。  1先上个图,看一下函数调用过程梗概,中间略过部分细节
  

DSC0000.bmp
  初始化共享内存方法调用流程图
  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 */
  

DSC0001.bmp

  共享内存及其索引"ShmemIndex"结构图
  
  这一节就到这儿吧。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-303147-1-1.html 上篇帖子: PostgreSQL的内存管理机制十一:初始化共享内存shared memory及其哈希表索引 下篇帖子: PostgreSQL服务过程中的那些事一:启动postgres服务进程一.八:加载DB基础设施,完成服务进程初始化
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表