Redis中基于hash的字典的hash算法

Redis中的hash实现。

Redis中hash表的数据结构:

typedef struct dictht{
	dictEntry **table;  //hash表数组
	unsigned long size;  //hash表大小
	unsigned long sizemask;  //hash表大小掩码,等于size-1,和hash值一起计算索引值
	unsigned long used;  //hash表中元素个数
}

其中hash数组中每一个元素指向一个dictEntry结构(hash表节点)。每个dictEntry都保存着一个键值对和一个dictEntry类型的next指针,这个指针是用来解决键冲突问题的。dictEntry的数据结构如下:

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

Redis中的字典使用hash表作为底层的实现,一个hash表里面可以有多个hash表节点,而每个hash表节点就保存的字典中的一个键值对。

字典的数据结构:

typedef struct dict{
dictType *type; //类型特定函数
void *privdate; //私有数据

dictht ht[2]; //hash表
int rehashidx; //rehash索引
}

【注】其中字典中包含两个hash表,一般情况下只使用ht[0]。在rehash时才会用到ht[1]。

hash算法:

当添加一个新的键值对到dict中时,会根据key使用hash函数计算出hash值,再根据sizemask计算出索引,然后将这个新的hashEntry节点使用头插法的方法插入到对应索引的链表中。

rehash

当hash表中的元素超过了某个阈值或者是低于某个阈值时,为了使负载因子处在一个合理的范围内,需要对hash表进行扩容或者收缩:
1.为ht[1]分配合理的空间。
2.将ht[0]中的元素rehash到ht[1]中
3.释放ht[0],将ht[1]赋值给ht[0],将ht[1]置空,为下一次rehash作准备。
【注】
1.rehash这个动作不是一次性完成的,而是渐进式完成的。在每一次查询,插入,更新或删除操作时,会根据dict中的rehashidx的值将ht[0]中对应位置的hash节点rehash到ht[1]中。直到ht[0]中所有的节点都rehash到ht[1]才会释放ht[0],将ht[1]赋值给ht[0],并将ht[1]置空。在rehash的过程中,各个操作都是基于两个hash表进行的,例如查询操作是:先在ht[0]表中查询,查不到再到ht[1]表中查询。插入操作是直接插入到ht[1]中。
2.

  • 当负载因子大于等于1(服务器没用执行BGSAVE或者BGREWRITEAOF命令)或者5时,则进行扩展操作,那么ht[1]的大小为不小于ht[0].used*2的第一个2n
  • 当负载因子小于等于0.1时,则进行收缩操作,那么ht[1]的大小为不大于ht[0].used的第一个2n
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值