字典

字典,map,是用于保存键值对的抽象数据结构,是hash表实现。字典中的键唯一,通过键来操作值。Redis的数据库使用字典来作为底层实现。

定义

Redis的字典使用哈希表作为底层实现,一个哈希表里面由多个哈希表节点,哈希表节点保存着键值对。

哈希表

哈希表结构定义包含:哈希表数组,哈希表大小,哈希表掩码,哈希表已有节点数。

 typedef struct dictht {
dicEntry **table;
unsigned long size;
unsigned long sizemask;
unsigned long used;
}dictht;

table就是哈希表数组,每个元素就是一个哈希表节点的指针。

size记录了哈希表的大小,也就是table的大小。

sizemask是哈希表的掩码,用于计算索引值,值总是size-1。

used就是哈希表已有节点数,注意与size进行区分哈希表大小并不等于节点数。

哈希表节点

哈希表节点结构包含:键,值,下一哈希表节点的指针(用于解决冲突)

 typedef struct dictEntry {
void *key
union {
void *val
uint64_t u64;
int64_t s64;
} v;
struct dictEntry *next;
} dictEntry;

next指针将哈希值相同的键值对连接在一起,形成链表,解决冲突。

字典

字典包含:一个大小为2的哈希表数组(方便rehash),rehash索引,特定类型的函数,复制键的函数。

 typedef struct dict {
dictType *type;
void *privdata;
dictht ht[];
int trehashidx;
} dict;

type 和privdata的作用具体并不清楚,书上介绍“针对不同类型的键值对,为创建多态字典而设置”。

ht即hashtable平时的哈希表节点在ht[0],rehash的时候用到ht[1]。

哈希方式

插入键值对时,先根据键计算出哈希值。再根据哈希值和哈希表的掩码计算出应放在哈希表的哪个索引上。哈希函数为Murmurhash算法,然而并不知道具体是怎么个实现,给自己挖个坑,有空学习下。

hash = dict->type->hashFunction(key);
index = hash & dict->ht[x].sizemask;(x为0或1,取决于实际情况)

提到哈希肯定要考虑冲突的解决方法。在上面的哈希表节点中就已经看到,在这里使用链地址法解决冲突。

单向链表而且没有记录尾节点,所以插入链表时使用头插入。如果插入到末尾的话还需要遍历到链表末尾,消耗时间。

rehash

负载因子 = 哈希表已保存的节点数量/哈希表大小

很显然负载因子大说明哈希表太小,为了避免冲突就要增大。而负载因子太小说明哈希表过大,浪费了空间。

我们要对哈希表进行扩展或者收缩。这个工作通过rehash来完成。

  1. 为ht[1]分配空间。
  2. 将ht[0]的键值对rehash到ht[1]
  3. 当ht[0]全部迁移到ht[1],释放ht[0],让ht[1]成为新ht[0]

从上面的过程中我们发现有三个问题:

  • 在什么情况下我们需要对哈希表进行扩展或收缩?
  • 新空间分配策略是怎样的?
  • rehash迁移的过程如何完成?

第一个问题:if 负载因子大于1且没有执行BGSAVE,BGREEWRITEAOF 或者 负载因子大于5 (具体为啥这么定我也不知道。。。第二个坑)

        执行扩展

      else if 负载因子小于0.1

        执行收缩      

第二个问题:扩展的大小为:大于等于(ht[0].used*2)的最小2的整数幂

      缩小的大小为:大于等于(ht[0].used)的最小2的整数幂

第三个问题:渐进式rehash

rehash的过程为了不堵住服务,将分成几次完成。

  1. 为ht[1]分配空间,将rehashidx设为0(不进行rehash的时候值为-1)
  2. 每次对字典进行增删查改,程序将同时将rehashidx索引上的所有键值对rehash到ht[1] ,完成后rehashidx加一。
  3. 当ht[0]上的所有键值对全部完成rehash,将rehashidx设为-1。rehash完成

在rehash过程中,字典的删查改将在两个hashtable上进行,而增加操作只会在ht[1]进行。

