因为redis是用c写的,c中没有自带的map,所以redis自己实现了map,来看一下redis是怎么实现的。

1、redis字典基本数据类型

redis是用哈希表作为字典的底层实现,dictht是哈希表的定义:

typedef struct dictht {

    // 哈希表节点指针数组(俗称桶,bucket)
dictEntry **table; // 指针数组的大小
unsigned long size; // 指针数组的长度掩码,用于计算索引值
unsigned long sizemask; // 哈希表现有的节点数量
unsigned long used; } dictht;

table是一个数组,数组中的元素都是一个指向dictEntry结构的指针,每个dictEntry结构保存着一个键值对。

dictEntry的结构如下:

typedef struct dictEntry {

    // 键
void *key; // 值
union {
void *val;
uint64_t u64;
int64_t s64;
} v; // 链往后继节点
struct dictEntry *next; } dictEntry;

可以看到有个next指针,是用链表法来解决hash冲突的;v保存值,可以是一个指针,uint64_t整数,或者int64_t整数。

Redis中字典的结构如下:

typedef struct dict {

    // 特定于类型的处理函数
dictType *type; // 类型处理函数的私有数据
void *privdata; // 哈希表(2个)
dictht ht[]; // 记录 rehash 进度的标志,值为-1 表示 rehash 未进行
int rehashidx; // 当前正在运作的安全迭代器数量
int iterators; } dict;

这里需要解释一下dictType和privdata,前者是一组用于操作键值对的函数,redis会对不同用途的字典使用不同的函数,后者是这些函数需要用的可选参数。

ht[2]就是两个哈希表,一般情况下只会ht[0],ht[1]会在对ht[0]进行rehash时使用。rehashidx记录了rehash目前的进度,如果目前没有进行rehash那么rehashidx=-1。

2、哈希算法以及解决哈希冲突

redis使用MurmurHash2算法,哈希冲突使用链地址法,redis总是将新节点添加到链表头部。

3、rehash和渐进式rehash

redis的哈希表会随着对其操作而增大或减小,那么为了让负载因子保持合理,也保持字典的高效,需要在哈希表中数量太多或太少时进行扩展或收缩。

redis最小哈希表大小为DICT_HT_INITIAL_SIZE=4,扩展操作的话ht[1]的大小为第一个大于等于ht[0].used*2的2^n;收缩操作ht[1]的大小为第一个大于等于ht[0].used的2^n。然后将ht[0]中的所有键值对rehash到ht[1]上,当全部rehash之后,把ht[1]置为ht[0],并为ht[1]新创建一个空白哈希表,为下次rehash做准备。

渐进式rehash,让字典同时持有ht[0]和ht[1],将rehashidx设为0,表示rehash开始;在rehash期间,每次对字典进行增删查改操作时,redis除了执行指定的操作以外,还会顺带把ht[0]哈希表在rehashidx索引上的所有键值对rehash到ht[1],当rehash完成,rehashidx++;随着时间及操作的执行,最终ht[0]的所有键值对会rehash到ht[1]上,然后把rehashidx置为-1;表示rehash结束。

在渐进式rehash的过程中,字典的删除,查找,更新等操作会在两个哈希表上进行,新增的键值对会保存到ht[1]里面,这样保证了ht[0]里的键值对只增不减,最终变为空表。

