字典、哈希表基本数据结构

redis字典使用哈希表作为底层实现,基本结构就是数组+散列

typedef struct dictht {
// 哈希表数组
dictEntry **table;
// 哈希表数组的大小
unsigned long size;
// 掩码,用于计算新加入的元素的index(sizemask值等于size-1)
unsigned ling sizemask;
// 哈希表中已有节点的数量
unsigned long used;
} dictht;

其中,哈希表数组中的每一个节点,与1.8之前的jdk中map很相似,也是链表结构

typedef struct dictEntry {
// 键
void *key
// 值
union {
void *val;
uint64_t u64;
int64_t s64;
} v;
// 指向下个哈希表节点,形成链表
struct dictEntry *next;
} dictEntry;

最终的redis字典内部,由2个哈希表构成。平时只使用其中的一个,当需要扩展或收缩哈希表时,启用第二个,后续详细介绍

redis字典结构如下:

typedef struct dict {
dictType *type
void *privdata;
// 哈希表(实际存储数据),平时使用ht[0],当需要扩展或收缩哈希表时,将ht[0]的数据rehash到ht[1],然后释放ht[0],将ht[1]设置为ht[0],并在ht[1]新建一个空白哈希表,done
dictht ht[2];
// 是否正在执行rehash的标识,不在进行时为-1
int trehashidx;
} dictEntry;

下面介绍一些hash操作常遇到的问题:index选择、index冲突、rehash触发条件、rehash流程

index选择

index选择和jdk类似

  • 首先计算出哈希值 hash = dict -> type -> hashFunction(key);
  • 再位运算 index = hash & dict -> ht[0].sizemask;
    • 注意,这要求ht[0]的大小为2的n次幂,方便hash值被按位与到哈希表的大小里

index冲突

采用链地址方法,冲突的节点被添加在冲突链的头部。不会变成树,就是链

rehash触发条件

哈希表的扩展、收缩会触发rehash,这里和jdk不类似了

扩展条件(满足任意一个即可):

  • 负载因子(已保存节点数量ht[0].used / 哈希表大小ht[0].size) >=1、且服务器目前没有在执行 BGSAVE 或 BGREWRITEAOF
  • 负载因子 >=5、且服务器目前在执行 BGSAVE 或 BGREWRITEAOF

收缩条件:

  • 负载因子 < 0.1

rehash流程

在rehash发生之前,数据都保存在两个哈希表中的第一个ht[0]中,从这里开始rehash流程:

  1. 为ht[1]分配空间。

    • 如果是扩展,则ht[1]大小为大于等于ht[0].used * 2 的第一个2的n次幂。比如ht[0]大小为16,used为17,则扩展后大小为64
    • 如果是收缩,则ht[1]大小为大于等于ht[0].used 的第一个2的n次幂。比如ht[0]大小为128,used为10,则收缩后大小为16
  2. 将ht[0]的所有键值对rehash到ht[1],即重新计算哈希、重新计算索引、重新处理冲突
  3. 释放ht[0]
  4. 将ht[1]设置为ht[0],并在ht[1]创建一个新的空白哈希表

渐进式rehash:

当键值对很多时,一次性rehash从ht[0]到ht[1]耗时耗资源很大,redis会分多次完成ht[0]到ht[1]

  • 渐进式rehash时,新增操作直接保存到ht[1],其他入删除、更新、查找等都会先操作ht[0]再操作ht[1]

这里性能影响、如何分批还不是很清楚