《Redis设计与实现》阅读笔记(四)--字典的更多相关文章

  1. 论文阅读笔记四:CTPN: Detecting Text in Natural Image with Connectionist Text Proposal Network(ECCV2016)

    前面曾提到过CTPN,这里就学习一下,首先还是老套路,从论文学起吧.这里给出英文原文论文网址供大家阅读:https://arxiv.org/abs/1609.03605. CTPN,以前一直认为缩写一 ...

  2. Redis设计与实现读书笔记(二) 链表

    链表作为最基础的数据结构,在许多高级语言上已经有了很好的实现.由于redis采用C语言编写,需要自己实现链表,于是redis在adlist.h定义了链表类型.作者对于这部分没什么好说,源码比较简单,如 ...

  3. Redis设计与实现读书笔记(一) SDS

    作为redis最基础的底层数据结构之一,SDS提供了许多C风格字符串所不具备的功能,为之后redis内存管理提供了许多方便.它们分别是: 二进制安全 减少字符串长度获取时间复杂度 杜绝字符串溢出 减少 ...

  4. Redis 设计与实现读书笔记一 Redis字符串

    1 Redis 是C语言实现的 2 C字符串是 /0 结束的字符数组 3 Redis具体的动态字符串实现 /* * 保存字符串对象的结构 */ struct sdshdr { // buf 中已占用空 ...

  5. 论文阅读笔记四十九:ScratchDet: Training Single-Shot Object Detectors from Scratch(CVPR2019)

    论文原址:https://arxiv.org/abs/1810.08425 github:https://github.com/KimSoybean/ScratchDet 摘要 当前较为流行的检测算法 ...

  6. 论文阅读笔记四十四:RetinaNet:Focal Loss for Dense Object Detection(ICCV2017)

    论文原址:https://arxiv.org/abs/1708.02002 github代码:https://github.com/fizyr/keras-retinanet 摘要 目前,具有较高准确 ...

  7. 论文阅读笔记四十三:DeeperLab: Single-Shot Image Parser(CVPR2019)

    论文原址:https://arxiv.org/abs/1902.05093 github:https://github.com/lingtengqiu/Deeperlab-pytorch 摘要 本文提 ...

  8. Redis设计与实现读书笔记——简单动态字符串

    前言 项目里用到了redis数据结构,不想只是简单的调用api,这里对我的读书笔记做一下记录.原文地址: http://www.redisbook.com/en/latest/internal-dat ...

  9. SOA 面向服务架构 阅读笔记(四)

    15  SOA管理 15.1 管理指的是实现一个制约和平衡的一致过程,以确保得到期望的结果. 15.2 管理被广泛应用于人工流程和软件流程中,一旦管理失败,后果会非常严重. 15.3 SOA管理的首要 ...

  10. <<redis设计和实现>>读书笔记

    redis如何实现主从同步的高效率?? 主从复制的同步有一个命令数据的同步文本,然后利用两个不同服务器的偏移量来进行进行同步,避免每次都是全部同步(并非会保存所有的命令数据,而是会有一个缓冲区(比如1 ...

随机推荐

  1. 【MySQL学习杂记】 2017年7月13日

    1. 关于分组 当select使用groupby语法时,select返回字段集合里面除去 <使用了聚合函数的字段>.<不包含在 group by 子句的字段> 的其他字段,这些 ...

  2. python3+OpenGL环境配置

    注:示例系统环境:Windows10 64位 + Anaconda3: 1.首先登录https://www.opengl.org/resources/libraries/glut/,下载下图箭头所指的 ...

  3. DA-GAN技术【简介】【机器通过文字描述创造图像】

    [题外话:今天上课我做了一个关于DA-GAN技术的ppt演讲,写一点东西留念一下...] 转载请注明出处:https://www.cnblogs.com/GraceSkyer/p/9107471.ht ...

  4. HDU 5550 - Game Rooms(DP + 前缀和预处理)

    链接: http://acm.hdu.edu.cn/showproblem.php?pid=5550 题意: 一个大楼有n(2≤n≤4000)层,每层可以建一个乒乓球房或者一个游泳房,且每种房间在大楼 ...

  5. 1483. [HNOI2009]梦幻布丁【平衡树-splay】

    Description N个布丁摆成一行,进行M次操作.每次将某个颜色的布丁全部变成另一种颜色的,然后再询问当前一共有多少段颜色. 例如颜色分别为1,2,2,1的四个布丁一共有3段颜色. Input ...

  6. linux 使用错误总结

    1.执行./shutdown.sh或./startup.sh命令,报错”Permission denied“(用户没有权限),执行以下语句: chmod u+x *.sh

  7. IIS提示出现RPC服务器不可用的解决方法

    如果你运行IIS时也遇到“RPC服务器不可用”的故障提示,不妨试试我们下面的办法 依次点击“管理工具→服务→Remote Procedure Call→属性”,其默认启动类别是“自动”,但选项是灰色的 ...

  8. 命令行编译执行java

    命令行编译运行java程序 使用命令 javac进行编译 和 java进行执行. javac 后面跟着的是java文件的文件名,例如 HelloWorld.java. 该命令用于将 java 源文件编 ...

  9. 公司架构理解 - 千万 pv 网站

    1.面试题 - 花架构图 commander 控制台,请求处理器 crp 资源分配器 相当于仓管 .推荐系统的架构流程图和每一个模块的作用一定要了解,一般会让你一边画流程图一边讲解每个模块. 2.我自 ...

  10. Angular动态表单生成(四)

    ng-dynamic-forms实践篇(下) 我们接着上篇,先把小目标中的所有字段都定义出来 这部分就是苦力活儿了,把KendoUiComponent中的formModel完善即可: formMode ...