EsgynDB中的共享内存

在数据库中,为了加快访问速度在很多地方设计了cache来进行加速。与很多数据库采用多线程来处理连接的做法不同,EsgynDB采用了多进程的设计。每个节点上有很多mxosrvr进程,每个进程对应一个客户端连接。这种做法有一个问题是,每个进程都需要申请内存做cache,导致节点内存占用非常高,且很浪费。解决这个问题的方法是使用共享内存,将那些在不同mxosrvr进程之间可以共享访问的部分放到共享内存里。

在使用共享内存时有两个主要的问题:

一是如何在不同进程之间共享对象。

二是如何处理不同进程之间的读写冲突,即并发状态下的一致性。

正常情况下,共享内存里是不能存放指针的,会导致bug。原因很简单,不同进程拥有不同的地址空间。假设在第一个进程中,一片共享内存映射到基地址0x10000000处,这片共享内存里有个指针本身的地址为0x10000100, 其指向的地址为0x10000200, 这片共享内存被第二个进程映射到基地址0x2000000处,第二个进程通过偏移0x100可以访问这个指针,但是这个指针指向的仍然是0x10000200,通过指针访问对应内存就会产生不可预知的错误。

解决这个问题的办法是给共享内存一个固定的映射地址,保证所有进程在访问同一片共享内存时一定在同一个基地址上。例如RMS_SHARED_MEMORY_ADDR这个值,默认为0x10000000, 也可以在ms.env中修改这个值,但是注意修改后一定要重启整个数据库生效,否则会出问题。通常情况下0x10000000这个地址是可以访问的,但是在不同的cpu/操作系统下,这个地址也有可能被别的程序所占用。这时候共享内存绑定失败,会导致集群无法启动。这时候就需要手动找到一个可用地址并修改ms.env配置。手动查找的方法是使用pmap命令查看进程地址空间。

[centos@nitaovm esgyndb]$ pmap 36068

36068:   mxosrvr -ZKHOST localhost:2181 -RZ nitaovm:1:2 -ZKPNODE /trafodion/1 -CNGTO 60 -ZKSTO 180 -EADSCO 0 -TCPADD 10.13.30.26 -MAXHEAPPCT 0 -STATISTICSINTERVAL 60 -STATISTICSLIMIT 60 -STATISTICSTYPE aggregated -STATISTICSCACHESIZE 0 -STATISTICSENABLE false -STOREINTERNALQUERIESINREPO false -SQLPLAN true -PORTMAPTOSECS -1 -PORTBINDTOSECS -1 -PUBLISHSTATSTOTSDB false -OPENTSDURL localhost:5242 -EXITSESSIONSCOUNT 100 -EXITLIVETIME 0 -WMSTIMEOUT 30 -MDSENABLE false -MDSLIMITMS 10000 -USESSLENABLE false -TCPKEEPALIV

0000000000400000   2660K r-x-- mxosrvr

0000000000898000      4K r---- mxosrvr

0000000000899000    208K rw--- mxosrvr

00000000008cd000    180K rw---   [ anon ]

0000000000cb8000  52252K rw---   [ anon ]

0000000010000000 524288K rw-s-   [ shmid=0x48004 ]

00000000f8000000 134016K rw---   [ anon ]

00000001002e0000 128128K -----   [ anon ]

00007fa1b0d05000   2064K rw---   [ anon ]

从这里可以看到36068是mxosrvr进程,在地址10000000处是共享内存,大小为524288K, shmid为0x48004。只要避开所有已经被占用的内存段,找一段空闲地址空间即可。

解决了以上问题后,目前可以在共享内存里存放指针了。但存放对象仍然可能会遇到问题。如果只是普通的对象,拿到共享内存地址后强制转换类型就可以了。

CacheEntry* e=(CacheEntry*) ptr;

e->xxx();

如果CacheEntry这个类有虚函数,虚函数表编译后是个固定的数据存放在数据区,程序每次运行的时候,会有一个动态绑定的过程。关于C++虚函数vtable的具体机制就不在这里详细展开了,总而言之就是需要有一个修复vtable的过程。修复的方法是new一个同类的本地对象,并且把对象地址首8字节拷贝覆盖即可。

void fixupVTable(HTableCache* targetTableCache) {

  static HTableCache tableCache;

  if (targetTableCache)

    memcpy((char*)targetTableCache, (char*)&tableCache, sizeof(void*));

}

到这里,就可以在不同进程之间,通过共享内存传递对象了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值