字典

字典,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. DotNET中的幕后英雄:MSCOREE.DLL

    现在做.NET Framework的开发的朋友应该是越来越多了,但是可能并非人人都对MSCOREE.DLL非常了解.而事实上,毫不夸张地说,MSCOREE.DLL是.NET Framework中最为核 ...

  2. Uva1395 POJ3522 Slim Span (最小生成树)

    Description Given an undirected weighted graph G, you should find one of spanning trees specified as ...

  3. Git rebase日志

    Git日志重写 为了方便管理,最近公司git接了jira,然后开发任务需要在jira上面先建立task,然后再task上面建立分支,后面该分支就和这个task进行了绑定. 因为之前一直使用传统的svn ...

  4. P1710 地铁涨价

    题目背景 本题开O2优化,请注意常数 题目描述 博艾市除了有海底高铁连接中国大陆.台湾与日本,市区里也有很成熟的轨道交通系统.我们可以认为博艾地铁系统是一个无向连通图.博艾有N个地铁站,同时有M小段地 ...

  5. Ingress 暴露tcp端口

    有一部分应用 需要暴露tcp端口,查看官方文档 https://github.com/kubernetes/ingress-nginx/blob/master/docs/user-guide/expo ...

  6. mysql安装后找不到sock文件

    mysql rpm安装方式之后,启动找不到sock文件,经排查是之前安装的由mysql, 需要时yum list installed mysql 或者  rpm -qa |grep -i mysql ...

  7. Metapackage包

    Metapackage(功能包集)是把一些相近的功能模块. 软件包放到一起. ROS里常见的Metapacakge有: 2.Metapackage写法 CMakeLists.txt 写法如下: cma ...

  8. Spring源码分析(十)注册解析的BeanDefinition

    摘要:本文结合<Spring源码深度解析>来分析Spring 5.0.6版本的源代码.若有描述错误之处,欢迎指正. 对配置文件解析完成后,获取的beanDefiniton已经可以进行使用了 ...

  9. 使用putty进行ssh tunnel远程内网机器

    通常我们通过登录具有外网ip的远程机器来连接内网的机器:本文介绍,通过putty进行ssh tunnel,进而达到使用本机直接连接远程内网机器: 1,在putty中创建一个session,输入具有外网 ...

  10. iOS渐变导航栏封装

    由于最近开发的几个项目都有渐变导航栏,每次写的时候都要copy一堆关于导航渐变相关的代码,显得类很冗余,所以花了点时间封装了一个渐变类,直接继承就可以满足大部分需求啦,这里简单写一下心路历程: 渐变的 ...