Redis中的数据结构 (12)

哈希对象的底层实现有两种, 一种是dict, 一种是ziplist. 分别对应编码HT与ZIPLIST. 而之前介绍的zipmap这种结构, 虽然也是一种轻量级的字典结构, 且纵使在源代码中有相应的编码宏值, 但遗憾的是, 至Redis 4.0.10, 目前哈希对象的底层编码仍然只有ziplist与dict两种

dict自不必说, 本身就是字典类型, 存储键值对的. 用ziplist作为底层数据结构时, 是将键值对以<key1><value1><key2><value2>...<keyn><valuen>这样的形式存储在ziplist中的. 两种编码内存布局分别如下:

hashObject

上图中不严谨的地方有:

ziplist中每个entry, 除了键与值本身的二进制数据, 还包括其它字段, 图中没有画出来

dict底层可能持有两个dictht实例

没有画出dict的哈希冲突

需要注意的是: 当采用HT编码, 即使用dict作为哈希对象的底层数据结构时, 键与值均是以sds的形式存储的.

哈希对象的相关接口如下:

分类 API名 功能
创建接口   robj *createHashObject(void)   创建一个空哈希对象
底层编码使用ZIPLIST, 即底层使用ziplist
 
释放接口   void freeHashObject(robj *o)   释放哈希对象
若哈希对象底层使用的是dict, 则调用dictRelease释放这个dict
若哈希对象底层使用的是ziplist, 则直接释放掉这个ziplist占用的连续内存空间
 
编码转换接口   void hashTypeConvertZiplist(robj *o, int enc)   将哈希对象的编码从ZIPLIST转换为HT, 即底层实现从ziplist转为dict  
--   void hashTypeConvert(robj *o, int enc)   转换哈希对象的编码.
虽然接口设计的好像可以在底层编码之间互相转换, 但实际上这个接口的实现, 目前仅支持从ZIPLIST转向HT
 
--   void hashTypeTryConversion(robj *o,robj **argv,int start,int end)   o是一个哈希对象. argv是其它对象的数组.(最好是字符串对象, 且为SDS实现)
这个函数会检查argv数组中, 从start到end之间的所有对象, 如果这些对象中, 但凡有一个对象是字符串对象, 且长度超过了用ziplist实现哈希对象时, ziplist的限长
那么o这个哈希对象的编码就会从ZIPLIST转为HT
 
读写接口   int hashTypeSet(robj *o,sds field,sds value,int flags)   向哈希对象写入一个键值对.
在底层编码为HT时, flag将影响插入键值对时的具体行为. flag可有标志位 HASH_SET_TAKE_VALUE与HASH_SET_TAKE_FIELD, 若对应位置1, 代表键与值直接引用参数值. 否则代表要调用sdsdup接口拷贝键与值.
在底层编码为ZIPLIST时, 键与值必然会被拷贝
 
--   int hashTypeExists(robj *o, sds field)   查询指定键在哈希对象中是否存在  
--   unsigned long hashTypeLength(const robj *o)   查询哈希对象中的键值对总数  
--   int hashTypeGetFromZiplist(robj *o, sds field,unsigned char **vstr,unsigned int *vlen,long long *vll)   从编码为ZIPLIST的哈希对象中, 取出一个键对应的值.
键从field传入, 当值为数值类型时, 值以*vll传出, 当值为二进制类型时, 值以*vstr与*vlen传出
 
--   sds hashTypeGetFromHashTable(robj *o, sds field)   从编码为HT的哈希对象中, 取出一个键对应的值.
键从field传入, 值以返回值传出. 若值不存在, 返回NULL"
 
--   "int hashTypeGetValue(robj *o,sds field,unsigned char **vstr,unsigned int *vlen,long long *vll)   取出哈希对象中指定键对应的值. 若值是数值类型, 则以*vll传出, 否则以*vstr与*vlen传出  
--   robj *hashTypeGetValueObject(robj *o, sds field)   取出哈希对象中指定键对应的值, 并包装成RedisObject返回. 返回的对象为字符串对象  
--   size_t hashTypeGetValueLength(robj *o, sds field)   取出哈希对象中指定键对应的值的长度  
--   int hashTypeDelete(robj *o, sds field)   删除哈希对象中的一个键值对. 键不存在时返回0, 成功删除返回1  
迭代器接口   hashTypeIterator *hashTypeInitIterator(robj *subject)   在指定哈希对象上创建一个迭代器  
--   void hashTypeReleaseIterator(hashTypeIterator *hi)   释放哈希对象的迭代器  
--   int hashTypeNext(hashTypeIterator *hi)   让哈希迭代器步进一步  
--   void hashTypeCurrentFromZiplist(hashTypeIterator *hi,int what,unsigned char **vstr,unsigned int *vlen,long long *vll)   取出哈希对象迭代器当前指向的键 或值. 当what传入OBJ_HASH_KEY时, 取的是键, 否则取的是值.
注意, 该函数仅在哈希对象的编码为ZIPLIST时才能正确运行
 
--   sds hashTypeCurrentFromHashTable(hashTypeIterator *hi,int what)   取出哈希对象迭代器当前指向的键 或值. 当what传入OBJ_HASH_KEY时, 取的是键, 否则取的是值.
注意, 该函数仅在哈希对象的编码为HT时才能正确运行
 
--   void hashTypeCurrentObject(hashTypeIterator *hi,int what,unsigned char **vstr,unsigned int *vlen,long long *vll)   取出哈希对象迭代器当前指向的键或值. 当what传入OBJ_HASH_KEY时, 取的是键, 否则取的是值.  
--   sds hashTypeCurrentObjectNewSds(hashTypeIterator *hi,int what)   取出哈希对象迭代器当前指向的键或值. 且把键或值以一个全新的SDS字符串返回. 当what传入OBJ_HASH_KEY时, 取的是键, 否则取的是值.  
3.3 列表对象

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zyzpsx.html