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 ...
随机推荐
- MapGIS计算瓦片数据集
https://www.docin.com/p-2103834433.html
- JAVA作业之两数的加减乘除
1.设计思路 把输入的字符转化为计算的数字问题,再以对话框的形式输入输出加减乘除的结果问题. 2.程序流程图 3.源代码 4.实验结果
- 28、vSocket模型详解及select应用详解
在上片文章已经讲过了TCP协议的基本结构和构成并举例,也粗略的讲过了SOCKET,但是讲解的并不完善,这里详细讲解下关于SOCKET的编程的I/O复用函数. 1.I/O复用:selec函数 在介绍so ...
- 《mysql必知必会》学习_第12章_20180801_欢
第12章:汇总数据 P76 avg()函数求平均值 select avg(prod_price) as avg_price from products; #计算prod_price的平均值,并且命名为 ...
- js五道经典练习题--第三道实现购物车功能
<!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>& ...
- Android-Java-synchronized同步代码块的使用场景
synchronized同步代码块的使用场景 (满足以下两种条件,就要考虑使用synchronize同步代码块了) 1.被synchronized同步代码块{同步的代码},是被多次异步调用,什么叫多次 ...
- min cost max flow算法示例
问题描述 给定g个group,n个id,n<=g.我们将为每个group分配一个id(各个group的id不同).但是每个group分配id需要付出不同的代价cost,需要求解最优的id分配方案 ...
- MySQL--REPALCE INTO操作
REPLACE INTO语法是MySQL数据库独特的扩展语法,可以提供“不存在即插入,存在即更新”的操作,MySQL官方文档解析其算法为: 1.尝试进行INSER 操作 2.如果INSERT 失败,则 ...
- ASP.NET Core ef启用数据迁移
创建一个项目 通过Nuget获取EF Core相关的扩展包 appsettings.json 建立数据库连接串 创建数据库上下文EntityDbContext类,用于实体类映射数据库表 使用包管理器控 ...
- ContentControl as CC和ContentPresenter as CP的使用
1.CC为文本控件的父类,它继承为control,所以他是控件, 2.CP继承FrameworkElement,所以他是容器,相当于占位符 3.想让控件中能包含子控件就需要用CP,反之用CC就行.(不 ...