哈希表

结构定义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设计与实现 (三): 字典的更多相关文章

  1. [Redis]Redis的设计与实现-链表/字典/跳跃表

    redis的设计与实现:1.假如有一个用户关系模块,要实现一个共同关注功能,计算出两个用户关注了哪些相同的用户,本质上是计算两个用户关注集合的交集,如果使用关系数据库,需要对两个数据表执行join操作 ...

  2. Redis学习笔记(三) 字典

    Redis的字典使用哈希表作为底层实现,一个哈希表中可以有多个哈希表节点,而每个哈希节点就保存在字典中的一个键值对. redis字典所用的哈希表由disht结构定义. typedef struct d ...

  3. Redis 设计与实现 4:字典

    Redis 中,字典是基础结构.Redis 数据库数据.过期时间.哈希类型都是把字典作为底层结构. 字典的结构 哈希表 哈希表的实现代码在:dict.h/dictht ,Redis 的字典用哈希表的方 ...

  4. Redis底层探秘(三):字典

    字典,又称为符号表(symbol table).关联数组(associative array)或映射(map),是一种用于保存键值对的抽象数据结构. 字典经常作为一种数据结构内置在很多高级编程语言里面 ...

  5. Redis设计与实现(一~五整合版)【搬运】

    Redis设计与实现(一~五整合版) by @飘过的小牛 一 前言 项目中用到了redis,但用到的都是最最基本的功能,比如简单的slave机制,数据结构只使用了字符串.但是一直听说redis是一个很 ...

  6. 《Redis设计与实现》读书笔记

    <Redis设计与实现>读书笔记 很喜欢这本书的创作过程,以开源的方式,托管到Git上进行创作: 作者通读了Redis源码,并分享了详细的带注释的源码,让学习Redis的朋友轻松不少: 阅 ...

  7. 《Redis设计与实现》

    <Redis设计与实现> 基本信息 作者: 黄健宏 丛书名: 数据库技术丛书 出版社:机械工业出版社 ISBN:9787111464747 上架时间:2014-6-3 出版日期:2014 ...

  8. 探索Redis设计与实现9:数据库redisDb与键过期删除策略

    本文转自互联网 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial ...

  9. 探索Redis设计与实现6:Redis内部数据结构详解——skiplist

    本文转自互联网 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial ...

随机推荐

  1. HTML中表格table边框border(1px还嫌粗)的解决方案:

    摘自:http://blog.sina.com.cn/s/blog_ae809a730102vrx8.html 第一种方法: 1.将table的属性设置为:BORDER=0 .cellspacing= ...

  2. Authentication token is no longer valid

    Linux: Authentication token is no longer valid Problem: Authentication token is no longer valid; new ...

  3. ssi include返回404页面

    项目中index.html中包含<!--#include virtual="/commonfrag/djdzkan/recomm_www_info.inc"  --> ...

  4. VRChat简易教程4-使用VRC的接口实现物体的移动(VRC的action和trigger接口)

    这个教程我们学习如何实现载具的驾驶 一.准备工作 1 最简单的载具驾驶需要至少两个元素,一是需要一个载具,二是需要一个前进的按钮(这里我们只做前进功能),为了直观的能感受到载具的移动,我们还得创造一个 ...

  5. void及void指针介绍【转】

    本文转载自:http://blog.csdn.net/renren900207/article/details/20769503 void类型指针(如void *p)所指向的数据类型不是确定的,或者说 ...

  6. COS-2OS结构和硬件支持

    操作系统(Operating System,简称OS),是电子计算机系统中负责支撑应用程序运行环境以及用户操作环境的系统软件,同时也是计算机系统的核心与基石.它的职责常包括对硬件的直接监管.对各种计算 ...

  7. Linux查看服务和强制结束服务

    查看服务id命令,常用的两种:      a: ps -ef | grep 服务名      b: netstat -antp             找到结果名称,然后            pki ...

  8. mysql的binlog查看

    1.如果是在window下可以进入mysql的安装bin下,把从linux上拷贝出来的binlog进行查看,步骤如下 a.在mysql的安装bin下右键在此处打开命令行 b.执行命令 C:\Progr ...

  9. jsp select multiple

    //File: index.html<HTML>    <HEAD>        <TITLE>Submitting Multiple Selection Sel ...

  10. All Classic Bluetooth profile for iPhone

    iPhone BC profiles Profile Decription HFP1.6 1.通知客户端有电话拨入:2.免提功能:3.音频的输入输出机制. PBAP 1.下载通讯录:2.查找通讯录:3 ...