3、字典

概念

一种用于保存键值对的抽象数据结构。又常被称作 符号表、关联数组、映射。Redis的数据库就是使用字典作为底层实现的、字典还是哈希键的底层实现之一。

实现

由于字典底层是有哈希表(分清哈希表和哈希键)实现,首先介绍哈希表

1、哈希表

typedef struct dictht{
    dictEntry **table;        //指向哈希表数组
    unsigned long size;       //hash表大小,上述数组的长度
    unsigned long sizemark;   //哈希表掩码,用于计算索引值,大小恒为size-1
    unsigned long used;       //已有的节点数量
}dictht;

索引计算方法,假设hash值为8,size=4,sizemark=3,index = 8&3=0;

算法主页:点击打开链接

2、hash表节点(键值对+指向下一个节点的next指针),next指针将多个hash值相同的键值对连接在一起,以此解决键冲突的问题,这种方法称为“链地址法”。为了速度考虑,总是将新节点添加到链表的表头位置。

3、字典

typedef struct dict{
    dictType *type;    //类型特定函数
    void *privdata;    //私有数据,保存传给那些类型特定函数的可选参数,这两个参数是为了实现多态而实现的
    dictht ht[2];      //hash表,平时只用ht[0],ht[1]是在rehash时候使用的
    int trehashidx;    //rehash索引,没有进行rehash的时候,值为-1;记录rehash的进度
}

rehash

首先了解一下负载因子,load_fact = ht[0].used/ht[0].size    //节点数量/hash表的大小

为什么要rehash:hash表中保存的键会增多或者减少,需要将负载因子维护在一个合理的范围中。

rehash的步骤:1、为ht[1]分配空间,这个空间大小取决于即将执行的操作和键值对的数量(ht[0].used)

                                如果是扩展操作,ht[1]的大小为大于等于ht[0].used*2的最小的2的整数次幂

                                如果是收缩操作,ht[1]的大小为大于等于ht[0].used的2的最小的整数次幂

                         2、重新计算hash值,将键值对摆放到ht[1]中

                         3、释放ht[0],将ht[1]置为ht[0],在ht[1]创建空白hash表,为下一次rehash做准备

rehash的影响因素:load_fact,BGSAVE和BGREWRITEAOF是否正在执行,后两者的执行是作为redis的子进程运行的,这时redis会提高负载上限,避免在子进程存在期间进行rehash。

渐进式rehash

概念:为了避免造成服务器性能上的影响,分批次的rehash;

即同时持有ht[0]和ht[1],在每次执行增删该查的操作后,对ht[0]rehash索引处的所有键值对进行rehash操作。所以,渐进式rehash过程中,所有的操作是发生在两张hash表中的,但是所有的新增节点都会被放在ht[1]上。把rehash均摊到了每次的操作上。

猜你喜欢

转载自blog.csdn.net/qq_24888697/article/details/81003785
今日推荐