redis代码解析-dictionary类型
dict本质上是为了解决算法中的查找问题(Searching),一般查找问题的解法分为两个大类:一个是基于各种平衡树,一个是基于哈希表。
redis中的dict传统的哈希算法类似,它采用某个哈希函数从key计算得到在哈希表中的位置,采用拉链法解决冲突,并在装载因子(load factor)超过预定值时自动扩展内存,引发重哈希(rehashing).在一个dict中有两个hash表,目的是来实现逐步的rehash,同时rehash时仍然可以访问dict.
正常使用的是ht[0],在rehash的时候先设置ht[1]大小为rehash后的需要的大小,然后逐步的将ht[0]中的内容rehash到ht[1]中,rehashidx记录着当前rehash到的index,在全部rehash完成之后,将ht[1]给ht[0],再reset ht[1].
当前dict是否处于rehash过程中可以通过rehashidx的值来判断,rehash时记录的是已经进行到的index,非rehash时为-1.
逐步的rehash是将rehash操作分散到对于dict的各个增删改查的操作中去。这种方法能做到每次只对一小部分key进行重哈希,而每次重哈希之间不影响dict的操作。dict这样设计避免重哈希期间单个请求的响应时间的剧烈增加
typedef struct dict {
dictType *type;
void *privdata;
dictht ht[2];
long rehashidx; /* rehashing not in progress if rehashidx == -1 */
unsigned long iterators; /* number of iterators currently running */
} dict;
一个hash table即dictht中的table是一个dictEntry数组,dict每次rehash时,table扩容或者缩小的时候都是2的n次方大小.
同时dictht还记录了当前table的大小,以及存在的dictEntry的数量.判断是否需要rehash就是通过used/size==1为需要rehash,used/size==5需要强制rehash
dictht中sizemask的值为size-1,因为size总是2的n次方,所以sizemask是n位的1,用来一个key的hash&sizemask定位出这个key应该在table中的位置.
同时,解决hash冲突的方法是链式
typedef struct dictEntry {
void *key;
union {
void *val;
uint64_t u64;
int64_t s64;
double d;
} v;
struct dictEntry *next;
} dictEntry;
/* This is our hash table structure. Every dictionary has two of this as we
* implement incremental rehashing, for the old to the new table. */
typedef struct dictht {
dictEntry **table;
unsigned long size;
unsigned long sizemask;
unsigned long used;
} dictht;
一个dict的图示如下:

