redis List底层数据实现
redis列表使用两种数据结构左为底层实现:
1.双端链表
2.压缩列表
今天我们来介绍redis中的双端链表,在前边的数据结构章节中已经介绍了通用双端链表的实现,在redis数据库中,双端链表还被很多内部模块所应用:
1.事务模块使用双端链表依序保存输入的命令;
2.服务器模块使用双端链表来保存多个客户端;
3.订阅/发送模块使用双端链表来保存订阅模式的多个客户端;
4.事件模块使用双端链表来保存时间事件(time event);
在redis的双端链表中,数据结构可以分为两个部分,一个是控制信息,一个是链表节点信息。
关于redis双端链表的定义和实现在其根目录src/adlist.c和src/adlist.h上进行定义和实现。
//链表控制信息
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;
//迭代器的迭代方向
#define AL_START_HEAD 0
#define AL_START_TAIL 1
值的一提的是链表的遍历操作采用的是迭代器操作,关于迭代器的定义如下所示:
//迭代器定义
typedef struct listIter {
listNode *next;
int direction;
} listIter;
不过比较其他开源库的迭代器设计,redis的迭代器设计并不算优雅,在博客<5.数据结构之通用动态数组>章节中,我们介绍了acl库中迭代器的操作,有兴趣的同学可以参考一下。
redis把指针的操作封装成了宏的类型,方便了程序员的使用,不过如果你习惯指针写法也可以采用指针的方式:
//宏定义操作
#define listLength(l) ((l)->len)
#define listFirst(l) ((l)->head)
#define listLast(l) ((l)->tail)
#define listPrevNode(n) ((n)->prev)
#define listNextNode(n) ((n)->next)
#define listNodeValue(n) ((n)->value)
#define listSetDupMethod(l,m) ((l)->dup = (m))
#define listSetFreeMethod(l,m) ((l)->free = (m))
#define listSetMatchMethod(l,m) ((l)->match = (m))
#define listGetDupMethod(l) ((l)->dup)
#define listGetFree(l) ((l)->free)
#define listGetMatchMethod(l) ((l)->match)
redis通用双端链表接口
//接口声明
list *listCreate(void) ; //链表的创建
void listRelease(list *list) ; //链表的释放
list *listAddNodeHead(list *list, void *value); //链表的头部添加
list *listAddNodeTail(list *list, void *value); //链表的尾部添加
list *listInsertNode(list *list, listNode *old_node, void *value, int after); //链表的节点插入
void listDelNode(list *list, listNode *node) ; //链表节点删除
listIter *listGetIterator(list *list, int direction) ; //初始化链表迭代器(可以通过direction调整初始化方向,头部或者尾部)
listNode *listNext(listIter *iter) ; //链表的下一个节点(有direction确定是向前遍历还是向后遍历)
void listReleaseIterator(listIter *iter) ; //链表迭代器的释放
list *listDup(list *orig) ; //链表的拷贝
listNode *listSearchKey(list *