redis对象编码源码阅读——列表对象编码与创建
1. 列表对象的编码类型
类型 | 编码 | 对象 |
---|---|---|
REDIS_LIST | REDIS_ENCODING_ZIPLIST | 使用压缩列表对象实现的列表对象 |
REDIS_LIST | REDIS_ENCODING_LINKEDLIST | 使用双端链表实现的列表对象 |
摘自《Redis设计与实现》第63页
2. 双端链表对象的创建
robj *createListObject(void) {
list *l = listCreate();
robj *o = createObject(REDIS_LIST,l);
listSetFreeMethod(l,decrRefCountVoid);
o->encoding = REDIS_ENCODING_LINKEDLIST;
return o;
}
3. 压缩列表对象的创建
robj *createZiplistObject(void) {
unsigned char *zl = ziplistNew();
robj *o = createObject(REDIS_LIST,zl);
o->encoding = REDIS_ENCODING_ZIPLIST;
return o;
}
4. 两种编码的转换
void listTypeConvert(robj *subject, int enc) {
// 类似于 c++ 中的迭代器
listTypeIterator *li;
listTypeEntry entry;
redisAssertWithInfo(NULL,subject,subject->type == REDIS_LIST);
if (enc == REDIS_ENCODING_LINKEDLIST) {
list *l = listCreate();
listSetFreeMethod(l,decrRefCountVoid);
/* listTypeGet returns a robj with incremented refcount */
// 类似于 c++ 中的赋初值: li = subject.begin()
// 因为这里 index = 0,所以是 begin()
li = listTypeInitIterator(subject,0,REDIS_TAIL);
// 因为 ListTypeIterator 是不知道 List 的具体编码的,具体的编码被封装起来了
// 所以在求 nextNode 的时候使用了一个中间类型 listTypeEntry
// 把 nextNode 求解出来之后,再赋值到最简单的链表 list 中
while (listTypeNext(li,&entry)) listAddNodeTail(l,listTypeGet(&entry));
// 释放迭代器的空间
listTypeReleaseIterator(li);
subject->encoding = REDIS_ENCODING_LINKEDLIST;
zfree(subject->ptr);
subject->ptr = l;
} else {
redisPanic("Unsupported list conversion");
}
}