Redis源码阅读-list双向链表
链表提供了高效的节点重排能力,以及顺序节点访问方式,并且节点的删除,增加都很灵活方便,但是Redis使用的C语言并不内置这种数据结构,所以Redis在adlist文件中实现了list,list在Redis中的应用非常广泛,如列表键,发布与订阅,慢查询,监视器等功能都用到了链表,Redis服务器本身也是用list来保存多个客户端的状态信息。链表的实现在adlist.h,adlist.c文件中。
list本体的实现
可以看到list中定义了三个数据类型,节点类型listNode,迭代器类型listIter,链表类型list。这些和一般的list没有什么不同,不做分析。可以关注一下,list结构体中的三个自定义函数:dup,free,match。
宏定义实现的函数
Redis中大量的使用了宏定义,此处是几个以宏实现的函数。特别是对于三个自定义函数的使用,值得思考。
创建链表
清空链表/删除链表
在链表头部添加节点
在某节点前或后插入新节点
插入一个节点有点意思,我大概分析了一下,在node后面插入newnode的步骤
//先设newnode的prev和next。
//1.newnode->next=node->next;
//2.newnode->prev=node;
//再更新tail节点
//3.if(node==list->tail)list->tail=newnode;
//再更新newnode的前后节点指向的位置。
//4.newnode->next->pre=newnode;
//5.newnode->prev->next=newnode;
删除节点
//删除某一节点
void listDelNode(list *list, listNode *node)
{
//删除节点不为头节点
if (node->prev)
node->prev->next = node->next;
else//为头节点需要改变头节点指向
list->head = node->next;
//删除节点不为尾结点
if (node->next)
node->next->prev = node->prev;
else//为尾结点需要改变尾结点指向
list->tail = node->prev;
//如果定义了节点的free函数,调用free函数
if (list->free) list->free(node->value);
zfree(node);
list->len--;
}
迭代器操作
获取迭代器
//获取迭代器
listIter *listGetIterator(list *list, int direction)
{
listIter *iter;
if ((iter = zmalloc(sizeof(*iter))