《Redis设计与实现》之第四章:字典

一,哈希表节点算法

哈希表节点使用dictEntry结构表示,每一个dictEntry结构都保存一个键值对。数组

typedef struct dictEntry{服务器

  //键函数

  void *key;性能

  //值ui

  union{指针

    void *val;blog

    uint64_t u64;索引

    int64_t s64;hash

  } v;

  //指向下一个哈希表节点,造成链表

  struct dictEntry *next;

}

 

二,哈希表

Redis的字典所使用的哈希表由dictht结构定义:

typedef struct dictht{

  //哈西表数组

  dictEntry **tables;

  //哈希表大小

  unsigned long size;

  //哈希表大小掩码,用来计算索引值,老是等于size-1

  unsigned long sizemask;

  //哈希表已经有的节点数量

  unsigned long used;

}

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

size记录了哈希表的大小,即table数组的大小

used记录了哈希表目前已经有的节点(键值对)的数量

sizemask和哈希值决定一个键应该被放到table数组的哪一个索引上(索引值 = hash值 / sizemask)

 

 三,字典

1. Redis字典使用的哈希表做为底层实现,一个哈希表里面能够有多个哈希表节点,每一个哈希表节点保存一个键值对。

Redis中的字典由dict结构表示:

typedef struct dict{

  //特定类型函数

  dictType *type;

  //私有数据

  void *privdata;

  //哈希表

  dictht ht[2];

  //rehash索引,当rehash不在进行时,值为-1

  int rehashidx;

}

type是一个指向dictType结构的指针,每一个dictType结构保存了一些用于操做特定类型键值对的函数,Redis会为不一样用途的字典设置不一样类型的函数

privdata保存了特定类型函数的参数

type属性和privdata属性时针对不一样类型的键值对,为建立多态字典而设置的

typedef struct dictType{

  //计算哈希值的函数

  unsigned int (*hashFunction)(const viod *key)

  //复制键的函数

  //复制值的函数

  //销毁键的函数

  //销毁值的函数

}

ht属性时一个包含两个项的数组,数组中每一个项都是一个dictht哈希表,通常状况下,字典只使用ht[0]哈希表,ht[1]哈希表只会对ht[0]哈希表rehash时才使用

rehashidx记录了rehash目前的进度,若是目前没有在进行rehash,那么它的值为-1

2. 哈希算法

当把一个新的键值对添加到字典中时,程序先根据键值对的键计算出哈希值,而后计算出索引值,最后把包含新键值对的哈希表节点放到哈希表数组的指定索引上。

使用字典设置的哈希函数,计算key的哈希值。 hash  = dict -->type --> hashFunction(key);

使用哈希表的sizemask属性和哈希值,计算出索引值。 index = hash & dict --> ht[x].sizemask;

 

3.解决键冲突

当有两个或两个以上数量的键被分配到了哈希表数组的同一个索引上面时,咱们称这些键发生了冲突。Redis的哈希表使用链地址法来解决键冲突

 

 4.rehash

为了让哈希表的负载因子维持在一个合理的范围以内,当哈希表保存的键值对数量太多或太少时,程序须要对哈希表的大小进行相应的扩展或收缩。扩展和收缩哈希表的工做能够经过rehash(从新散列)操做来完成。

5.渐进式rehash

进行rehash操做时,须要将ht[0]中全部的键值对rehash到ht[1]上。若是哈希表中有大量的数据,只用一次rehash完成操做的话,会很是消耗服务器的性能,致使服务器在一段时间内中止服务。那么如何避免对服务器形成影响呢? 这就须要渐进式rehash了。

在rehash进行期间,每次对字典执行添加,删除,查找,或更新操做时,程序除了执行指定的操做外,还会顺带执行一次rehash操做(将ht[0]哈希表在rehashidx索引上的全部键值对rehash到ht[1]上,rehash完成后,将rehashidx值增长一)。咱们每次只rehash 哈希表ht[0]的某一个索引上的键值对。

相关文章
相关标签/搜索