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;
- }
- unsigned int dictIntHashFunction(unsigned int 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;
- }
- unsigned int dictGenHashFunction(const void *key, int len) {
- 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 ...
随机推荐
- 使用Kotlin&Anko, 扔掉XML开发Android应用
尝鲜使用Kotlin写了一段时间Android.说大幅度的减少了Java代码一点不夸张.用Java的时候动不动就new一个OnClickListener()匿名类,动不动就类型转换的地方都可以省下很多 ...
- shell脚本-成长之路
我对shell脚本的认识,除了执行过同事写的shell 脚本外,其他一无所知,为了让自己强大,我决定自己研究shell脚本,也许在你看来很简答,没必要说这么多废话,但是我希望在我的技术log里记录下来 ...
- Codeforces Round #540 (Div. 3)--1118D1 - Coffee and Coursework (Easy version)
https://codeforces.com/contest/1118/problem/D1 能做完的天数最大不超过n,因为假如每天一杯咖啡,每杯咖啡容量大于1 首先对容量进行从大到小的排序, sor ...
- kafka讲解
转载http://www.jasongj.com/2015/01/02/Kafka深度解析 Kafka是Apache下的一个子项目,是一个高性能跨语言分布式发布/订阅消息队列系统,而Jafka是在Ka ...
- TBB的学习
1. TBB简介 TBB ( Thread Building Blocks, 线程构建模块) 是Intel公司开发的并行编程开发的工具.它支持Windows,OS X, Linux平台,支持的编译器有 ...
- spring security文档地址
https://docs.spring.io/spring-security/site/docs/4.1.0.RELEASE/reference/htmlsingle/
- Android-Java-封装
先看一个未封装的Demo案例一: package android.java.oop03; class Person { int age; } public class PottingDemo { pu ...
- cnn公式推导
CNN公式推导 1 前言 在看此blog之前,请确保已经看懂我的前两篇blog[深度学习笔记1(卷积神经网络)]和[BP算法与公式推导].并且已经看过文献[1]的论文[Notes on Convolu ...
- 获取用户真实ip
public static string GetRealIP() { string result = System.Web.HttpContext.Current.Request.Headers[&q ...
- .net core 与ELK(3)安装Kibana
1.去产品官网下载https://www.elastic.co/downloads/kibana 对应的tar.gz的压缩包,放到/usr/local/src目录 2.解压 -linux-x86_64 ...