关于tokyocabinet的memory db的参数说明

官方文档针对不同类型的存储一股脑地介绍了一大堆选项,至于哪个选项适用于哪种类型的存储并不清楚(可能是我没看清楚),下面只说一下影响memory db的参数选项:

参考源码:
tcadb.c :

 
  1. /* Open an abstract database. */
  2. bool tcadbopen(TCADB *adb, const char *name){
  3.     …
  4.     } else if(!tcstricmp(path, "*")){
  5.         adb->mdb = bnum > 0 ? tcmdbnew2(bnum) : tcmdbnew();
  6.         adb->capnum = capnum;
  7.         adb->capsiz = capsiz;
  8.         adb->capcnt = 0;
  9.         adb->omode = ADBOMDB;
  10.     } else if(!tcstricmp(path, "+")){
  11.         …
  12.     }
  13. }

说明:
有三个选项影响全内存型的hash存储:
bnum: 总的bucket的数量; 注意map有8个(固定的);8个map中共有bnum个bucket
capnum: 最大允许的记录数;
capsize: 最大允许的key-value使用的存储的大小;

下面解释一下capnum与capsize的使用逻辑:
先看一下源代码吧:
tcadb.c :

 
  1. /* Store a record into an abstract database object. */
  2. bool tcadbput(TCADB *adb, const void *kbuf, int ksiz, const void *vbuf, int vsiz){
  3.     assert(adb && kbuf && ksiz >= 0 && vbuf && vsiz >= 0);
  4.     bool err = false;
  5.     char numbuf[TCNUMBUFSIZ];
  6.     ADBSKEL *skel;
  7.     switch(adb->omode){
  8.         case ADBOMDB:
  9.         if(adb->capnum > 0 || adb->capsiz > 0){
  10.             tcmdbput3(adb->mdb, kbuf, ksiz, vbuf, vsiz);
  11.             adb->capcnt++;
  12.             if((adb->capcnt & 0xff) == 0){ // 256的倍数时才检查,否则会比较影响性能
  13.                 if(adb->capnum > 0 && tcmdbrnum(adb->mdb) > adb->capnum + 0x100)
  14.                     tcmdbcutfront(adb->mdb, 0x100);
  15.                     if(adb->capsiz > 0 && tcmdbmsiz(adb->mdb) > adb->capsiz)
  16.                         tcmdbcutfront(adb->mdb, 0x200);
  17.             }      
  18.         } else {
  19.             tcmdbput(adb->mdb, kbuf, ksiz, vbuf, vsiz);
  20.         }      
  21.         break
  22.         case ADBONDB:
  23.         …    
  24.     }
  25. }

说明:
1. 如果设置了capnum或者设置了capsiz, 则使用tcmdbput3()来写入,然后判断capnum或capsiz是否超过了设置;
2. 并不是记录数超过设置立即删除,也不是超过多少删除多少; 而是记录数为0x100(即:256)的倍数时才检查,如果超过则删除,而且是删除256条记录;
3. 如果内存使用(这里说内存使用不确切,而应是key-value字节数)超过了capsiz限制,则直接删除256条记录;
4. 这里面的tcmdbput3() 和 tcmdbput() 的差别在于:
如果插入的记录是存在的,对于tcmput3()来讲,将把该条记录移动到链表的尾部,视为热数据,删除总是从链表头开始的。但是作者没有在get的时候也做这样的调整,不知道是疏忽还是另有考虑。

或许你测试发现删除的并非恰好256条记录,原因是这样的,先看源码:
tcutil.c

 
  1. void tcmdbcutfront(TCMDB *mdb, int num){
  2.     assert(mdb && num >= 0);
  3.     num = num / TCMDBMNUM + 1;
  4.     for(int i = 0; i < TCMDBMNUM; i++){
  5.         if(pthread_rwlock_wrlock((pthread_rwlock_t *)mdb->mmtxs + i) == 0){
  6.             tcmapcutfront(mdb->maps, num);
  7.             pthread_rwlock_unlock((pthread_rwlock_t *)mdb->mmtxs + i);
  8.         }  
  9.     }
  10. }

说明:
因为存储是分了TCMDBMNUM(8)个map来存储的,不能只删除一个map中的num个,这样太不公平了。所以平均了一下,但是可能平均的不能分完,所以每个就多删除1个; 即使这样,其实还是有问题的,因为有的map重可能不够num条记录,或者根本就没有记录;

关于从map中删除记录tcmapcutfront的说明:
tcutil.c

 
  1. /* Remove front records of a map object. */
  2. void tcmapcutfront(TCMAP *map, int num){
  3.     assert(map && num >= 0);
  4.     tcmapiterinit(map);
  5.     while(num– > 0){
  6.         int ksiz;
  7.         const char *kbuf = tcmapiternext(map, &ksiz);
  8.         if(!kbuf) break;
  9.         tcmapout(map, kbuf, ksiz);
  10.     }
  11. }

说明:
因为每个map下面的记录通过pre、next指针形成一个链表结构; 删除记录的时候也就从链表的头部开始删除了; 而且这种删除也是不会考虑到数据的冷热的,删除完全是一种先进先出的策略;
对于memcache来讲,内存不够用时,也是从一头儿开始删除,但是因为memcache在读取的时候会将数据调整到链表的另一头,所以memcache删除的总是最冷的数据。

在tc的memory db的实现中,获取数据时,完全可以把获取的数据调整到链表的尾部(在非全内存的btree的map中是这么实现的,见tcutil.c:tcmapget3()),这样剔除的时候就不至于把热数据给删除掉了

————————-
说句废话:
xmsiz选项对mdb是没有关系的。

留下评论

邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据