列表对象的创建API依然支持从ziplist的实例创建一个列表对象, 即你可以创建一个底层编码为ZIPLIST的列表对象, 但如果用该列表对象去调用任何其它列表对象的API, 都会导致panic. 在使用之前, 你只能再次调用相关的底层编码转换接口, 将这个列表对象的底层编码转换为QUICKLIST.
并且遗憾的是, LINKEDLIST这种编码, 即底层为list的列表, 被彻底淘汰了. 也就是说, 截止目前(Redis 4.0.10), Redis定义的10个对象编码方式宏名中, 有两个被完全闲置了, 分别是: OBJ_ENCODING_ZIPMAP与OBJ_ENCODING_LINKEDLIST. 从Redis的演进历史上来看, 前者是后续可能会得到支持的编码值, 后者则应该是被彻底淘汰了.
列表对象的内存布局如下图所示:
列表对象的API接口如下:
分类 API名 功能创建接口 robj *createQuicklistObject(void) 创建一个列表对象. 内部编码为QUICKLIST
即内部使用quicklist实现的列表对象
-- robj *createZiplistObject(void) 创建一个列表对象. 内部编码为ZIPLIST
即内部使用ziplist实现的列表对象
释放接口 void freeListObject(robj *o) 释放一个列表对象
编码转换接口 void listTypeConvert(robj *subject, int enc) 转换列表对象的内部编码.
虽然接口设计的好你可以在底层编码之间互相转换, 但实际上这个接口的实现, 目前仅支持从ZIPLIST转换为QUICKLIST
并且蛋疼的是, 4.0.10这个版本中, 所有的列表对象操作API内部实现都仅支持编码方式为QUICKLIST的列表对象, 其它编码方式会panic.
所以目前为止, 这个API的唯一作用, 就是配合createZiplistObject接口, 来使用一个ziplist创建一个内部编码为QUICKLIST的列表对象.
读写接口 void listTypePush(robj *subject,robj *value,int where) 向列表对象中添加一个数据.
由where参数的值控制是在头部添加, 还是尾部添加.
where可选的值为LIST_HEAD, LIST_TAIL
-- robj *listTypePop(robj *subject,int where) 从列表对象的头部或尾部取出一个数据.
取出的数据通过被包装成字符串对象后返回. 具体取出位置通过参数where控制
-- unsigned long listTypeLength(const robj *subject) 获取列表对象中保存的数据的个数
-- void listTypeInsert(listTypeEntry *entry,robj *value, int where) 将字符串对象中的数据插入到列表对象的头部或尾部.
插入过程中不会拷贝字符串对象持有的数据本身. 但会缩减字符串对象的引用计数.
-- int listTypeEqual(listTypeEntry *entry, robj *o) 判断字符串对象o与列表对象中指定位置上存储的数据是否相同.
-- robj *listTypeGet(listTypeEntry *entry) 获取列表对象中指定位置的数据.
位置信息通过entry传入, 这是一个入参. 数据将拷贝一份后通过SDS形式返回
迭代器接口 listTypeIterator *listTypeInitIterator(robj *subject,long index,unsigned char direction) 创建一个列表对象迭代器
-- void listTypeReleaseIterator(listTypeIterator *li) 释放一个列表对象迭代器
-- int listTypeNext( listTypeIterator *li, listTypeEntry *entry) 让列表对象迭代器步进一步, 并将步进之前迭代器所指向的数据保存在entry中
-- void listTypeDelete( listTypeIterator *iter, listTypeEntry *entry) 删除列表迭代器当前指向的列表对象中存储的数据.
被删除的数据通过entry返回
3.4 集合对象