redis_字典_哈希hash的更多相关文章

  1. Colored Sticks (字典树哈希+并查集+欧拉路)

    Time Limit: 5000MS   Memory Limit: 128000K Total Submissions: 27704   Accepted: 7336 Description You ...

  2. BZOJ_3573_[Hnoi2014]米特运输_树形DP+hash

    BZOJ_3573_[Hnoi2014]米特运输_树形DP+hash 题意: 给你一棵树每个点有一个权值,要求修改最少的权值,使得每个节点的权值等于其儿子的权值和且儿子的权值都相等. 分析: 首先我们 ...

  3. BZOJ_1212_[HNOI2004]L语言_哈希

    BZOJ_1212_[HNOI2004]L语言_哈希 Description 标点符号的出现晚于文字的出现,所以以前的语言都是没有标点的.现在你要处理的就是一段没有标点的文章. 一段文章T是由若干小写 ...

  4. NSDictionary实现原理-ios哈希hash和isEqual

    NSDictionary实现原理-ios哈希hash和isEqual   OC中自定义类的NSCopying实现的注意事项(isEqual & hash实现) http://blog.csdn ...

  5. 大话Java中的哈希(hash)结构(一)

    o( ̄▽ ̄)d 小伙伴们在上网或者搞程序设计的时候,总是会听到关于“哈希(hash)”的一些东西.比如哈希算法.哈希表等等的名词,那么什么是hash呢? 一.相关概念 1.hash算法:一类特殊的算法 ...

  6. Python操作redis系列以 哈希(Hash)命令详解(四)

    # -*- coding: utf-8 -*- import redis #这个redis不能用,请根据自己的需要修改 r =redis.Redis(host=") 1. Hset 命令用于 ...

  7. BZOJ_3207_花神的嘲讽计划Ⅰ_哈希+主席树

    BZOJ_3207_花神的嘲讽计划Ⅰ_哈希+主席树 Description 背景 花神是神,一大癖好就是嘲讽大J,举例如下: “哎你傻不傻的![hqz:大笨J]” “这道题又被J屎过了!!” “J这程 ...

  8. BZOJ_2124_等差子序列_线段树+Hash

    BZOJ_2124_等差子序列_线段树+Hash Description 给一个1到N的排列{Ai},询问是否存在1<=p1<p2<p3<p4<p5<…<pL ...

  9. redis 哈希(hash)函数

    哈希(hash)函数 hSet 命令/方法/函数 Adds a value to the hash stored at key. If this value is already in the has ...

随机推荐

  1. jquery中的 deferred之 then (二)

    例: var def = $.Deferred(); var prs1 = def.then(function (val) { var result = val + "_123" ...

  2. pytorch1.0 安装执行后报错ImportError: No module named future.utils

    File "/usr/local/lib/python2.7/dist-packages/caffe2/python/utils.py", line 10, in <modu ...

  3. jQuery之遍历索引相关方法

    遍历索引相关方法: .each(),补充.children() .index() 1 .each() 2..children() .index()

  4. python中list操作方法

    1,创建一个列表 只要把逗号分隔的不同的数据项使用方括号括起来即可.如下所示:复制代码 代码如下:list1 = ['physics', 'chemistry', 1997, 2000];list2 ...

  5. Android 网络编程的陷阱

    陷阱一,不要在主线程或者UI线程中建立网络连接 Androd4.0以后,不允许在主线程中建立网络连接,不然会出现莫名其妙的程序退出情况.正确的做法是在主线程中,创建新的线程来运行网络连接程序. // ...

  6. React中this.props的主要属性

    this.props主要包含:history属性.location属性.match属性 ①history属性又包含 ②location属性又包含 ③match属性又包含

  7. svn 恢复删除文件

    参考这个 https://blog.csdn.net/qdujunjie/article/details/37766167

  8. 移动端与web端的测试点的差别

    单纯从功能测试的层面上来讲的话,APP 测试.web 测试 在流程和功能测试上是没有区别的.根据两者载体不一样,则区别如下:系统结构方面web项目,b/s架构,基于浏览器的:web测试只要更新了服务器 ...

  9. Java中代理

    普通代理(最简单的代理) 需要有两个实现同一个接口的类,一个是被代理的类,一个是代理类 被代理类中我们按照自己想实现的功能重写接口中的方法 代理类中因为需要代理被代理类,所以在代理类中需要有个被代理类 ...

  10. 泛型List去除重复指定字段

    泛型List去除重复指定字段ID var list=listTemp.Distinct(new IDComparer ()).ToList(); 重写比较的方法: public class IDCom ...