redis的hash/key lookup的实现就是在redis.c的lookupKey里.
里面除了hash的查找过程dictFind之外,还有一些关于swap/vm的内容.
暂且按下不表.
redis的hash表"实现"是dict这个数据结构,在dict.h里定义.
typedef struct dict {
dictType *type;
void *privdata;
dictht ht[2];
int rehashidx; /* rehashing not in progress if rehashidx == -1 */
int iterators; /* number of iterators currently running */
} dict;
typedef struct dictht {
dictEntry **table;
unsigned long size;
unsigned long sizemask;
unsigned long used;
} dictht;
可以看出,redic是用了两个数组做hash table.
至于为什么要用两个hash tbale,这个可以从dictRehash函数里看出.
在做rehash的时候,其实是把ht[0]的所有内容移到ht[1].然后再把两者交换而已.
至于什么时候以及为什么要rehash,一般是在查key的entry的时候,也就是_dictKeyIndex这个拿table index的时候,会看当前table里元素的大小.
扩容的策略很简单,double.
接下来看下table的分布情况.
对于key计算出来的hash值,_dictKeyIndex先会将其跟table的sizemask做一个掩码.
sizemask的值其实是table的"size" -1.
由于table是按幂级数扩容的,于是sizemask上基本就是说,保留hash值的低级位的bit而已.
得到计算出来的掩码之后,就以这个计算出来idx作为table的index.
事实上,hash table数组里的值是一个链表.
换句话说,其实redis hash table的分布方式类似内存的分页.
用sizemask找出key所在的页,然后直接loop这个页的内容.
于是,单对查找时间来衡量的话,当然是页内的东西越少查找越快了(因为是线性查找).
换句话说,对于32bit的hash值,出去sizemaske的bit越多,查找理论上会越快.
也就是说,当table越大,hash表越大的时候,查找效率会越高.
当然,这也只是理论上的.
而且,是在一定数量范围内才成立.
因为redis毕竟是基于内存的,当数量超过可用内存的时候,自然效率不能担保.
还有就是redis做save的时候(save到硬盘是通过fork clone一个进程做到的),也会占用一部分.
所以,在处理redis的时候,需要考虑好内存的使用状况.
不然out of memory的问题就麻烦了.
至于redis的vm选项,貌似当开启的时候,不是用的内存而是用的swap或者说文件来存储的.
这个可以在 lookupKey里看出点端倪.
但vm选项开启,并且,第一次lookup出来的值没有REDIS_VM_MEMORY标记的时候,是从文件load进来的.
至于,什么时候swap出去的嘛.
还没看明白.
2010-06-16
再谈Redis
订阅:
博文评论 (Atom)
聊聊终末地
这几天玩了下终末地. 坦白说,开始预期并不算高,甚至谈不上什么预期. 毕竟一开始就有种开拓者带着绳匠队伍搜集原石的感觉. 尤其有时候看着严肃台词和经典二次元美少女混杂在一起的场景. 加上性癖还极其统一的兽耳. 但也不是一无是处. 在开场新手指导的自动炮塔出现的时候,就觉得算某种程...
-
看完了一部未完成的电影. 这部片片子比较有意思的是一开始那段自嘲. 秦昊关于既然拍了也播不了,只是私下小圈子里自嗨的事情又什么意义的质问. 片里导演也 讪讪地承认生活的现实. 到这里其实沿着原有的思路,把补拍和一些意外穿插进去,可能还是一个不错的文艺片. 至少于戏里戏外的导演来说...
-
去看了长安的荔枝. 前半段还可以,尤其像荔枝林里不知道是笑还是哭的几个镜头表演算是相当出色了. 结合人物背景的那种对目标的绝望与对当下人际环境的希望的交叉矛盾心理. 后半段就有些过滤潦草了. 如果说整片是对于一骑红尘妃子笑,无人知是荔枝来的解构的话. 带入民生潦倒涂炭这点是没问题...
-
看 金枝 ,读到关于求雨的各种巫术习惯的时候忽然发觉,这其实跟当时的社会需求有关吧. 农业为主,自然是靠天吃饭,尤其在无法弄清下雨原因的时候. 这种"崇拜"虽然说是出于"无知",但究其本质还是因为对于天气有着不可替代的需求. 有所求的...
没有评论:
发表评论