Redis设计与实现 (三): 字典
哈希表
结构定义dict.h/dictht
/*
* 哈希表
*
* 每个字典都使用两个哈希表,从而实现渐进式 rehash 。
*/
typedef struct dictht { // 哈希表数组
dictEntry **table; // 哈希表大小
unsigned long size; // 哈希表大小掩码,用于计算索引值
// 总是等于 size - 1
unsigned long sizemask; // 该哈希表已有节点的数量
unsigned long used; } dictht;
table是一个数组, 每个元素是一个指向dict.h/dictEntry 结构的指针.
哈希表节点
/*哈希表节点*/
typedef struct dictEntry {
// 键
void *key;
// 值
union {
void *val;
uint64_t u64;
int64_t s64;
} v;
// 指向下个哈希表节点,形成链表
struct dictEntry *next; } dictEntry;
next属性指向下一个节点, 形成链表, 解决哈希冲突.
字典
/*
* 字典
*/
typedef struct dict {
// 类型特定函数
dictType *type;
// 私有数据
void *privdata;
// 哈希表
dictht ht[];
// rehash 索引
// 当 rehash 不在进行时,值为 -1
int rehashidx; /* rehashing not in progress if rehashidx == -1 */
// 目前正在运行的安全迭代器的数量
int iterators; /* number of iterators currently running */
} dict;
type 和 privdata属性都是针对不同类型的键值对, 为创建多态字典设置.
/*
* 字典类型特定函数
*/
typedef struct dictType {
// 计算哈希值的函数
unsigned int (*hashFunction)(const void *key);
// 复制键的函数
void *(*keyDup)(void *privdata, const void *key);
// 复制值的函数
void *(*valDup)(void *privdata, const void *obj);
// 对比键的函数
int (*keyCompare)(void *privdata, const void *key1, const void *key2);
// 销毁键的函数
void (*keyDestructor)(void *privdata, void *key);
// 销毁值的函数
void (*valDestructor)(void *privdata, void *obj);
} dictType;
ht数组包含两个哈希表, 一般情况下操作ht[0], ht[1] 只有在ht[0]哈希表进行rehash时使用. rehashidx, 记录了rehash的进度, 没有则为 -1 ;
哈希算法
Redis 使用MurmurHash2算法计算哈希值
解决键冲突
链地址法, 采用头插法, 时间复杂度为O(1).
rehash
1. 为 ht[1] 分配空间 : 如果是扩容, 分配大小为 第一个大于等于 ht[0] .used * 2 的 2的n次幂; 如果是收缩, 分配空间大小为 第一个大于等于 ht[0] .used 的 2的n次幂.
2. 将ht[0] 上的键值对 通过重新计算键的哈希值和索引重新分配到ht[1] 上.
3. 这时ht[0] 将变为空表, 释放ht[0], 将ht[1] 设置为ht[0], 并在ht[1]创建一个空表, 为下次rehash做准备.
渐进式rehash
在字典维持一个索引计数器 rehashidx, 设置为0, 表示正式工作.
在对字典执行添加, 删除, 查找或修改时, 将 rehashidx 索引上的所有键值对 rehash 到 hd[1], 完成后 rehashidx++;
当ht[0] 上的所有键值对被 rehash到 ht[ 1 ], 设置 rehashidx = - 1, 表示操作已经完成了.
在此期间操作数据, 会使用ht[0] 和 ht[1]两个hash表, 例如要找某个键值, 会先在ht[0] 找, 没有就去ht[ 1 ] 找. 新增操作都保存到ht[ 1 ] 中. 保证了ht[0] 只减不增, 最终为空.
Redis设计与实现 (三): 字典的更多相关文章
- [Redis]Redis的设计与实现-链表/字典/跳跃表
redis的设计与实现:1.假如有一个用户关系模块,要实现一个共同关注功能,计算出两个用户关注了哪些相同的用户,本质上是计算两个用户关注集合的交集,如果使用关系数据库,需要对两个数据表执行join操作 ...
- Redis学习笔记(三) 字典
Redis的字典使用哈希表作为底层实现,一个哈希表中可以有多个哈希表节点,而每个哈希节点就保存在字典中的一个键值对. redis字典所用的哈希表由disht结构定义. typedef struct d ...
- Redis 设计与实现 4:字典
Redis 中,字典是基础结构.Redis 数据库数据.过期时间.哈希类型都是把字典作为底层结构. 字典的结构 哈希表 哈希表的实现代码在:dict.h/dictht ,Redis 的字典用哈希表的方 ...
- Redis底层探秘(三):字典
字典,又称为符号表(symbol table).关联数组(associative array)或映射(map),是一种用于保存键值对的抽象数据结构. 字典经常作为一种数据结构内置在很多高级编程语言里面 ...
- Redis设计与实现(一~五整合版)【搬运】
Redis设计与实现(一~五整合版) by @飘过的小牛 一 前言 项目中用到了redis,但用到的都是最最基本的功能,比如简单的slave机制,数据结构只使用了字符串.但是一直听说redis是一个很 ...
- 《Redis设计与实现》读书笔记
<Redis设计与实现>读书笔记 很喜欢这本书的创作过程,以开源的方式,托管到Git上进行创作: 作者通读了Redis源码,并分享了详细的带注释的源码,让学习Redis的朋友轻松不少: 阅 ...
- 《Redis设计与实现》
<Redis设计与实现> 基本信息 作者: 黄健宏 丛书名: 数据库技术丛书 出版社:机械工业出版社 ISBN:9787111464747 上架时间:2014-6-3 出版日期:2014 ...
- 探索Redis设计与实现9:数据库redisDb与键过期删除策略
本文转自互联网 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial ...
- 探索Redis设计与实现6:Redis内部数据结构详解——skiplist
本文转自互联网 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial ...
随机推荐
- DbEntry.Net(Lephone Framework) Access ORM:安装和简单使用
项目中用到Access数据库,之前用的普通Ado.Net 三层.遇到表字段叫多时,就比较费力.想要使用ORM,无奈EF不支持Access.虽然可以改写linq to sql为Linq to Acces ...
- Node单线程与异步编程的初步理解
最近学习了一些关于node的单线程与异步的知识,想拿过来和大家分享下: var async = require('async') //并行无关联,等待事件为最长时间请求过程.如以下两个任务执行时间 c ...
- Android 电池关机充电
android 电池(一):锂电池基本原理篇 android 电池(二):android关机充电流程.充电画面显示 android 电池(三):android电池系统 android电池(四):电池 ...
- 苹果Dock样式的菜单
在线演示 本地下载
- nc之netcat端口测试与nmap工具
nc介绍: nc是netcat的简写,有着网络界的瑞士军刀美誉.因为它短小精悍.功能实用,被设计为一个简单.可靠的网络工具,其有Windows和Linux的版本,可通过TCP或UDP协议传输读写数据. ...
- 详解Linux系统下PXE服务器的部署过程
在大规模安装服务器时,需要批量自动化方法来安装服务器,来减少日常的工作量. 但是批量自动化安装服务器的基础是网络启动服务器(bootserver). 下面我们就介绍一下 网络启动服务器的 安装和配置方 ...
- Spring AOP(3)
- spark 参数调优
调整partition数量,每次reduece和distict的时候都应该调整,数量太大和太小都不好,通常来讲保证一个partition的大小在1-2G左右为宜 调整excutors 调整core 调 ...
- java中Vector类的常用方法
Vector类是实现List接口,所以继承的方法就不在这里讲了 https://www.cnblogs.com/xiaostudy/p/9503199.html public void add(int ...
- javascript练习题(2):变量作用域
1. 外层变量在内部可以找到,反之找不到 以下看个案例: var a=10; function aaa(){ alert(a); } function bbb(){ var a=20; aaa(); ...