双hash_table设计
typedef struct dict {
dictType *type;
void *privdata;
dictht ht[2];
long rehashidx;
int iterators;
} dict;
作者在dict数据类型中引入了两个hash_table,其作用是为了动态变化hash_table的大小。
按照常规操作,如果我们想要将一个hash_table的大小进行动态变化,我们需要进行两个步骤
1:改变数组大小
2:将old_hash_table内全部元素进行rehash,重新链接至new_hash_table上。
如果我们在瞬时间内完成从old_hash_table到new_hash_table的转化的话,意味着我们必须对old_hash_table的元素全部遍历一遍,这种操作显然是很费时间的,容易导致CPU在一段时间内处于一个很繁忙的状态(这里没有引入线程什么的,所以这个操作在dict内存储很多数据时,很可能致使Redis无法及时相应其他请求,而致使服务质量下降)。
因此这里引入了一个rehash
状态,表示当前字典正在进行rehash
,即将old_hash_table数据迁移至new_hash_table的状态。通过阅读源代码,我们会发现这样一个函数static void _dictRehashStep(dict *d)
。这个函数会将一部分old_hash_table的数据迁移至new_hash_table中,但不是全部。这个函数在对字典进行增、删、改、查的时候都会调用,通过这种操作我们结果了迁移过程中负载过高的问题。
并且针对rehash状态,查找会对两个表都进行key
查找,增加会将最新数据增长到new_hash_table
中去,删除查找两个表,修改则是由删除和添加两个操作组合而成。
hash_Table迭代器问题
不同于链表这种结构,hash_table如果想要遍历所有元素,不引入迭代器完全无法实现,因为hash_table的查找方式为hash(key)
的方式进行,在不知道所有key
的情况下,我们根本就无法利用这种方式查找。
所以我们必须直接针对其存储的数据结构进行查找,来实现遍历。
但是在迭代器迭代时,会发生这个问题。如果我们迭代过程中,进行了rehash
操作,那么将会造成致命的错误。因此我们作者引入了安全迭代器
和非安全迭代器
。安全迭代器
:安全迭代器进行操作时,会将rehash
操作禁用,所以可以调用增加、查找、修改等操作。ps:我觉删除操作也可能致使迭代器发生错误,不过dict
属于底层数据结构,这个应该是由上层应用去控制的,来避免删除操作跟迭代操作发生冲突。非安全迭代器
:他在迭代前会通过hash_table的状态计算fingerprint
,在他进行操作时,我们不能对hash_table做任何修改操作。如果分安全迭代器迭代完成时,hash_table状态发生了变化,意味着我们进行了不可控的操作,会执行assert(iter->fingerprint == dictFingerprint(iter->d));
。
dictScan函数
这段代码是整个程序里面最牛逼的
它实现了对动态扩展的字典的遍历,即使字典大小不断变化,他也能保证字典在遍历过程中遍历完所有的元素
其实现原理解释如下:
首先我们的key_index 的计算过程为 hash(key) & mask。
当我们有两个表时,小表为ht[0],大表为ht[1]。
一个10111的hash值,在mask1 = 111 和 mask2 = 11111时,对应的值为 111和 10111
所以,假如我们执行了rehashing操作,那么原来ht[0]111位置的数据,会迁移到ht[1] 00111,01111,10111,11111四个位置。此处为扩张操作。
同理变小一样。
这里要讨论下v的计算方式,
最开始v为0,假设mask0 = 111, mask1 = 11111。那么我们最开始找的就是以000结尾的对应的全部hash位置
000完成之后,我们需要进行的是100结尾的所有hash位置。剩下的位置依次是010, 110, 001, 101, 011,111。
让我们来看这样操作的用处,首先000, 100。执行完毕后,保证了以00结尾的hash全部扫面完成,000,100,010,110,保证了以0结尾的hash全部完毕.
这样当我们在计算v = 100时,此时我们进行了表的收缩,mask0 变为了 00, mask1 变为了111。
此时我们会对ht[0]的00结尾进行搜索,ht的[100],[000]进行搜索。由此我们可以看出为什么ht的遍历会出现重复情况,也看出为什么v的增长方式要这样进行
来源:CSDN
作者:劲蜡鸡腿堡
链接:https://blog.csdn.net/qq_37654704/article/details/103962365