图片引用自:http://zhangtielei.com/posts/blog-redis-dict.html
dict的其他操作都非常简单,都是正常的对hash table的操作
dict scan还有点意思,因为redis中dict数据结构的关系,所以没办法使用传统的顺序遍历,因为
1 如果发生了扩容,原来的表大小是8,扩容之后是16,就会把原来的1-8rehash到新的1-16个slot中.如果现在要顺序访问8,则从8-16之前的其实全部在旧的表中1-7中访问过,会有大量的重复访问.
2 如果发生了缩表,原来的16缩小到8,就正好相反会有遗漏.
3 如果正在rehash,t0表中的数据是不全的也依然肯定有问题.
所以,redis中dict scan设计了一种新的遍历方法:对二进制高位进行加1遍历.
如果表的大小是8的话,和大小为2的访问顺序会是如下:
000 -> 0 00-> 0
100 -> 4 10-> 2
010 -> 2 01-> 1
110 -> 6 11-> 3
001 -> 1
101 -> 5
011 -> 3
111 -> 7
1 表扩容,先访问n,然后是访问n+2的n次方,不会重复,不会遗漏.
2 表缩小,通过n&m0(size mask)定位,可能会有重复的情况,不会遗漏.
3 如果正在rehash过程中,访问n的时候,会先在容量小的表中访问(n&m0),然后在大的表中遍历出全部的n&m0对应的位置.
dict scan 详细可参考这篇blog,http://chenzhenianqing.cn/articles/1101.html
redis代码解析-dictionary类型的更多相关文章
- redis代码解析-事务
redis 的事务相关的几个命令分别为 watch multi exec. watch 可以监控一个变量在事务开始执行之前是否有被修改.使用方式为: WATCH key [key ...] 在redi ...
- Redis源码解析:18Hiredis同步API和回复解析API代码解析
Redis的sentinel模式使用了Hiredis代码,Hiredis是redis数据库一个轻量级的C语言客户端库.它实现的向Redis发送命令的API函数redisCommand,使用方法类似于p ...
- GraphSAGE 代码解析(一) - unsupervised_train.py
原创文章-转载请注明出处哦.其他部分内容参见以下链接- GraphSAGE 代码解析(二) - layers.py GraphSAGE 代码解析(三) - aggregators.py GraphSA ...
- VBA常用代码解析
031 删除工作表中的空行 如果需要删除工作表中所有的空行,可以使用下面的代码. Sub DelBlankRow() DimrRow As Long DimLRow As Long Dimi As L ...
- java集合框架之java HashMap代码解析
java集合框架之java HashMap代码解析 文章Java集合框架综述后,具体集合类的代码,首先以既熟悉又陌生的HashMap开始. 源自http://www.codeceo.com/arti ...
- linux内存管理--slab及其代码解析
Linux内核使用了源自于 Solaris 的一种方法,但是这种方法在嵌入式系统中已经使用了很长时间了,它是将内存作为对象按照大小进行分配,被称为slab高速缓存. 内存管理的目标是提供一种方法,为实 ...
- redis(Remote Dictionary Server)
redis的简介和使用 简介 redis(Remote Dictionary Server)是一种Nosql技术,它是一个开源的高级kv存储和数据结构存储系统,它经常被拿来和Memcached相比 ...
- Redis源代码分析(一)--Redis结构解析
从今天起,本人将会展开对Redis源代码的学习,Redis的代码规模比較小,很适合学习,是一份很不错的学习资料,数了一下大概100个文件左右的样子,用的是C语言写的.希望终于能把他啃完吧,C语言好久不 ...
- C# 获取与解析枚举类型的 DescriptionAttribute
原文:C# 获取与解析枚举类型的 DescriptionAttribute System.ComponentModel.DescriptionAttribute 这个 Attribute,经常被用来为 ...
随机推荐
- POJ3349 Language: Snowflake Snow Snowflakes
POJ3349 Language: Snowflake Snow Snowflakes 题目:传送门 题解: 链表+hash的一道水题 填个坑补个漏... 代码: #include<cstdio ...
- Linux - 理不清的权限chmod与chown区别
chmod是修改第一列内容的 ,chown是修改第3,4列内容的. [root@local ~]# chmod 777 -R add.sh [root@local ~]# chown jiqing:j ...
- day63-webservice 11.cxf整合spring
如果我们有Spring配置文件,怎么把WebService整合到Spring里面,用Ioc容器来管理这个Bean. 做项目的时候一般都是分层:Dao层.Service层.Service层要调Dao层, ...
- linux git保存用户名密码(避免每次push输用户名密码)
Linux/Unix/Mac 系统 新建一个 ~/.netrc 文件, 将 git 服务器, 用户名以及密码记录在这个文件, 如下所示: machine your-git-server log ...
- centos 80端口占用
netstat -lnp|grep 80 kill -9 1777 #杀掉编号为1777的进程(请根据实际情况输入)service httpd start #启动apache
- shp系列(七)——利用C++进行Shx文件的写(创建)
之前介绍了Shp文件和Dbf的写(创建),最后来介绍一下Shx文件的写(创建).Shx文件是三者之中最简单的一个,原因有两个:第一是Shx文件的头文件与Shp文件的头文件几乎一样(除了FileLeng ...
- 【算法】Quick Select
针对问题 找到一对无序的数中第 K 大,或者第 K 小的元素,返回该元素的值或者它的 index(index 的情况比较适合这堆数每个都独一无二的情况,不然可能会有多个答案). 关键思想 拿一个数 ...
- Mysql数据库概述
阅读目录 引擎介绍 表介绍 创建表 查看表结构 mysql中的数据类型 表的完整性约束 修改表结构 删除表 多表结构的创建与分析 练习 返回顶部 引擎介绍 mysql中的存储引擎(https://ww ...
- 测试数据准备中用到到csv写文件知识点
对于大数据测试中,有时需要自己去准备一些数据,用csvreader来写一个比较大的文件就比较方便,下面我就直接贴示例代码了: package com.acxm.amysu.test;import co ...
- Kettle 版本及使用问题
kettle 简介 Kettle也叫PDI (Pentaho Data Intergration) Kettle 版本及下载 7.1及更早版本: https://sourceforge.net/pro ...