redis源码从main开始11中讲了string对象类型,本章我们来看list对象类型
12 redis对象之list
目前list对象有两种编码方式,一种是链表,一种是压缩表
#define REDIS_ENCODING_LINKEDLIST 4 /* Encoded as regular linked list */
#define REDIS_ENCODING_ZIPLIST 5 /* Encoded as ziplist */
以下为两种编码方式的list对象的创建方式
robj *createListObject(void) {
list *l = listCreate();
robj *o = createObject(REDIS_LIST,l);
listSetFreeMethod(l,decrRefCountVoid);
o->encoding = REDIS_ENCODING_LINKEDLIST;
return o;
}
robj *createZiplistObject(void) {
unsigned char *zl = ziplistNew();
robj *o = createObject(REDIS_LIST,zl);
o->encoding = REDIS_ENCODING_ZIPLIST;
return o;
}
// 下面先来看编码方式为链表的list对象的创建过程
// 双端链表的相关内容主要在dlist.c中
//第一步,首先创建一个链表list结构
list *listCreate(void)
{
struct list *list;
if ((list = zmalloc(sizeof(*list))) == NULL)
return NULL;
list->head = list->tail = NULL;
list->len = 0;
list->dup = NULL;
list->free = NULL;
list->match = NULL;
return list;
}
//链表结构体
typedef struct list {
listNode *head; // 头结点
listNode *tail; // 尾节点
void *(*dup)(void *ptr); // 一个复制函数
void (*free)(void *ptr); // 一个释放函数
int (*match)(void *ptr, void *key); // 一个对比函数
unsigned long len; // 链表节点数
} list;
//单个节点的结构
typedef struct listNode {
struct listNode *prev; // 前置节点
struct listNode *next; // 后继节点
void *value; // 节点值
} listNode;
// 第二步,接下来创建一个REDIS_LIST类型的redis对象,并把刚刚创建的list传入
robj *o = createObject(REDIS_LIST,l);
//第三步,设置list的释放函数,decrRefCountVoid是一个包装,会根据传入的redis对象类型调用对应的释放方法,此处是list对象,会调用freeListObject方法
listSetFreeMethod(l,decrRefCountVoid);
//根据编码释放列表对象, 链表列表和压缩列表对应不同释放方法
void freeListObject(robj *o) {
switch (o->encoding) {
case REDIS_ENCODING_LINKEDLIST:
listRelease((list*) o->ptr);
break;
case REDIS_ENCODING_ZIPLIST:
zfree(o->ptr);
break;
default:
redisPanic("Unknown list encoding type");
}
}
//第四步,设置编码类型为链表编码
o->encoding = REDIS_ENCODING_LINKEDLIST;
// 下面来看压缩列表
// 压缩列表的主要内容在ziplist.c中
// 可以看出与链表列表不同的是,链表列表返回的是一个双端链表的结构体,这里返回的是无符号字节
// 第一步,创建压缩列表的机构
unsigned char *ziplistNew(void) {
// 默认大小,是压缩列表头尾的大小,头大小为4+4+2字节,尾巴为1字节
unsigned int bytes = ZIPLIST_HEADER_SIZE+1;
// 分配初始化的大小
unsigned char *zl = zmalloc(bytes);
// 初始化表属性
ZIPLIST_BYTES(zl) = intrev32ifbe(bytes);
ZIPLIST_TAIL_OFFSET(zl) = intrev32ifbe(ZIPLIST_HEADER_SIZE);
ZIPLIST_LENGTH(zl) = 0;
// 设置这个压缩表的尾巴是255既二进制的11111111
zl[bytes-1] = ZIP_END;
return zl;
}
// 这里需要注意intrev32ifbe,这里redis做了一个转换
// 当宿主机是小端的时候intrev32ifbe不作处理,当宿主机是大端的时候会做大端向小端的转化
#if (BYTE_ORDER == LITTLE_ENDIAN)
#define memrev16ifbe(p)
#define memrev32ifbe(p)
#define memrev64ifbe(p)
#define intrev16ifbe(v) (v)
#define intrev32ifbe(v) (v)
#define intrev64ifbe(v) (v)
#else
#define memrev16ifbe(p) memrev16(p)
#define memrev32ifbe(p) memrev32(p)
#define memrev64ifbe(p) memrev64(p)
#define intrev16ifbe(v) intrev16(v)
#define intrev32ifbe(v) intrev32(v)
#define intrev64ifbe(v) intrev64(v)
#endif
基于版本3.0.0版本,点击下载https://download.redis.io/releases/redis-3.0.0.tar.gz
本文地址,https://www.ccagml.com/?p=410