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类型的更多相关文章

  1. redis代码解析-事务

    redis 的事务相关的几个命令分别为 watch multi exec. watch 可以监控一个变量在事务开始执行之前是否有被修改.使用方式为: WATCH key [key ...] 在redi ...

  2. Redis源码解析:18Hiredis同步API和回复解析API代码解析

    Redis的sentinel模式使用了Hiredis代码,Hiredis是redis数据库一个轻量级的C语言客户端库.它实现的向Redis发送命令的API函数redisCommand,使用方法类似于p ...

  3. GraphSAGE 代码解析(一) - unsupervised_train.py

    原创文章-转载请注明出处哦.其他部分内容参见以下链接- GraphSAGE 代码解析(二) - layers.py GraphSAGE 代码解析(三) - aggregators.py GraphSA ...

  4. VBA常用代码解析

    031 删除工作表中的空行 如果需要删除工作表中所有的空行,可以使用下面的代码. Sub DelBlankRow() DimrRow As Long DimLRow As Long Dimi As L ...

  5. java集合框架之java HashMap代码解析

     java集合框架之java HashMap代码解析 文章Java集合框架综述后,具体集合类的代码,首先以既熟悉又陌生的HashMap开始. 源自http://www.codeceo.com/arti ...

  6. linux内存管理--slab及其代码解析

    Linux内核使用了源自于 Solaris 的一种方法,但是这种方法在嵌入式系统中已经使用了很长时间了,它是将内存作为对象按照大小进行分配,被称为slab高速缓存. 内存管理的目标是提供一种方法,为实 ...

  7. redis(Remote Dictionary Server)

    redis的简介和使用   简介 redis(Remote Dictionary Server)是一种Nosql技术,它是一个开源的高级kv存储和数据结构存储系统,它经常被拿来和Memcached相比 ...

  8. Redis源代码分析(一)--Redis结构解析

    从今天起,本人将会展开对Redis源代码的学习,Redis的代码规模比較小,很适合学习,是一份很不错的学习资料,数了一下大概100个文件左右的样子,用的是C语言写的.希望终于能把他啃完吧,C语言好久不 ...

  9. C# 获取与解析枚举类型的 DescriptionAttribute

    原文:C# 获取与解析枚举类型的 DescriptionAttribute System.ComponentModel.DescriptionAttribute 这个 Attribute,经常被用来为 ...

随机推荐

  1. ETL (数据仓库技术)

    ETL,是英文 Extract-Transform-Load 的缩写,用来描述将数据从来源端经过抽取(extract).转换(transform).加载(load)至目的端的过程.ETL一词较常用在数 ...

  2. Vue环境搭建+VSCode+Win10

    一.安装Node.js(js的运行环境) 1.在Node.js官网https://nodejs.org/en/download/下载安装包.2.下载后进行安装.3.打开命令行,输入node -v可以查 ...

  3. 【Linux】YUM Repositories for CentOS, RHEL & Fedora Systems

    这里是官方wiki:https://wiki.centos.org/AdditionalResources/Repositories 一.简介 YUM(Yellowdog Updater Modifi ...

  4. Several Ideas on Perl List Context

    According to Beginning Perl Book published by Tsinghua Pub., the list context appears when you are t ...

  5. 文档控件NTKO OFFICE 详细使用说明之预览PDF文件(禁止打印、下载、另存为、防抓包下载)

    1.在线预览PDF文件(禁止打印.下载.复制.另存为) (1) 运行环境 ① 浏览器:支持IE7-IE11(平台版本还支持Chrome和Firefox) ② IE工具栏-Internet 选项:将ww ...

  6. tp5数据库操作 模型层

    一.数据模型作用 相同功能代码不用重复写多次 二.创建方式 在模块下建立model文件夹,php文件,文件名为数据库表名,其中类为数据库表名,继承Model类,模型层即为此表 namespace ap ...

  7. javascript一个作用域案例分析

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  8. Javassist介绍

    要想将编译时不存在的类在运行时动态创建并加载,通常有两种策略: 1. 动态编译 2. 动态生成二进制字节码(.class) 对于第二种策略,实际上已经有诸多比较成熟的开源项目提供支持,如CGLib.A ...

  9. lz的第一个RN项目

    这是lz 成功在原有项目上集成的第一个ReactNative 项目. 参考官方网址: http://reactnative.cn/docs/0.43/integration-with-existing ...

  10. ubuntu 搭建简易的https网站

    ubuntu 搭建简易的https网站 环境:ubuntu 12.04.5 openssl (1)创建一个ssl的保存路径 sudo mkdir /opt/nginx/ssl (2)生存密钥sudo ...