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 ...
随机推荐
- PHP与Python哪个做网站产品好?
虽然python现在比较火,但在传统的LAMP组合里Linux+apache/tomcat+MySql+PHP里是PHP做网站的脚本语言,但现在已经变了:https://baike.baidu.com ...
- java中的中文字符转码技术
package com.yin.test; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; impor ...
- kafka参数
转载地址http://debugo.com/kafka-params/ ############################# System ########################### ...
- curl工具介绍和常用命令
curl是利用URL语法在命令行方式下工作的开源文件传输工具.它被广泛应用在Unix.Linux发行版中,并且有DOS和Win32.Win64的移植版本.curl是一个利用URL规则在命令行下工作的文 ...
- Android-Kotlin-继承
上一篇博客 Android-Kotlin-配置/入门 配置好了 AndroidStudio Kotlin 的环境: 1.先看一个案例,子类使用到父类的资源 [案例一] 父类 张翠山: package ...
- UC浏览器 - 不负责任思考
前言 UC浏览器的辉煌应该是我读大学(2008年)的时候,转眼间,十年过去了,庆幸的是UC还在,我从使用者变成了一名UC的员工. 以下都是个人的不负责任的猜想或者思考 变更 塞班时代 UC浏览器的地位 ...
- MQ的demo
public class WorkTest { @Test public void send() throws Exception{ //获取连接 Connection conn = ...
- 【计算机网络】TCP通信的细节及TCP连接对HTTP事务处理性能影响
从三次握手的细节说起 刚开始尝试使用java等后端语言写IO流,或用套接字(socket)实现简单C/S通信的同学们,常常会接触到的一个概念:就是所谓的“三次握手”,socket作为一个API接口,封 ...
- Ubuntu修改apt-get源
1.背景 服务器上安装了最新的Ubuntu Server 17.04,代号为zesty.使用apt-get命令安装软件时,有时候速度比较慢,有时候会失败.因此考虑用国内的镜像源更换下apt-get的默 ...
- Python 爬虫(二十五) Cookie的处理--cookielib库的使用
Python中cookielib库(python3中为http.cookiejar)为存储和管理cookie提供客户端支持. 该模块主要功能是提供可存储cookie的对象.使用此模块捕获cookie并 ...