Redis源码阅读笔记(2)——字典(Map)实现原理的更多相关文章

  1. [Redis源码阅读]dict字典的实现

    dict的用途 dict是一种用于保存键值对的抽象数据结构,在redis中使用非常广泛,比如数据库.哈希结构的底层. 当执行下面这个命令: > set msg "hello" ...

  2. Redis源码阅读笔记(1)——简单动态字符串sds实现原理

    首先,sds即simple dynamic string,redis实现这个的时候使用了一个技巧,并且C99将其收录为标准,即柔性数组成员(flexible array member),参考资料见这里 ...

  3. CI框架源码阅读笔记3 全局函数Common.php

    从本篇开始,将深入CI框架的内部,一步步去探索这个框架的实现.结构和设计. Common.php文件定义了一系列的全局函数(一般来说,全局函数具有最高的加载优先权,因此大多数的框架中BootStrap ...

  4. Three.js源码阅读笔记-5

    Core::Ray 该类用来表示空间中的“射线”,主要用来进行碰撞检测. THREE.Ray = function ( origin, direction ) { this.origin = ( or ...

  5. jdk源码阅读笔记-LinkedHashMap

    Map是Java collection framework 中重要的组成部分,特别是HashMap是在我们在日常的开发的过程中使用的最多的一个集合.但是遗憾的是,存放在HashMap中元素都是无序的, ...

  6. faster rcnn源码阅读笔记1

    自己保存的源码阅读笔记哈 faster rcnn 的主要识别过程(粗略) (开始填坑了): 一张3通道,1600*1600图像输入中,经过特征提取网络,得到100*100*512的feature ma ...

  7. Apollo源码阅读笔记(二)

    Apollo源码阅读笔记(二) 前面 分析了apollo配置设置到Spring的environment的过程,此文继续PropertySourcesProcessor.postProcessBeanF ...

  8. Apollo源码阅读笔记(一)

    Apollo源码阅读笔记(一) 先来一张官方客户端设计图,方便我们了解客户端的整体思路. 我们在使用Apollo的时候,需要标记@EnableApolloConfig来告诉程序开启apollo配置,所 ...

  9. Redis源码阅读(五)集群-故障迁移(上)

    Redis源码阅读(五)集群-故障迁移(上) 故障迁移是集群非常重要的功能:直白的说就是在集群中部分节点失效时,能将失效节点负责的键值对迁移到其他节点上,从而保证整个集群系统在部分节点失效后没有丢失数 ...

随机推荐

  1. MVC打包压缩JS&CSS文件调试时过滤了一些文件

    BundleTable.这个确实是比较好用,打包并压缩了CSS,使之加载时减少流量. 但是在调试的时候会疑问为何有很多JS,CSS文件无法打包,其实是因为调试时VS自动过滤了如下文件:   后台跟踪了 ...

  2. Two ways to create file using 'doc'.

    Here are two ways to create file using 'doc' command: Method i: copy con [file name][enter key] [con ...

  3. hdoj 2049 错排

    代码: #include <stdio.h> int main(){ int n,a,b,i,j; __int64 s[22],h[22]; s[1]=0; s[2]=1; s[3]=2; ...

  4. 微软SQLHelper.cs类

    using System; using System.Data; using System.Xml; using System.Data.SqlClient; using System.Collect ...

  5. 【HDU3802】【降幂大法+矩阵加速+特征方程】Ipad,IPhone

    Problem Description In ACM_DIY, there is one master called “Lost”. As we know he is a “-2Dai”, which ...

  6. 了解负载均衡 会话保持 session同步(转)

    一,什么负载均衡 一个新网站是不要做负载均衡的,因为访问量不大,流量也不大,所以没有必要搞这些东西.但是随着网站访问量和流量的快速增长,单台服务器受自身硬件条件的限制,很难承受这么大的访问量.在这种情 ...

  7. Android 中文 API (29) —— CompoundButton

    前言 本章内容是android.widget.CompoundButton,翻译来自德罗德,再次感谢德罗德 !期待你一起参与Android API 的中文翻译,联系我over140@gmail.com ...

  8. C# 窗体间传值方法大汇总(转)

    第一种方法:创建一个类,里面声明用于存储接收的字段.传的时候存储于字段中,要用的时候,直接类名.字段名 进行调用.(这种方法传递是双向的) 第二种方法:1.在Form1里定义 public strin ...

  9. python读写Excel文件的函数--使用xlrd/xlwt

    python中读取Excel的模块或者说工具有很多,如以下几种: Packages 文档下载 说明 openpyxl Download | Documentation | Bitbucket  The ...

  10. Android RecyclerView Adapter 新式用法之SortedListAdapterCallback

    引言 前几天在同事的提醒下发现V7中有了一个新的工具类SortedListAdapterCallback,配合RecyclerView Adapter和SortedList一起使用更加方便的管理我们在 ...