今天再次来记录下hash对象的存储是什么样的,hash对象在java里是比较有意思的一个东西,虽然最底层的实现我不是很懂,但是jdk源码中关于hash的一些东西我还是比较了解的,对于hash来说,主要的就是你的hash算法是怎么保证该值落到hash槽内,并且还要保证尽可能的均匀。
hash对象的编码是ziplist或者是hashtable,和列表对象一样,也使用了ziplist,这是个神奇的东西呢,,
ziplist编码
ziplist编码的hash对象使用zip列表作为底层实现,每当有新的键值对加入到hash对象时,会先将保存的键的压缩列表节点推入到列表结尾,然后再将保存了值的压缩列表节点推入到压缩列表表尾。
1. 同一键值对的两个节点在一起。
2.先保存的在头,后保存的在尾。
hashtable编码
底层使用字典实现,hash对象中每个键值对使用一个字典值来保存。
1.字典中的每个键都是一个字符串对象,对象中保存键
2.字典中的每个值都是一个字符串对象,对象中保存值
如果上例中不是ziplist,而是hashtable,那底层就是这样的
编码转换
ziplist使用条件和列表对象一样
1.所有键值对的字符串长度都小于64字节
2.保存的键值对数量小于512个。
当然可以通过修改配置文件去改变hash-max-ziplist-value 选项和 hash-max-ziplist-entries
转换的例子不做了,跟列表对象一样。
最后贴一下实现:
表 8-9 哈希命令的实现
命令 | ziplist 编码实现方法 | hashtable 编码的实现方法 |
---|---|---|
HSET | 首先调用 ziplistPush 函数, 将键推入到压缩列表的表尾, 然后再次调用 ziplistPush 函数, 将值推入到压缩列表的表尾。 | 调用 dictAdd 函数, 将新节点添加到字典里面。 |
HGET | 首先调用 ziplistFind 函数, 在压缩列表中查找指定键所对应的节点, 然后调用 ziplistNext 函数, 将指针移动到键节点旁边的值节点, 最后返回值节点。 | 调用 dictFind 函数, 在字典中查找给定键, 然后调用 dictGetVal 函数, 返回该键所对应的值。 |
HEXISTS | 调用 ziplistFind 函数, 在压缩列表中查找指定键所对应的节点, 如果找到的话说明键值对存在, 没找到的话就说明键值对不存在。 | 调用 dictFind 函数, 在字典中查找给定键, 如果找到的话说明键值对存在, 没找到的话就说明键值对不存在。 |
HDEL | 调用 ziplistFind 函数, 在压缩列表中查找指定键所对应的节点, 然后将相应的键节点、 以及键节点旁边的值节点都删除掉。 | 调用 dictDelete 函数, 将指定键所对应的键值对从字典中删除掉。 |
HLEN | 调用 ziplistLen 函数, 取得压缩列表包含节点的总数量, 将这个数量除以 2 , 得出的结果就是压缩列表保存的键值对的数量。 | 调用 dictSize 函数, 返回字典包含的键值对数量, 这个数量就是哈希对象包含的键值对数量。 |
HGETALL | 遍历整个压缩列表, 用 ziplistGet 函数返回所有键和值(都是节点)。 | 遍历整个字典, 用 dictGetKey 函数返回字典的键, 用 dictGetVal 函数返回字典的值。 |