redis源码学习-dict
- 1.字典相关的几个结构体
dict由hash table存储key-value, hash table数组每一个元素存放dictEntry链接的链表头结点,dictEntry节点存放key-value
typedef struct dictEntry {
void *key;
union {
void *val;
uint64_t u64;
int64_t s64;
double d;
} v;
struct dictEntry *next;
} dictEntry;
typedef struct dictht {
dictEntry **table; // 指向dictEntry数组的指针
unsigned long size; //哈希表table的大小,初始化大小为4
unsigned long sizemask; // size - 1 ,用来对hash值求与计算获得index
unsigned long used; // 已经赋值了的数量
} dictht;
typedef struct dict {
dictType *type; // 方法
void *privdata; // 保存key和value
dictht ht[]; // hash table
long rehashidx; // 如果rehashidx=-1表示没有进行rehash,如果如果rehashidx>-1,则表示正在进行rehash,搬运的位置是rehashidx
int iterators; /* number of iterators currently running */
} dict;
- 2.动态扩容方法 int dictRehash(dict *d, int n)
为了对dictht进行动态扩容,rehash方法将ht[0]中的值搬n个到ht[1]中, 分批次进行搬运,直到ht[0]中的值都搬到ht[1]上,再将ht[1]指针交给ht[0],rehashidx=-1,完成此次rehash过程
int dictRehash(dict *d, int n) {
int empty_visits = n * ; /* Max number of empty buckets to visit. */
if (!dictIsRehashing(d)) return ;
// 从ht[0]中搬n个链表到ht[1]中
while (n-- && d->ht[].used != ) {
dictEntry *de, *nextde;
/* Note that rehashidx can't overflow as we are sure there are more
* elements because ht[0].used != 0 */
assert(d->ht[].size > (unsigned long) d->rehashidx);
// 通过rehashidx可以接着从上一次搬完的位置开始搬
while (d->ht[].table[d->rehashidx] == NULL) {
d->rehashidx++;
if (--empty_visits == ) return ;
}
de = d->ht[].table[d->rehashidx];
/* Move all the keys in this bucket from the old to the new hash HT */
// 把ht[0]上的一个链表搬到ht[1]上
while (de) {
unsigned int h;
nextde = de->next;
/* Get the index in the new hash table */
h = dictHashKey(d, de->key) & d->ht[].sizemask;
de->next = d->ht[].table[h];
d->ht[].table[h] = de;
d->ht[].used--;
d->ht[].used++;
de = nextde;
}
d->ht[].table[d->rehashidx] = NULL;
d->rehashidx++;
}
/* Check if we already rehashed the whole table... */
if (d->ht[].used == ) {
zfree(d->ht[].table);
d->ht[] = d->ht[];
_dictReset(&d->ht[]);
d->rehashidx = -;
return ;
}
/* More to rehash... */
return ;
}
3.使用到的几个hash算法
针对int的hash函数
unsigned int dictIntHashFunction(unsigned int key) {
key += ~(key << );
key ^= (key >> );
key += (key << );
key ^= (key >> );
key += ~(key << );
key ^= (key >> );
return key;
}MurmurHash2算法
unsigned int dictGenHashFunction(const void *key, int len) {
/* 'm' and 'r' are mixing constants generated offline.
They're not really 'magic', they just happen to work well. */
uint32_t seed = dict_hash_function_seed;
const uint32_t m = 0x5bd1e995;
const int r = ; /* Initialize the hash to a 'random' value */
uint32_t h = seed ^len; /* Mix 4 bytes at a time into the hash */
const unsigned char *data = (const unsigned char *) key; // 长度大于等于4的情况
while (len >= ) {
uint32_t k = *(uint32_t *) data; // 4*8=32, 取4个字节当作uint32 k *= m;
k ^= k >> r;
k *= m; h *= m;
h ^= k; data += ;
len -= ;
} /* Handle the last few bytes of the input array */
// 剩下的长度小于4
switch (len) {
case :
h ^= data[] << ;
case :
h ^= data[] << ;
case :
h ^= data[];
h *= m;
}; /* Do a few final mixes of the hash to ensure the last few
* bytes are well-incorporated. */
h ^= h >> ;
h *= m;
h ^= h >> ; return (unsigned int) h;
}- djb hash算法
unsigned int dictGenCaseHashFunction(const unsigned char *buf, int len) {
unsigned int hash = (unsigned int) dict_hash_function_seed;
while (len--)
hash = ((hash << ) + hash) + (tolower(*buf++)); /* hash * 33 + c */
return hash;
}
细节前往 (https://github.com/fangwendong/redis-learning/tree/master/struct/dict)
redis源码学习-dict的更多相关文章
- Redis源码学习:字符串
Redis源码学习:字符串 1.初识SDS 1.1 SDS定义 Redis定义了一个叫做sdshdr(SDS or simple dynamic string)的数据结构.SDS不仅用于 保存字符串, ...
- Redis源码学习:Lua脚本
Redis源码学习:Lua脚本 1.Sublime Text配置 我是在Win7下,用Sublime Text + Cygwin开发的,配置方法请参考<Sublime Text 3下C/C++开 ...
- redis源码学习之slowlog
目录 背景 环境说明 redis执行命令流程 记录slowlog源码分析 制造一条slowlog slowlog分析 1.slowlog如何开启 2.slowlog数量限制 3.slowlog中的耗时 ...
- 柔性数组(Redis源码学习)
柔性数组(Redis源码学习) 1. 问题背景 在阅读Redis源码中的字符串有如下结构,在sizeof(struct sdshdr)得到结果为8,在后续内存申请和计算中也用到.其实在工作中有遇到过这 ...
- __sync_fetch_and_add函数(Redis源码学习)
__sync_fetch_and_add函数(Redis源码学习) 在学习redis-3.0源码中的sds文件时,看到里面有如下的C代码,之前从未接触过,所以为了全面学习redis源码,追根溯源,学习 ...
- redis源码学习之工作流程初探
目录 背景 环境准备 下载redis源码 下载Visual Studio Visual Studio打开redis源码 启动过程分析 调用关系图 事件循环分析 工作模型 代码分析 动画演示 网络模块 ...
- redis源码学习之lua执行原理
聊聊redis执行lua原理 从一次面试场景说起 "看你简历上写的精通redis" "额,还可以啦" "那你说说redis执行lua脚本的原理&q ...
- redis源码之dict
大家都知道redis默认是16个db,但是这些db底层的设计结构是什么样的呢? 我们来简单的看一下源码,重要的字段都有所注释 typedef struct redisDb { dict *dict; ...
- Redis源码学习-Master&Slave的命令交互
0. 写在前面 Version Redis2.2.2 Redis中可以支持主从结构,本文主要从master和slave的心跳机制出发(PING),分析redis的命令行交互. 在Redis中,serv ...
随机推荐
- 2018-03-10 VCard备份恢复联系人
主要在VCardComposer类中备份联系人的逻辑 导出流程: http://blog.csdn.net/michael_yt/article/details/78270537 导入流程: http ...
- noip第23课作业
1. 营救 铁塔尼号遇险了!他发出了求救信号.距离最近的哥伦比亚号收到了讯息,时间就是生命,必须尽快赶到那里. 通过侦测,哥伦比亚号获取了一张海洋图.这张图将海洋部分分化成n*n个比较小的单位,其 ...
- Java关键字、标识符、表达式、常用符号
关键字 包:package(包).import(导入) 类:class(类).enum(枚举).interface(接口).extends(继承).implements(实现) 方法:void(空). ...
- 4.动态HTML处理和机器图像识别
Selenium Selenium是一个Web的自动化测试工具,最初是为网站自动化测试而开发的,类型像我们玩游戏用的按键精灵,可以按指定的命令自动操作,不同是Selenium 可以直接运行在浏览器上, ...
- Android-Java静态代码块&局部代码块
静态代码块: 静态代码块什么时候执行,是由当前类被加载进内存的时候,什么时候当前类被加载进内存? 答:例如 描述好了Student对象,当 new Student(); 的时候,第一步:是把Stude ...
- 关于tableview下拉刷新崩溃的问题
逻辑应该是这样的:1. 下拉2. 达到下拉临界值以后再请求网络数据3. 待数据加载到本地以后才更新 data source4. reload tableview 如果先清空再下拉,后果就是往下拉的距离 ...
- PCA和Whitening
PCA: PCA的具有2个功能,一是维数约简(可以加快算法的训练速度,减小内存消耗等),一是数据的可视化. PCA并不是线性回归,因为线性回归是保证得到的函数是y值方面误差最小,而PCA是保证得到的函 ...
- 在推送提交之后阻止Azure DevOps (TFS)持续集成
在Azure DevOps服务器上配置生成定义时,可以配置连续集成(CI)生成.每次签入或提交到源代码库时都会自动运行一个CI构建.这种机制允许开发人员启动一个自动化的过程,例如编译和部署构建.这是一 ...
- BAE上部署Ghost 0.5.1注意事项
BAE上部署Ghost可参考基本安装上述安装使用的是ghost0.4.7版本 在ghost 0.5 中为了解决测试时事件侦听器过多引发的警告,在注册single事件时,将代码由原先的 process. ...
- node.js second day
create global link 使用全局模式安装的包不能直接通过require使用,但是nmp提供了一个 nmp link ,这个可以打破限制 $ nmp link [express] ./no ...